bool PlayerCreationManager::createCharacter(MessageCallback* data) {
	TemplateManager* templateManager = TemplateManager::instance();

	ClientCreateCharacterCallback* callback = cast<
			ClientCreateCharacterCallback*>(data);
	ZoneClientSession* client = data->getClient();

	if (client->getCharacterCount(zoneServer.get()->getGalaxyID()) >= 10) {
		ErrorMessage* errMsg = new ErrorMessage("Create Error", "You are limited to 10 characters per galaxy.", 0x0);
		client->sendMessage(errMsg);

		return false;
	}

	PlayerManager* playerManager = zoneServer.get()->getPlayerManager();

	SkillManager* skillManager = SkillManager::instance();

	//Get all the data and validate it.
	UnicodeString characterName;
	callback->getCharacterName(characterName);

	//TODO: Replace this at some point?
	if (!playerManager->checkPlayerName(callback))
		return false;

	String raceFile;
	callback->getRaceFile(raceFile);

	uint32 serverObjectCRC = raceFile.hashCode();

	PlayerCreatureTemplate* playerTemplate =
			dynamic_cast<PlayerCreatureTemplate*>(templateManager->getTemplate(
					serverObjectCRC));

	if (playerTemplate == NULL) {
		error("Unknown player template selected: " + raceFile);
		return false;
	}

	int raceID = playerTemplate->getRace();


	String fileName = playerTemplate->getTemplateFileName();
	String clientTemplate = templateManager->getTemplateFile(
			playerTemplate->getClientObjectCRC());

	RacialCreationData* raceData = racialCreationData.get(fileName);

	if (raceData == NULL)
		raceData = racialCreationData.get(0); //Just get the first race, since they tried to create a race that doesn't exist.

	String profession, customization, hairTemplate, hairCustomization;
	callback->getSkill(profession);

	if (profession.contains("jedi"))
		profession = "crafting_artisan";

	callback->getCustomizationString(customization);
	callback->getHairObject(hairTemplate);
	callback->getHairCustomization(hairCustomization);

	float height = callback->getHeight();
	height = MAX(MIN(height, playerTemplate->getMaxScale()),
			playerTemplate->getMinScale());

	//validate biography
	UnicodeString bio;
	callback->getBiography(bio);

	bool doTutorial = callback->getTutorialFlag();
	//bool doTutorial = false;

	ManagedReference<CreatureObject*> playerCreature =
			zoneServer.get()->createObject(
					serverObjectCRC, 2).castTo<CreatureObject*>();

	if (playerCreature == NULL) {
		error("Could not create player with template: " + raceFile);
		return false;
	}

	Locker playerLocker(playerCreature);

	playerCreature->createChildObjects();
	playerCreature->setHeight(height);
	playerCreature->setCustomObjectName(characterName, false); //TODO: Validate with Name Manager.

	client->setPlayer(playerCreature);
	playerCreature->setClient(client);

	// Set starting cash and starting bank
	playerCreature->setCashCredits(startingCash, false);
	playerCreature->setBankCredits(startingBank, false);

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

	if (ghost != NULL) {
		//Set skillpoints before adding any skills.
		ghost->setSkillPoints(skillPoints);
		ghost->setStarterProfession(profession);
	}

	addCustomization(playerCreature, customization,
			playerTemplate->getAppearanceFilename());
	addHair(playerCreature, hairTemplate, hairCustomization);
	if (!doTutorial) {
		addProfessionStartingItems(playerCreature, profession, clientTemplate,
				false);
		addStartingItems(playerCreature, clientTemplate, false);
		addRacialMods(playerCreature, fileName,
				playerTemplate->getStartingSkills(),
				playerTemplate->getStartingItems(), false);
	} else {
		addProfessionStartingItems(playerCreature, profession, clientTemplate,
				true);
		addStartingItems(playerCreature, clientTemplate, true);
		addRacialMods(playerCreature, fileName,
				playerTemplate->getStartingSkills(),
				playerTemplate->getStartingItems(), true);
	}

	// Set starting cash and starting bank
	playerCreature->setCashCredits(startingCash, false);
	playerCreature->setBankCredits(startingBank, false);

	if (ghost != NULL) {

		ghost->setAccountID(client->getAccountID());

		if (!freeGodMode) {
			try {
				uint32 accID = client->getAccountID();

				ManagedReference<Account*> playerAccount = playerManager->getAccount(accID);

				if (playerAccount == NULL) {
					playerCreature->destroyPlayerCreatureFromDatabase(true);
					return false;
				}

				int accountPermissionLevel = playerAccount->getAdminLevel();
				String accountName = playerAccount->getUsername();

				if(accountPermissionLevel > 0 && (accountPermissionLevel == 9 || accountPermissionLevel == 10 || accountPermissionLevel == 12 || accountPermissionLevel == 15)) {
					playerManager->updatePermissionLevel(playerCreature, accountPermissionLevel);

					/*
					Reference<ShipControlDevice*> shipControlDevice = zoneServer->createObject(STRING_HASHCODE("object/intangible/ship/sorosuub_space_yacht_pcd.iff"), 1).castTo<ShipControlDevice*>();
					//ShipObject* ship = (ShipObject*) server->createObject(STRING_HASHCODE("object/ship/player/player_sorosuub_space_yacht.iff"), 1);
					Reference<ShipObject*> ship = zoneServer->createObject(STRING_HASHCODE("object/ship/player/player_basic_tiefighter.iff"), 1).castTo<ShipObject*>();

					shipControlDevice->setControlledObject(ship);

					if (!shipControlDevice->transferObject(ship, 4))
						info("Adding of ship to device failed");

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

					if (datapad != NULL) {
						if (!datapad->transferObject(shipControlDevice, -1)) {
							shipControlDevice->destroyObjectFromDatabase(true);
						}
					} else {
						shipControlDevice->destroyObjectFromDatabase(true);
						error("could not get datapad from player");
					}
					*/
				}

				if (accountPermissionLevel < 9) {
					try {
						StringBuffer query;
						//query << "SELECT UNIX_TIMESTAMP(creation_date) FROM characters c WHERE galaxy_id = " << zoneServer.get()->getGalaxyID() << " AND account_id = " << client->getAccountID() << " ORDER BY creation_date desc;";
						uint32 galaxyId = zoneServer.get()->getGalaxyID();
						uint32 accountId = client->getAccountID();
						query << "(SELECT UNIX_TIMESTAMP(c.creation_date) as t FROM characters as c WHERE c.account_id = " << accountId << " AND c.galaxy_id = " << galaxyId << " ORDER BY c.creation_date DESC) UNION (SELECT UNIX_TIMESTAMP(d.creation_date) FROM deleted_characters as d WHERE d.account_id = " << accountId << " AND d.galaxy_id = " << galaxyId << " ORDER BY d.creation_date DESC) ORDER BY t DESC LIMIT 1";

						Reference<ResultSet*> res = ServerDatabase::instance()->executeQuery(query);

						if (res != NULL && res->next()) {
							uint32 sec = res->getUnsignedInt(0);

							Time timeVal(sec);

							if (timeVal.miliDifference() < 86400000) {
								ErrorMessage* errMsg = new ErrorMessage("Create Error", "You are only permitted to create one character every 24 hours. Repeat attempts prior to 24 hours elapsing will reset the timer.", 0x0);
								client->sendMessage(errMsg);

								playerCreature->destroyPlayerCreatureFromDatabase(true);
								return false;
							}
							//timeVal.se
						}
					} catch (DatabaseException& e) {
						error(e.getMessage());
					}

					Locker locker(&charCountMutex);

					if (lastCreatedCharacter.containsKey(accID)) {
						Time lastCreatedTime = lastCreatedCharacter.get(accID);

						if (lastCreatedTime.miliDifference() < 86400000) {
							ErrorMessage* errMsg = new ErrorMessage("Create Error", "You are only permitted to create one character every 24 hours. Repeat attempts prior to 24 hours elapsing will reset the timer.", 0x0);
							client->sendMessage(errMsg);

							playerCreature->destroyPlayerCreatureFromDatabase(true);
							return false;
						} else {
							lastCreatedTime.updateToCurrentTime();

							lastCreatedCharacter.put(accID, lastCreatedTime);
						}
					} else {
						lastCreatedCharacter.put(accID, Time());
					}
				}

			} catch (Exception& e) {
				error(e.getMessage());
			}
		} else {
			playerManager->updatePermissionLevel(playerCreature, PermissionLevelList::instance()->getLevelNumber("admin"));
		}

		if (doTutorial)
			playerManager->createTutorialBuilding(playerCreature);
		else
			playerManager->createSkippedTutorialBuilding(playerCreature);

		ValidatedPosition* lastValidatedPosition =
				ghost->getLastValidatedPosition();
		lastValidatedPosition->update(playerCreature);

		ghost->setBiography(bio);
		ghost->setRaceID(raceID);

		ghost->setLanguageID(playerTemplate->getDefaultLanguage());
	}

	playerCreature->setLevel(1);

	ClientCreateCharacterSuccess* msg = new ClientCreateCharacterSuccess(
			playerCreature->getObjectID());
	playerCreature->sendMessage(msg);

	ChatManager* chatManager = zoneServer.get()->getChatManager();
	chatManager->addPlayer(playerCreature);

	String firstName = playerCreature->getFirstName();
	String lastName = playerCreature->getLastName();

	try {
		StringBuffer query;
		query
				<< "INSERT INTO `characters_dirty` (`character_oid`, `account_id`, `galaxy_id`, `firstname`, `surname`, `race`, `gender`, `template`)"
				<< " VALUES (" << playerCreature->getObjectID() << ","
				<< client->getAccountID() << "," << zoneServer.get()->getGalaxyID()
				<< "," << "'" << firstName.escapeString() << "','"
				<< lastName.escapeString() << "'," << raceID << "," << 0 << ",'"
				<< raceFile.escapeString() << "')";

		ServerDatabase::instance()->executeStatement(query);
	} catch (DatabaseException& e) {
		error(e.getMessage());
	}

	playerManager->addPlayer(playerCreature);

	// Copy claimed veteran rewards from player's alt character
	uint32 accID = client->getAccountID();
	ManagedReference<Account*> playerAccount = playerManager->getAccount(accID);
	if (playerAccount != NULL && ghost != NULL) {

		// Find the first alt character
		ManagedReference<CreatureObject*> altPlayer = NULL;
		CharacterList* characters = playerAccount->getCharacterList();
		for(int i = 0; i < characters->size(); ++i) {
			CharacterListEntry* entry = &characters->get(i);
			if(entry->getGalaxyID() == zoneServer.get()->getGalaxyID() &&
		       entry->getFirstName() != playerCreature->getFirstName() ) {

				altPlayer = playerManager->getPlayer(entry->getFirstName());
				if( altPlayer != NULL ){
					break;
				}
			}
		}

		// Record the rewards if alt player was found
		if( altPlayer != NULL && altPlayer->getPlayerObject() != NULL){

			Locker alocker( altPlayer );
			for( int i = 0; i < playerManager->getNumVeteranRewardMilestones(); i++ ){
				int milestone = playerManager->getVeteranRewardMilestone(i);
				String claimedReward = altPlayer->getPlayerObject()->getChosenVeteranReward(milestone);
				if( !claimedReward.isEmpty() ){
					ghost->addChosenVeteranReward(milestone,claimedReward);
				}
			}
		}
	}

	client->addCharacter(playerCreature->getObjectID(), zoneServer.get()->getGalaxyID());

	JediManager::instance()->onPlayerCreated(playerCreature);

	ManagedReference<SuiMessageBox*> box = new SuiMessageBox(playerCreature, SuiWindowType::NONE);
	box->setPromptTitle("PLEASE NOTE");
	box->setPromptText("You are limited to creating one character every 24 hours. Attempting to create another character or deleting your character before the 24 hour timer expires will reset the timer.");

	ghost->addSuiBox(box);
	playerCreature->sendMessage(box->generateMessage());
	ghost->recalculateCombatLevel(playerCreature);

	return true;
}
void ForageManagerImplementation::startForaging(CreatureObject* player, int forageType) {
	if (player == NULL)
		return;

	Locker playerLocker(player);

	int actionCostForage = 50;
	int mindCostShellfish = 100;
	int actionCostShellfish =  100;

	//Check if already foraging.
	Reference<Task*> pendingForage = player->getPendingTask("foraging");
	if (pendingForage != NULL) {

		if (forageType == ForageManager::SHELLFISH)
			player->sendSystemMessage("@harvesting:busy");
		else
			player->sendSystemMessage("@skl_use:sys_forage_already"); //"You are already foraging."
		return;
	}

	// Check if mounted
	if (player->isRidingMount()) {
		player->sendSystemMessage("@error_message:survey_on_mount"); // You cannot perform that action while mounted on a creature or driving a vehicle.
		return;
	}

	//Check if player is inside a structure.
	if (player->getParentID() != 0) {
		if (forageType == ForageManager::SHELLFISH)
			player->sendSystemMessage("@harvesting:inside");
		else
			player->sendSystemMessage("@skl_use:sys_forage_inside"); //"You can't forage inside a structure."
		return;
	}

	//Check if a player is swimming for shellfish harvesting
	if (forageType == ForageManager::SHELLFISH && player->isSwimming()){
		player->sendSystemMessage("@harvesting:swimming");
		return;
	}

	//Check if player is in water for shellfish harvesting
	if (forageType == ForageManager::SHELLFISH && !player->isInWater()){
		player->sendSystemMessage("@harvesting:in_water");
		return;
	}
    //Check for action and deduct cost.

	if (forageType == ForageManager::SHELLFISH){

		//Adjust costs based upon player's Focus and Quickness
		int mindCost = player->calculateCostAdjustment(CreatureAttribute::FOCUS, mindCostShellfish);
		int actionCost = player->calculateCostAdjustment(CreatureAttribute::QUICKNESS, actionCostShellfish);

		if (player->getHAM(CreatureAttribute::MIND) < mindCost + 1 || player->getHAM(CreatureAttribute::ACTION) < actionCost + 1)
			return;
		else {
			player->inflictDamage(player, CreatureAttribute::MIND, mindCost, false, true);
			player->inflictDamage(player, CreatureAttribute::ACTION, actionCost, false, true);
		}
	}
	else {

		//Adjust action cost based upon a player's Quickness
		int actionCost = player->calculateCostAdjustment(CreatureAttribute::QUICKNESS, actionCostForage);

		if (player->getHAM(CreatureAttribute::ACTION) >= actionCost + 1)
			player->inflictDamage(player, CreatureAttribute::ACTION, actionCost, false, true);

		else {
			player->sendSystemMessage("@skl_use:sys_forage_attrib"); //"You need to rest before you can forage again."
			return;
		}
	}


	//Collect player's current position.
	float playerX = player->getPositionX();
	float playerY = player->getPositionY();
	ManagedReference<ZoneServer*> zoneServer = player->getZoneServer();

	//Queue the foraging task.
	Zone* zone = player->getZone();

	if (zone == NULL)
		return;

	Reference<Task*> foragingEvent = new ForagingEvent(player, forageType, playerX, playerY, zone->getZoneName());
	player->addPendingTask("foraging", foragingEvent, 8500);

	if(forageType == ForageManager::LAIR){
		player->sendSystemMessage("You begin to search the lair for creatures"); //"You begin to search the lair for creatures."
	}
	else{
		player->sendSystemMessage("@skl_use:sys_forage_start"); //"You begin to search the area for goods."
	}
	player->doAnimation("forage");

}
bool ForageManagerImplementation::forageGiveItems(CreatureObject* player, int forageType, float forageX, float forageY, const String& planet) {
	if (player == NULL)
		return false;

	Locker playerLocker(player);

	ManagedReference<LootManager*> lootManager = player->getZoneServer()->getLootManager();
	ManagedReference<SceneObject*> inventory = player->getSlottedObject("inventory");

	if (lootManager == NULL || inventory == NULL) {
		player->sendSystemMessage("@skl_use:sys_forage_fail");
		return false;
	}

	//Check if inventory is full.
	if (inventory->hasFullContainerObjects()) {
		player->sendSystemMessage("@skl_use:sys_forage_noroom"); //"Some foraged items were discarded, because your inventory is full."
		return false;
	}

	int itemCount = 1;
	//Determine how many items the player finds.
	if (forageType == ForageManager::SCOUT) {
		if (player->hasSkill("outdoors_scout_camp_03") && System::random(5) == 1)
			itemCount += 1;
		if (player->hasSkill("outdoors_scout_master") && System::random(5) == 1)
			itemCount += 1;
	}

	//Discard items if player's inventory does not have enough space.
	int inventorySpace = inventory->getContainerVolumeLimit() - inventory->getContainerObjectsSize();
	if (itemCount > inventorySpace) {
		itemCount = inventorySpace;
		player->sendSystemMessage("@skl_use:sys_forage_noroom"); //"Some foraged items were discarded, because your inventory is full."
	}

	//Determine what the player finds.
	int dice;
	int level = 1;
	String lootGroup = "";
	String resName = "";

	if (forageType == ForageManager::SHELLFISH){
		bool mullosks = false;
		if (System::random(100) > 50) {
			resName = "seafood_mollusk";
			mullosks = true;
		}
		else
			resName = "seafood_crustacean";

		if(forageGiveResource(player, forageX, forageY, planet, resName)) {
			if (mullosks)
				player->sendSystemMessage("@harvesting:found_mollusks");
			else
				player->sendSystemMessage("@harvesting:found_crustaceans");
			return true;
		}
		else {
			player->sendSystemMessage("@harvesting:found_nothing");
			return false;
		}

	}


	if (forageType == ForageManager::SCOUT) {

		for (int i = 0; i < itemCount; i++) {
			dice = System::random(200);
			level = 1;

			if (dice >= 0 && dice < 160) {
				lootGroup = "forage_food";
			} else if (dice > 159 && dice < 200) {
				lootGroup = "forage_bait";
			} else {
				lootGroup = "forage_rare";
			}

			lootManager->createLoot(inventory, lootGroup, level);
		}

	} else if (forageType == ForageManager::MEDICAL) { //Medical Forage
		dice = System::random(200);
		level = 1;

		if (dice >= 0 && dice < 40) { //Forage food.
			lootGroup = "forage_food";

		} else if (dice > 39 && dice < 110) { //Resources.
			if(forageGiveResource(player, forageX, forageY, planet, resName)) {
				player->sendSystemMessage("@skl_use:sys_forage_success");
				return true;
			} else {
				player->sendSystemMessage("@skl_use:sys_forage_fail");
				return false;
			}
		} else if (dice > 109 && dice < 170) { //Average components.
			lootGroup = "forage_medical_component";
			level = 1;
		} else if (dice > 169 && dice < 200) { //Good components.
			lootGroup = "forage_medical_component";
			level = 60;
		} else { //Exceptional Components
			lootGroup = "forage_medical_component";
			level = 200;
		}

		lootManager->createLoot(inventory, lootGroup, level);

	} else if (forageType == ForageManager::LAIR) { //Lair Search
		dice = System::random(109);
		level = 1;

		if (dice >= 0 && dice < 40) { // Live Creatures
			lootGroup = "forage_live_creatures";
		}
		else if (dice > 39 && dice < 110) { // Eggs
			resName = "meat_egg";
			if(forageGiveResource(player, forageX, forageY, planet, resName)) {
				player->sendSystemMessage("@lair_n:found_eggs");
				return true;
			} else {
				player->sendSystemMessage("@lair_n:found_nothing");
				return false;
			}
		}

		if(!lootManager->createLoot(inventory, lootGroup, level)) {
			player->sendSystemMessage("Unable to create loot for lootgroup " + lootGroup);
			return false;
		}

		player->sendSystemMessage("@lair_n:found_bugs");
		return true;
	}

	player->sendSystemMessage("@skl_use:sys_forage_success");
	return true;
}
void ForageManagerImplementation::finishForaging(CreatureObject* player, int forageType, float forageX, float forageY, const String& zoneName) {
	if (player == NULL)
		return;

	Locker playerLocker(player);
	Locker forageAreasLocker(_this.get());

	player->removePendingTask("foraging");

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

	//Check if player moved.
	float playerX = player->getPositionX();
	float playerY = player->getPositionY();

	if ((fabs(playerX - forageX) > 2.0) || (fabs(playerY - forageY) > 2.0) || player->getZone()->getZoneName() != zoneName) {
		player->sendSystemMessage("@skl_use:sys_forage_movefail"); //"You fail to forage because you moved."
		return;
	}

	//Check if player is in combat.
	if (player->isInCombat()) {
		player->sendSystemMessage("@skl_use:sys_forage_combatfail"); //"Combat distracts you from your foraging attempt."
		return;
	}

	//Check if player is allowed to forage in this area.
	if (forageType != ForageManager::SHELLFISH) {

		Reference<ForageAreaCollection*> forageAreaCollection = forageAreas.get(player->getFirstName());

		if (forageAreaCollection != NULL) { //Player has foraged before.
			if (!forageAreaCollection->checkForageAreas(forageX, forageY, zoneName, forageType)) {
				if( forageType == LAIR ){
					player->sendSystemMessage("There is nothing of interest remaining in the lair.");
				}
				else{
					player->sendSystemMessage("@skl_use:sys_forage_empty"); //"There is nothing in this area to forage."
				}
				return;
			}

		} else { //Player has not foraged before.
			forageAreaCollection = new ForageAreaCollection(player, forageX, forageY, zoneName, forageType);
			forageAreas.put(player->getFirstName(), forageAreaCollection);
		}
	}

	//Calculate the player's chance to find an item.
	int chance;
	int skillMod;

	switch(forageType) {
	case ForageManager::SCOUT:
	case ForageManager::LAIR:
		skillMod = player->getSkillMod("foraging");
		chance = (int)(15 + (skillMod * 0.8));
		break;
	case ForageManager::MEDICAL:
		skillMod = player->getSkillMod("medical_foraging");
		chance = (int)(15 + (skillMod * 0.6));
		break;
	default:
		skillMod = 20;
		chance = (int)(15 + (skillMod * 0.6));
		break;
	}

	//Determine if player finds an item.
	if (chance > 100) //There could possibly be +foraging skill tapes.
		chance = 100;

	if (System::random(80) > chance) {
		if (forageType == ForageManager::SHELLFISH)
			player->sendSystemMessage("@harvesting:found_nothing");
		else if (forageType == ForageManager::LAIR)
			player->sendSystemMessage("@lair_n:found_nothing");
		else
			player->sendSystemMessage("@skl_use:sys_forage_fail"); //"You failed to find anything worth foraging."

	} else {

		forageGiveItems(player, forageType, forageX, forageY, zoneName);

	}

	return;

}