/*!
 * @file Creature.cpp
 * @brief ゲーム中のクリーチャーを定義する
 * @date 2013/12/10
 * @author Deskull
 * 2013 Sikabane Works.
 */

#include "stdafx.h"
#include "Creature.h"

namespace Deeangband
{

	SOUL Creature::soulLevel[CREATURE_MAX_LEVEL] =
	{
		// 0    // ロスト域
		50,	 // Lv1デフォルト基準ソウル
		100, // Lv2到達ソウル
		130, // :
		180,
		260,
		360,
		480,
		630,
		880,
		1280, // Lv10到達ソウル
		1700,
		2200,
		2800,
		3600,
		4600,
		6100,
		8800,
		10600,
		12600,
		15000, // Lv20到達ソウル
		18000,
		24000,
		35000,
		50000,
		75000,
		100000,
		150000,
		200000,
		275000,
		350000, // Lv30到達ソウル
		450000,
		550000,
		700000,
		1000000,
		1500000,
		2100000,
		2700000,
		3600000,
		4700000,
		6000000, // Lv40到達ソウル
		7500000,
		9000000,
		11500000,
		14500000,
		19000000,
		26000000,
		33000000,
		45000000,
		60000000,
		90000000, // Lv50到達ソウル
		150000000,
		230000000,
		400000000,
		620000000,
		880000000,
		1150000000,
		1500000000,
		3200000000,
		6400000000,
		11100000000, // Lv60到達ソウル
	};

	Creature::Creature(std::map<TAG, boost::shared_ptr<Species>>::iterator speciesIt) : GameInstance(), HaveSymbol(), HaveHp(), HaveGameTime(), HavePosition(), HaveInventory(), HaveSize()
	{
		WipeData();
		SetSpeciesData(&(*speciesIt->second));
	}

	Creature::Creature(std::map<TAG, boost::shared_ptr<Species>>::iterator speciesIt, ID FieldID, Coordinates *coordinates) : GameInstance(), HaveSymbol(), HaveHp(), HaveGameTime(), HavePosition(fieldID, coordinates), HaveInventory(), HaveSize()
	{
		WipeData();
		SetSpeciesData(&(*speciesIt->second));
	}

	Creature::Creature(std::map<TAG, boost::shared_ptr<Species>>::iterator speciesIt, ID FieldID, int x, int y) : GameInstance(), HaveSymbol(), HaveHp(), HaveGameTime(), HavePosition(fieldID, x, y), HaveInventory(), HaveSize()
	{
		WipeData();
		SetSpeciesData(&(*speciesIt->second));
	}

	Creature::Creature(void)
	{
		WipeData();
	}

	Creature::~Creature(void)
	{
	}

	void Creature::SetSpeciesData(Species *speciesPtr)
	{
		std::normal_distribution<> distHeight(speciesPtr->GetHeight(), GameConstants::HeightStandardDeviation);
		std::normal_distribution<> distWeight(speciesPtr->GetWeight(), GameConstants::WeightStandardDeviation);
		this->name = speciesPtr->GetName();
		this->symbol = speciesPtr->GetSymbol();
		this->symbolColor = speciesPtr->GetSymbolColor();
		this->currentSoul = this->maxSoul = speciesPtr->GetBaseSoul();
		this->currentFeed = speciesPtr->GetBaseFeed() * 3 / 4;
		this->maxFeed = speciesPtr->GetBaseFeed();
		this->weight = distWeight(Dice::mt);
		this->height = distHeight(Dice::mt);
		this->campTag = TAG_VARIABLE;
		this->firstRace = speciesPtr->GetFirstRaceTag();
		this->secondRace = speciesPtr->GetSecondtRaceTag();
	}

