<commit_before>
#ifndef TAMECREATURETASK_H_
#define TAMECREATURETASK_H_

#include "server/zone/managers/combat/CombatManager.h"
#include "server/zone/managers/creature/CreatureManager.h"
#include "server/zone/managers/creature/PetManager.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/intangible/PetControlDevice.h"
#include "server/chat/ChatManager.h"
#include "engine/engine.h"

class TameCreatureTask : public Task {

private:
	enum Phase { INITIAL, SECOND, THIRD, FOURTH, FINAL} currentPhase;
	int originalMask;
	ManagedReference<Creature*> creature;
	ManagedReference<CreatureObject*> player;
	bool force;

public:
	TameCreatureTask(Creature* cre, CreatureObject* playo, int pvpMask, bool forced) : Task() {
		currentPhase = INITIAL;
		creature = cre;
		player = playo;
		originalMask = pvpMask;
		force = forced;
	}

	void run() {
		Locker locker(creature);

		Locker _clocker(player, creature);

		player->removePendingTask("tame_pet");

		if (force) {
			success(player, creature);
			return;
		}

		if (!creature->isInRange(player, 8.0f)) {
			player->sendSystemMessage("@hireling/hireling:taming_toofar"); // You are too far away to continue taming.
			creature->showFlyText("npc_reaction/flytext","toofar", 204, 0, 0);  // You are too far away to tame the creature.
			creature->setPvpStatusBitmask(originalMask, true);
			return;
		}

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

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

		switch (currentPhase) {
		case INITIAL:
			chatManager->broadcastMessage(player, "@hireling/hireling:taming_2"); // Steady.
			player->doAnimation("");
			currentPhase = SECOND;
			player->addPendingTask("tame_pet", this, 8000);
			break;
		case SECOND:
			chatManager->broadcastMessage(player, "@hireling/hireling:taming_3"); // Don't be scared.
			currentPhase = THIRD;
			player->addPendingTask("tame_pet", this, 8000);
			break;
		case THIRD:
			chatManager->broadcastMessage(player, "@hireling/hireling:taming_4"); // Don't bite me.
			currentPhase = FOURTH;
			player->addPendingTask("tame_pet", this, 8000);
			break;
		case FOURTH:
			chatManager->broadcastMessage(player, "@hireling/hireling:taming_5"); // Good... er... boy?
			currentPhase = FINAL;
			player->addPendingTask("tame_pet", this, 8000);
			break;
		case FINAL:
			float tamingChance = creature->getChanceToTame(player);

			if (tamingChance > System::random(100))
				success(player, creature);
			else {
				player->sendSystemMessage("@hireling/hireling:taming_fail"); // You fail to tame the creature.
				creature->showFlyText("npc_reaction/flytext","fail", 204, 0, 0);  // You fail to tame the creature.
				creature->setPvpStatusBitmask(originalMask, true);

				int ferocity = creature->getFerocity();
				if (System::random(20 - ferocity) == 0)
					CombatManager::instance()->startCombat(creature,player,true);
			}

			break;
		}

		return;
	}

	void success(CreatureObject* player, Creature* creature) {
		ZoneServer* zoneServer = player->getZoneServer();

		String objectString = creature->getControlDeviceTemplate();
		if (objectString == "")
			objectString = "object/intangible/pet/pet_control.iff";

		ManagedReference<PetControlDevice*> controlDevice = zoneServer->createObject(objectString.hashCode(), 1).castTo<PetControlDevice*>();

		if (controlDevice == NULL)
			return;

		SceneObject* datapad = player->getSlottedObject("datapad");
		PlayerManager* playerManager = zoneServer->getPlayerManager();
		ObjectManager* objectManager = zoneServer->getObjectManager();

		if (datapad == NULL || playerManager == NULL || objectManager == NULL)
			return;

		controlDevice->setControlledObject(creature);<commit_msg>[Fixed] babies sometimes staying unattackable when a tame fails<commit_after>
#ifndef TAMECREATURETASK_H_
#define TAMECREATURETASK_H_

#include "server/zone/managers/combat/CombatManager.h"
#include "server/zone/managers/creature/CreatureManager.h"
#include "server/zone/managers/creature/PetManager.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/intangible/PetControlDevice.h"
#include "server/chat/ChatManager.h"
#include "engine/engine.h"

class TameCreatureTask : public Task {

private:
	enum Phase { INITIAL, SECOND, THIRD, FOURTH, FINAL} currentPhase;
	int originalMask;
	ManagedReference<Creature*> creature;
	ManagedReference<CreatureObject*> player;
	bool force;

public:
	TameCreatureTask(Creature* cre, CreatureObject* playo, int pvpMask, bool forced) : Task() {
		currentPhase = INITIAL;
		creature = cre;
		player = playo;
		originalMask = pvpMask;
		force = forced;
	}

	void run() {
		Locker locker(creature);

		Locker _clocker(player, creature);

		player->removePendingTask("tame_pet");

		if (force) {
			success(player, creature);
			return;
		}

		if (!creature->isInRange(player, 8.0f)) {
			player->sendSystemMessage("@hireling/hireling:taming_toofar"); // You are too far away to continue taming.
			creature->showFlyText("npc_reaction/flytext","toofar", 204, 0, 0);  // You are too far away to tame the creature.
			creature->setPvpStatusBitmask(originalMask, true);
			return;
		}

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

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

		switch (currentPhase) {
		case INITIAL:
			chatManager->broadcastMessage(player, "@hireling/hireling:taming_2"); // Steady.
			player->doAnimation("");
			currentPhase = SECOND;
			player->addPendingTask("tame_pet", this, 8000);
			break;
		case SECOND:
			chatManager->broadcastMessage(player, "@hireling/hireling:taming_3"); // Don't be scared.
			currentPhase = THIRD;
			player->addPendingTask("tame_pet", this, 8000);
			break;
		case THIRD:
			chatManager->broadcastMessage(player, "@hireling/hireling:taming_4"); // Don't bite me.
			currentPhase = FOURTH;
			player->addPendingTask("tame_pet", this, 8000);
			break;
		case FOURTH:
			chatManager->broadcastMessage(player, "@hireling/hireling:taming_5"); // Good... er... boy?
			currentPhase = FINAL;
			player->addPendingTask("tame_pet", this, 8000);
			break;
		case FINAL:
			float tamingChance = creature->getChanceToTame(player);

			if (tamingChance > System::random(100))
				success(player, creature);
			else {
				player->sendSystemMessage("@hireling/hireling:taming_fail"); // You fail to tame the creature.
				creature->showFlyText("npc_reaction/flytext","fail", 204, 0, 0);  // You fail to tame the creature.
				creature->setPvpStatusBitmask(originalMask, true);

				int ferocity = creature->getFerocity();
				if (System::random(20 - ferocity) == 0)
					CombatManager::instance()->startCombat(creature,player,true);
			}

			break;
		}

		return;
	}

	void success(CreatureObject* player, Creature* creature) {
		ZoneServer* zoneServer = player->getZoneServer();

		String objectString = creature->getControlDeviceTemplate();
		if (objectString == "")
			objectString = "object/intangible/pet/pet_control.iff";

		ManagedReference<PetControlDevice*> controlDevice = zoneServer->createObject(objectString.hashCode(), 1).castTo<PetControlDevice*>();

		if (controlDevice == NULL) {
			creature->setPvpStatusBitmask(originalMask, true);
			return;
		}

		SceneObject* datapad = player->getSlottedObject("datapad");
		PlayerManager* playerManager = zoneServer->getPlayerManager();
		ObjectManager* objectManager = zoneServer->getObjectManager();

		if (datapad == NULL || playerManager == NULL || objectManager == NULL) {
			creature->setPvpStatusBitmask(originalMask, true);
			return;
		}

		controlDevice->setControlledObject(creature);
{'fraction_non_alphanumeric': 0.13482007095793208, 'fraction_numerical': 0.009883426254434871, 'mean_word_length': 4.965986394557823, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 79, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6961774', 'n_tokens_mistral': 2931, 'n_tokens_neox': 2541, 'n_words': 507}