From: <roa...@us...> - 2011-08-01 21:52:03
|
Revision: 7575 http://planeshift.svn.sourceforge.net/planeshift/?rev=7575&view=rev Author: roanduku Date: 2011-08-01 21:51:56 +0000 (Mon, 01 Aug 2011) Log Message: ----------- Finished coding the requirements check and function execution for recipe data. Added a pre-parser method in RecipeManager to allow dynamic data in recipe scripting. (E.g. REPRODUCTION_RESOURCE will be replaced by the tribe's main resource) Modified the contents of tribe_recipes tables. Still it will need more data to produce examples. Modified Paths: -------------- soc/2011/tribe/data/npcbehave.xml soc/2011/tribe/src/npcclient/recipe.cpp soc/2011/tribe/src/npcclient/recipe.h soc/2011/tribe/src/npcclient/tribe.cpp soc/2011/tribe/src/npcclient/tribe.h soc/2011/tribe/src/server/database/mysql/tribe_recipes.sql Modified: soc/2011/tribe/data/npcbehave.xml =================================================================== --- soc/2011/tribe/data/npcbehave.xml 2011-08-01 20:54:43 UTC (rev 7574) +++ soc/2011/tribe/data/npcbehave.xml 2011-08-01 21:51:56 UTC (rev 7575) @@ -393,29 +393,32 @@ <wait anim="stand" duration="100" /> </behavior> <behavior name="peace_meet" completion_decay="100"> - <locate obj="perception" /> + <locate obj="target" /> <emote cmd="/bow" /> </behavior> <behavior name="aggressive_meet" completion_decay="150"> - <locate obj="enemy" /> - <melee seek_range="10" melee_range="2" /> + <locate obj="target" /> + <melee seek_range="20" melee_range="3" /> </behavior> <behavior name="coward_attacked" decay="10"> <emote cmd="/me flees in panic." /> <wander anim="walk" /> </behavior> <behavior name="normal_attacked" decay="10"> - <locate obj="enemy" /> - <melee seek_range="10" melee_range="2" /> + <locate obj="target" /> + <melee seek_range="20" melee_range="3" /> </behavior> <behavior name="united_attacked" decay="10"> <locate obj="enemy" /> <percept event="tribesman attacked" target="tribe" /> - <melee seek_range="10" melee_range="2" /> + <melee seek_range="20" melee_range="3" /> </behavior> + <behavior name="Chase" initial="0" growth="0" decay="1" complection_decay="-1" > + <chase type="target" chase_range="20" anim="run" vel="5" /> + </behavior> <behavior name="GoToWork" loop="yes" resume="yes" resume="yes"> <locate obj="tribe:memory:activeBuilding" /> - <moveto coords="tribe:memory:activeCoord" anim="walk" /> + <moveto coords="tribe:memory:activeLocation" anim="walk" /> <wander anim="walk" /> </behavior> <behavior name="Explore" completion_decay="100" resume="yes"> @@ -453,7 +456,7 @@ <resurrect /> </behavior> <behavior name="Guard" resume="yes"> - <locate obj="tribe:memory:activeCoord" /> + <locate obj="tribe:memory:activeLocation" /> <wander anim="walk" /> <circle anim="walk" radius="2" /> </behavior> @@ -463,6 +466,8 @@ <react event="tribe:gather" behavior="GatherResource" delta="100" /> <react event="tribe:breed" behavior="Breed" delta="100" /> <react event="tribe:explore" behavior="Explore" delta="100" /> + <react event="target out of range" behavior="Chase" /> + <react event="target out of chase" behavior="Chase" absolute="0" only_interrupt="chase" /> </npctype> <npctype name="MineingTribe" vel="2.5"> Modified: soc/2011/tribe/src/npcclient/recipe.cpp =================================================================== --- soc/2011/tribe/src/npcclient/recipe.cpp 2011-08-01 20:54:43 UTC (rev 7574) +++ soc/2011/tribe/src/npcclient/recipe.cpp 2011-08-01 21:51:56 UTC (rev 7575) @@ -109,8 +109,7 @@ } newReq.name = explodedReq.Get(1); - newReq.quantity = atoi(explodedReq.Get(2)); - // TODO -- find a better solution for this + newReq.quantity = explodedReq.Get(2); requirements.Push(newReq); } @@ -148,6 +147,20 @@ eventmanager = eventManager; } +csString RecipeManager::Preparse(csString function, Tribe* tribe) +{ + csString container; + + container.Append(tribe->GetReproductionCost()); + function.ReplaceAll("REPRODUCTION_COST", container.GetData()); + + container = ""; + container.Append(tribe->GetNeededResource()); + function.ReplaceAll("REPRODUCTION_RESOURCE", container.GetData()); + + // TODO -- Add more if required +} + bool RecipeManager::LoadRecipes() { Result rs(db->Select("SELECT * FROM tribe_recipes")); @@ -163,7 +176,6 @@ Recipe* newRecipe = new Recipe; recipes.Push(newRecipe); newRecipe->Load(rs[i]); - //newRecipe->Dump(); //TODO - remove } CPrintf(CON_NOTIFY, "Recipes loaded.\n"); return true; @@ -205,6 +217,11 @@ { newTribe.sleepPeriod = keywords.Get(1); } + else if(strcmp(keywords.Get(0), "loadRecipe") == 0) + { + Recipe* newRecipe = GetRecipe(csString(keywords.Get(1))); + tribe->AddRecipe(newRecipe, newTribe.tribalRecipe); + } else { Error2("Unknown tribe stat: '%s'. Abandon ship.", keywords[0]); exit(1); @@ -223,11 +240,9 @@ CreateGlobalNPCType(tribe); } -bool RecipeManager::ParseFunction(csString function, Tribe* tribe) +bool RecipeManager::ParseFunction(csString function, Tribe* tribe, csArray<NPC*> npcs) { - // TODO - Do actions in respect of the primitives - return true; // Remove this later :)) - + return true; // Remove After We have Enough Database Content csStringArray functionParts; csString functionBody; csStringArray functionArguments; @@ -236,14 +251,43 @@ functionBody = functionParts.Get(0); functionArguments.SplitString(functionParts.Get(1), ","); - if(functionBody == "someFunction") + if(functionBody == "alterResource") { - // Do Something + tribe->AddResource(functionArguments.Get(0), atoi(functionArguments.Get(1))); } - else if(functionBody == "someOtherFunction") + else if(functionBody == "go") { - // Do Something else + tribe->SendPerception("tribe:gotowork", npcs); } + else if(functionBody == "locateMemory" || functionBody == "locateResource") + { + tribe->LoadActiveLocation(functionArguments.Get(0)); + } + else if(functionBody == "addKnowledge") + { + tribe->AddKnowledge(functionArguments.Get(0)); + } + else if(functionBody == "addBuilding") + { + tribe->SpawnBuilding(functionArguments.Get(0)); + } + else if(functionBody == "attack") + { + tribe->SendPerception("tribe:attack", npcs); + } + else if(functionBody == "gather") + { + tribe->SendPerception("tribe:gather", npcs); + } + else if(functionBody == "mine") + { + tribe->SendPerception("tribe:mine", npcs); + } + else if(functionBody == "select") + { + npcs.Empty(); + npcs = tribe->SelectNPCs(functionArguments.Get(0), functionArguments.Get(1)); + } else { Error2("Unknown function primitive: %s. Bail.\n", functionBody.GetData()); @@ -254,30 +298,50 @@ return true; } -bool RecipeManager::ParseRequirement(Recipe::Requirement requirement, Tribe* tribe) +bool RecipeManager::ParseRequirement(Recipe::Requirement requirement, Tribe* tribe, Recipe* recipe) { + csString name = Preparse(requirement.name, tribe); + int quantity = atoi(Preparse(requirement.quantity, tribe)); + // Check type of requirement and do something for each if(requirement.type == REQ_TYPE_TRIBESMAN) { - // Check to see if enough tribesman - // of type 'requirement.name' are available + if(tribe->CheckMembers(name, quantity)) + return true; + + // If false + // Spawn more members or wait for them to be free //TODO + return false; } else if(requirement.type == REQ_TYPE_RESOURCE) { - // Check to see if enough resources - // of type 'requirement.name' are available + if(tribe->CheckResource(name, quantity)) + return true; + + // Mine more resources of this kind // TODO + return false; } else if(requirement.type == REQ_TYPE_ITEM) { - // Idem above. + if(tribe->CheckItems(name, quantity)) + return true; + + // Get more of these items // TODO + return false; } else if(requirement.type == REQ_TYPE_KNOWLEDGE) { - // Idem above. + if(tribe->CheckKnowledge(name)) + return true; + + // Get this knowledge // TODO + return false; } else if(requirement.type == REQ_TYPE_RECIPE) { - // Idem above. + Recipe* required = GetRecipe(name); + tribe->AddRecipe(required, recipe); + return true; } else { @@ -360,11 +424,14 @@ csArray<Recipe::Requirement> requirements = recipe->GetRequirements(); csStringArray algorithm = recipe->GetAlgorithm(); csString function; + // selectedNPCs will keep the npcs required for the recipe + // It is used so that the ParseFunction method can fire perceptions on them + csArray<NPC*> selectedNPCs; // Check all requirements for(int i=0;i<requirements.GetSize();i++) { - if(!ParseRequirement(requirements[i], tribe)) + if(!ParseRequirement(requirements[i], tribe, recipe)) return -2; } @@ -375,7 +442,7 @@ { function = algorithm.Get(i); // If algorithm step needs wait time, signal it and return the step - if(!ParseFunction(function, tribe)) + if(!ParseFunction(function, tribe, selectedNPCs)) return i; } Modified: soc/2011/tribe/src/npcclient/recipe.h =================================================================== --- soc/2011/tribe/src/npcclient/recipe.h 2011-08-01 20:54:43 UTC (rev 7574) +++ soc/2011/tribe/src/npcclient/recipe.h 2011-08-01 21:51:56 UTC (rev 7575) @@ -71,7 +71,7 @@ { int type; ///< Type. Can be workforce, resource, item, knowledge csString name; ///< Name of the requirement. - int quantity; ///< Number needed. + csString quantity; ///< Number needed. }; /** Construct a Recipe object */ @@ -156,6 +156,18 @@ /** Destruct the Recipe Manager */ virtual ~RecipeManager() { }; + /** Preparser + * + * Method to preparse the scripts in recipes in order + * to replace variables used while scripting. + * E.g. GROW_RESOURCE, HOME + * + * @param function The function to preparse + * @param tribe The tribe from which values are needed + * @return The preparsed text with actual values + */ + csString Preparse(csString function, Tribe* tribe); + /** Loads all recipes from the database */ bool LoadRecipes(); @@ -189,9 +201,10 @@ * * @param function String containing a function and it's arguments * @param tribe The tribe on which to apply the changes + * @param npcs The list of npcs to send perceptions to * @return True if function is done, false if it needs wait time. */ - bool ParseFunction(csString function, Tribe* tribe); + bool ParseFunction(csString function, Tribe* tribe, csArray<NPC*> npcs); /** Check Requirement * @@ -201,9 +214,10 @@ * * @param requirement Data structure containing requirement * @param tribe Tribe to check requirements on + * @param recipe The recipe this requirement belongs to * @return True if all requirements are met, false otherwise. */ - bool ParseRequirement(Recipe::Requirement requirement, Tribe* tribe); + bool ParseRequirement(Recipe::Requirement requirement, Tribe* tribe, Recipe* recipe); /** Apply Recipe * Modified: soc/2011/tribe/src/npcclient/tribe.cpp =================================================================== --- soc/2011/tribe/src/npcclient/tribe.cpp 2011-08-01 20:54:43 UTC (rev 7574) +++ soc/2011/tribe/src/npcclient/tribe.cpp 2011-08-01 21:51:56 UTC (rev 7575) @@ -497,7 +497,7 @@ // Get most important recipe and apply it if wait time <= 0 RecipeData bestRecipe = GetHighestRecipe(); - if(bestRecipe.wait <= 0) + if(bestRecipe.wait <= 0 || !bestRecipe.persistent) { bestRecipe.nextStep = recipeManager->ApplyRecipe(bestRecipe.recipe, this, bestRecipe.nextStep); @@ -524,7 +524,6 @@ if ((behavior && strcasecmp(behavior->GetName(),npcIdleBehavior.GetDataSafe())==0) || (!npc->IsAlive()) ) - //if(!npc->IsAlive()) { csString perc; @@ -748,7 +747,7 @@ bool Tribe::GetResource(NPC* npc, csVector3 startPos, iSector * startSector, csVector3& locatedPos, iSector* &locatedSector, float range, bool random) { float locatedRange=0.0; - Tribe::Memory * memory = NULL; + Tribe::Memory* memory = NULL; if (psGetRandom(100) > 10) // 10% chance for go explor a new resource arae { @@ -1057,6 +1056,15 @@ } } +void Tribe::SendPerception(const char* pcpt, csArray<NPC*> npcs) +{ + Perception perception(pcpt); + for(int i=0;i<npcs.GetSize();i++) + { + members[i]->TriggerEvent(&perception, -1, NULL, NULL, false); + } +} + gemNPCActor* Tribe::GetMostHated(NPC* npc, float range, bool includeInvisible, bool includeInvincible, float* hate) { float mostHatedAmount = 0.0; @@ -1223,3 +1231,73 @@ } CPrintf(CON_CMDOUTPUT, "+----------------------------------+\n"); } + +void Tribe::LoadActiveLocation(const char* name) +{ + Memory* activeLocation = FindMemory("activeLocation"); + delete activeLocation; + activeLocation = FindMemory(csString(name)); +} + +bool Tribe::CheckMembers(csString name, int number) +{ + // TODO Filter the search only for a kind of npcs (explorers, warriors, etc) + for(int i=0;i<members.GetSize();i++) + { + if(strcmp(members[i]->GetCurrentBehavior()->GetName(), "do nothing") == 0) + { + number--; + } + if(number == 0) + return true; + } + // We don't have enough members + if(number != 0) + { + return false; + } +} + +bool Tribe::CheckResource(csString resource, int number) +{ + for(int i=0;i<resources.GetSize();i++) + { + if(resources[i].name == resource) + { + if(resources[i].amount >= number) + return true; + } + } + return false; +} + +bool Tribe::CheckItems(csString items, int number) +{ + // TODO -- Implement Tribal Items + return true; +} + +void Tribe::SpawnBuilding(const char* building) +{ + // TODO -- Select a suitable place for the building + // and drop it on the ground +} + +csArray<NPC*> Tribe::SelectNPCs(const char* type, const char* number) +{ + int count = atoi(number); + csArray<NPC*> npcs; + for(int i=0;i<members.GetSize();i++) + { + // if( ~checkType~ ) + if(strcmp(members[i]->GetCurrentBehavior()->GetName(), "do nothing") == 0) + { + count--; + npcs.Push(members[i]); + } + if(count == 0) + return npcs; + } + + return npcs; +} Modified: soc/2011/tribe/src/npcclient/tribe.h =================================================================== --- soc/2011/tribe/src/npcclient/tribe.h 2011-08-01 20:54:43 UTC (rev 7574) +++ soc/2011/tribe/src/npcclient/tribe.h 2011-08-01 21:51:56 UTC (rev 7575) @@ -346,6 +346,16 @@ void TriggerEvent(Perception* pcpt, float maxRange=-1.0, csVector3* basePos=NULL, iSector* baseSector=NULL); + /** Sends the given perception to the given list of npcs + * + * Used by the recipe manager to send perceptions to tribe members + * selected by the active recipe. + * + * @param pcpt The perception name to be sent + * @param npcs The list of npcs to send perception to. + */ + void SendPerception(const char* pcpt, csArray<NPC*> npcs); + /** Find the most hated entity for tribe within range * * Check the hate list and retrive most hated entity within range @@ -429,6 +439,29 @@ /** Dumps all information about recipes to console */ void DumpRecipesToConsole(); + + /** Loads a location + * + * Loads a location in the activeLocation memory buffer. + * + * @param name Name of the memory/resource to load. + */ + void LoadActiveLocation(const char* name); + + /** Check to see if enough members are idle */ + bool CheckMembers(csString name, int number); + + /** Check to see if enough resources are available */ + bool CheckResource(csString resource, int number); + + /** Check to see if enough items are available */ + bool CheckItems(csString items, int number); + + /** Spawn a building */ + void SpawnBuilding(const char* building); + + /** Returns pointers to required npcs for a task */ + csArray<NPC*> SelectNPCs(const char* type, const char* number); protected: Modified: soc/2011/tribe/src/server/database/mysql/tribe_recipes.sql =================================================================== --- soc/2011/tribe/src/server/database/mysql/tribe_recipes.sql 2011-08-01 20:54:43 UTC (rev 7574) +++ soc/2011/tribe/src/server/database/mysql/tribe_recipes.sql 2011-08-01 21:51:56 UTC (rev 7575) @@ -18,6 +18,8 @@ # Dumping test data for recipe table # -INSERT INTO `tribe_recipes` VALUES (1, 'Mine Coal', 'tribesman(gatherer,1);item(pickaxe,1);', 'goToMemory(coal);equip(pickaxe);dig;goHome;alterResource(coal,1);', 0, 0); -INSERT INTO `tribe_recipes` VALUES (2, 'Build Well', 'tribesman(builder,3);item(shovel,3);', 'selectLocation(x,y,z);goTo(x,y,z);alterResource(food,-1);dig;alterResource(food,-2);addBuilding(well);', 0, 0); -INSERT INTO `tribe_recipes` VALUES (3, 'tribe_mining', ' ', 'brain(civilised);aggressivity(pacifist);growth(conservatory);unity(organised);', 1, 1); +INSERT INTO `tribe_recipes` VALUES (1, 'tribe_mining', ' ', 'brain(civilised);aggressivity(pacifist);growth(conservatory);unity(organised);', 1, 1); +INSERT INTO `tribe_recipes` VALUES (2, 'mate', 'resource(REPRODUCTION_RESOURCE,REPRODUCTION_COST);tribesman(any,1);', 'goHome();mate();wait(20);addMember();', 0, 0); +INSERT INTO `tribe_recipes` VALUES (3, 'Dig Resource', 'tribesman(miner,1)', 'locateResource(ACTIVE_RESOURCE);go();mine();', 0, 0); +INSERT INTO `tribe_recipes` VALUES (4, 'Gather Resource', 'tribesman(gatherer,1)', 'loadResource(ACTIVE_RESOURCE);go();gather();', 0, 0); +INSERT INTO `tribe_recipes` VALUES (5, 'Build Hut', 'tribesman(builder,1);resource(REPRODUCTION_RESOURCE, 30)', 'addBuilding(hut);alterResource(REPRODUCTION_RESOURCE, 30);locateMemory(ACTIVE_BUILDING);go();wait(50);', 0, 0); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |