int CreatureTemplateManager::addTemplate(lua_State* L) {
	if (checkArgumentCount(L, 2) == 1) {
		instance()->error("incorrect number of arguments passed to CreatureTemplateManager::addTemplate");
		ERROR_CODE = INCORRECT_ARGUMENTS;
		return 0;
	}

	String ascii =  lua_tostring(L, -2);
	uint32 crc = (uint32) ascii.hashCode();

	LuaObject obj(L);
	CreatureTemplate* newTemp = new CreatureTemplate();
	newTemp->setTemplateName(ascii);
	newTemp->readObject(&obj);

	if (instance()->hashTable.containsKey(crc)) {
		luaL_where (L, 2);
		String luaMethodName = lua_tostring(L, -1);

		lua_pop(L, 1);

		instance()->error("overwriting mobile " + ascii + " with " + luaMethodName);

		ERROR_CODE = DUPLICATE_MOBILE;
	}

	CreatureTemplateManager::instance()->hashTable.put(crc, newTemp);

	int count = loadedMobileTemplates.increment();

	if (ConfigManager::instance()->isProgressMonitorActivated() && !DEBUG_MODE)
		printf("\r\tLoading mobile templates: [%d] / [?]\t", count);

	return 0;
}
CreatureObject* CreatureManagerImplementation::spawnCreatureAsBaby(uint32 templateCRC, float x, float z, float y, uint64 parentID) {
	CreatureTemplate* creoTempl = creatureTemplateManager->getTemplate(templateCRC);

	if (creoTempl == NULL || creoTempl->getTame() <= 0)
		return NULL;

	CreatureObject* creo = NULL;

	String templateToSpawn = getTemplateToSpawn(templateCRC);
	uint32 objectCRC = templateToSpawn.hashCode();

	creo = createCreature(objectCRC, false, templateCRC);

	if (creo != NULL && creo->isCreature()) {
		Creature* creature = cast<Creature*>(creo);
		creature->loadTemplateDataForBaby(creoTempl);
	} else {
		error("could not spawn template " + templateToSpawn + " as baby.");
		creo = NULL;
	}

	placeCreature(creo, x, z, y, parentID);

	if (creo != NULL && creo->isAiAgent())
		cast<AiAgent*>(creo)->activateLoad("");
	else {
		error("could not spawn template " + templateToSpawn + " as baby with AI.");
		creo = NULL;
	}

	return creo;
}
bool CreatureManagerImplementation::createCreatureChildrenObjects(CreatureObject* creature, uint32 templateCRC, bool persistent, uint32 mobileTemplateCRC) {
	if (creature->hasSlotDescriptor("default_weapon")) {

		uint32 defaultWeaponCRC = 0;
		if (creature->isNonPlayerCreatureObject()) {
			defaultWeaponCRC = STRING_HASHCODE("object/weapon/melee/unarmed/unarmed_default.iff");
		} else {
			defaultWeaponCRC = STRING_HASHCODE("object/weapon/creature/creature_default_weapon.iff");
		}
		ManagedReference<SceneObject*> defaultWeapon = zoneServer->createObject(defaultWeaponCRC, persistent);
		ManagedReference<SceneObject*> otherWeapon;

		if(mobileTemplateCRC != 0) {
			CreatureTemplate* creoTempl = creatureTemplateManager->getTemplate(mobileTemplateCRC);

			if(creoTempl != NULL && creoTempl->getDefaultWeapon() != ""){
				uint32 otherWeaponCRC = String(creoTempl->getDefaultWeapon()).hashCode();
				otherWeapon = zoneServer->createObject(otherWeaponCRC, persistent);
			}
		}

		if(otherWeapon != NULL) {
			if (defaultWeapon != NULL && defaultWeapon->isPersistent()) {
				Locker clocker(defaultWeapon, creature);
				defaultWeapon->destroyObjectFromDatabase(true);
			}

			defaultWeapon = otherWeapon;
		}

		if (defaultWeapon == NULL) {
			error("could not create creature default weapon");
			return false;
		}

		Locker clocker(defaultWeapon, creature);

		creature->transferObject(defaultWeapon, 4);
	}

	if (creature->hasSlotDescriptor("inventory")) {
		Reference<SceneObject*> creatureInventory = zoneServer->createObject(STRING_HASHCODE("object/tangible/inventory/creature_inventory.iff"), persistent);

		if (creatureInventory == NULL) {
			error("could not create creature inventory");

			return false;
		}

		Locker clocker(creatureInventory, creature);

		creatureInventory->setContainerDefaultDenyPermission(ContainerPermissions::MOVECONTAINER);
		creatureInventory->setContainerDenyPermission("owner", ContainerPermissions::MOVECONTAINER);
		creatureInventory->setContainerInheritPermissionsFromParent(false);

		creature->transferObject(creatureInventory, 4);
	}

	return true;
}
TEST_F(LuaMobileTest, LuaMobileTemplatesTest) {
	CreatureTemplateManager::DEBUG_MODE = 1;

	// Verify that all mobiles load
	ASSERT_EQ(CreatureTemplateManager::instance()->loadTemplates(), 0);

	// Verify loot group map loads
	LootGroupMap* lootGroupMap = LootGroupMap::instance();
	ASSERT_EQ(lootGroupMap->initialize(), 0);

	HashTableIterator<uint32, Reference<CreatureTemplate*> > iter = CreatureTemplateManager::instance()->iterator();
	while (iter.hasNext()) {
		CreatureTemplate* creature = iter.next();
		std::string templateName( creature->getTemplateName().toCharArray() );

		// Verify loot group percentages
		LootGroupCollection* groupCollection = creature->getLootGroups();
		if( groupCollection->count() > 0 ){


			for( int i = 0; i < groupCollection->count(); i++ ){

				LootGroupCollectionEntry* collectionEntry = groupCollection->get(i);
				LootGroups* groups = collectionEntry->getLootGroups();
				if( groups->count() > 0){

					int totalChance = 0;
					for( int j = 0; j < groups->count(); j++ ){

						LootGroupEntry* lootGroup = groups->get(j);
						totalChance += lootGroup->getLootChance();

						// Verify loot group is configured correctly
						LootGroupTemplate* foundGroup = lootGroupMap->getLootGroupTemplate( lootGroup->getLootGroupName() );
						std::string groupName( lootGroup->getLootGroupName().toCharArray() );
						EXPECT_TRUE( foundGroup != NULL ) << "Loot group " << groupName << " from " << templateName << " was not found in LootGroupMap";

					}

					EXPECT_EQ( 10000000, totalChance ) << "Loot groups total chance is incorrect " << templateName;
				}
			}
		}

		// Verify weapon groups exist
		Vector<String> weapons = creature->getWeapons();
		for (int i = 0; i < weapons.size(); i++) {
			String weaponGroup = weapons.get(i);
			std::string groupName( weaponGroup.toCharArray() );
			Vector<String> group = CreatureTemplateManager::instance()->getWeapons(weaponGroup);
			EXPECT_TRUE( group.size() > 0 ) << "Weapon group " << groupName << " from " << templateName << " was not found in weaponMap";
		}
	}

}
String CreatureManagerImplementation::getTemplateToSpawn(uint32 templateCRC) {
	String templateToSpawn = "";

	CreatureTemplate* creoTempl = creatureTemplateManager->getTemplate(templateCRC);

	Vector<String> objTemps = creoTempl->getTemplates();

	if (objTemps.size() > 0) {
		uint32 randomTemp = System::random(objTemps.size() - 1);
		templateToSpawn = objTemps.get(randomTemp);
	} else {
		StringBuffer errMsg;
		errMsg << "could not spawn creature... no object templates in script " << creoTempl->getTemplateName();

		//error(errMsg.toString());
	}

	return templateToSpawn;
}
int HuntingMissionObjectiveImplementation::notifyObserverEvent(MissionObserver* observer, uint32 eventType, Observable* observable, ManagedObject* arg1, int64 arg2) {
	ManagedReference<MissionObject* > mission = this->mission.get();

	if (eventType == ObserverEventType::KILLEDCREATURE) {
		if (cast<CreatureObject*>(observable) != getPlayerOwner().get())
			return 0;

		CreatureObject* creature = cast<CreatureObject*>(arg1);
		AiAgent* agent = cast<AiAgent*>(creature);

		if (agent == NULL)
			return 0;

		CreatureTemplate* creatureTemplate = agent->getCreatureTemplate();

		if (creatureTemplate == NULL)
			return 0;

		String temp1 = mission->getTemplateString1();
		String temp2 = mission->getTemplateString2();

		if (creatureTemplate->getTemplateName() == temp1 || creatureTemplate->getTemplateName() == temp2) {
			targetsKilled--;

			if (targetsKilled <= 0) {
				complete();
				return 1;
			}

			StringIdChatParameter message("mission/mission_generic", "hunting_kills_remaining");
			message.setDI(targetsKilled);
			message.setTO(mission->getTargetName());

			getPlayerOwner().get()->sendSystemMessage(message);
		}
	}

	return 0;
}
void DnaManager::generateSample(Creature* creature, CreatureObject* player,int quality){
	if (quality < 0 || quality > 7) {
		return;
	}
	Locker lock(creature,player);
	CreatureTemplate* creatureTemplate = dynamic_cast<CreatureTemplate*>(creature->getCreatureTemplate());

	int ferocity = creatureTemplate->getFerocity();
	int cl = creature->getLevel();
	int cle = Genetics::hitChanceToValue(creature->getChanceHit(),quality);
	int cou = Genetics::meatTypeToValue(creature->getMeatType(),quality);
	int dep = Genetics::dietToValue(creature->getDiet(),quality);
	int dex = Genetics::hamToValue(creature->getMaxHAM(3),quality);
	int end = Genetics::accelerationToValue(creature->getWalkAcceleration(),quality);
	int fie = Genetics::ferocityToValue(ferocity,quality);
	int frt = Genetics::resistanceToValue(creature->getEffectiveResist(),creature->getArmor(),quality);
	int har = Genetics::hamToValue(creature->getMaxHAM(0),quality);
	int ite = Genetics::hamToValue(creature->getMaxHAM(6),quality);
	int pow = Genetics::damageToValue((creature->getDamageMax() + creature->getDamageMin())/2,quality);

	ManagedReference<SceneObject*> inventory = player->getSlottedObject("inventory");

	if (inventory->hasFullContainerObjects()) {
		StringIdChatParameter err("survey", "no_inv_space");
		player->sendSystemMessage(err);
		player->setPosture(CreaturePosture::UPRIGHT, true);
		return;
	}

	// We should now have enough to generate a sample
	ManagedReference<DnaComponent*> prototype = player->getZoneServer()->createObject(qualityTemplates.get(quality), 1).castTo<DnaComponent*>();
	if (prototype == NULL) {
		return;
	}
	Locker clocker(prototype);
	// Check Here for unique npcs
	StringId* nameId = creature->getObjectName();
	if (nameId->getFile().isEmpty() || nameId->getStringID().isEmpty()) {
		prototype->setSource(creature->getCreatureName().toString());
	} else {
		prototype->setSource(nameId->getFullPath());
	}
	prototype->setQuality(quality);
	prototype->setLevel(cl);
	String serial = player->getZoneServer()->getCraftingManager()->generateSerial();
	prototype->setSerialNumber(serial);
	prototype->setStats(cle,end,fie,pow,ite,cou,dep,dex,frt,har);
	prototype->setStun(creatureTemplate->getStun());
	prototype->setKinetic(creatureTemplate->getKinetic());
	prototype->setEnergy(creatureTemplate->getEnergy());
	prototype->setBlast(creatureTemplate->getBlast());
	prototype->setHeat(creatureTemplate->getHeat());
	prototype->setCold(creatureTemplate->getCold());
	prototype->setElectric(creatureTemplate->getElectricity());
	prototype->setAcid(creatureTemplate->getAcid());
	prototype->setSaber(creatureTemplate->getLightSaber());
	prototype->setRanged(creatureTemplate->getWeapons().size() > 0);
	prototype->setArmorRating(creatureTemplate->getArmor());

	if (creatureTemplate->isSpecialProtection(WeaponObject::STUN))
		prototype->setSpecialResist(WeaponObject::STUN);
	if (creatureTemplate->isSpecialProtection(WeaponObject::KINETIC))
		prototype->setSpecialResist(WeaponObject::KINETIC);
	if (creatureTemplate->isSpecialProtection(WeaponObject::ENERGY))
		prototype->setSpecialResist(WeaponObject::ENERGY);
	if (creatureTemplate->isSpecialProtection(WeaponObject::BLAST))
		prototype->setSpecialResist(WeaponObject::BLAST);
	if (creatureTemplate->isSpecialProtection(WeaponObject::HEAT))
		prototype->setSpecialResist(WeaponObject::HEAT);
	if (creatureTemplate->isSpecialProtection(WeaponObject::COLD))
		prototype->setSpecialResist(WeaponObject::COLD);
	if (creatureTemplate->isSpecialProtection(WeaponObject::ELECTRICITY))
		prototype->setSpecialResist(WeaponObject::ELECTRICITY);
	if (creatureTemplate->isSpecialProtection(WeaponObject::ACID))
		prototype->setSpecialResist(WeaponObject::ACID);
	if (creatureTemplate->isSpecialProtection(WeaponObject::LIGHTSABER))
		prototype->setSpecialResist(WeaponObject::LIGHTSABER);

	CreatureAttackMap* attackMap = creatureTemplate->getAttacks();
	if (attackMap->size() > 0) {
		prototype->setSpecialAttackOne(String(attackMap->getCommand(0)));
		if(attackMap->size() > 1) {
			prototype->setSpecialAttackTwo(String(attackMap->getCommand(1)));
		}
	}

	Locker locker(inventory);
	if (inventory->transferObject(prototype, -1, true, false)) {
		inventory->broadcastObject(prototype, true);
	} else {
		prototype->destroyObjectFromDatabase(true);
	}
}
bool LairObserverImplementation::checkForNewSpawns(TangibleObject* lair, TangibleObject* attacker, bool forceSpawn) {
	if (lair->getZone() == NULL)
		return false;

	if (spawnedCreatures.size() >= lairTemplate->getSpawnLimit() && !lairTemplate->hasBossMobs())
		return false;

	if (forceSpawn) {
		spawnNumber++;
	} else if (getMobType() == LairTemplate::NPC) {
		return false;
	} else {
		int conditionDamage = lair->getConditionDamage();
		int maxCondition = lair->getMaxCondition();

		switch (spawnNumber) {
		case 0:
			spawnNumber++;
			break;
		case 1:
			if (conditionDamage > (maxCondition / 10)) {
				spawnNumber++;
			} else {
				return false;
			}
			break;
		case 2:
			if (conditionDamage > (maxCondition / 2)) {
				spawnNumber++;
			} else {
				return false;
			}
			break;
		case 3:
			if (lairTemplate->hasBossMobs() && conditionDamage > ((maxCondition * 9) / 10)) {
				spawnNumber++;
			} else {
				return false;
			}
			break;
		default:
			return false;
			break;
		}
	}

	VectorMap<String, int> objectsToSpawn; // String mobileTemplate, int number to spawn

	if (spawnNumber == 4) {
		if (System::random(100) > 9)
			return false;

		VectorMap<String, int>* mobs = lairTemplate->getBossMobiles();

		for (int i = 0; i < mobs->size(); i++) {
			objectsToSpawn.put(mobs->elementAt(i).getKey(), mobs->elementAt(i).getValue());
		}

	} else {
		Vector<String>* mobiles = lairTemplate->getWeightedMobiles();
		int amountToSpawn = 0;

		if (getMobType() == LairTemplate::CREATURE) {
			amountToSpawn = System::random(3) + ((lairTemplate->getSpawnLimit() / 3) - 2);
		} else {
			amountToSpawn = System::random(lairTemplate->getSpawnLimit() / 2) + (lairTemplate->getSpawnLimit() / 2);
		}

		if (amountToSpawn < 1)
			amountToSpawn = 1;

		for (int i = 0; i < amountToSpawn; i++) {
			int num = System::random(mobiles->size() - 1);
			String mob = mobiles->get(num);

			if (objectsToSpawn.contains(mob)) {
				int value = objectsToSpawn.get(mob);
				objectsToSpawn.drop(mob);
				objectsToSpawn.put(mob, value + 1);
			} else {
				objectsToSpawn.put(mob, 1);
			}
		}
	}

	for(int i = 0; i < objectsToSpawn.size(); ++i) {

		if (spawnNumber != 4 && spawnedCreatures.size() >= lairTemplate->getSpawnLimit())
			return true;

		String templateToSpawn = objectsToSpawn.elementAt(i).getKey();
		int numberToSpawn = objectsToSpawn.get(templateToSpawn);

		CreatureTemplate* creatureTemplate = CreatureTemplateManager::instance()->getTemplate(templateToSpawn);

		if (creatureTemplate == NULL)
			continue;

		float tamingChance = creatureTemplate->getTame();

		CreatureManager* creatureManager = lair->getZone()->getCreatureManager();

		for (int j = 0; j < numberToSpawn; j++) {

			float x = lair->getPositionX() + (size - System::random(size * 20) / 10.0f);
			float y = lair->getPositionY() + (size - System::random(size * 20) / 10.0f);
			float z = lair->getZone()->getHeight(x, y);

			ManagedReference<CreatureObject*> creo = NULL;

			if (creatureManager->checkSpawnAsBaby(tamingChance, babiesSpawned, 500)) {
				creo = creatureManager->spawnCreatureAsBaby(templateToSpawn.hashCode(), x, z, y);
				babiesSpawned++;
			}

			if (creo == NULL)
				creo = creatureManager->spawnCreatureWithAi(templateToSpawn.hashCode(), x, z, y);

			if (creo == NULL)
				continue;

			if (!creo->isAiAgent()) {
				error("spawned non player creature with template " + templateToSpawn);
			} else {
				AiAgent* ai = cast<AiAgent*>( creo.get());

				//Locker clocker(npc, lair);

				ai->setDespawnOnNoPlayerInRange(false);
				ai->setHomeLocation(x, z, y);
				ai->setRespawnTimer(0);
				ai->setHomeObject(lair);

				spawnedCreatures.add(creo);
			}
		}
	}

	if (spawnNumber == 4) {
		Reference<LairAggroTask*> task = new LairAggroTask(lair, attacker, _this.get(), true);
		task->schedule(1000);
	}

	return objectsToSpawn.size() > 0;
}
void CreatureManagerImplementation::tame(Creature* creature, CreatureObject* player, bool force) {
	Zone* zone = creature->getZone();

	if (zone == NULL || !creature->isCreature())
		return;

	if(player->getPendingTask("tame_pet") != NULL) {
		player->sendSystemMessage("You are already taming a pet");
		return;
	}

	if(player->getPendingTask("call_pet") != NULL) {
		player->sendSystemMessage("You cannot tame a pet while another is being called");
		return;
	}

	if (!creature->canTameMe(player) || !creature->isAttackableBy(player)) {
		player->sendSystemMessage("@pet/pet_menu:sys_cant_tame"); // You can't tame that
		return;
	}

	CreatureTemplate* creatureTemplate = creature->getCreatureTemplate();

	if (creatureTemplate == NULL)
		return;

	int templateLevel = creatureTemplate->getLevel();
	int maxLevelofPets = player->getSkillMod("tame_level");

	if (!player->hasSkill("outdoors_creaturehandler_novice") || (templateLevel > maxLevelofPets)) {
		player->sendSystemMessage("@pet/pet_menu:sys_lack_skill"); // You lack the skill to be able to tame that creature.
		return;
	}

	if ((creature->isVicious() && player->getSkillMod("tame_aggro") < 1) || creature->getChanceToTame(player) <= 0) {
		player->sendSystemMessage("@pet/pet_menu:sys_lack_skill"); // You lack the skill to be able to tame that creature.
		return;
	}

	ManagedReference<SceneObject*> datapad = player->getSlottedObject("datapad");

	if (datapad == NULL)
		return;

	if (datapad->getContainerObjectsSize() >= datapad->getContainerVolumeLimit()) {
		player->sendSystemMessage("@faction_recruiter:datapad_full"); // Your datapad is full. You must first free some space.
		return;
	}

	ManagedReference<PlayerManager*> playerManager = zoneServer->getPlayerManager();

	int numberStored = 0;
	int maxStoredPets = playerManager->getBaseStoredCreaturePets() + player->getSkillMod("stored_pets");

	for (int i = 0; i < datapad->getContainerObjectsSize(); ++i) {
		ManagedReference<SceneObject*> object = datapad->getContainerObject(i);

		if (object != NULL && object->isPetControlDevice()) {
			PetControlDevice* device = cast<PetControlDevice*>( object.get());

			if (device->getPetType() == PetManager::CREATUREPET) {
				if (++numberStored >= maxStoredPets) {
					player->sendSystemMessage("@pet/pet_menu:sys_too_many_stored"); // There are too many pets stored in this container. Release some of them to make room for more.
					return;
				}

			}
		}
	}

	ManagedReference<PlayerObject*> ghost = player->getPlayerObject();

	int currentlySpawned = 0;
	int spawnedLevel = 0;
	int level = creature->getLevel();
	int maxPets = player->getSkillMod("keep_creature");

	for (int i = 0; i < ghost->getActivePetsSize(); ++i) {
		ManagedReference<AiAgent*> object = ghost->getActivePet(i);

		if (object != NULL) {
			ManagedReference<PetControlDevice*> pcd = object->getControlDevice().get().castTo<PetControlDevice*>();

			if (pcd == NULL || pcd->getPetType() != PetManager::CREATUREPET) {
				continue;
			}

			if (++currentlySpawned >= maxPets) {
				player->sendSystemMessage("@pet/pet_menu:too_many"); // You can't control any more pets. Store one first
				return;
			}

			spawnedLevel += object->getLevel();

			if ((spawnedLevel + level) >= maxLevelofPets) {
				player->sendSystemMessage("Taming this pet would exceed your control level ability.");
				return;
			}
		}
	}

	if (force && !ghost->isPrivileged())
		force = false;

	ChatManager* chatManager = player->getZoneServer()->getChatManager();

	chatManager->broadcastMessage(player, "@hireling/hireling:taming_1"); // Easy.

	Locker clocker(creature);

	int mask = creature->getPvpStatusBitmask();
	creature->setPvpStatusBitmask(0, true);

	if (creature->isAiAgent()) {
		AiAgent* agent = cast<AiAgent*>(creature);
		agent->activateLoad("wait");
	}

	ManagedReference<TameCreatureTask*> task = new TameCreatureTask(creature, player, mask, force);

	player->addPendingTask("tame_pet", task, 8000);
}
void PetControlDeviceImplementation::callObject(CreatureObject* player) {
	if (player->isInCombat() || player->isDead() || player->isIncapacitated() || player->getPendingTask("tame_pet") != NULL) {
		player->sendSystemMessage("@pet/pet_menu:cant_call"); // You cannot call this pet right now.
		return;
	}

	if (player->isRidingMount()) {
		player->sendSystemMessage("@pet/pet_menu:mounted_call_warning"); // You cannot call a pet while mounted or riding a vehicle.
		return;
	}

	if (player->getParent() != NULL) {
		ManagedReference<SceneObject*> strongRef = player->getRootParent();
		ManagedReference<BuildingObject*> building = NULL;

		if (strongRef != NULL)
			building = strongRef.castTo<BuildingObject*>();

		if (building == NULL || building->isPrivateStructure()) {
			player->sendSystemMessage("@pet/pet_menu:private_house"); // You cannot call pets in a private building.
			return;
		}
	}

	if (!isASubChildOf(player))
		return;

	ManagedReference<TangibleObject*> controlledObject = this->controlledObject.get();

	if (controlledObject == NULL || !controlledObject->isAiAgent())
		return;

	ManagedReference<AiAgent*> pet = cast<AiAgent*>(controlledObject.get());
	ManagedReference<PlayerObject*> ghost = player->getPlayerObject();

	if (ghost->hasActivePet(pet))
		return;

	FrsManager* frsManager = server->getZoneServer()->getFrsManager();

	if (frsManager->isFrsEnabled() && frsManager->isPlayerInEnclave(player)) {
		player->sendSystemMessage("@pet/pet_menu:cant_call"); //  You cannot call this pet right now.
		return;
	}

	if (vitality <= 0) {
		player->sendSystemMessage("@pet/pet_menu:dead_pet"); // This pet is dead. Select DESTROY from the radial menu to delete this pet control device.
		return;
	}

	if (!pet->getCooldownTimerMap()->isPast("call_cooldown")) {
		if (petType == PetManager::DROIDPET)
			player->sendSystemMessage("@pet/droid_modules:droid_maint_on_maint_run"); //You cannot call that droid. It is currently on a maintenance run.
		else
			player->sendSystemMessage("@pet/pet_menu:cant_call"); // cant call pet right now
		return;
	}
	assert(pet->isLockedByCurrentThread());

	unsigned int petFaction = pet->getFaction();

	if (petFaction != 0) {
		if (player->getFaction() == 0) {
			StringIdChatParameter message("@faction_perk:prose_be_declared"); // You must be declared to a faction to use %TT.
			message.setTT(pet->getDisplayedName());
			player->sendSystemMessage(message);
			return;
		}

		if (player->getFaction() != petFaction || player->getFactionStatus() == FactionStatus::ONLEAVE) {
			StringIdChatParameter message("@faction_perk:prose_be_declared_faction"); // You must be a declared %TO to use %TT.
			message.setTO(pet->getFactionString());
			message.setTT(pet->getDisplayedName());
			player->sendSystemMessage(message);
			return;
		}
	}

	if(player->getPendingTask("call_pet") != NULL) {
		StringIdChatParameter waitTime("pet/pet_menu", "call_delay_finish_pet"); // Already calling a Pet: Call will be finished in %DI seconds.
		AtomicTime nextExecution;
		Core::getTaskManager()->getNextExecutionTime(player->getPendingTask("call_pet"), nextExecution);
		int timeLeft = (nextExecution.getMiliTime() / 1000) - System::getTime();
		waitTime.setDI(timeLeft);

		player->sendSystemMessage(waitTime);
		return;
	}

	if (!growPet(player))
		return;

	if (petType == PetManager::CREATUREPET && !isValidPet(pet)) {
		ManagedReference<SuiMessageBox*> box = new SuiMessageBox(player,SuiWindowType::PET_FIX_DIALOG);
		box->setCallback(new PetFixSuiCallback(player->getZoneServer(), _this.getReferenceUnsafeStaticCast()));
		box->setPromptText("@bio_engineer:pet_sui_text");
		box->setPromptTitle("@bio_engineer:pet_sui_title");
		box->setOkButton(true,"@bio_engineer:pet_sui_fix_stats");
		box->setCancelButton(true,"@bio_engineer:pet_sui_abort");
		box->setOtherButton(true,"@bio_engineer:pet_sui_fix_level");
		box->setUsingObject(_this.getReferenceUnsafeStaticCast());
		player->getPlayerObject()->addSuiBox(box);
		player->sendMessage(box->generateMessage());
		return;
	}

	int currentlySpawned = 0;
	int spawnedLevel = 0;
	int maxPets = 1;
	int maxLevelofPets = 10;
	int level = pet->getLevel();

	if (pet->getCreatureTemplate() == NULL) {
		player->sendSystemMessage("Invalid creature to spawn!"); // Old npc without a npc template?
		return;
	}

	if (petType == PetManager::CREATUREPET) {
		ManagedReference<Creature*> creaturePet = cast<Creature*>(pet.get());
		if (creaturePet == NULL)
			return;

		bool ch = player->hasSkill("outdoors_creaturehandler_novice");

		if (ch) {
			maxPets = player->getSkillMod("keep_creature");
			maxLevelofPets = player->getSkillMod("tame_level");
		}

		if (creaturePet->getAdultLevel() > maxLevelofPets) {
			player->sendSystemMessage("@pet/pet_menu:control_exceeded"); // Calling this pet would exceed your Control Level ability.
			return;
		}

		if (creaturePet->isVicious() && (player->getSkillMod("tame_aggro") <= 0 || !ch)) {
			player->sendSystemMessage("@pet/pet_menu:lack_skill"); // You lack the skill to call a pet of this type.
			return;
		}

	} else if (petType == PetManager::FACTIONPET){
		maxPets = 3;
	}

	for (int i = 0; i < ghost->getActivePetsSize(); ++i) {
		ManagedReference<AiAgent*> object = ghost->getActivePet(i);

		if (object != NULL) {
			if (object->isCreature() && petType == PetManager::CREATUREPET) {
				CreatureTemplate* activePetTemplate = object->getCreatureTemplate();

				if (activePetTemplate == NULL || activePetTemplate->getTemplateName() == "at_st")
					continue;

				if (++currentlySpawned >= maxPets) {
					player->sendSystemMessage("@pet/pet_menu:at_max"); // You already have the maximum number of pets of this type that you can call.
					return;
				}

				spawnedLevel += object->getLevel();

				if ((spawnedLevel + level) > maxLevelofPets) {
					player->sendSystemMessage("@pet/pet_menu:control_exceeded"); // Calling this pet would exceed your Control Level ability.
					return;
				}
			} else if (object->isNonPlayerCreatureObject() && petType == PetManager::FACTIONPET) {
				if (++currentlySpawned >= maxPets) {
					player->sendSystemMessage("@pet/pet_menu:at_max"); // You already have the maximum number of pets of this type that you can call.
					return;
				}
			} else if (object->isCreature() && petType == PetManager::FACTIONPET) {
				CreatureTemplate* activePetTemplate = object->getCreatureTemplate();
				CreatureTemplate* callingPetTemplate = pet->getCreatureTemplate();

				if (activePetTemplate == NULL || callingPetTemplate == NULL || activePetTemplate->getTemplateName() != "at_st")
					continue;

				if (++currentlySpawned >= maxPets || (activePetTemplate->getTemplateName() == "at_st" && callingPetTemplate->getTemplateName() == "at_st")) {
					player->sendSystemMessage("@pet/pet_menu:at_max"); // You already have the maximum number of pets of this type that you can call.
					return;
				}
			} else if (object->isDroidObject() && petType == PetManager::DROIDPET) {
				if (++currentlySpawned >= maxPets) {
					player->sendSystemMessage("@pet/pet_menu:at_max"); // You already have the maximum number of pets of this type that you can call.
					return;
				}
			}

		}
	}

	ManagedReference<TradeSession*> tradeContainer = player->getActiveSession(SessionFacadeType::TRADE).castTo<TradeSession*>();

	if (tradeContainer != NULL) {
		server->getZoneServer()->getPlayerManager()->handleAbortTradeMessage(player);
	}

	if (player->getCurrentCamp() == NULL && player->getCityRegion() == NULL) {

		Reference<CallPetTask*> callPet = new CallPetTask(_this.getReferenceUnsafeStaticCast(), player, "call_pet");

		StringIdChatParameter message("pet/pet_menu", "call_pet_delay"); // Calling pet in %DI seconds. Combat will terminate pet call.
		message.setDI(15);
		player->sendSystemMessage(message);

		player->addPendingTask("call_pet", callPet, 15 * 1000);

		if (petControlObserver == NULL) {
			petControlObserver = new PetControlObserver(_this.getReferenceUnsafeStaticCast());
			petControlObserver->deploy();
		}

		player->registerObserver(ObserverEventType::STARTCOMBAT, petControlObserver);

	} else { // Player is in a city or camp, spawn pet immediately

		if( player->getCooldownTimerMap() == NULL )
			return;

		// Check cooldown
		if( !player->getCooldownTimerMap()->isPast("petCallOrStoreCooldown") ){
			player->sendSystemMessage("@pet/pet_menu:cant_call_1sec"); //"You cannot CALL for 1 second."
			return;
		}

		spawnObject(player);

		// Set cooldown
		player->getCooldownTimerMap()->updateToCurrentAndAddMili("petCallOrStoreCooldown", 1000); // 1 sec
	}

	EnqueuePetCommand* enqueueCommand = new EnqueuePetCommand(pet, String("petFollow").toLowerCase().hashCode(), String::valueOf(player->getObjectID()), player->getObjectID(), 1);
	enqueueCommand->execute();
}
Exemple #11
0
TEST_F(LuaMobileTest, LuaMobileTemplatesTest) {
	CreatureTemplateManager::DEBUG_MODE = 1;

	// Verify that all mobiles load
	ASSERT_EQ(CreatureTemplateManager::instance()->loadTemplates(), 0);

	// Verify loot group map loaded
	ASSERT_EQ(LootGroupMap::ERROR_CODE, 0);

	// Verify factions load
	FactionManager::instance()->loadData();
	ASSERT_FALSE(FactionManager::instance()->getFactionMap()->isEmpty());

	// Load Templates
	ASSERT_TRUE( TemplateManager::instance() != NULL );
	if( TemplateManager::instance()->loadedTemplatesCount == 0 ){
		TemplateManager::instance()->loadLuaTemplates();
		ASSERT_EQ(TemplateManager::ERROR_CODE, 0);
	}
	// verify DNA manager loads
	DnaManager::instance()->loadSampleData();
	ASSERT_TRUE( DnaManager::instance() != NULL);


	// Test Creature Templates
	HashTableIterator<uint32, Reference<CreatureTemplate*> > creatureIterator = CreatureTemplateManager::instance()->iterator();
	while (creatureIterator.hasNext()) {
		CreatureTemplate* creature = creatureIterator.next();
		std::string templateName( creature->getTemplateName().toCharArray() );
		//Verify non-empty objectName is a valid string
		String objName = creature->getObjectName();
		if (!objName.isEmpty()) {
			std::string name = objName.toCharArray();
			EXPECT_TRUE( mobNames.contains(objName) ) << "Mobile " << templateName << " has invalid objectName: "  << name;
		}

		// Check configured templates
		Vector<String> objTemps = creature->getTemplates();
		EXPECT_FALSE( objTemps.isEmpty() ) << "Mobile " << templateName << " does not have any templates configured";
		int objectType = 0;
		for( int j=0; j< objTemps.size(); j++ ){
			SharedObjectTemplate* templateData = templateManager->getTemplate(objTemps.get(j).hashCode());
			std::string objName = objTemps.get(j).toCharArray();
			EXPECT_TRUE( templateData != NULL ) << "Mobile " << templateName << " has invalid template configured: " << objName;

			// Check Template Genetics math to find invalid mobs
			if (templateData != NULL) {
				SharedCreatureObjectTemplate* creoData = dynamic_cast<SharedCreatureObjectTemplate*> (templateData);
				if (creoData != NULL) {
				}
			}

			if (objectType == 0) {
				objectType = templateData->getGameObjectType();
			}
		}
		// Verify that control device template is valid
		String controlDeviceTemplate = creature->getControlDeviceTemplate();
		if (!controlDeviceTemplate.isEmpty()) {
			SharedObjectTemplate* controlDeviceTemplateData = templateManager->getTemplate(controlDeviceTemplate.hashCode());
			EXPECT_TRUE( controlDeviceTemplateData != NULL ) << "Control device template " << controlDeviceTemplate.toCharArray() << " from " << templateName << " does not exist.";
			EXPECT_TRUE( controlDeviceTemplate.beginsWith("object/intangible/pet/") ) << "Control device template " << controlDeviceTemplate.toCharArray() << " from " << templateName << " is not a pet/droid control device template.";
		}

		// Verify that faction is valid
		String faction = creature->getFaction();
		if (!faction.isEmpty()) {
			EXPECT_TRUE( FactionManager::instance()->isFaction(faction) ) << "Faction, " << faction.toCharArray() << ", from mobile template " << templateName << " does not exist.";
		}

		// Verify level
		int level = creature->getLevel();
		EXPECT_TRUE( level > 0 ) << "Level is not a positive value on mobile: " << templateName;

		// Verify hit chance
		float hitChance = creature->getChanceHit();
		EXPECT_TRUE( hitChance > 0 ) << "ChanceHit is not a positive value on mobile: " << templateName;

		// Verify xp
		int xp = creature->getBaseXp();
		EXPECT_TRUE( xp >= 0 ) << "Xp has a negative value on mobile: " << templateName;

		// Verify damage
		int minDamage = creature->getDamageMin();
		int maxDamage = creature->getDamageMax();
		EXPECT_TRUE( minDamage > 0 ) << "Min damage is not a positive value on mobile: " << templateName;
		EXPECT_TRUE( maxDamage >= minDamage ) << "Max damage is lower than min damage on mobile: " << templateName;

		// Verify HAM
		int minHam = creature->getBaseHAM();
		int maxHam = creature->getBaseHAMmax();
		EXPECT_TRUE( minHam > 0 ) << "Base ham is not a positive value on mobile: " << templateName;
		EXPECT_TRUE( maxHam >= minHam ) << "Base ham max is lower than base ham on mobile: " << templateName;

		// Verify armor
		int armor = creature->getArmor();
		EXPECT_TRUE( armor >= 0 && armor <= 3 ) << "Armor is not a valid value on mobile: " << templateName;

		// Verify resists
		float kinetic = creature->getKinetic();
		EXPECT_TRUE( kinetic >= -1 && kinetic <= 200 ) << "Kinetic resist is not a valid value on mobile: " << templateName;
		float energy = creature->getEnergy();
		EXPECT_TRUE( energy >= -1 && energy <= 200 ) << "Energy resist is not a valid value on mobile: " << templateName;
		float electricity = creature->getElectricity();
		EXPECT_TRUE( electricity >= -1 && electricity <= 200 ) << "Electricity resist is not a valid value on mobile: " << templateName;
		float stun = creature->getStun();
		EXPECT_TRUE( stun >= -1 && stun <= 200 ) << "Stun resist is not a valid value on mobile: " << templateName;
		float blast = creature->getBlast();
		EXPECT_TRUE( blast >= -1 && blast <= 200 ) << "Blast resist is not a valid value on mobile: " << templateName;
		float heat = creature->getHeat();
		EXPECT_TRUE( heat >= -1 && heat <= 200 ) << "Heat resist is not a valid value on mobile: " << templateName;
		float cold = creature->getCold();
		EXPECT_TRUE( cold >= -1 && cold <= 200 ) << "Cold resist is not a valid value on mobile: " << templateName;
		float acid = creature->getAcid();
		EXPECT_TRUE( acid >= -1 && acid <= 200 ) << "Acid resist is not a valid value on mobile: " << templateName;
		float lightSaber = creature->getLightSaber();
		EXPECT_TRUE( lightSaber >= -1 && lightSaber <= 200 ) << "LightSaber resist is not a valid value on mobile: " << templateName;

		// Verify creature resources
		String meat = creature->getMeatType();
		float meatMax = creature->getMeatMax();
		if (!meat.isEmpty()) {
			String meatResources = "meat_domesticated,meat_wild,meat_herbivore,meat_carnivore,meat_reptilian,meat_avian,meat_insect";
			StringTokenizer tokenizer(meatResources);
			tokenizer.setDelimeter(",");
			bool match = false;
			String token;
			while (tokenizer.hasMoreTokens()) {
				tokenizer.getStringToken(token);
				if (meat == token)
					match = true;
			}
			EXPECT_TRUE( match ) << "Meat type on mobile " << templateName << " is not a valid meat resource";
			EXPECT_TRUE( meatMax > 0 ) << "Meat amount on mobile " << templateName << " is zero.";
		} else {
			EXPECT_TRUE( meatMax == 0 ) << "MeatAmount is not zero yet has no type defined on mobile " << templateName;
		}

		String hide = creature->getHideType();
		float hideMax = creature->getHideMax();
		if (!hide.isEmpty()) {
			String hideResources = "hide_bristley,hide_leathery,hide_scaley,hide_wooly";
			StringTokenizer tokenizer(hideResources);
			tokenizer.setDelimeter(",");
			bool match = false;
			String token;
			while (tokenizer.hasMoreTokens()) {
				tokenizer.getStringToken(token);
				if (hide == token)
					match = true;
			}
			EXPECT_TRUE( match ) << "Hide type on mobile " << templateName << " is not a valid hide resource";
			EXPECT_TRUE( hideMax > 0 ) << "Hide amount on mobile " << templateName << " is zero.";
		} else {
			EXPECT_TRUE( hideMax == 0 ) << "HideAmount is not zero yet has no type defined on mobile " << templateName;
		}

		String bone = creature->getBoneType();
		float boneMax = creature->getBoneMax();
		if (!bone.isEmpty()) {
			String boneResources = "bone_avian,bone_mammal";
			StringTokenizer tokenizer(boneResources);
			tokenizer.setDelimeter(",");
			bool match = false;
			String token;
			while (tokenizer.hasMoreTokens()) {
				tokenizer.getStringToken(token);
				if (bone == token)
					match = true;
			}
			EXPECT_TRUE( match ) << "Bone type on mobile " << templateName << " is not a valid bone resource";
			EXPECT_TRUE( boneMax > 0 ) << "Bone amount on mobile " << templateName << " is zero.";
		} else {
			EXPECT_TRUE( boneMax == 0 ) << "BoneAmount is not zero yet has no type defined on mobile " << templateName;
		}

		String milk = creature->getMilkType();
		float milkMax = creature->getMilk();
		if (!milk.isEmpty()) {
			String milkResources = "milk_domesticated,milk_wild";
			StringTokenizer tokenizer(milkResources);
			tokenizer.setDelimeter(",");
			bool match = false;
			String token;
			while (tokenizer.hasMoreTokens()) {
				tokenizer.getStringToken(token);
				if (milk == token)
					match = true;
			}
			EXPECT_TRUE( match ) << "Milk type on mobile " << templateName << " is not a valid milk resource";
			EXPECT_TRUE( milkMax > 0 ) << "Milk amount on mobile " << templateName << " is zero.";
		} else {
			EXPECT_TRUE( milkMax == 0 ) << "Milk is not zero yet has no type defined on mobile " << templateName;
		}

		// Verify taming chance
		float tamingChance = creature->getTame();
		EXPECT_TRUE( tamingChance >= 0 && tamingChance <= 1 ) << "Taming chance is not a valid value on mobile: " << templateName;

		// Verify diet on creatures
		if (boneMax > 0 || hideMax > 0 || meatMax > 0 || milkMax > 0 || tamingChance > 0) {
			uint32 diet = creature->getDiet();
			EXPECT_TRUE( diet != 0 ) << "Diet is NONE on creature type mobile " << templateName;
		}

		// Verify scale
		float scale = creature->getScale();
		EXPECT_TRUE( scale > 0 ) << "Scale is not a positive value on mobile: " << templateName;

		// Verify PACK mobs have a social group
		uint32 creatureBitmask = creature->getCreatureBitmask();
		String socialGroup = creature->getSocialGroup();
		if (creatureBitmask & CreatureFlag::PACK) {
			EXPECT_FALSE( socialGroup.isEmpty() ) << "Social group is empty on pack mobile: " << templateName;
		}

		// Verify loot group percentages
		LootGroupCollection* groupCollection = creature->getLootGroups();
		if( groupCollection->count() > 0 ){


			for( int i = 0; i < groupCollection->count(); i++ ){

				LootGroupCollectionEntry* collectionEntry = groupCollection->get(i);
				LootGroups* groups = collectionEntry->getLootGroups();
				if( groups->count() > 0){

					int totalChance = 0;
					for( int j = 0; j < groups->count(); j++ ){

						LootGroupEntry* lootGroup = groups->get(j);
						totalChance += lootGroup->getLootChance();

						// Verify loot group is configured correctly
						LootGroupTemplate* foundGroup = lootGroupMap->getLootGroupTemplate( lootGroup->getLootGroupName() );
						std::string groupName( lootGroup->getLootGroupName().toCharArray() );
						EXPECT_TRUE( foundGroup != NULL ) << "Loot group " << groupName << " from " << templateName << " was not found in LootGroupMap";

					}

					EXPECT_EQ( 10000000, totalChance ) << "Loot groups total chance is incorrect " << templateName;
				}
			}
		}

		// Verify weapon groups exist
		Vector<String> weapons = creature->getWeapons();
		for (int i = 0; i < weapons.size(); i++) {
			String weaponGroup = weapons.get(i);
			std::string groupName( weaponGroup.toCharArray() );
			Vector<String> group = CreatureTemplateManager::instance()->getWeapons(weaponGroup);
			EXPECT_TRUE( group.size() > 0 ) << "Weapon group " << groupName << " from " << templateName << " was not found in weaponMap";
		}

		// Verify conversation template exist, and the mob has converse option bit
		uint32 convoTemplate = creature->getConversationTemplate();
		uint32 optionsBitmask = creature->getOptionsBitmask();
		if (convoTemplate != 0) {
			ConversationTemplate* convoTemp = CreatureTemplateManager::instance()->getConversationTemplate(convoTemplate);
			EXPECT_TRUE( convoTemp != NULL ) << "Conversation template from " << templateName << " was not found.";
			EXPECT_TRUE( optionsBitmask & OptionBitmask::CONVERSE ) << templateName << " has a convo template but not the CONVERSE options bit.";
		}
		// Verify that mobs with converse option bit have a convo template
		if (optionsBitmask & OptionBitmask::CONVERSE) {
			EXPECT_TRUE( convoTemplate != 0 ) << templateName << " has the CONVERSE options bit but not a convo template.";
		}

		// Verify that outfits exist
		String outfit = creature->getOutfit();
		if (!outfit.isEmpty()) {
			MobileOutfitGroup* outfitGroup = CreatureTemplateManager::instance()->getMobileOutfitGroup(outfit);
			EXPECT_TRUE( outfitGroup != NULL ) << "Outfit group " << outfit.toCharArray() << " from " << templateName << " was not found.";
		}

		// Verify attacks are valid commands
		CreatureAttackMap* cam = creature->getAttacks();
		for (int i = 0; i < cam->size(); i++) {
			String commandName = cam->getCommand(i);

			EXPECT_TRUE( commandName.isEmpty() || commandConfigManager->contains(commandName) ) << "Attack: " << commandName.toCharArray() << " is not a valid command in mobile template: " << templateName;
		}

		// Very attackable npcs
		uint32 pvpBitmask = creature->getPvpBitmask();
		if ((pvpBitmask & CreatureFlag::ATTACKABLE) && objectType == 1025) {
			// Verify attackable npcs have attacks
			EXPECT_TRUE( cam->size() > 0 ) << "Attackable npc " << templateName << " does not have attacks.";
		}
	}

	// Test Lair Templates
	HashTableIterator<uint32, Reference<LairTemplate*> > lairIterator = CreatureTemplateManager::instance()->lairTemplateIterator();
	while (lairIterator.hasNext()) {
		LairTemplate* lair = lairIterator.next();
		std::string templateName( lair->getName().toCharArray() );

		// Verify that mobiles exist and that their weighting is positive
		VectorMap<String, int>* mobiles = lair->getMobiles();
		for (int i = 0; i < mobiles->size(); i++) {
			int weighting = mobiles->elementAt(i).getValue();
			String mobile = mobiles->elementAt(i).getKey();
			std::string mobName = mobile.toCharArray();
			EXPECT_TRUE( CreatureTemplateManager::instance()->getTemplate(mobile) != NULL ) << "Mobile " << mobName << " in lair template " << templateName << " does not exist";
			EXPECT_TRUE( weighting > 0 ) << "Mobile " << mobName << " in lair template " << templateName << " has a non positive weighting";
		}

		// Verify that boss mobiles exist and that their count is positive
		VectorMap<String, int>* bossMobiles = lair->getBossMobiles();
		for (int i = 0; i < bossMobiles->size(); i++) {
			int count = bossMobiles->elementAt(i).getValue();
			String bossMob = bossMobiles->elementAt(i).getKey();
			std::string bossName = bossMob.toCharArray();
			EXPECT_TRUE( CreatureTemplateManager::instance()->getTemplate(bossMob) != NULL ) << "Boss mobile " << bossName << " in lair template " << templateName << " does not exist";
			EXPECT_TRUE( count > 0 ) << "Boss mobile " << bossName << " in lair template " << templateName << " has a non positive spawn count";
		}

		// Verify spawn limit is positive
		int limit = lair->getSpawnLimit();
		EXPECT_TRUE( limit > 0 ) << "Spawn limit in lair template " << templateName << " is not positive";

		// Verify any configured buildings exist
		int buildingCount = 0;
		for(int i=0; i<=4; i++){

			Vector<String>* buildings = lair->getBuildings( i );
			if( buildings == NULL )
				continue;

			buildingCount += buildings->size();

			for( int j=0; j < buildings->size(); j++ ){
				String buildingTemplate = buildings->get(j);
				std::string buildingStr = buildingTemplate.toCharArray();
				SharedObjectTemplate* templateObject = templateManager->getTemplate(buildingTemplate.hashCode());
				EXPECT_TRUE( templateObject != NULL && templateObject->isSharedTangibleObjectTemplate() ) << "Building template " << buildingStr << " in lair template " << templateName << " does not exist";
				if( lair->getBuildingType() == LairTemplate::LAIR ){
					EXPECT_TRUE( buildingTemplate.beginsWith( "object/tangible/lair/") ) << "Building template " << buildingStr << " in lair template " << templateName << " is not a child of object/tangible/lair/";
				}
				if( lair->getBuildingType() == LairTemplate::THEATER ){
					EXPECT_TRUE( buildingTemplate.beginsWith( "object/building/poi/") ) << "Building template " << buildingStr << " in lair template " << templateName << " is not a child of object/building/poi/";
				}
			}
		}

		// Verify mission buildings exist and are lairs
		String missionBuilding = lair->getMissionBuilding(10);
		if (!missionBuilding.isEmpty()) {
			std::string buildingStr = missionBuilding.toCharArray();
			SharedObjectTemplate* templateObject = templateManager->getTemplate(missionBuilding.hashCode());
			EXPECT_TRUE( templateObject != NULL && templateObject->isSharedTangibleObjectTemplate() ) << "Mission building template " << buildingStr << " in lair template " << templateName << " does not exist";
			EXPECT_TRUE( missionBuilding.beginsWith( "object/tangible/lair/") ) << "Mission building template " << buildingStr << " in lair template " << templateName << " is not a child of object/tangible/lair/";
		}

		if( lair->getBuildingType() == LairTemplate::THEATER ){
			EXPECT_TRUE( buildingCount > 0 ) << "There are no buildings configured in theater type lair template " << templateName;
		}
		if( lair->getBuildingType() == LairTemplate::NONE ){
			EXPECT_TRUE( buildingCount == 0 ) << "There are buildings configured in 'none' type lair template " << templateName;
		}
		if( lair->getBuildingType() == LairTemplate::LAIR ){
			EXPECT_TRUE( buildingCount > 0 ) << "There are no buildings configured in lair type lair template " << templateName;
		}

	}

	// Test Spawn Groups
	HashTableIterator<uint32, Reference<SpawnGroup*> > spawnIterator = CreatureTemplateManager::instance()->spawnGroupIterator();
	while (spawnIterator.hasNext()) {
		SpawnGroup* group = spawnIterator.next();
		std::string templateName( group->getTemplateName().toCharArray() );

		Vector<String> lairTemplates;

		// Verify spawn list
		Vector<Reference<LairSpawn*> >* spawnList = group->getSpawnList();
		for (int i = 0; i < spawnList->size(); i++) {
			LairSpawn* spawn = spawnList->get(i);
			std::string lairName( spawn->getLairTemplateName().toCharArray() );

			// Verify lair template exists and isn't duplicated in the group
			String lairTemplateName = spawn->getLairTemplateName();
			Reference<LairTemplate*> lairTemplate = CreatureTemplateManager::instance()->getLairTemplate(lairTemplateName.hashCode());
			EXPECT_TRUE( lairTemplate != NULL ) << "Lair template " << lairName << " in spawn group " << templateName << " does not exist.";
			EXPECT_FALSE( lairTemplates.contains(lairTemplateName) ) << "Lair template " << lairName << " is duplicated in spawn group " << templateName;
			lairTemplates.add(lairTemplateName);

			// Verify spawn limit is at least -1
			float spawnLimit = spawn->getSpawnLimit();
			EXPECT_TRUE( spawnLimit >= -1 ) << "SpawnLimit for lairTemplate " << lairName << " in spawn group " << templateName << " is less than -1.";

			// Verify difficulties
			int minDiff = spawn->getMinDifficulty();
			int maxDiff = spawn->getMaxDifficulty();
			EXPECT_TRUE( minDiff > 0 ) << "MinDifficulty for lairTemplate " << lairName << " in spawn group " << templateName << " is not positive.";
			EXPECT_TRUE( maxDiff >= minDiff ) << "MaxDifficulty for lairTemplate " << lairName << " in spawn group " << templateName << " is less than min difficulty.";

			// Verify number to spawn is not negative
			int numberToSpawn = spawn->getNumberToSpawn();
			EXPECT_TRUE( numberToSpawn >= 0 ) << "NumberToSpawn for lairTemplate " << lairName << " in spawn group " << templateName << " is negative.";

			// Verify weighting is positive
			int weighting = spawn->getWeighting();
			EXPECT_TRUE( weighting > 0 ) << "Weighting for lairTemplate " << lairName << " in spawn group " << templateName << " is not positive.";

			// Verify size is at least 1
			float size = spawn->getSize();
			EXPECT_TRUE( size >= 1 ) << "Size for lairTemplate " << lairName << " in spawn group " << templateName << " is less than 1.";
		}
	}

	// Test Destroy Mission Spawn Groups
	HashTableIterator<uint32, Reference<SpawnGroup*> > missionIterator = CreatureTemplateManager::instance()->destroyMissionGroupIterator();
	while (missionIterator.hasNext()) {
		SpawnGroup* group = missionIterator.next();
		std::string templateName( group->getTemplateName().toCharArray() );

		Vector<String> lairTemplates;

		// Verify spawn list
		Vector<Reference<LairSpawn*> >* spawnList = group->getSpawnList();
		for (int i = 0; i < spawnList->size(); i++) {
			LairSpawn* spawn = spawnList->get(i);
			std::string lairName( spawn->getLairTemplateName().toCharArray() );

			// Verify lair template exists
			String lairTemplateName = spawn->getLairTemplateName();
			Reference<LairTemplate*> lairTemplate = CreatureTemplateManager::instance()->getLairTemplate(lairTemplateName.hashCode());
			EXPECT_TRUE( lairTemplate != NULL ) << "Lair template " << lairName << " in destroy mission spawn group " << templateName << " does not exist.";
			EXPECT_FALSE( lairTemplates.contains(lairTemplateName) ) << "Lair template " << lairName << " is duplicated in destroy mission spawn group " << templateName;
			lairTemplates.add(lairTemplateName);

			if (lairTemplate != NULL) {
				// Verify that lair template has a valid mission building or is of type LAIR
				String missionBuilding = lairTemplate->getMissionBuilding(10);
				if (!missionBuilding.isEmpty()) {
					std::string buildingStr = missionBuilding.toCharArray();
					SharedObjectTemplate* templateObject = templateManager->getTemplate(missionBuilding.hashCode());
					EXPECT_TRUE( templateObject != NULL && templateObject->isSharedTangibleObjectTemplate() ) << "Mission building template " << buildingStr << " in lair template " << lairName << ", part of destroy mission group " << templateName << " does not exist";
					EXPECT_TRUE( missionBuilding.beginsWith( "object/tangible/lair/") ) << "Mission building template " << buildingStr << " in lair template " << lairName << ", part of destroy mission group " << templateName << " is not a child of object/tangible/lair/";
				} else {
					EXPECT_TRUE( lairTemplate->getBuildingType() == LairTemplate::LAIR ) << "Lair template " << lairName << ", part of destroy mission group " << templateName << " is not of type LAIR";
				}
			}

			// Verify difficulties
			int minDiff = spawn->getMinDifficulty();
			int maxDiff = spawn->getMaxDifficulty();
			EXPECT_TRUE( minDiff > 0 ) << "MinDifficulty for lairTemplate " << lairName << " in destroy mission spawn group " << templateName << " is not positive.";
			EXPECT_TRUE( maxDiff >= minDiff ) << "MaxDifficulty for lairTemplate " << lairName << " in destroy mission spawn group " << templateName << " is less than min difficulty.";

			// Verify size is at least 1
			float size = spawn->getSize();
			EXPECT_TRUE( size >= 1 ) << "Size for lairTemplate " << lairName << " in destroy mission spawn group " << templateName << " is less than 1.";
		}
	}
}
bool PetManagerImplementation::handleCommandTraining(CreatureObject* speaker, AiAgent* pet, const String& message){

	if( speaker == NULL || pet == NULL )
		return false;

	if( message.isEmpty() )
		return false;

	ManagedWeakReference< CreatureObject*> linkedCreature = pet->getLinkedCreature();
	if( linkedCreature == NULL )
		return false;

	// Only owner may train
	if( linkedCreature != speaker)
		return false;

	ManagedReference<PetControlDevice*> pcd = pet->getControlDevice().get().castTo<PetControlDevice*>();

	if( pcd == NULL )
		return false;

	if( pcd->hasTrainedCommandString(message) ){
		pet->showFlyText("npc_reaction/flytext","confused", 204, 0, 0);  // "?!!?!?!"
		return true;
	}

	unsigned int trainingCommand = pcd->getTrainingCommand();
	int petType = pcd->getPetType();

	// Train command
	if (petType == CREATUREPET) {
		bool alreadyTrained = pcd->hasTrainedCommand(trainingCommand);

		if (!alreadyTrained) {
			bool success = false;

			int skill = speaker->getSkillMod("tame_level");
			int roll = System::random(skill + 30);

			if (skill > roll)
				success = true;

			if (!success) {
				pet->showFlyText("npc_reaction/flytext","confused", 204, 0, 0);  // "?!!?!?!"
				speaker->sendSystemMessage("@pet/pet_menu:pet_nolearn"); // Your pet doesn't seem to understand you.
				return true;
			}
		}

		// Success
		pcd->addTrainedCommand( trainingCommand, message );
		pet->showFlyText("npc_reaction/flytext","threaten", 204, 0, 0);  // "!"
		speaker->sendSystemMessage("@pet/pet_menu:pet_learn"); // You teach your pet a new command.

		if (!alreadyTrained) {
			CreatureTemplate* creatureTemplate = pet->getCreatureTemplate();

			if (creatureTemplate == NULL)
				return true;

			PlayerManager* playerManager = zoneServer->getPlayerManager();
			playerManager->awardExperience(speaker, "creaturehandler", 10 * creatureTemplate->getLevel());
		}
	}
	else{
		pcd->addTrainedCommand( trainingCommand, message );
		pet->showFlyText("npc_reaction/flytext","threaten", 204, 0, 0);  // "!"
		speaker->sendSystemMessage("@pet/pet_menu:pet_learn"); // You teach your pet a new command.
	}

	// No renaming of faction pets
	if (petType == FACTIONPET)
		return true;

	// Check for naming string
	StringTokenizer tokenizer(message);
	tokenizer.setDelimeter(" ");
	String parsedName = "";
	int numberOfSubStrings = 0;

	while (tokenizer.hasMoreTokens()) {
		numberOfSubStrings++;

		if (!parsedName.isEmpty())
			break;

		tokenizer.getStringToken(parsedName);
	}

	String futureName = pcd->getFutureName();
	unsigned int namingProgress = pcd->getNamingProgress();

	// Validate and check name
	if (numberOfSubStrings > 1) {
		ZoneProcessServer* zps = pet->getZoneProcessServer();
		NameManager* nameManager = zps->getNameManager();

		if (nameManager->validateName(parsedName) != NameManagerResult::ACCEPTED) {
			return true;
		}
		if (futureName == parsedName  && !pcd->hasUsedNamingCommand(trainingCommand)) {
			pcd->incrementNamingProgress(trainingCommand);
		}
		else {
			pcd->resetNamingProgress();
			pcd->incrementNamingProgress(trainingCommand);
			pcd->setFutureName(parsedName);
			return true;
		}
	} else {
		pcd->resetNamingProgress();
		parsedName = "";
		pcd->setFutureName(parsedName);
		return true;
	}

	// Set name, if applicable
	if (pcd->getNamingProgress() == 4) {
		UnicodeString newName = "(" + futureName + ")";
		pcd->setCustomObjectName(newName, true);
		pet->setCustomObjectName(newName, true);
		pcd->resetNamingProgress();
	}

	return true;
}
Exemple #13
0
void DnaManager::generateSample(Creature* creature, CreatureObject* player,int quality){
	if (quality < 0 || quality > 7) {
		return;
	}
	Locker lock(creature,player);
	CreatureTemplate* creatureTemplate = dynamic_cast<CreatureTemplate*>(creature->getCreatureTemplate());

	int ferocity = creatureTemplate->getFerocity();
	int cl = creature->getLevel();
	int cle = instance()->generateScoreFor(DnaManager::CLEVERNESS,cl,quality);
	int cou = instance()->generateScoreFor(DnaManager::COURAGE,cl,quality);
	int dep = instance()->generateScoreFor(DnaManager::DEPENDABILITY,cl,quality);
	int dex = instance()->generateScoreFor(DnaManager::DEXTERITY,cl,quality);
	int end = instance()->generateScoreFor(DnaManager::ENDURANCE,cl,quality);
	int fie = instance()->generateScoreFor(DnaManager::FIERCENESS,ferocity,quality);
	int frt = instance()->generateScoreFor(DnaManager::FORTITUDE,cl,quality);
	int har = instance()->generateScoreFor(DnaManager::HARDINESS,cl,quality);
	int ite = instance()->generateScoreFor(DnaManager::INTELLIGENCE,cl,quality);
	int pow = instance()->generateScoreFor(DnaManager::POWER,cl,quality);
	// We should now have enough to generate a sample
	ManagedReference<DnaComponent*> prototype = player->getZoneServer()->createObject(qualityTemplates.get(quality), 1).castTo<DnaComponent*>();
	if (prototype == NULL) {
		return;
	}
	Locker clocker(prototype);
	// Check Here for unique npcs
	StringId* nameId = creature->getObjectName();
	if (nameId->getFile().isEmpty() || nameId->getStringID().isEmpty()) {
		prototype->setSource(creature->getCreatureName().toString());
	} else {
		prototype->setSource(nameId->getFullPath());
	}
	prototype->setQuality(quality);
	prototype->setLevel(cl);
	String serial = player->getZoneServer()->getCraftingManager()->generateSerial();
	prototype->setSerialNumber(serial);
	prototype->setStats(cle,end,fie,pow,ite,cou,dep,dex,frt,har);
	prototype->setStun(creatureTemplate->getStun());
	prototype->setKinetic(creatureTemplate->getKinetic());
	prototype->setEnergy(creatureTemplate->getEnergy());
	prototype->setBlast(creatureTemplate->getBlast());
	prototype->setHeat(creatureTemplate->getHeat());
	prototype->setCold(creatureTemplate->getCold());
	prototype->setElectric(creatureTemplate->getElectricity());
	prototype->setAcid(creatureTemplate->getAcid());
	prototype->setSaber(creatureTemplate->getLightSaber());
	prototype->setRanged(creatureTemplate->getWeapons().size() > 0);
	prototype->setArmorRating(creatureTemplate->getArmor());
	CreatureAttackMap* attackMap = creatureTemplate->getAttacks();
	if (attackMap->size() > 0) {
		prototype->setSpecialAttackOne(String(attackMap->getCommand(0)));
		if(attackMap->size() > 1) {
			prototype->setSpecialAttackTwo(String(attackMap->getCommand(1)));
		}
	}

	ManagedReference<SceneObject*> inventory = player->getSlottedObject("inventory");

	if (inventory->hasFullContainerObjects()) {
		StringIdChatParameter err("survey", "no_inv_space");
		player->sendSystemMessage(err);
		player->setPosture(CreaturePosture::UPRIGHT, true);
		return;
	}

	Locker locker(inventory);
	inventory->transferObject(prototype, -1, true,false);
	inventory->broadcastObject(prototype, true);
}
bool CreatureImplementation::isVicious() {
	CreatureTemplate* creatureTemplate = npcTemplate.get();

	return creatureTemplate->getPvpBitmask() & CreatureFlag::AGGRESSIVE;
}
void PetControlDeviceImplementation::fillAttributeList(AttributeListMessage* alm, CreatureObject* object) {
	SceneObjectImplementation::fillAttributeList(alm, object);

	if (petType == PetManager::DROIDPET) {
		alm->insertAttribute("creature_vitality", String::valueOf(vitality) + "/" + String::valueOf(maxVitality));

		ManagedReference<DroidObject*> droid = this->controlledObject.get().castTo<DroidObject*>();

		if (droid != NULL) {
			droid->fillAttributeList(alm, object);
		}
	} else {
		ManagedReference<AiAgent*> pet = cast<AiAgent*>(this->controlledObject.get().get());

		if (pet != NULL) {
			alm->insertAttribute("challenge_level", pet->getLevel());

			if (petType == PetManager::CREATUREPET)
				alm->insertAttribute("creature_vitality", String::valueOf(vitality) + "/" + String::valueOf(maxVitality));

			alm->insertAttribute("creature_health", pet->getBaseHAM(0));
			alm->insertAttribute("creature_action", pet->getBaseHAM(3));
			alm->insertAttribute("creature_mind", pet->getBaseHAM(6));

			int armor = pet->getArmor();
			if (armor == 0)
				alm->insertAttribute("armor_rating", "None");
			else if (armor == 1)
				alm->insertAttribute("armor_rating", "Light");
			else if (armor == 2)
				alm->insertAttribute("armor_rating", "Medium");
			else if (armor == 3)
				alm->insertAttribute("armor_rating", "Heavy");

			if (pet->getKinetic() < 0)
				alm->insertAttribute("dna_comp_armor_kinetic", "Vulnerable");
			else
				alm->insertAttribute("dna_comp_armor_kinetic", pet->getKinetic());

			if (pet->getEnergy() < 0)
				alm->insertAttribute("dna_comp_armor_energy", "Vulnerable");
			else
				alm->insertAttribute("dna_comp_armor_energy", pet->getEnergy());

			if (pet->getBlast() < 0)
				alm->insertAttribute("dna_comp_armor_blast", "Vulnerable");
			else
				alm->insertAttribute("dna_comp_armor_blast", pet->getBlast());

			if (pet->getHeat() < 0)
				alm->insertAttribute("dna_comp_armor_heat", "Vulnerable");
			else
				alm->insertAttribute("dna_comp_armor_heat", pet->getHeat());

			if (pet->getCold() < 0)
				alm->insertAttribute("dna_comp_armor_cold", "Vulnerable");
			else
				alm->insertAttribute("dna_comp_armor_cold", pet->getCold());

			if (pet->getElectricity() < 0)
				alm->insertAttribute("dna_comp_armor_electric", "Vulnerable");
			else
				alm->insertAttribute("dna_comp_armor_electric", pet->getElectricity());

			if (pet->getAcid() < 0)
				alm->insertAttribute("dna_comp_armor_acid", "Vulnerable");
			else
				alm->insertAttribute("dna_comp_armor_acid", pet->getAcid());

			if (pet->getStun() < 0)
				alm->insertAttribute("dna_comp_armor_stun", "Vulnerable");
			else
				alm->insertAttribute("dna_comp_armor_stun", pet->getStun());

			if (pet->getLightSaber() < 0)
				alm->insertAttribute("dna_comp_armor_saber", "Vulnerable");
			else
				alm->insertAttribute("dna_comp_armor_saber", pet->getLightSaber());

			ManagedReference<WeaponObject*> weapon = pet->getWeapon();
			if (weapon != NULL)
				alm->insertAttribute("creature_attack", weapon->getAttackSpeed());

			alm->insertAttribute("creature_tohit", pet->getChanceHit());
			alm->insertAttribute("creature_damage", String::valueOf(pet->getDamageMin()) + " - " + String::valueOf(pet->getDamageMax()));

			if (petType == PetManager::CREATUREPET) {
				CreatureAttackMap* attMap = pet->getAttackMap();
				if (attMap->size() > 0) {
					String str = StringIdManager::instance()->getStringId(("@combat_effects:" + pet->getAttackMap()->getCommand(0)).hashCode()).toString();
					alm->insertAttribute("spec_atk_1", str);
				} else
					alm->insertAttribute("spec_atk_1", " ---");

				if (attMap->size() > 1) {
					String str = StringIdManager::instance()->getStringId(("@combat_effects:" + pet->getAttackMap()->getCommand(1)).hashCode()).toString();
					alm->insertAttribute("spec_atk_2", str);
				} else
					alm->insertAttribute("spec_atk_2", " ---");

				CreatureTemplate* creatureTemplate = pet->getCreatureTemplate();
				if (creatureTemplate != NULL) {
					if (creatureTemplate->getWeapons().size() > 0)
						alm->insertAttribute("dna_comp_ranged_attack", "Yes");
					else
						alm->insertAttribute("dna_comp_ranged_attack", "No");
				} else
					alm->insertAttribute("dna_comp_ranged_attack", "No");
			}
		}
	}

	// Trained Commands
	if ( trainedCommands.size() > 0) {
		alm->insertAttribute("pet_command", "" );
	}

	if( trainedCommands.contains(PetManager::STAY) ){
		alm->insertAttribute("pet_command_1", trainedCommands.get(PetManager::STAY) );
	}

	if( trainedCommands.contains(PetManager::FOLLOW) ){
		alm->insertAttribute("pet_command_0", trainedCommands.get(PetManager::FOLLOW) );
	}

	if( trainedCommands.contains(PetManager::STORE) ){
		alm->insertAttribute("pet_command_11", trainedCommands.get(PetManager::STORE) );
	}

	if( trainedCommands.contains(PetManager::ATTACK) ){
		alm->insertAttribute("pet_command_4", trainedCommands.get(PetManager::ATTACK) );
	}

	if( trainedCommands.contains(PetManager::GUARD) ){
		alm->insertAttribute("pet_command_2", trainedCommands.get(PetManager::GUARD) );
	}

	if( trainedCommands.contains(PetManager::FRIEND) ){
		alm->insertAttribute("pet_command_3", trainedCommands.get(PetManager::FRIEND) );
	}

	if( trainedCommands.contains(PetManager::FOLLOWOTHER) ){
		alm->insertAttribute("pet_command_17", trainedCommands.get(PetManager::FOLLOWOTHER) );
	}

	if( trainedCommands.contains(PetManager::TRICK1) ){
		alm->insertAttribute("pet_command_12", trainedCommands.get(PetManager::TRICK1) );
	}

	if( trainedCommands.contains(PetManager::TRICK2) ){
		alm->insertAttribute("pet_command_13", trainedCommands.get(PetManager::TRICK2) );
	}

	if( trainedCommands.contains(PetManager::PATROL) ){
		alm->insertAttribute("pet_command_5", trainedCommands.get(PetManager::PATROL) );
	}

	if( trainedCommands.contains(PetManager::FORMATION1) ){
		alm->insertAttribute("pet_command_8", trainedCommands.get(PetManager::FORMATION1) );
	}

	if( trainedCommands.contains(PetManager::FORMATION2) ){
		alm->insertAttribute("pet_command_9", trainedCommands.get(PetManager::FORMATION2) );
	}

	if( trainedCommands.contains(PetManager::SPECIAL_ATTACK1) ){
		alm->insertAttribute("pet_command_18", trainedCommands.get(PetManager::SPECIAL_ATTACK1) );
	}

	if( trainedCommands.contains(PetManager::SPECIAL_ATTACK2) ){
		alm->insertAttribute("pet_command_19", trainedCommands.get(PetManager::SPECIAL_ATTACK2) );
	}

	if( trainedCommands.contains(PetManager::RANGED_ATTACK) ){
		alm->insertAttribute("pet_command_20", trainedCommands.get(PetManager::RANGED_ATTACK) );
	}

	if( trainedCommands.contains(PetManager::GROUP) ){
		alm->insertAttribute("pet_command_16", trainedCommands.get(PetManager::GROUP) );
	}

	if( trainedCommands.contains(PetManager::RECHARGEOTHER) ){
		alm->insertAttribute("@pet/pet_menu:menu_recharge_other", trainedCommands.get(PetManager::RECHARGEOTHER) );
	}

	if( trainedCommands.contains(PetManager::TRANSFER) ){
		alm->insertAttribute("pet_command_10", trainedCommands.get(PetManager::TRANSFER) );
	}
}