NPCObject* PersistentNpcFactory::_createPersistentNpc(DatabaseResult* result) { NPCObject* npc ; NpcIdentifier npcIdentifier; uint64 count = result->getRowCount(); result->GetNextRow(mNpcIdentifierBinding,(void*)&npcIdentifier); result->ResetRowIndex(); switch(npcIdentifier.mFamilyId) { case NpcFamily_Trainer: npc = new Trainer(); break; case NpcFamily_Filler: npc = new FillerNPC(); break; case NpcFamily_QuestGiver: npc = new QuestGiver(); break; default: { npc = new NPCObject(); gLogger->log(LogManager::DEBUG,"PersistentNpcFactory::createPersistent unknown Family %u",npcIdentifier.mFamilyId); } break; } Inventory* npcInventory = new Inventory(); npcInventory->setParent(npc); result->GetNextRow(mPersistentNpcBinding,(void*)npc); npc->mHam.mHealth.setCurrentHitPoints(500); npc->mHam.mAction.setCurrentHitPoints(500); npc->mHam.mMind.setCurrentHitPoints(500); npc->mHam.calcAllModifiedHitPoints(); // inventory npcInventory->setId(npc->mId + INVENTORY_OFFSET); npcInventory->setParentId(npc->mId); npcInventory->setModelString("object/tangible/inventory/shared_creature_inventory.iff"); npcInventory->setName("inventory"); npcInventory->setNameFile("item_n"); npcInventory->setTangibleGroup(TanGroup_Inventory); npcInventory->setTangibleType(TanType_CreatureInventory); npc->mEquipManager.addEquippedObject(CreatureEquipSlot_Inventory,npcInventory); npc->mTypeOptions = 0x108; //npc->setPvPStatus(npc->getPvPStatus() + CreaturePvPStatus_Attackable + CreaturePvPStatus_Aggressive); npc->setLoadState(LoadState_Attributes); // Save default direction, since player can make the npc change heading. npc->storeDefaultDirection(); return npc; }
bool Tutorial::isLowHam(uint64 npcId, int32 hamLevel) { NPCObject* npc = dynamic_cast<NPCObject*>(gWorldManager->getObjectById(npcId)); if (npc) { if ((npc->getHam()->getPropertyValue(HamBar_Health,HamProperty_CurrentHitpoints) < hamLevel) || (npc->getHam()->getPropertyValue(HamBar_Action,HamProperty_CurrentHitpoints) < hamLevel) || (npc->getHam()->getPropertyValue(HamBar_Mind,HamProperty_CurrentHitpoints) < hamLevel) || (mPlayerObject->getHam()->getPropertyValue(HamBar_Health,HamProperty_CurrentHitpoints) < hamLevel) || (mPlayerObject->getHam()->getPropertyValue(HamBar_Action,HamProperty_CurrentHitpoints) < hamLevel) || (mPlayerObject->getHam()->getPropertyValue(HamBar_Mind,HamProperty_CurrentHitpoints) < hamLevel)) { return true; } } return false; }
void Food::prepareCustomRadialMenu(CreatureObject* creatureObject, uint8 itemCount) { RadialMenu* radial = new RadialMenu(); CreatureObject* unknownCreature; Inventory* creatureInventory; if (this->getParentId() && (unknownCreature = dynamic_cast<CreatureObject*>(gWorldManager->getObjectById(this->getParentId() - 1))) && (creatureInventory = dynamic_cast<Inventory*>(unknownCreature->getEquipManager()->getEquippedObject(CreatureEquipSlot_Inventory))) && (creatureInventory->getId() == this->getParentId())) { // Its an object in an inventory NPCObject* npcObject = dynamic_cast<NPCObject*>(unknownCreature); if (npcObject) { if ((npcObject->getNpcFamily() == NpcFamily_AttackableCreatures) && npcObject->isDead()) { // I'm pretty sure we are a loot item. radial->addItem(1,0,radId_itemPickup,radAction_ObjCallback,"@ui_radial:loot"); radial->addItem(2,0,radId_examine,radAction_Default); mRadialMenu = RadialMenuPtr(radial); return; } } } // Note: If we are to never use the default "Eat", THEN remove the isTutorial()-condition test. if (gWorldConfig->isTutorial()) { // Tutorial clearly states that we shall use the "Use"-option. radial->addItem(1,0,radId_itemUse,radAction_ObjCallback,"Use"); } else { radial->addItem(1,0,radId_itemUse,radAction_ObjCallback,""); // Default. } radial->addItem(2,0,radId_examine,radAction_ObjCallback,""); radial->addItem(3,0,radId_itemDestroy,radAction_ObjCallback,""); mRadialMenu = RadialMenuPtr(radial); }
void PersistentNpcFactory::handleDatabaseJobComplete(void* ref,DatabaseResult* result) { QueryContainerBase* asyncContainer = reinterpret_cast<QueryContainerBase*>(ref); switch(asyncContainer->mQueryType) { case PersistentNpcQuery_MainData: { NPCObject* npc = _createPersistentNpc(result); if(npc->getLoadState() == LoadState_Loaded && asyncContainer->mOfCallback) asyncContainer->mOfCallback->handleObjectReady(npc,asyncContainer->mClient); else if(npc->getLoadState() == LoadState_Attributes) { QueryContainerBase* asContainer = new(mQueryContainerPool.ordered_malloc()) QueryContainerBase(asyncContainer->mOfCallback,PersistentNpcQuery_Attributes,asyncContainer->mClient); asContainer->mObject = npc; mDatabase->ExecuteSqlAsync(this,asContainer,"SELECT attributes.name,persistent_npc_attributes.value,attributes.internal" " FROM persistent_npc_attributes" " INNER JOIN attributes ON (persistent_npc_attributes.attribute_id = attributes.id)" " WHERE persistent_npc_attributes.npc_id = %"PRIu64" ORDER BY persistent_npc_attributes.order",npc->getId()); } } break; case PersistentNpcQuery_Attributes: { _buildAttributeMap(asyncContainer->mObject,result); if(asyncContainer->mObject->getLoadState() == LoadState_Loaded && asyncContainer->mOfCallback) asyncContainer->mOfCallback->handleObjectReady(asyncContainer->mObject,asyncContainer->mClient); } break; default: break; } mQueryContainerPool.free(asyncContainer); }
uint8 CombatManager::_executeAttack(CreatureObject* attacker,CreatureObject* defender,ObjectControllerCmdProperties *cmdProperties,Weapon* weapon) { uint8 randomHitPool = 100; //uint8 randomPoolHitChance = 100; uint8 stateApplied = 0; int32 multipliedDamage = 0; BString combatSpam = "melee"; // first see if we actually hit our target uint8 attackResult = _hitCheck(attacker,defender,cmdProperties,weapon); // only proceed, if so if(!attackResult) { // TODO: retrieve from weapon int32 baseMinDamage = 50; int32 baseMaxDamage = 100; // NOTE: Some weapon data just for tesing and to give the npc a fair chance... if (weapon->hasAttribute("cat_wpn_damage.wpn_damage_min")) { baseMinDamage = weapon->getAttribute<int32>("cat_wpn_damage.wpn_damage_min"); } if (weapon->hasAttribute("cat_wpn_damage.wpn_damage_max")) { baseMaxDamage = weapon->getAttribute<int32>("cat_wpn_damage.wpn_damage_max"); } //Sanity checks of db data if (baseMinDamage < 1) baseMinDamage = 1; if (baseMaxDamage < 1) baseMaxDamage = 1; if(baseMaxDamage <= baseMinDamage) { baseMaxDamage = baseMinDamage +1; } int32 baseDamage = -((gRandom->getRand()%(baseMaxDamage - baseMinDamage)) + baseMinDamage); // apply damage multiplier if(cmdProperties->mDamageMultiplier) { multipliedDamage = static_cast<uint32>(static_cast<float>(baseDamage) * cmdProperties->mDamageMultiplier); } else { multipliedDamage = baseDamage; } // mitigation multipliedDamage = _mitigateDamage(attacker,defender,cmdProperties,multipliedDamage,weapon); // state effects stateApplied = _tryStateEffects(attacker,defender,cmdProperties,weapon); // Here is the deal. When a player makes damage to a npc, we have to register the player, its group, damage done and what (kind of) weapon used. NPCObject* npc = dynamic_cast<NPCObject*>(defender); if (!defender->isDead() && npc) { PlayerObject* player = dynamic_cast<PlayerObject*>(attacker); if (player) { npc->updateDamage(player->getId(), player->getGroupId(), weapon->getGroup(), -multipliedDamage, player->GetPosture(), glm::distance(defender->mPosition, player->mPosition)); } } // ham damage // if no target pool set, pick a random one if(!cmdProperties->mHealthHitChance && !cmdProperties->mActionHitChance && !cmdProperties->mMindHitChance) { switch(gRandom->getRand()%3) { case 0: randomHitPool = HamBar_Health; break; case 1: randomHitPool = HamBar_Action; break; case 2: randomHitPool = HamBar_Mind; break; default: randomHitPool = 0; break; } } auto ham = gWorldManager->getKernel()->GetServiceManager()->GetService<swganh::ham::HamService>("HamService"); //this is pure idiocy in my eyes. Why for gods sake should an object be a creature ? // is there precedent through SOE??????????? if (defender->getCreoGroup() != CreoGroup_AttackableObject) { // random pool attack if(randomHitPool != 100) { ham->UpdateCurrentHitpoints(defender,randomHitPool,multipliedDamage); //defender->getHam()->updatePropertyValue(randomHitPool,HamProperty_CurrentHitpoints,multipliedDamage,true); } // direct pool attack else { // health hit if(cmdProperties->mHealthHitChance) { ham->UpdateCurrentHitpoints(defender,HamBar_Health,multipliedDamage); //defender->getHam()->updatePropertyValue(HamBar_Health,HamProperty_CurrentHitpoints,multipliedDamage,true); } // action hit else if(cmdProperties->mActionHitChance) { ham->UpdateCurrentHitpoints(defender,HamBar_Action,multipliedDamage); //defender->getHam()->updatePropertyValue(HamBar_Action,HamProperty_CurrentHitpoints,multipliedDamage,true); } // mind hit else if(cmdProperties->mMindHitChance) { ham->UpdateCurrentHitpoints(defender,HamBar_Mind,multipliedDamage); //defender->getHam()->updatePropertyValue(HamBar_Mind,HamProperty_CurrentHitpoints,multipliedDamage,true); } } } else { ham->UpdateCurrentHitpoints(defender,HamBar_Health,multipliedDamage); //defender->getHam()->updateSingleHam(multipliedDamage, true); } if (defender->isIncapacitated()) { PlayerObject* playerAttacker = dynamic_cast<PlayerObject*>(attacker); if (playerAttacker && playerAttacker->isConnected()) { gMessageLib->SendSystemMessage(::common::OutOfBand("base_player", "prose_target_incap", 0, defender->getId(), 0), playerAttacker); } } if (defender->isDead()) { PlayerObject* playerAttacker = dynamic_cast<PlayerObject*>(attacker); if (playerAttacker && playerAttacker->isConnected()) { gMessageLib->SendSystemMessage(::common::OutOfBand("base_player", "killer_target_dead"), playerAttacker, true); } } } // fly text and animations // default attack(s) if(cmdProperties->mCmdCrc == 0xa8fef90a) { uint32 animCrc = getDefaultAttackAnimation(weapon->getGroup()); switch(attackResult) { // hit case 0: case 2: case 3: case 4: { gMessageLib->sendCombatAction(attacker,defender,animCrc,0,0,1); } break; // miss case 1: { gMessageLib->sendCombatAction(attacker,defender,animCrc); } break; } } // special attack else { switch(attackResult) { // hit case 0: case 2: case 3: case 4: { gMessageLib->sendCombatAction(attacker,defender,cmdProperties->mAnimationCrc,cmdProperties->mTrail1,cmdProperties->mTrail2,1); } break; //miss case 1: { gMessageLib->sendCombatAction(attacker,defender,cmdProperties->mAnimationCrc,cmdProperties->mTrail1,cmdProperties->mTrail2); } break; } } switch(attackResult) { case 0: { // Defender got hit. } break; case 1: { gMessageLib->sendFlyText(defender,"combat_effects","miss",255,255,255); } break; case 2: // We cant block yet, can we? { gMessageLib->sendFlyText(defender,"combat_effects","block",0,255,0); gMessageLib->sendCombatAction(defender,attacker,0xe430ff04); } break; case 3: { gMessageLib->sendFlyText(defender,"combat_effects","dodge",0,255,0); gMessageLib->sendCombatAction(defender,attacker,0xe430ff04); // Dodge } break; case 4: { gMessageLib->sendFlyText(defender,"combat_effects","counterattack",0,255,0); // I can's see this effect working? } break; } // send combat spam // default attack if(cmdProperties->mCmdCrc == 0xa8fef90a) { combatSpam = getDefaultSpam(weapon->getGroup()); } // special attack else { if(cmdProperties->mCbtSpam.getLength()) { combatSpam = cmdProperties->mCbtSpam.getAnsi(); } } switch(attackResult) { case 0: combatSpam << "_hit"; break; case 1: combatSpam << "_miss"; break; case 2: combatSpam << "_block"; break; case 3: combatSpam << "_evade"; break; case 4: combatSpam << "_counter"; break; default: break; } gMessageLib->sendCombatSpam(attacker,defender,-multipliedDamage,"cbt_spam",combatSpam); return(0); }
void ScriptSupport::npcSpawnGeneral(uint64 npcId, uint64 npcPrivateOwnerId, uint64 cellForSpawn, std::string firstname, std::string lastname, float dirY, float dirW, float posX, float posY, float posZ, uint64 respawnDelay) // , uint64 templateId) { glm::quat direction; glm::vec3 position; direction.x = 0.0; direction.y = dirY; direction.z = 0.0; direction.w = dirW; position.x = posX; position.y = posY; position.z = posZ; NPCObject* npc = dynamic_cast<NPCObject*>(gWorldManager->getObjectById(npcId)); assert(npc); if (!npc) { // Fallback for running in release mode. LOG(WARNING) << "ScriptSupport::npcSpawnGeneral: Failed to access NPC id " << npcId; return; } // npc->setId(npcId); npc->setParentId(cellForSpawn); // The cell we will spawn in. npc->setCellIdForSpawn(cellForSpawn); // THESE TWO ARE NOT GENERALLY FIXED YET. npc->setFirstName((int8*)firstname.c_str()); npc->setLastName((int8*)lastname.c_str()); // THIS ONE IS NOT GENERALLY FIXED YET. // If used for re-spawning npc's, add this id as an internal attribute. npc->setPrivateOwner(npcPrivateOwnerId); npc->mPosition = position; npc->setSpawnPosition(position); npc->mDirection = direction; npc->setSpawnDirection(direction); npc->setRespawnDelay(respawnDelay); // Register object with WorldManager. // gWorldManager->addObject(npc, true); // Update the world about my presence. /* if (npc->getParentId()) { // insert into cell npc->setSubZoneId(0); if (CellObject* cell = dynamic_cast<CellObject*>(gWorldManager->getObjectById(npc->getParentId()))) { cell->addChild(npc); } else { } } else { if (QTRegion* region = gWorldManager->getSI()->getQTRegion(npc->mPosition.x,npc->mPosition.z)) { npc->setSubZoneId((uint32)region->getId()); region->mTree->addObject(npc); } } */ //Inventory* inventory = dynamic_cast<Inventory*>(npc->getEquipManager()->getEquippedObject(CreatureEquipSlot_Inventory)); // Register the NPC with the NPC AI-manager. if (npc->getTemplateId() == 0) { // Just to make sure we do not have any old scripts running. assert(false); } npc->respawn(); // Now we can remove this object from our internal list. WorldManager will handle the destruction. // Except for the npc's used in tutorial, they are spawned-despawned with the player. if (!gWorldConfig->isTutorial()) { this->eraseObject(npcId); } /* // The dynamic spawned private owned npc MUST register with their owner. // It's not always the case that the player have had time to track this newly spawned objects, // Private owned objects are invisible to most players and using getKnownPlayers()->empty() to try and save the // sendDataTransformWithParent // and // sendUpdateTransformMessageWithParent // from being called is just ridicules, it's not like we going to spwan a npc from script every second or so. // So please stop messing with this code!!! // Add us to the world. gMessageLib->broadcastContainmentMessage(npc->getId(),npc->getParentId(),-1,npc); // send out position updates to known players npc->setInMoveCount(npc->getInMoveCount() + 1); if (gWorldConfig->isTutorial()) { // We need to get the player object that is the owner of this npc. if (npcPrivateOwnerId != 0) { PlayerObject* playerObject = dynamic_cast<PlayerObject*>(gWorldManager->getObjectById(npcPrivateOwnerId)); if (playerObject) { if (npc->getParentId()) { // We are inside a cell. gMessageLib->sendDataTransformWithParent(npc, playerObject); gMessageLib->sendUpdateTransformMessageWithParent(npc, playerObject); } else { gMessageLib->sendDataTransform(npc, playerObject); gMessageLib->sendUpdateTransformMessage(npc, playerObject); } return; } } } else { if (npc->getParentId()) { // We are inside a cell. gMessageLib->sendDataTransformWithParent(npc); gMessageLib->sendUpdateTransformMessageWithParent(npc); } else { gMessageLib->sendDataTransform(npc); gMessageLib->sendUpdateTransformMessage(npc); } } */ }
MissionObject* MissionManager::generateCraftingMission(MissionObject* mission) { mission->setMissionType(crafting); //TEMP! string targets[8][2] = { {"@item_n:output_governor","object/tangible/mission/quest_item/shared_attunement_grid.iff"}, {"@item_n:current_alternator","object/tangible/mission/quest_item/shared_current_alternator.iff"}, {"@item_n:nym_hard_drive","object/tangible/loot/quest/shared_nym_hard_drive.iff"}, {"@item_n:hyperdrive_part_s01","object/tangible/loot/misc/shared_hyperdrive_part_s01.iff"}, {"@item_n:dermal_analyzer","object/tangible/loot/npc_loot/shared_dermal_analyzer_generic.iff"}, {"@item_n:feedback_controller","object/tangible/mission/quest_item/shared_feedback_controller.iff"}, {"@item_n:power_regulator","object/tangible/mission/quest_item/shared_power_regulator.iff"}, {"@item_n:attunement_grid","object/tangible/mission/quest_item/shared_attunement_grid.iff"} }; int target_num = gRandom->getRand() % 8; //END TEMP //Randomly choose a crafting mission int mission_num = (gRandom->getRand() % 50)+1; mission->setNum(mission_num); //Creator mission->setCreator(creators[gRandom->getRand() % 9]); //Title sprintf(mt,"m%dt",mission_num); mission->setTitleFile("mission/mission_npc_crafting_neutral_easy"); mission->setTitle(mt); //Details sprintf(md,"m%dd",mission_num); mission->setDetailFile("mission/mission_npc_crafting_neutral_easy"); mission->setDetail(md); //END TEMP ObjectSet inRangeNPCs; gWorldManager->getSI()->getObjectsInRange(mission->getOwner(),&inRangeNPCs,ObjType_NPC,1500); uint32 cntLoop = 0; //Start & End bool found = false; Location mission_start; Location mission_dest; ObjectSet::iterator it = inRangeNPCs.begin(); while(!found && !inRangeNPCs.empty()) { cntLoop++; ++it; if(it == inRangeNPCs.end()) it = inRangeNPCs.begin(); NPCObject* npc = dynamic_cast<NPCObject*>(*it); if(npc->getNpcFamily() == NpcFamily_Filler) { uint32 roll = (gRandom->getRand() / (RAND_MAX + 1ul) * (9 - 1) + 1); if((roll = 5)||(cntLoop > inRangeNPCs.size())) { if(mission_dest.Coordinates.x == 0) { mission->setDestinationNPC(npc); mission_dest.Coordinates = npc->mPosition; mission_dest.CellID = 0; mission_dest.PlanetCRC = BString(gWorldManager->getPlanetNameThis()).getCrc(); mission->setDestination(mission_dest); } else if(mission_start.Coordinates.x == 0 && mission->getDestinationNPC() != npc) { mission->setStartNPC(npc); mission_start.Coordinates = npc->mPosition; mission_start.CellID = 0; mission_start.PlanetCRC = BString(gWorldManager->getPlanetNameThis()).getCrc(); mission->setStart(mission_start); } else { found = true; } } } } //Difficulty mission->setDifficulty((gRandom->getRand() % 41) + 40); //value from 30 - 80 //Reward mission->setReward(mission->getDifficulty() * ((gRandom->getRand() % 14) + 15)); //Difficulty * rand: 15-28 //Target mission->setTarget((targets[target_num][0]).getRawData()); //will need to be located from the db //Mission Target mission->setTargetModel((targets[target_num][1]).getCrc()); //crc = object/tangible/mission/quest_item/shared_attunement_grid.iff return mission; }
MissionObject* MissionManager::generateEntertainerMission(MissionObject* mission,int count) { count < 5 ? mission->setMissionType(musician): mission->setMissionType(dancer); //Randomly choose an entertainer mission int mission_num = (gRandom->getRand() % 50)+1; mission->setNum(mission_num); ObjectSet inRangeNPCs; gWorldManager->getSI()->getObjectsInRange(mission->getOwner(),&inRangeNPCs,ObjType_NPC,3000); //Start uint32 cntLoop = 0; bool found = false; Location mission_dest; ObjectSet::iterator it = inRangeNPCs.begin(); while(!found && !inRangeNPCs.empty()) { cntLoop++; ++it; if(it == inRangeNPCs.end()) it = inRangeNPCs.begin(); NPCObject* npc = dynamic_cast<NPCObject*>(*it); if(npc->getNpcFamily() == NpcFamily_Filler) { uint32 roll = (gRandom->getRand() / (RAND_MAX + 1ul) * (9 - 1) + 1); if((roll = 5)||(cntLoop > inRangeNPCs.size())) { if(mission_dest.Coordinates.x == 0 && mission->getDestinationNPC() != npc) { mission->setStartNPC(npc); mission_dest.Coordinates = npc->mPosition; mission_dest.CellID = 0; mission_dest.PlanetCRC = BString(gWorldManager->getPlanetNameThis()).getCrc(); mission->setDestination(mission_dest); mission->setDestinationNPC(npc); found = true; } } } } //Creator mission->setCreator(creators[gRandom->getRand() % 9]); //Mission Title sprintf(mt,"m%dt",mission_num); count < 5 ? mission->setTitleFile("mission/mission_npc_musician_neutral_easy") : mission->setTitleFile("mission/mission_npc_dancer_neutral_easy"); mission->setTitle(mt); //Mission Description sprintf(md,"m%do",mission_num); count < 5 ? mission->setDetailFile("mission/mission_npc_musician_neutral_easy") : mission->setDetailFile("mission/mission_npc_dancer_neutral_easy"); mission->setDetail(md); //Diffaculty mission->setDifficulty((gRandom->getRand() % 90)+3); //Payment mission->setReward((gRandom->getRand() % 2500)+500); //Target Name mission->setTarget("Entertainer"); //Mission Target mission->setTargetModel(0x491099A6); //crc = object/tangible/instrument/shared_organ_max_rebo.iff return mission; }
MissionObject* MissionManager::generateDeliverMission(MissionObject* mission) { mission->setMissionType(deliver); //TEMP missionData mission_deliver_hard[2] = { {"mission/mission_deliver_neutral_hard",25}, {"mission/mission_deliver_neutral_hard_non_persistent_from_npc",15}, }; //Randomly choose a stf file int stf_file = gRandom->getRand() % 2; //Randomly choose a mission in that file int mission_num = (gRandom->getRand() % mission_deliver_hard[stf_file].num)+1; mission->setNum(mission_num); //END TEMP ObjectSet inRangeNPCs; gWorldManager->getSI()->getObjectsInRange(mission->getOwner(),&inRangeNPCs,ObjType_NPC,1500); //Start & End bool found = false; Location mission_start; Location mission_dest; ObjectSet::iterator it = inRangeNPCs.begin(); //we may stall the main thread with the way it was done ???? however often enough the mission generation never finished!!!!!!!!!!!!!!! //get a list containing all suitable npcs and generate a random number corresponding to one of the npcs if(inRangeNPCs.size() < 2) return NULL; uint32 count = 0; while(!found && !inRangeNPCs.empty()) { count ++; ++it; if(it == inRangeNPCs.end()) it = inRangeNPCs.begin(); NPCObject* npc = dynamic_cast<NPCObject*>(*it); if(npc->getNpcFamily() == NpcFamily_Filler) { uint32 roll = (gRandom->getRand() / (RAND_MAX + 1ul) * (9 - 1) + 1); if((roll = 5)||(count > inRangeNPCs.size())) { if(mission_dest.Coordinates.x == 0) { mission->setDestinationNPC(npc); mission_dest.Coordinates = npc->mPosition; mission_dest.CellID = 0; mission_dest.PlanetCRC = BString(gWorldManager->getPlanetNameThis()).getCrc(); mission->setDestination(mission_dest); } else if(mission_start.Coordinates.x == 0 && mission->getDestinationNPC() != npc) { mission->setStartNPC(npc); mission_start.Coordinates = npc->mPosition; mission_start.CellID = 0; mission_start.PlanetCRC = BString(gWorldManager->getPlanetNameThis()).getCrc(); mission->setStart(mission_start); found = true; } } } } //Creator mission->setCreator(creators[gRandom->getRand() % 9]); //Mission Title sprintf(mt,"m%dt",mission_num); mission->setTitleFile(mission_deliver_hard[stf_file].mSTF); mission->setTitle(mt); //Mission Description sprintf(md,"m%dd",mission_num); mission->setDetailFile(mission_deliver_hard[stf_file].mSTF); mission->setDetail(md); //Diffaculty mission->setDifficulty((gRandom->getRand() % 10)+3); //Payment mission->setReward((gRandom->getRand() % 300)+50); //Mission Target mission->setTargetModel(0xE191DBAB); //crc = object/tangible/mission/shared_mission_datadisk.iff return mission; }
void ObjectController::_handleNPCConversationStart(uint64 targetId,Message* message,ObjectControllerCmdProperties* cmdProperties) { PlayerObject* player = dynamic_cast<PlayerObject*>(mObject); NPCObject* npc = dynamic_cast<NPCObject*>(gWorldManager->getObjectById(targetId)); if(!npc) { DLOG(info) << "ObjController::_handleNPCConversationStart: Couldn't find object " << targetId; return; } // in range check uint64 playerParentId = player->getParentId(); uint64 npcParentId = npc->getParentId(); bool inRange = true; uint64 playerBuildingId = 0; uint64 npcBuildingId = 0; //get building Ids if they are in buildings if(playerParentId) { playerBuildingId = gWorldManager->getObjectById(playerParentId)->getParentId(); } if(npcParentId) { npcBuildingId = gWorldManager->getObjectById(npcParentId)->getParentId(); } // not inside same parent, or out of range float distance = glm::distance(player->getWorldPosition(), npc->getWorldPosition()); if ((npcBuildingId != playerParentId) || distance > 10.0f) { inRange = false; } // we are out of range if(!inRange) { float distance = glm::distance(player->mPosition, npc->mPosition); char buffer[100]; sprintf(buffer, "You are out of range (%f m).", distance); BString msg(buffer); msg.convert(BSTRType_Unicode16); gMessageLib->SendSystemMessage(msg.getUnicode16(), player); // gMessageLib->sendSystemMessage(player,L"","system_msg","out_of_range"); return; } //check to see if he is part of a mission /*if(gMissionManager->checkDeliverMission(player,npc) || gMissionManager->checkCraftingMission(player,npc) ) return;*/ // we don't want him to talk if(npc->hasInternalAttribute("no_chat")) return; // initiate a conversation dialog if(npc->hasInternalAttribute("base_conversation")) { // Let the npc have your attention, and some npc-movement. npc->prepareConversation(player); gConversationManager->startConversation(npc,player); } // say some chatter else { // spam protection uint64 localTime = Anh_Utils::Clock::getSingleton()->getLocalTime(); if(npc->getLastConversationTarget() == player->getId()) { if(localTime - npc->getLastConversationRequest() < NPC_CHAT_SPAM_PROTECTION_TIME) { return; } else { npc->setLastConversationRequest(localTime); } } else { npc->setLastConversationRequest(localTime); npc->setLastConversationTarget(player->getId()); } // Let the npc have your attention, and some npc-movement. // Nope... npc->prepareConversation(player); std::wstring npc_chat; uint32_t animation = 0; // say a specific preset sentence if(npc->hasInternalAttribute("npc_chat")) { std::string tmp = npc->getInternalAttribute<std::string>("npc_chat"); npc_chat = std::wstring(tmp.begin(), tmp.end()); } else { std::pair<std::wstring,uint32> chat = gWorldManager->getRandNpcChatter(); npc_chat = chat.first; animation = chat.second; } if (!gWorldConfig->isInstance()) { gMessageLib->SendSpatialChat(npc, npc_chat, player); if (animation) gMessageLib->sendCreatureAnimation(npc,gWorldManager->getNpcConverseAnimation(animation)); } else { gMessageLib->SendSpatialChat(npc, npc_chat, player); if (animation) gMessageLib->sendCreatureAnimation(npc,gWorldManager->getNpcConverseAnimation(animation), player); } } }
NPCObject* NonPersistentNpcFactory::createNonPersistentNpc(DatabaseResult* result, uint64 templateId, uint64 npcNewId, uint32 familyId, uint64 controllingObject) { NPCObject* npc; switch(familyId) { case NpcFamily_Trainer: { npc = new Trainer(); } break; case NpcFamily_Filler: { npc = new FillerNPC(); } break; case NpcFamily_QuestGiver: { npc = new QuestGiver(); } break; case NpcFamily_AttackableObject: { // Stuff like Debris. npc = new AttackableStaticNpc(); } break; case NpcFamily_AttackableCreatures: { // gLogger->logMsgF("NonPersistentNpcFactory::_createNonPersistentNpc() Created a NpcFamily_AttackableCreatures", MSG_NORMAL); // Stuff like npc's and womp rats :). npc = new AttackableCreature(templateId); } break; case NpcFamily_NaturalLairs: { // First time lairs. // gLogger->logMsgF("NonPersistentNpcFactory::createNonPersistentNpc() Created a NpcFamily_NaturalLairs", MSG_NORMAL); //Lairs are not supported here, at least not yet. assert(false && "NonPersistentNpcFactory::createNonPersistent NpcFamily_NaturalLairs Lairs are not supported here yet."); npc = new LairObject(templateId); } break; default: { gLogger->logMsgF("NonPersistentNpcFactory::createNonPersistent unknown Family %u",MSG_HIGH,familyId); assert(false && "NonPersistentNpcFactory::createNonPersistent unknown family"); npc = new NPCObject(); } break; } // Set the new temporarily id. npc->setId(npcNewId); // Register object with WorldManager. gWorldManager->addObject(npc, true); Inventory* npcInventory = new Inventory(); npcInventory->setCapacity(50);//we want to be able to fill something in our inventory npcInventory->setParent(npc); uint64 count = result->getRowCount(); result->GetNextRow(mNonPersistentNpcBinding,(void*)npc); // The template for this creature, in case of a respawn. npc->mNpcTemplateId = templateId; // Should bet fetched from attributes, these will do as defaults. npc->mHam.mHealth.setCurrentHitPoints(500); npc->mHam.mAction.setCurrentHitPoints(500); npc->mHam.mMind.setCurrentHitPoints(500); npc->mHam.calcAllModifiedHitPoints(); // inventory npcInventory->setId(npc->mId + 1); npcInventory->setParentId(npc->mId); npcInventory->setModelString("object/tangible/inventory/shared_creature_inventory.iff"); npcInventory->setName("inventory"); npcInventory->setNameFile("item_n"); npcInventory->setTangibleGroup(TanGroup_Inventory); npcInventory->setTangibleType(TanType_CreatureInventory); npc->mEquipManager.addEquippedObject(CreatureEquipSlot_Inventory,npcInventory); if (npc->getNpcFamily() == NpcFamily_AttackableObject) { // Dynamic spawned pve-enabled "static" creatures like debris. npc->setType(ObjType_Creature); npc->setCreoGroup(CreoGroup_AttackableObject); npc->mTypeOptions = 0x0; // Let's start as non-attackable. // npc->togglePvPStateOn((CreaturePvPStatus)(CreaturePvPStatus_Attackable)); } else if (npc->getNpcFamily() == NpcFamily_NaturalLairs) { //Lairs are not supported here, at least not yet. assert(false && "NonPersistentNpcFactory::createNonPersistent NpcFamily_NaturalLairs Lairs not supported here yet"); // Dynamic spawned pve-enabled "static" creatures like lairs. npc->setType(ObjType_Creature); // This will ensure the use of the single H(am) bar. npc->setCreoGroup(CreoGroup_AttackableObject); npc->mTypeOptions = 0x0; npc->togglePvPStateOn((CreaturePvPStatus)(CreaturePvPStatus_Attackable)); // npc->mHam.mHealth.setCurrentHitPoints(5000); // npc->mHam.mHealth.setMaxHitPoints(5000); // npc->mHam.mHealth.setBaseHitPoints(5000); // npc->mHam.calcAllModifiedHitPoints(); // Let's put some credits in the inventory. // npcInventory->setCredits((gRandom->getRand()%25) + 10); // gLogger->logMsgF("NonPersistentNpcFactory::createNonPersistentNpc() WOW, I'm a lair", MSG_NORMAL); } else if (npc->getNpcFamily() == NpcFamily_AttackableCreatures) { // Dynamic spawned pve-enabled creatures. npc->setType(ObjType_Creature); npc->setCreoGroup(CreoGroup_Creature); npc->mTypeOptions = 0x0; if (gWorldConfig->isTutorial()) { npc->togglePvPStateOn((CreaturePvPStatus)(CreaturePvPStatus_Attackable + CreaturePvPStatus_Aggressive + CreaturePvPStatus_Enemy )); } else { npc->togglePvPStateOn((CreaturePvPStatus)(CreaturePvPStatus_Attackable)); } AttackableCreature* attackableNpc = dynamic_cast<AttackableCreature*>(npc); assert(attackableNpc && "NonPersistentNpcFactory::createNonPersistent unable to cast npc to AttackableCreature instance"); // Fix this later // Also set the owner (lair) who's controlling this creature. attackableNpc->setLairId(controllingObject); Weapon* defaultWeapon = new Weapon(); defaultWeapon->setId(gWorldManager->getRandomNpId()); defaultWeapon->setParentId(npc->mId); defaultWeapon->setModelString("object/weapon/melee/unarmed/shared_unarmed_default_player.iff"); defaultWeapon->setGroup(WeaponGroup_Unarmed); defaultWeapon->setEquipSlotMask(CreatureEquipSlot_Weapon); defaultWeapon->addInternalAttribute("weapon_group","1"); npc->mEquipManager.setDefaultWeapon(defaultWeapon); npc->mEquipManager.equipDefaultWeapon(); // Weapon to use should be gotten from attibutes or whereever we find that kind of info. // This little fellow may need a gun. Weapon* pistol = new Weapon(); pistol->setId(gWorldManager->getRandomNpId()); pistol->setParentId(npc->mId); pistol->setModelString("object/weapon/ranged/pistol/shared_pistol_cdef.iff"); pistol->setGroup(WeaponGroup_Pistol); pistol->setEquipSlotMask(CreatureEquipSlot_Weapon); pistol->addInternalAttribute("weapon_group","32"); attackableNpc->setPrimaryWeapon(pistol); // A saber can be handy, too. Weapon* saber = new Weapon(); saber->setId(gWorldManager->getRandomNpId()); saber->setParentId(npc->mId); saber->setModelString("object/weapon/melee/sword/shared_sword_lightsaber_vader.iff"); saber->setGroup(WeaponGroup_2h); saber->setEquipSlotMask(CreatureEquipSlot_Weapon); saber->addInternalAttribute("weapon_group","4"); attackableNpc->setSecondaryWeapon(saber); if (gWorldConfig->isTutorial()) { attackableNpc->equipPrimaryWeapon(); } else { // attackableNpc->equipSecondaryWeapon(); } // Should be handle by "loot manager" // Let's put some credits in the inventory. npcInventory->setCredits((gRandom->getRand()%25) + 10); } else { npc->mTypeOptions = 0x108; } npc->setLoadState(LoadState_Attributes); // Save default direction, since player can make the npc change heading. // Can't apply this to a dynamically created npc. // npc->storeDefaultDirection(); return npc; }
void NonPersistentNpcFactory::handleDatabaseJobComplete(void* ref,DatabaseResult* result) { QueryNonPersistentNpcFactory* asyncContainer = reinterpret_cast<QueryNonPersistentNpcFactory*>(ref); switch(asyncContainer->mQueryType) { case NonPersistentNpcQuery_Attributes: { // gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() AT NonPersistentNpcQuery_Attributes:", MSG_NORMAL); Object* object = gWorldManager->getObjectById(asyncContainer->mId); if (object) { _buildAttributeMap(object,result); if (object->getLoadState() == LoadState_Loaded && asyncContainer->mOfCallback) { // gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() Invoking mOfCallback->handleObjectReady(npc)", MSG_NORMAL); asyncContainer->mOfCallback->handleObjectReady(object); } else { // gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() Invoking NOTHING", MSG_NORMAL); } } else { gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() Object is GONE", MSG_NORMAL); } } break; //============================================================================= // // Upgrade version for use of the correct DB. // //============================================================================= case NonPersistentNpcQuery_LairTemplate: { // gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() AT NonPersistentNpcQuery_LairTemplate:", MSG_NORMAL); NpcLairEntityEx lair; DataBinding* lairSpawnBinding = mDatabase->CreateDataBinding(9); lairSpawnBinding->addField(DFT_uint64,offsetof(NpcLairEntityEx,mCreatureSpwanRegion),8,0); lairSpawnBinding->addField(DFT_uint64,offsetof(NpcLairEntityEx,mTemplateId),8,1); lairSpawnBinding->addField(DFT_uint32,offsetof(NpcLairEntityEx,mCreatureGroup),4,2); lairSpawnBinding->addField(DFT_uint32,offsetof(NpcLairEntityEx,mNumberOfLairs),4,3); lairSpawnBinding->addField(DFT_float,offsetof(NpcLairEntityEx,mSpawnPosX),4,4); lairSpawnBinding->addField(DFT_float,offsetof(NpcLairEntityEx,mSpawnPosZ),4,5); lairSpawnBinding->addField(DFT_float,offsetof(NpcLairEntityEx,mSpawnDirY),4,6); lairSpawnBinding->addField(DFT_float,offsetof(NpcLairEntityEx,mSpawnDirW),4,7); lairSpawnBinding->addField(DFT_uint32,offsetof(NpcLairEntityEx,mFamily),4,8); DataBinding* lairSpawnNpcBinding = mDatabase->CreateDataBinding(4); lairSpawnNpcBinding->addField(DFT_bstring,offsetof(NPCObject,mModel),255,9); lairSpawnNpcBinding->addField(DFT_bstring,offsetof(NPCObject,mSpecies),255,10); lairSpawnNpcBinding->addField(DFT_bstring,offsetof(NPCObject,mSpeciesGroup),255,11); lairSpawnNpcBinding->addField(DFT_bstring,offsetof(NPCObject,mFaction),32,12); uint64 count = result->getRowCount(); result->GetNextRow(lairSpawnBinding,&lair); // Let's create the lair. // We save the lairs-type... that's kinda a template for the complete lair. LairObject* npc = new LairObject(asyncContainer->mTemplateId); // Set the new if of this temp object. npc->setId(asyncContainer->mId); // Register object with WorldManager. gWorldManager->addObject(npc, true); // May need the height also, in case of pre set (fixed) spawn position. npc->mPosition.x = lair.mSpawnPosX; npc->mPosition.z = lair.mSpawnPosZ; if (npc->getParentId() == 0) { // Heightmap only works outside. npc->mPosition.y = npc->getHeightAt2DPosition(lair.mSpawnPosX, lair.mSpawnPosZ, true); } else { // We do not have support for handling creatures inside. assert(false && "NonPersistentNpcFactory::handleDatabaseJobComplete NonPersistentNpcQuery_LairTemplate No support for handling creatures inside"); npc->mPosition.y = 0; } npc->mDirection.y = lair.mSpawnDirY; npc->mDirection.w = lair.mSpawnDirW; // Let's get the spawn area. const Anh_Math::Rectangle spawnArea = gWorldManager->getSpawnArea(lair.mCreatureSpwanRegion); // lair.mCreatureSpwanRegion npc->setSpawnArea(spawnArea); result->ResetRowIndex(); result->GetNextRow(lairSpawnNpcBinding,(void*)npc ); mDatabase->DestroyDataBinding(lairSpawnBinding); mDatabase->DestroyDataBinding(lairSpawnNpcBinding); Inventory* npcInventory = new Inventory(); npcInventory->setParent(npc); npc->mHam.mHealth.setCurrentHitPoints(500); npc->mHam.mAction.setCurrentHitPoints(500); npc->mHam.mMind.setCurrentHitPoints(500); npc->mHam.calcAllModifiedHitPoints(); // inventory npcInventory->setId(npc->mId + 1); npcInventory->setParentId(npc->mId); npcInventory->setModelString("object/tangible/inventory/shared_creature_inventory.iff"); npcInventory->setName("inventory"); npcInventory->setNameFile("item_n"); npcInventory->setTangibleGroup(TanGroup_Inventory); npcInventory->setTangibleType(TanType_CreatureInventory); npc->mEquipManager.addEquippedObject(CreatureEquipSlot_Inventory,npcInventory); npc->setType(ObjType_Creature); // This will ensure the use of the single H(am) bar. npc->setCreoGroup(CreoGroup_AttackableObject); npc->mTypeOptions = 0x0; npc->togglePvPStateOn((CreaturePvPStatus)(CreaturePvPStatus_Attackable)); // gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() Attempting to get the creature templates for group %u used by this lair.", MSG_NORMAL, lair.mCreatureGroup); QueryNonPersistentNpcFactory* asContainer = new QueryNonPersistentNpcFactory(asyncContainer->mOfCallback, NonPersistentNpcQuery_LairCreatureTemplates, asyncContainer->mTemplateId, asyncContainer->mId); // Do not transfer object refs, use the handle, i.e. asyncContainer->mId // asContainer->mObject = npc; mDatabase->ExecuteSqlAsync(this, asContainer, "SELECT creature_groups.creature_id " "FROM creature_groups " "WHERE creature_groups.creature_group_id=%u;",lair.mCreatureGroup); } break; case NonPersistentNpcQuery_LairCreatureTemplates: { // Get the lair object. LairObject* npc = dynamic_cast<LairObject*>(gWorldManager->getObjectById(asyncContainer->mId)); assert(npc && "NonPersistentNpcFactory::handleDatabaseJobComplete NonPersistentNpcQuery_LairCreatureTemplates WorldManager unable to find object id"); uint64 creatureTemplateId; DataBinding* creatureTemplateBinding = mDatabase->CreateDataBinding(1); creatureTemplateBinding->addField(DFT_uint64,0,8,0); uint64 count = result->getRowCount(); int32 spawnRateInc = 100/static_cast<uint32>(count); int32 spawnRate = -1; for (uint64 i = 0; i < count; i++) { result->GetNextRow(creatureTemplateBinding, &creatureTemplateId); // gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() Creature template %"PRIu64" used by lair ", MSG_NORMAL, creatureTemplateId); npc->setCreatureTemplate((uint32)i, creatureTemplateId); spawnRate += spawnRateInc; npc->setCreatureSpawnRate((uint32)i, (uint32)spawnRate); } if (count > 0 && spawnRate < 99) { npc->setCreatureSpawnRate(static_cast<uint32>(count) - 1, 99); } mDatabase->DestroyDataBinding(creatureTemplateBinding); // gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() Attempting to get the Attributes", MSG_NORMAL); QueryNonPersistentNpcFactory* asContainer = new QueryNonPersistentNpcFactory(asyncContainer->mOfCallback,NonPersistentNpcQuery_Attributes, 0, npc->getId()); mDatabase->ExecuteSqlAsync(this,asContainer,"SELECT attributes.name,lair_attributes.value,attributes.internal" " FROM lair_attributes" " INNER JOIN attributes ON (lair_attributes.attribute_id = attributes.id)" " WHERE lair_attributes.lair_id = %"PRIu64" ORDER BY lair_attributes.order", asyncContainer->mTemplateId); } break; case NonPersistentNpcQuery_NpcTemplate: { // gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() AT NonPersistentNpcQuery_NpcTemplate:", MSG_NORMAL); NPCObject* npc = _createNonPersistentNpc(result, asyncContainer->mTemplateId, asyncContainer->mId, asyncContainer->mParentObjectId); assert(npc); // Spawn related data. npc->setCellIdForSpawn(asyncContainer->mSpawnCellId); npc->setSpawnPosition(asyncContainer->mSpawnPosition); npc->setSpawnDirection(asyncContainer->mSpawnDirection); npc->setRespawnDelay(asyncContainer->mRespawnDelay); if( npc->getLoadState() == LoadState_Loaded && asyncContainer->mOfCallback) { // gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() Invoking mOfCallback->handleObjectReady(npc)", MSG_NORMAL); asyncContainer->mOfCallback->handleObjectReady(npc); } else if (npc->getLoadState() == LoadState_Attributes) { QueryNonPersistentNpcFactory* asContainer = new QueryNonPersistentNpcFactory(asyncContainer->mOfCallback,NonPersistentNpcQuery_Attributes, 0, npc->getId()); // gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() Invoking NonPersistentNpcQuery_Attributes NPC ID = %"PRIu64"", MSG_NORMAL, npc->getId()); mDatabase->ExecuteSqlAsync(this,asContainer,"SELECT attributes.name,non_persistent_npc_attributes.value,attributes.internal" " FROM non_persistent_npc_attributes" " INNER JOIN attributes ON (non_persistent_npc_attributes.attribute_id = attributes.id)" " WHERE non_persistent_npc_attributes.npc_id = %"PRIu64" ORDER BY non_persistent_npc_attributes.order", asyncContainer->mTemplateId); } } break; default: { gLogger->logMsgF("NonPersistentNpcFactory::handleDatabaseJobComplete() UNKNOWN query = %u\n", MSG_NORMAL, asyncContainer->mQueryType); } break; } delete asyncContainer; }