	void Creature::WipeData(void)
	{
		GameInstance::WipeData();
		HaveSymbol::WipeData();
		HaveSize::WipeData();
		this->currentMp = this->maxMp = this->maxMaxMp = 10;
		this->currentSoul = this->maxSoul = Creature::soulLevel[0];
		this->currentDiscipilne.SetPoint(0, 0, 0, 0, 0);
		this->firstRace = "";
		this->secondRace = "";
		this->height = 160.0f;
		this->weight = 50.0f;
		this->divineLevel = -1;
		savings.Set(10, 10, 10);
		this->currentFeed = this->maxFeed = 20000;

		currentStatus.Set(8, 8, 8, 8, 8, 8);
		maxStatus.Set(8, 8, 8, 8, 8, 8);
		maxMaxStatus.Set(20, 20, 20, 20, 20, 20);

		this->calcHPTable();
		this->currentHp = this->maxHp = this->GetNorMaxHP();

		this->skillExpList.clear();

		this->turn = 0;
		this->campTag = TAG_VARIABLE;

		//this->fieldID = -1;
		//this->position.Set(0, 0);

		this->skillExpList.clear();

		this->symbol = '@';
		this->symbolColor.SetColor(255, 255, 255, 255);
	}

	bool Creature::IsAlive(void)
	{
		return this->currentHp > 0 && this->currentSoul > 0;
	}

	bool Creature::TakeEffect(Effect *effectPtr, POWER amount)
	{
		if(effectPtr) this->CalcHP(-amount);
		return false;
	}

	void Creature::die(void)
	{
	}

	void Creature::calcHPTable(void)
	{
		int lev;
		HP hitDice = this->GetSize();
		HP minLine = hitDice * (CREATURE_MAX_LEVEL + 4) * 70 / 100;
		HP maxLine = hitDice * (CREATURE_MAX_LEVEL + 4) * 130 / 100;

		if(hitDice <= 0) hitDice = 1;

		do
		{
			this->hpTable[0] = hitDice + Dice::Cast(3, hitDice);
			for(lev = 0; lev < CREATURE_MAX_LEVEL - 1; lev++)
			{
				this->hpTable[lev + 1] = this->hpTable[lev] + Dice::Rand1(hitDice);
			}
		}
		while(this->hpTable[CREATURE_MAX_LEVEL - 1] < minLine && this->hpTable[CREATURE_MAX_LEVEL - 1] > maxLine);
	}

	void Creature::calcMP(MP amount)
	{
		this->currentMp += amount;
		if(this->currentMp > this->maxMp) this->currentMp = this->maxMp;
		if(this->currentMp < 0) this->currentMp = 0;
	}

	void Creature::setMP(MP amount)
	{
		this->currentMp += amount;
		if(this->currentMp > this->maxMp) this->currentMp = this->maxMp;
		if(this->currentMp < 0) this->currentMp = 0;
	}

	LEVEL Creature::GetLevel(void)
	{
		LEVEL level;
		if(this->currentSoul <= 0) return 0;
		if(this->currentSoul < Creature::soulLevel[1]) return 1;
		for(level = 2; level < CREATURE_MAX_LEVEL; level++)
		{
			if(Creature::soulLevel[level - 1] > this->currentSoul) return level;
		}
		return level;
	}

	HP Creature::GetNorMaxHP(void)
	{
		return this->hpTable[this->GetLevel()];
	}

	MP Creature::GetCurMP(void)
	{
		return this->currentMp;
	}

	MP Creature::GetMaxMP(void)
	{
		return this->maxMp;
	}

	MP Creature::GetNorMaxMP(void)
	{
		return this->maxMaxMp;
	}

	AC Creature::GetArmorSaving(void)
	{
		return this->savings.GetArmor();
	}

	EV Creature::GetEvasionSaving(void)
	{
		return this->savings.GetEvasion();
	}

	VO Creature::GetVolitionSaving(void)
	{
		return this->savings.GetVolition();
	}

	SOUL Creature::GetCurrentSoul(void)
	{
		return this->currentSoul;
	}

	SOUL Creature::GetMaxSoul(void)
	{
		return this->maxSoul;
	}

	BASE_STATUS Creature::GetCurrentStatus(CREATURE_STATUS stat)
	{
		return currentStatus.Get(stat);
	}

	BASE_STATUS Creature::GetMaxStatus(CREATURE_STATUS stat)
	{
		return maxStatus.Get(stat);
	}

	BASE_STATUS Creature::GetMaxMAXStatus(CREATURE_STATUS stat)
	{
		return maxMaxStatus.Get(stat);
	}

	DISCIPLINE_POINT Creature::GetDiscipilnePoint(DISCIPLINE_TYPE typ)
	{
		return this->currentDiscipilne.GetPoint(typ);
	}

	DISCIPLINE_POINT Creature::GetDiscipilneRank(DISCIPLINE_TYPE typ)
	{
		return this->currentDiscipilne.GetRank(typ);
	}

	void Creature::GainSoul(SOUL amount)
	{
		SOUL diff;
		if(this->currentSoul < this->maxSoul)
		{
			diff = this->maxSoul - this->currentSoul;
			if(diff < amount)
			{
				this->maxSoul += diff / 20;
				this->currentSoul = this->maxSoul;
				amount -= diff;
			}
			else
			{
				this->maxSoul += amount / 20;
				this->currentSoul += amount;
				amount = 0;
			}
		}
		this->currentSoul += amount;
		this->maxSoul += amount;
	}

	void Creature::LostSoul(SOUL amount)
	{
		this->currentSoul -= amount;
		this->maxSoul -= amount / 20;
		if(this->currentSoul < 1) this->die();
	}

	LEVEL Creature::GetDivineLevel(void)
	{
		return this->divineLevel;
	}

	FEED Creature::GetCurrentFeedPoint(void)
	{
		return this->currentFeed;
	}

	FEED Creature::GetMaxFeedPoint(void)
	{
		return this->maxFeed;
	}

	void Creature::TurnProcess(void)
	{
	}

	void Creature::TimeProcess(void)
	{
		this->currentFeed -= 10;
	}

	TURN Creature::GetTurn(void)
	{
		return this->turn;
	}

	SKILL_EXP Creature::GetSkillExp(TAG tag)
	{
		if(this->skillExpList.count(tag)) return this->skillExpList[tag];
		else return 0;
	}

	TAG Creature::GetCampTag(void)
	{
		return this->campTag;
	}

	bool Creature::Walk(GameLogger *gameLoggerPtr, DIRECTION dir)
	{
		gameLoggerPtr->CreatureMoved(0, this->name, dir);
		this->position += Direction::DirectionVector[dir];
		return true;
	}

	bool Creature::Melee(Creature *targerPtr)
	{
		return true;
	}

	bool Creature::PickUpItem(std::map<ID, boost::shared_ptr<Item>>::iterator itemIt)
	{
		return true;
	}

	bool Creature::DropItem(std::map<ID, boost::shared_ptr<Item>>::iterator itemIt)
	{
		return true;
	}

	bool Creature::EatItem(std::map<ID, boost::shared_ptr<Item>>::iterator itemIt)
	{
		return true;
	}

	bool Creature::QuaffItem(std::map<ID, boost::shared_ptr<Item>>::iterator itemIt)
	{
		return true;
	}

	bool Creature::ActivateItem(std::map<ID, boost::shared_ptr<Item>>::iterator itemIt)
	{
		return true;
	}

	bool Creature::ThrowItem(std::map<ID, boost::shared_ptr<Item>>::iterator itemIt)
	{
		return true;
	}

	bool Creature::ReadItem(std::map<ID, boost::shared_ptr<Item>>::iterator itemIt)
	{
		return true;
	}

	bool Creature::CanEnterPosition(GameWorld *worldPtr, Coordinates coordinates)
	{
		Coordinates targetPosition = this->position += coordinates;
		return true;
	}

	void Creature::XMLSave(std::string filename)
	{
		std::ofstream ofs(filename);
		assert(ofs);
		boost::archive::xml_oarchive oa(ofs);
		oa << boost::serialization::make_nvp("Creature", *this);
	}

}