RESULT BehaviorManager::PushBehaviorOnToGameObject( IN HBehavior hBehavior, IN HGameObject hGameObject, IN StateMachineQueue queue ) { RESULT rval = S_OK; string gameObjectName = ""; Behavior* pBehavior = GetObjectPointer( hBehavior ); if (pBehavior) { GOMan.GetName( hGameObject, &gameObjectName ); RETAILMSG(ZONE_STATEMACHINE | ZONE_VERBOSE, "BehaviorManager::PushBehaviorOnToGameObject( \"%s\", \"%s\", queue: %d )", pBehavior->GetName().c_str(), gameObjectName.c_str(), queue); CHR(pBehavior->BindToGameObject( hGameObject, queue )); } else { rval = E_FAIL; } Exit: if (FAILED(rval)) { RETAILMSG(ZONE_ERROR, "ERROR: BehaviorManager::PushBehaviorOnToGameObject( \"%s\", \"%s\" ): Behavior or GO not found", pBehavior ? pBehavior->GetName().c_str() : "NULL", gameObjectName.c_str()); } return rval; }
void Object::UnserializeFrom(gd::Project & project, const SerializerElement & element) { //Name and type are already loaded. objectVariables.UnserializeFrom(element.GetChild("variables", 0, "Variables")); //Compatibility with GD <= 3.3 if (element.HasChild("Automatism")) { for (std::size_t i = 0; i < element.GetChildrenCount("Automatism"); ++i) { SerializerElement & behaviorElement = element.GetChild("Automatism", i); gd::String autoType = behaviorElement.GetStringAttribute("type", "", "Type") .FindAndReplace("Automatism", "Behavior"); gd::String autoName = behaviorElement.GetStringAttribute("name", "", "Name"); Behavior* behavior = project.CreateBehavior(autoType); if ( behavior != NULL ) { behavior->SetName(autoName); behavior->UnserializeFrom(behaviorElement); behaviors[behavior->GetName()] = behavior; } else std::cout << "WARNING: Unknown behavior " << autoType << std::endl; } } //End of compatibility code else { SerializerElement & behaviorsElement = element.GetChild("behaviors", 0, "automatisms"); behaviorsElement.ConsiderAsArrayOf("behavior", "automatism"); for (std::size_t i = 0; i < behaviorsElement.GetChildrenCount(); ++i) { SerializerElement & behaviorElement = behaviorsElement.GetChild(i); gd::String autoType = behaviorElement.GetStringAttribute("type") .FindAndReplace("Automatism", "Behavior"); //Compatibility with GD <= 4 gd::String autoName = behaviorElement.GetStringAttribute("name"); Behavior* behavior = project.CreateBehavior(autoType); if ( behavior != NULL ) { behavior->SetName(autoName); behavior->UnserializeFrom(behaviorElement); behaviors[behavior->GetName()] = behavior; } else std::cout << "WARNING: Unknown behavior " << autoType << std::endl; } } DoUnserializeFrom(project, element); }
gd::Behavior * Object::AddNewBehavior(gd::Project & project, const gd::String & type, const gd::String & name) { Behavior * behavior = project.GetCurrentPlatform().CreateBehavior(type); if ( behavior != NULL ) { behavior->SetName(name); behaviors[behavior->GetName()] = behavior; } return behavior; }
RESULT BehaviorManager::Init( IN const string& settingsFilename ) { RETAILMSG(ZONE_INFO, "BehaviorManager::Init( %s )", settingsFilename.c_str()); RESULT rval = S_OK; char path[MAX_PATH]; // // Create a Settings object and load the file. // Settings mySettings; if ( FAILED(mySettings.Read( settingsFilename )) ) { RETAILMSG(ZONE_ERROR, "ERROR: BehaviorManager::Init( %s ): failed to load settings file", settingsFilename.c_str() ); return E_UNEXPECTED; } // // Create each Behavior. // UINT32 numBehaviors = mySettings.GetInt("/Behaviors.NumBehaviors"); for (int i = 0; i < numBehaviors; ++i) { sprintf(path, "/Behaviors/Behavior%d", i); //DEBUGMSG(ZONE_INFO, "Loading [%s]", path); Behavior *pBehavior = NULL; CreateBehavior( &mySettings, path, &pBehavior ); if (!pBehavior) { RETAILMSG(ZONE_ERROR, "ERROR: BehaviorManager::Init( %s ): failed to create Behavior", path); // Continue loading other Behaviors rather than aborting. continue; } //DEBUGMSG(ZONE_Behavior, "Created Behavior [%s]", pBehavior->GetName().c_str()); CHR(Add(pBehavior->GetName(), pBehavior)); } Exit: return rval; }
csArray<NPC*> Tribe::SelectNPCs(const csString &type, const char* number) { int count = atoi(number); csArray<NPC*> npcs; bool selectAny = type.CompareNoCase("any"); // Loop all members. Check for type and if they are idle. for(size_t i=0; i<members.GetSize(); i++) { NPC* member = members[i]; if((member->GetTribeMemberType() != type) && !selectAny) { // Just skip any members of wrong type. continue; } Behavior* currentBehavior = member->GetCurrentBehavior(); if(!currentBehavior) { // Newly created NPC or some malfunction. // Just skip and try this npc next loop. continue; } if(strcasecmp(currentBehavior->GetName(),npcIdleBehavior.GetDataSafe())==0) { count--; npcs.Push(member); } // Check if we found the number requested if(count == 0) return npcs; } // Return what we found return npcs; }
bool NPCType::Load(iResultRow &row) { csString parents = row.GetString("parents"); if(!parents.IsEmpty()) // this npctype is a subclass of another npctype { csArray<csString> parent = psSplit(parents,','); for(size_t i = 0; i < parent.GetSize(); i++) { NPCType *superclass = npcclient->FindNPCType(parent[i]); if(superclass) { DeepCopy(*superclass); // This pulls everything from the parent into this one. } else { Error2("Specified parent npctype '%s' could not be found.", parent[i].GetDataSafe()); return false; } } } name = row.GetString("name"); if(name.Length() == 0) { Error1("NPCType has no name attribute. Error in DB"); return false; } ang_vel = row.GetFloat("ang_vel"); csString velStr = row.GetString("vel"); velStr.Upcase(); if(velStr.IsEmpty()) { // Do nothing. Use velSource from constructor default value // or as inherited from superclass. } else if(velStr == "$WALK") { velSource = VEL_WALK; } else if (velStr == "$RUN") { velSource = VEL_RUN; } else if(row.GetFloat("vel")) { velSource = VEL_USER; vel = row.GetFloat("vel"); } collisionPerception = row.GetString("collision"); outOfBoundsPerception = row.GetString("out_of_ounds"); inBoundsPerception = row.GetString("in_bounds"); fallingPerception = row.GetString("falling"); csRef<iDocumentSystem> xml = csPtr<iDocumentSystem>(new csTinyDocumentSystem); csRef<iDocument> doc = xml->CreateDocument(); const char* error = doc->Parse(row.GetString("script")); if(error) { Error3("NPCType script parsing error:%s in %s", error, name.GetData()); return false; } csRef<iDocumentNode> node = doc->GetRoot(); if(!node) { Error2("No XML root in npc type script of %s", name.GetData()); return false; } // Now read in behaviors and reactions csRef<iDocumentNodeIterator> iter = node->GetNodes(); while(iter->HasNext()) { csRef<iDocumentNode> node = iter->Next(); if(node->GetType() != CS_NODE_ELEMENT) continue; // This is a widget so read it's factory to create it. if(strcmp(node->GetValue(), "behavior") == 0) { Behavior *b = new Behavior; if(!b->Load(node)) { Error3("Could not load behavior '%s'. Error in DB XML in node '%s'.", b->GetName(),node->GetValue()); delete b; return false; } behaviors.Add(b); Debug3(LOG_STARTUP,0, "Added behavior '%s' to type %s.\n",b->GetName(),name.GetData() ); } else if(strcmp( node->GetValue(), "react" ) == 0) { Reaction *r = new Reaction; if(!r->Load(node,behaviors)) { Error1("Could not load reaction. Error in DB XML"); delete r; return false; } // check for duplicates and keeps the last one for(size_t i=0; i<reactions.GetSize(); i++) { // Same event with same type if(!strcmp(reactions[i]->GetEventType(),r->GetEventType())&& (reactions[i]->type == r->type)&& (reactions[i]->values == r->values)) { // Check if there is a mach in affected for(size_t k=0; k< r->affected.GetSize(); k++) { for(size_t j=0; j< reactions[i]->affected.GetSize(); j++) { if(!strcmp(r->affected[k]->GetName(),reactions[i]->affected[j]->GetName())) { // Should probably delete and clear out here // to allow for overiding of event,affected pairs. // Though now give error, until needed. Error4("Reaction of type '%s' already connected to '%s' in '%s'", r->GetEventType(),reactions[i]->affected[j]->GetName(), name.GetDataSafe()); return false; // delete reactions[i]; //reactions.DeleteIndex(i); //break; } } } } } reactions.Insert(0,r); // reactions get inserted at beginning so subclass ones take precedence over superclass. } else { Error1("Node under NPCType is not 'behavior' or 'react'. Error in DB XML"); return false; } } return true; // success }
void Tribe::Advance(csTicks when, EventManager* eventmgr) { int delta = when - lastAdvance; if(delta < 0) // Handle wrappover of tick { delta = 250; // We just set it to the event timer. } lastAdvance = when; // Manage Wealth if(when - lastGrowth > 1000) { float growth; // We need to help tribes that have no members with some resources // so that they can spawn the first entity if(AliveCount() <= 0 && CountResource(wealthResourceName) < reproductionCost) { growth = wealthResourceGrowth; } else if(CountResource(wealthResourceName) < wealthResourceGrowthActiveLimit) { // Some tribes need constant growth in wealth, though capped to a limit // to prevent tribes with no strain on the resources to grow // infinit in wealth growth = wealthResourceGrowthActive; } else { growth = 0; } // Now calculate the growth. Adding what part that wasn't added // the last time this code where run. accWealthGrowth += growth* ((when - lastGrowth)/1000.0); int amount = int(floor(accWealthGrowth)); accWealthGrowth -= amount; if(amount != 0) AddResource(wealthResourceName, amount); lastGrowth = when; } else if(when - lastGrowth < 0) // Handle wrappoer of tick { lastGrowth = when; } // And manage tribe assignments csString perc; int decreaseValue = delta; // Set it to change the scale on recipe wait times // Manage cyclic recipes for(size_t i=0; i<cyclicRecipes.GetSize(); i++) { cyclicRecipes[i].timeLeft -= decreaseValue; if(cyclicRecipes[i].timeLeft <= 0) { // Add the recipe and reset counter RecipeTreeNode* newNode = new RecipeTreeNode(cyclicRecipes[i].recipe, 0); tribalRecipe->AddChild(newNode); newNode->priority = CYCLIC_RECIPE_PRIORITY; cyclicRecipes[i].timeLeft = cyclicRecipes[i].timeTotal; } } // Manage standard recipes for(size_t i=0; i < members.GetSize(); i++) { NPC* npc = members[i]; Behavior* behavior = npc->GetCurrentBehavior(); // For dead npcs just resurrect them if(!npc->IsAlive()) { // Issue the resurrect perception if we have enough // resources perc = "tribe:resurrect"; Perception pcpt(perc); if(AliveCount() == 0 && (CountResource(wealthResourceName) >= 10 * reproductionCost)) { AddResource(wealthResourceName, -10*reproductionCost); npc->TriggerEvent(&pcpt); } else if(CanGrow()) { AddResource(wealthResourceName,-reproductionCost); npc->TriggerEvent(&pcpt); } continue; } // If we have any npcs with no assignments then // we can parse recipes and send them to work if(behavior && strcasecmp(behavior->GetName(),npcIdleBehavior.GetDataSafe())==0) { RDebug(this, 5, "*** Found Idle NPC %s(%s) checking recipes ***", npc->GetName(),ShowID(npc->GetEID())); // Update recipes wait times UpdateRecipeData(decreaseValue); // Get best recipe. (highest level, no wait time) RecipeTreeNode* bestRecipe = tribalRecipe->GetNextRecipe(); if(!bestRecipe) { // Something went wrong... it should never re-parse the tribal recipe // High chances to be a scripting error break; } if(bestRecipe->wait <= 0) { RDebug(this, 5, "Applying recipe %s.", bestRecipe->recipe->GetName().GetDataSafe()); bestRecipe->nextStep = recipeManager->ApplyRecipe( bestRecipe, this, bestRecipe->nextStep); } // If nextStep is -1 => Recipe is Completed if(bestRecipe->nextStep == -1) { // TODO -- Remove TimeStamp csString rName = bestRecipe->recipe->GetName(); if(rName != "do nothing") { RDebug(this, 5, "Recipe %s completed.", rName.GetData()); } tribalRecipe->RemoveChild(bestRecipe->recipe); } // If nextStep is -2, the recipe has unmet requirements else if(bestRecipe->nextStep == -2) { bestRecipe->nextStep = 0; } } } }