From: <roa...@us...> - 2011-07-15 01:56:54
|
Revision: 7515 http://planeshift.svn.sourceforge.net/planeshift/?rev=7515&view=rev Author: roanduku Date: 2011-07-15 01:56:48 +0000 (Fri, 15 Jul 2011) Log Message: ----------- Added "triberecipes" command in npcclient, which list all active recipes for a tribe. Added the methods and mechanics which handle the recipe order and choosing in a tribe. Modified Paths: -------------- soc/2011/tribe/data/npcbehave.xml soc/2011/tribe/src/npcclient/command.cpp soc/2011/tribe/src/npcclient/npc.cpp soc/2011/tribe/src/npcclient/npcclient.cpp soc/2011/tribe/src/npcclient/npcclient.h 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 Modified: soc/2011/tribe/data/npcbehave.xml =================================================================== --- soc/2011/tribe/data/npcbehave.xml 2011-07-14 20:23:27 UTC (rev 7514) +++ soc/2011/tribe/data/npcbehave.xml 2011-07-15 01:56:48 UTC (rev 7515) @@ -389,7 +389,7 @@ </npctype> <npctype name="AbstractTribesman" vel="2.5"> - <behavior name="do nothing" initial="80"> + <behavior name="do nothing" initial="80" resume="yes"> <wait anim="stand" duration="100" /> </behavior> <behavior name="peace_meet" completion_decay="100"> Modified: soc/2011/tribe/src/npcclient/command.cpp =================================================================== --- soc/2011/tribe/src/npcclient/command.cpp 2011-07-14 20:23:27 UTC (rev 7514) +++ soc/2011/tribe/src/npcclient/command.cpp 2011-07-15 01:56:48 UTC (rev 7515) @@ -104,6 +104,12 @@ return 0; } +int com_triberecipes(char *arg) +{ + npcclient->ListTribeRecipes(arg); + return 0; +} + int com_waypointlist(char *arg) { npcclient->ListWaypoints(arg); @@ -122,7 +128,6 @@ return 0; } - int com_locationtest(char *line) { WordArray words(line,false); @@ -430,6 +435,7 @@ { "showlogs", false, com_showlogs, "Show server logs" }, { "showtime", false, com_showtime, "Show the current game time"}, { "tribelist", false, com_tribelist, "List all known tribes (tribelist [pattern])"}, + { "triberecipes", false, com_triberecipes, "List all recipes in a tribe. (triberecipes [tribeid])"}, { "waypointlist", false, com_waypointlist, "List all known waypoints (waypointlist [pattern])"}, { "status", false, com_status, "Give some general statistics on the npcclient"}, { 0, 0, 0, 0 } Modified: soc/2011/tribe/src/npcclient/npc.cpp =================================================================== --- soc/2011/tribe/src/npcclient/npc.cpp 2011-07-14 20:23:27 UTC (rev 7514) +++ soc/2011/tribe/src/npcclient/npc.cpp 2011-07-15 01:56:48 UTC (rev 7515) @@ -415,7 +415,6 @@ } } - Printf(15,"Got event %s",pcpt->ToString().GetData() ); brain->FirePerception(this, pcpt); } Modified: soc/2011/tribe/src/npcclient/npcclient.cpp =================================================================== --- soc/2011/tribe/src/npcclient/npcclient.cpp 2011-07-14 20:23:27 UTC (rev 7514) +++ soc/2011/tribe/src/npcclient/npcclient.cpp 2011-07-15 01:56:48 UTC (rev 7515) @@ -1582,6 +1582,18 @@ } } +void psNPCClient::ListTribeRecipes(const char* tribeID) +{ + int tribeid = atoi(tribeID); + for(int i=0;i<tribes.GetSize();i++) + { + if(tribeid == tribes[i]->GetID()) + tribes[i]->DumpRecipesToConsole(); + return; + } + CPrintf(CON_CMDOUTPUT, "No Tribe with id '%d' found.\n", tribeID); +} + void psNPCClient::ListWaypoints(const char * pattern) { pathNetwork->ListWaypoints(pattern); Modified: soc/2011/tribe/src/npcclient/npcclient.h =================================================================== --- soc/2011/tribe/src/npcclient/npcclient.h 2011-07-14 20:23:27 UTC (rev 7514) +++ soc/2011/tribe/src/npcclient/npcclient.h 2011-07-15 01:56:48 UTC (rev 7515) @@ -366,6 +366,11 @@ * List all tribes matching pattern to console. */ void ListTribes(const char* pattern); + + /** + * List all the active recipes in a tribe + */ + void ListTribeRecipes(const char* tribeID); /** * List all waypoints matching pattern to console. Modified: soc/2011/tribe/src/npcclient/recipe.cpp =================================================================== --- soc/2011/tribe/src/npcclient/recipe.cpp 2011-07-14 20:23:27 UTC (rev 7514) +++ soc/2011/tribe/src/npcclient/recipe.cpp 2011-07-15 01:56:48 UTC (rev 7515) @@ -43,10 +43,10 @@ Recipe::Recipe() { - id = -1; - name = ""; - persistent = false; - unique = false; + id = -1; + name = ""; + persistence = false; + unique = false; } bool Recipe::Load(iResultRow &row) @@ -58,7 +58,7 @@ name = row["name"]; // Set persistance - if(pers == 1) persistent = true; + if(pers == 1) persistence = true; // Set unique if(isUnique == 1) unique = true; @@ -123,7 +123,7 @@ CPrintf(CON_NOTIFY, "Name: %s \n", name.GetData()); DumpAlgorithm(); DumpRequirements(); - CPrintf(CON_NOTIFY, "Persistent: %d \n", persistent); + CPrintf(CON_NOTIFY, "Persistent: %d \n", persistence); CPrintf(CON_NOTIFY, "Unique: %d \n", unique); } @@ -223,9 +223,10 @@ CreateGlobalNPCType(tribe); } -void RecipeManager::ParseFunction(csString function, Tribe* tribe) +bool RecipeManager::ParseFunction(csString function, Tribe* tribe) { // TODO - Do actions in respect of the primitives + return true; // Remove this later :)) csStringArray functionParts; csString functionBody; @@ -245,15 +246,16 @@ } else { - Error2("Unknown function primitive: %s\n. Bail.", functionBody.GetData()); + Error2("Unknown function primitive: %s. Bail.\n", functionBody.GetData()); exit(1); } + + // If we got here then the function was completed + return true; } bool RecipeManager::ParseRequirement(Recipe::Requirement requirement, Tribe* tribe) { - // TODO - Check requirements in the given tribe - // Check type of requirement and do something for each if(requirement.type == REQ_TYPE_TRIBESMAN) { @@ -284,25 +286,6 @@ } } -void RecipeManager::FollowRecipe(Recipe* recipe, int tribeID) -{ - // TODO - // Add another array keeping a structure about - // recipes being used by tribes. - // Not sure this method will be kept -} - -csArray<RMAnswer> RecipeManager::ComputeNPCs(Tribe* tribe) -{ - // TODO -- Will assign the number of npcs (and their type) required for a recipe - csArray<RMAnswer> testArray; - RMAnswer test; - test.npcNumbers = 1; - test.memberType = 1; - testArray.Push(test); - return testArray; -} - void RecipeManager::CreateGlobalNPCType(Tribe* tribe) { csString assembledType; @@ -314,28 +297,23 @@ assembledType.Append(tribe->GetID()); assembledType.Append("\" parent=\"AbstractTribesman\">"); - //TODO -- Add reactions based on traits // Aggressivity Trait if(currentTribe->aggressivity == "warlike") { - reaction = "<react event=\"player nearby\" behavior=\"aggressive_meet\" delta=\"150\" />"; - reaction = "<react event=\"damage\" behavior=\"aggressive_meet\" delta=\"150\" />"; + reaction = "<react event=\"player anyrange\" behavior=\"aggressive_meet\" delta=\"150\" />"; + reaction = "<react event=\"attack\" behavior=\"aggressive_meet\" delta=\"150\" />"; assembledType += reaction; } else if(currentTribe->aggressivity == "pacifist") { - // TODO - // Add attack when attacked - reaction = "<react event=\"player nearby\" behavior=\"peace_meet\" delta=\"100\" />\n"; - reaction += "<react event=\"damage\" behavior=\"normal_attacked\" delta=\"150\" />"; + reaction = "<react event=\"player anyrange\" behavior=\"peace_meet\" delta=\"100\" />\n"; + reaction += "<react event=\"attack\" behavior=\"normal_attacked\" delta=\"150\" />"; assembledType += reaction; } else if(currentTribe->aggressivity == "coward") { - // TODO - // Add flee in panic - reaction = "<react event=\"player nearby\" behavior=\"peace_meet\" delta=\"100\" />\n"; - reaction += "<react event=\"damage\" behavior=\"coward_attacked\" delta=\"100\" />\n"; + reaction = "<react event=\"player anyrange\" behavior=\"peace_meet\" delta=\"100\" />\n"; + reaction += "<react event=\"attack\" behavior=\"coward_attacked\" delta=\"100\" />\n"; assembledType += reaction; } else @@ -349,7 +327,7 @@ if(currentTribe->unity != "cowards") { // Tell tribe to help - reaction = "<react event=\"damage\" behavior=\"united_attacked\" delta=\"100\" />"; + reaction = "<react event=\"attack\" behavior=\"united_attacked\" delta=\"100\" />"; assembledType += reaction; } @@ -376,8 +354,37 @@ currentTribe->global = assembledType; } -void RecipeManager::Update() +int RecipeManager::ApplyRecipe(Recipe* recipe, Tribe* tribe, int step) { + csArray<RMAnswer> answer; + csArray<Recipe::Requirement> requirements = recipe->GetRequirements(); + csStringArray algorithm = recipe->GetAlgorithm(); + csString function; + + // Check all requirements + for(int i=0;i<requirements.GetSize();i++) + { + if(!ParseRequirement(requirements[i], tribe)) + return -2; + } + + // If we got here it means requirements are met + + // Execute Algorithm + for(int i=step;i<algorithm.GetSize();i++) + { + function = algorithm.Get(i); + // If algorithm step needs wait time, signal it and return the step + if(!ParseFunction(function, tribe)) + return i; + } + + // If we reached the end of the algorithm then it is completed + return -1; +} + +void RecipeManager::Update(Tribe* tribe) +{ // TODO // Watch the recipes currently in-progress and update tribe + tribeData. } Modified: soc/2011/tribe/src/npcclient/recipe.h =================================================================== --- soc/2011/tribe/src/npcclient/recipe.h 2011-07-14 20:23:27 UTC (rev 7514) +++ soc/2011/tribe/src/npcclient/recipe.h 2011-07-15 01:56:48 UTC (rev 7515) @@ -50,8 +50,8 @@ #define REQ_TYPE_RECIPE 4 /** -* Structure that keeps the data returned to the tribe -*/ + * Structure that keeps the data returned to the tribe + */ struct RMAnswer { NPCType* computedType; ///< Keeps the computed npctype @@ -60,8 +60,8 @@ }; /** -* This object represents recipes for the tribe AI. -*/ + * This object represents recipes for the tribe AI. + */ class Recipe { @@ -74,9 +74,6 @@ int quantity; ///< Number needed. }; - bool persistent; ///< True if the recipe never ends - bool unique; ///< True if the recipe can be done only once - /** Construct a Recipe object */ Recipe(); @@ -103,7 +100,16 @@ /** Getter for Recipe's Algorithm */ csStringArray GetAlgorithm() { return algorithm; } + + /** Getter for Persistance */ + bool IsPersistent() { return persistence; } + + /** Getter for Requirements */ + csArray<Requirement> GetRequirements() { return requirements; } + private: + bool persistence; ///< True if recipe never ends + bool unique; ///< True if recipe is unique int id; csString name; csArray<Requirement> requirements; ///< Keeps all the requirements for this recipe. @@ -111,22 +117,21 @@ int steps; ///< Number of steps the algorithm has. }; - /** -* Class that represents the Recipe Manager of the game. -* This object loads and stores all the recipes in-game. It also -* keeps track of the progress the tribes have in their recipes -* and triggers changes in tribes once recipes are completed. -*/ + * Class that represents the Recipe Manager of the game. + * This object loads and stores all the recipes in-game. It also + * keeps track of the progress the tribes have in their recipes + * and triggers changes in tribes once recipes are completed. + */ class RecipeManager { public: /** Keeps details of all tribes enrolled in the manager */ struct TribeData { - int tribeID; - Recipe* tribalRecipe; ///< Recipe keeping tribe information - int currentStep; ///< Keeps the step the tribe is currently at in the recipe. + int tribeID; + Recipe* tribalRecipe; ///< Recipe keeping tribe information + int currentStep; ///< Keeps the step the tribe is currently at in the recipe. // Tribe Traits csString aggressivity; @@ -164,18 +169,6 @@ */ void AddTribe(Tribe *tribe); - /** Computes NPCTypes - * - * Receives the needlist from the tribe and computes - * the required NPCTypes and the actions needed done - * to achieve the recipe. - * - * @param needs The need list of the tribe. - * @param tribeID The id of the tribe we're doing the work. - * @return An array of 'Answer' data structures for the tribe to apply. - */ - csArray<RMAnswer> ComputeNPCs(Tribe* tribe); - /** Compute global npctype * * Computes a global part of an npctype for each tribe. The global @@ -196,8 +189,9 @@ * * @param function String containing a function and it's arguments * @param tribe The tribe on which to apply the changes + * @return True if function is done, false if it needs wait time. */ - void ParseFunction(csString function, Tribe* tribe); + bool ParseFunction(csString function, Tribe* tribe); /** Check Requirement * @@ -211,18 +205,19 @@ */ bool ParseRequirement(Recipe::Requirement requirement, Tribe* tribe); - /** Follow Recipe + /** Apply Recipe * - * Follows the execution of a recipe inside a tribe and - * updates tribe data accordingly. + * Applies a recipe to a tribe. * - * @param recipe The recipe to follow. - * @param tribeID The id of the tribe that's applying the recipe. - */ - void FollowRecipe(Recipe* recipe, int tribeID); + * @param recipe The recipe to be applied. + * @param tribe The tribe on which to apply + * @param step The step on which to start + * @return The step on which the algorithm stopped, or -1 if completed. + */ + int ApplyRecipe(Recipe* recipe, Tribe* tribe, int step); /** Update the status of the recipes and the tribe data */ - void Update(); + void Update(Tribe* tribe); /** Get pointer to recipe based on ID */ Recipe* GetRecipe(int recipeID); Modified: soc/2011/tribe/src/npcclient/tribe.cpp =================================================================== --- soc/2011/tribe/src/npcclient/tribe.cpp 2011-07-14 20:23:27 UTC (rev 7514) +++ soc/2011/tribe/src/npcclient/tribe.cpp 2011-07-15 01:56:48 UTC (rev 7515) @@ -67,7 +67,14 @@ id = row.GetInt("id"); name = row["name"]; // Add tribal recipe - activeRecipes.Push(recipeManager->GetRecipe(row.GetInt("tribal_recipe"))); + RecipeData tribalRecipe; + tribalRecipe.recipe = recipeManager->GetRecipe(row.GetInt("tribal_recipe")); + tribalRecipe.cost = 0; + tribalRecipe.priority = 0; + tribalRecipe.persistent = tribalRecipe.recipe->IsPersistent(); + tribalRecipe.parentRecipe = NULL; + tribalRecipe.wait = -1; // All persistent recipes should have -1 + activeRecipes.Push(tribalRecipe); homePos = csVector3(row.GetFloat("home_x"),row.GetFloat("home_y"),row.GetFloat("home_z")); homeRadius = row.GetFloat("home_radius"); @@ -480,6 +487,34 @@ lastGrowth = when; } + // Recipe Content + // We'll set decreaseValue according to the scale we want to use + int decreaseValue = 1; + + // Update recipes wait period according to the given delta value + UpdateRecipeData(decreaseValue); + + // Get most important recipe and apply it if wait time <= 0 + RecipeData bestRecipe = GetHighestRecipe(); + + if(bestRecipe.wait <= 0) + { + bestRecipe.nextStep = recipeManager->ApplyRecipe(bestRecipe.recipe, + this, bestRecipe.nextStep); + } + + // If nextStep is -1, the recipe is completed + if(bestRecipe.nextStep == -1) + { + DeleteRecipe(bestRecipe.recipe); + } + // If nextStep is -2, the recipe still has unmet requirements + else if(bestRecipe.nextStep = -2) + { + bestRecipe.nextStep = 0; + } + + // End of recipe Content for (size_t i=0; i < members.GetSize(); i++) { @@ -489,6 +524,7 @@ if ((behavior && strcasecmp(behavior->GetName(),npcIdleBehavior.GetDataSafe())==0) || (!npc->IsAlive()) ) + //if(!npc->IsAlive()) { csString perc; @@ -1078,6 +1114,70 @@ } } +void Tribe::UpdateRecipeData(int delta) +{ + for(int i=0;i<activeRecipes.GetSize();i++) + { + if(!activeRecipes[i].persistent) + { + activeRecipes[i].wait -= delta; + } + } +} + +void Tribe::AddRecipe(Recipe* recipe, Recipe* parentRecipe) +{ + RecipeData newRecipe; + newRecipe.recipe = recipe; + newRecipe.parentRecipe = parentRecipe; + newRecipe.cost = 0; // TODO - Assign costs + newRecipe.persistent = recipe->IsPersistent(); + newRecipe.priority = -1; + + // In case we have an orphan recipe + if(parentRecipe == NULL) + { + newRecipe.priority = 0; + } + + // Get the priority + for(int i=0;i<activeRecipes.GetSize();i++) + { + if(activeRecipes[i].recipe->GetID() == parentRecipe->GetID()) + { + newRecipe.priority = activeRecipes[i].priority + 1; + } + } + + activeRecipes.Push(newRecipe); +} + +void Tribe::DeleteRecipe(Recipe* recipe) +{ + // Check just in case + if(recipe->IsPersistent()) return; + + for(int i=0;i<activeRecipes.GetSize();i++) + { + if(activeRecipes[i].recipe->GetID() == recipe->GetID()) + activeRecipes.DeleteIndex(i); + } +} + +RecipeData Tribe::GetHighestRecipe() +{ + RecipeData copy; + copy = activeRecipes[0]; + for(int i=0;i<activeRecipes.GetSize();i++) + { + if(activeRecipes[i].priority > copy.priority) + { + copy = activeRecipes[i]; + } + } + return copy; +} + bool Tribe::CheckKnowledge(csString knowHow) { for(int i=0;i<knowledge.GetSize();i++) @@ -1108,3 +1208,18 @@ } } +void Tribe::DumpRecipesToConsole() +{ + CPrintf(CON_CMDOUTPUT, "+----------------------------------+\n"); + CPrintf(CON_CMDOUTPUT, "| No | ID | Name |Pers|\n"); + CPrintf(CON_CMDOUTPUT, "+----------------------------------+\n"); + for(int i=0;i<activeRecipes.GetSize();i++) + { + CPrintf(CON_CMDOUTPUT, "|%4d|%4d|%19s|%4d|\n", + (i+1), + activeRecipes[i].recipe->GetID(), + activeRecipes[i].recipe->GetName().GetData(), + activeRecipes[i].persistent); + } + CPrintf(CON_CMDOUTPUT, "+----------------------------------+\n"); +} Modified: soc/2011/tribe/src/npcclient/tribe.h =================================================================== --- soc/2011/tribe/src/npcclient/tribe.h 2011-07-14 20:23:27 UTC (rev 7514) +++ soc/2011/tribe/src/npcclient/tribe.h 2011-07-15 01:56:48 UTC (rev 7515) @@ -23,6 +23,7 @@ // Crystal Space Includes //============================================================================= #include <csutil/array.h> +#include <csutil/priorityqueue.h> #include <csutil/list.h> #include <csgeom/vector3.h> #include <iengine/sector.h> @@ -53,8 +54,26 @@ struct RMAnswer; +/** + * Structure containing data about recipes used by tribes + */ +struct RecipeData +{ + Recipe* recipe; ///< The Recipe this data is about + int cost; ///< Computed cost for this recipe + int priority; ///< Priority of this recipe + bool persistent; ///< True if recipe is persistent + Recipe* parentRecipe; ///< Parent recipe who depends on this one + csArray<Recipe*> brotherRecipes; ///< Recipes of the same level + int wait; ///< Wait time... recipe in progress. + int nextStep; ///< Next step that needs execution +}; + #define TRIBE_UNLIMITED_SIZE 100 +/** + * Class used to define a Tribal Object + */ class Tribe : public ScopedTimerCB { public: @@ -86,7 +105,7 @@ PID pid; uint32_t tribeMemberType; ///< Used to select needSet by index. }; - + /** Construct a new tribe object */ Tribe(EventManager* eventmngr); @@ -366,7 +385,7 @@ void SetRecipeManager(RecipeManager* rm) { recipeManager = rm; } /** Gets the id of this recipe */ - Recipe* GetTribalRecipe() { return activeRecipes[0]; } + Recipe* GetTribalRecipe() { return activeRecipes[0].recipe; } /** Assign NPCTypes to NPC * @@ -378,8 +397,27 @@ void AssignNPCs(csArray<RMAnswer> data); /** Gets the recipe array */ - csArray<Recipe*> GetActiveRecipes() { return activeRecipes; } + csArray<RecipeData> GetActiveRecipes() { return activeRecipes; } + /** Gets the highest recipe (in respect of priority) */ + RecipeData GetHighestRecipe(); + + /** Updates recipe wait times */ + void UpdateRecipeData(int delta); + + /** Add a recipe + * + * Adds a recipe to activeRecipes array in respect of it's + * priority and cost. + * + * @param recipe Recipe to add. + * @param parentRecipe Recipe that requires the new recipe. + */ + void AddRecipe(Recipe* recipe, Recipe* parentRecipe); + + /** Delete a recipe -- used when recipe is completed */ + void DeleteRecipe(Recipe* recipe); + /** Add a knowledge token */ void AddKnowledge(csString knowHow) { knowledge.Push(knowHow); } @@ -388,6 +426,9 @@ /** Save a knowledge piece in the database */ void SaveKnowledge(csString knowHow); + + /** Dumps all information about recipes to console */ + void DumpRecipesToConsole(); protected: @@ -438,7 +479,7 @@ EventManager* eventManager; ///< Link to the event manager RecipeManager* recipeManager; ///< The Recipe Manager handling this tribe - csArray<Recipe*> activeRecipes; ///< List of active recipes of this tribe + csArray<RecipeData> activeRecipes; ///< List of active recipes of this tribe }; #endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |