
#include "StdAfx.h"
#include "PhysicsObj.h"
#include "Monster.h"
#include "World.h"
#include "Item.h"
#include "GameMode.h"
#include "Lifestone.h"
#include "ChatMsgs.h"

CBaseMonster::CBaseMonster()
{
	m_ItemType = TYPE_CREATURE;
}

CBaseMonster::~CBaseMonster()
{
}

void CBaseMonster::Precache(void)
{
	CalculateSpeed();
}

void CBaseMonster::PostSpawn()
{
	if (!IsPlayer())
	{
		EmitEffect(88, 1.0f);
	}
}

void CBaseMonster::CalculateSpeed(void)
{
	DWORD dwRunSkill;
	ATTRIBUTE *quick = GetAttributeData(eQuickness);
	SKILL *run = GetSkillData(eRun);

	dwRunSkill = quick->data.base + quick->data.raises;
	dwRunSkill += run->data.bonus + run->data.raises;

	m_fSpeedMod = Calc_AnimSpeed(dwRunSkill, GetBurdenPercent()) * m_fScale;
}

void CBaseMonster::MonsterThink(void)
{
	Animation_Think();
	Movement_Think();
}

float CBaseMonster::GetBurdenPercent(void)
{
	//should base this off our total burden and strength
	return 0.0f;
}

//	returns the new number of raises, or zero if unchanged.
DWORD CBaseMonster::GiveAttributeXP(eAttribute index, DWORD dwXP)
{
	ATTRIBUTE* pAttrib = GetAttributeData(index);
	if (!pAttrib)
		return 0;
	//if ( WillOF( pAttrib->data.exp, dwXP ) )
	//	return 0;

	DWORD dwMaxXP = GetAttributeMaxXP();
	DWORD dwOldAttribXP = pAttrib->data.exp;
	DWORD dwNewAttribXP = dwOldAttribXP + dwXP;
	if (dwNewAttribXP > dwMaxXP)
		dwNewAttribXP = dwMaxXP;

	DWORD dwOldRaises = pAttrib->data.raises;
	DWORD dwNewRaises = GetAttributeLevel(dwNewAttribXP);

	pAttrib->data.exp = dwNewAttribXP;
	pAttrib->data.raises = dwNewRaises;

	if (index == eEndurance)
	{
		DWORD dwTotalValue = GetAttributeMax(pAttrib, 0.0f);
		DWORD dwMaxHealth = dwTotalValue / 2;
		if (dwTotalValue % 2) dwMaxHealth++;
		DWORD dwMaxStamina = dwTotalValue;

		//GetVitalData( eHealth )->data.base	= dwMaxHealth;
		//GetVitalData( eStamina )->data.base	= dwMaxStamina;
	}
	else if (index == eQuickness)
		CalculateSpeed();
	else if (index == eSelf)
	{
		DWORD dwTotalValue = GetAttributeMax(pAttrib, 0.0f);
		DWORD dwMaxMana = dwTotalValue;

		//GetVitalData( eMana )->data.base	= dwMaxMana;
	}

	return (dwOldRaises != dwNewRaises) ? dwNewRaises : 0;
}

DWORD CBaseMonster::GiveVitalXP(eVital index, DWORD dwXP)
{
	VITAL* pVital = GetVitalData(index);
	if (!pVital)
		return 0;
	//if ( WillOF( pVital->data.exp, dwXP ) )
	//	return 0;

	DWORD dwMaxXP = GetVitalMaxXP();
	DWORD dwOldVitalXP = pVital->data.exp;
	DWORD dwNewVitalXP = dwOldVitalXP + dwXP;
	if (dwNewVitalXP > dwMaxXP)
		dwNewVitalXP = dwMaxXP;

	DWORD dwOldRaises = pVital->data.raises;
	DWORD dwNewRaises = GetVitalLevel(dwNewVitalXP);

	pVital->data.exp = dwNewVitalXP;
	pVital->data.raises = dwNewRaises;

	return (dwOldRaises != dwNewRaises) ? dwNewRaises : 0;
}

DWORD CBaseMonster::GiveSkillXP(eSkill index, DWORD dwXP)
{
	SKILL* pSkill = GetSkillData(index);
	if (!pSkill)
		return 0;
	//if ( WillOF( pSkill->data.exp, dwXP ) )
	//	return 0;

	DWORD dwMaxXP;
	switch (pSkill->data.training)
	{
	default:
	case eUnusable:
	case eUntrained:
		return 0;
	case eTrained:
		dwMaxXP = GetTrainedMaxXP();
		break;
	case eSpecialized:
		dwMaxXP = GetSpecializedMaxXP();
		break;
	}
	DWORD dwOldSkillXP = pSkill->data.exp;
	DWORD dwNewSkillXP = dwOldSkillXP + dwXP;
	if (dwNewSkillXP > dwMaxXP)
		dwNewSkillXP = dwMaxXP;

	DWORD dwOldRaises = pSkill->data.raises;

	DWORD dwNewRaises;
	switch (pSkill->data.training)
	{
	case eTrained:
		dwNewRaises = GetTrainedLevel(dwNewSkillXP);
		break;
	case eSpecialized:
		dwNewRaises = GetSpecializedLevel(dwNewSkillXP);
		break;
	}

	pSkill->data.exp = dwNewSkillXP;
	pSkill->data.raises = (WORD) dwNewRaises;

	if (index == eRun)
		CalculateSpeed();

	return (dwOldRaises != dwNewRaises) ? dwNewRaises : 0;
}

SKILL* CBaseMonster::GetSkillData(eSkill index)
{
	if (index < 0x1 || index > 0x27)
		return NULL;

	return &m_skills[index - 1];
}

ATTRIBUTE* CBaseMonster::GetAttributeData(eAttribute index)
{
	if (index < 1 || index > 6)
		return NULL;

	return &m_attributes[index - 1];
}

VITAL* CBaseMonster::GetVitalData(eVital index)
{
	if (index < 1 || index > 6)
		return NULL;

	return &m_vitals[index - 1];
}

void CBaseMonster::Animation_Complete(animation_t *data)
{
	switch (data->dwAction)
	{
	case ANIM_SPELLCAST:
	{
		DWORD dwSpellID = data->dwActionData[0];
		DWORD dwTarget = data->dwTarget;

		LaunchSpell(dwSpellID, dwTarget);

		break;
	}
	case ANIM_LSRECALL:
	{
		if (m_bLifestoneBound)
		{
			Movement_Teleport(m_LifestonePlacement.origin, m_LifestonePlacement.angles);
		}

		break;
	}
	case ANIM_MPRECALL:
	{
		Movement_Teleport(loc_t(0x016C01BC, 49.11f, -31.22f, 0.005f), heading_t(0.7009f, 0, 0, -0.7132f));
		break;
	}
	case ANIM_BINDLIFESTONE:
	{
		if (IsPlayer())
		{
			CBasePlayer *pPlayer = (CBasePlayer *)this;

			DWORD dwLifestone = data->dwActionData[0];

			CPhysicsObj *pLifestone = g_pWorld->FindWithinPVS(this, dwLifestone);
			if (pLifestone)
			{
				if (pLifestone->DistanceTo(this) <= LIFESTONE_MAX_BIND_DISTANCE)
				{
					pPlayer->SendNetMessage(ServerText("You have attuned your spirit to this Lifestone. You will resurrect here after you die.", 7), PRIVATE_MSG, FALSE, TRUE);
					m_LifestonePlacement.origin = m_Origin;
					m_LifestonePlacement.angles = m_Angles;
					m_bLifestoneBound = true;
				}
				else
				{
					pPlayer->SendNetMessage(ServerText("You are too far away for that!", 7), PRIVATE_MSG, FALSE, TRUE);
				}
			}
		}

		break;
	}
	default:
		break;
	}

	CPhysicsObj::Animation_Complete(data);
}

void CBaseMonster::LaunchSpell(DWORD dwSpellID, DWORD dwTarget)
{
	switch (dwSpellID)
	{
	case 2366: //Bovine Intervention
	{
		if ((GetLandcell() & 0xFFFF) < 0x100)
		{
			for (int i = 0; i < 30; i++)
			{
				CBaseMonster *pCow = new CBaseMonster();
				pCow->m_dwGUID = g_pWorld->GenerateGUID(eDynamicGUID);
				pCow->m_dwModel = 0x02000006;
				pCow->m_fScale = 1.0f;
				pCow->m_strName = "Cow";
				pCow->m_Origin.landcell = m_Origin.landcell;
				pCow->m_Origin.x = m_Origin.x + RandomFloat(-20.0f, 20.0f);
				pCow->m_Origin.y = m_Origin.y + RandomFloat(-20.0f, 20.0f);
				pCow->m_Origin.z = m_Origin.z + RandomFloat(40.0f, 80.0f);
				pCow->m_Angles.w = RandomFloat(-1.0f, 1.0f);
				pCow->m_Angles.z = RandomFloat(-1.0f, 1.0f);
				g_pWorld->CreateEntity(pCow);

				pCow->SetDescription("Mooooo!");
			}
		}
		else {
			if (IsPlayer())
				((CBasePlayer *)this)->SendText("Cows don't live indoors, silly!", 1);
		}

		break;
	}
	}
}

void CBaseMonster::Attack(DWORD dwTarget, DWORD dwHeight, float flPower)
{
	CPhysicsObj *pTarget = g_pWorld->FindWithinPVS(this, dwTarget);
	
	if (!pTarget || !pTarget->IsAttackable())
	{
		return;
	}

	float dist = DistanceTo(pTarget);

	if (dist >= 5)
	{
		return;
	}

	if (g_pWorld->GetGameMode())
	{
		g_pWorld->GetGameMode()->OnTargetAttacked(pTarget, this);
	}

	WORD wAttackAnim;

	switch (dwHeight)
	{
	case 0x01: wAttackAnim = 0x62; break;
	case 0x02: wAttackAnim = 0x63; break;
	case 0x03: wAttackAnim = 0x64; break;
	default: return;
	}

	if (flPower >= 0.25f)
		wAttackAnim += 3;
	if (flPower >= 0.75f)
		wAttackAnim += 3;

	if (flPower < 0 || flPower > 1)
		return;

	float flTime = 0.5f + (flPower * 0.5f);
	float fSpeed = 1.5f;

	Animation_Attack(dwTarget, wAttackAnim, fSpeed, Container_GetWeaponID());
}


CBaelZharon::CBaelZharon()
{
	m_dwModel = 0x0200099E;
	m_fScale = 1.8f;

	m_strName = "Bael'Zharon";

	m_miBaseModel.dwBasePalette = 0x1071;
	m_miBaseModel.lPalettes.push_back(PaletteRpl(0x1072, 0x00, 0x00));
	// SetThink(&CBaelZharon::CrazyThink);
}

BOOL CBaelZharon::CrazyThink()
{
	// SpeakLocal(csprintf("Today's lucky numbers are %u %u %u", RandomLong(0, 9), RandomLong(0, 9), RandomLong(0, 9)));

	m_fNextThink = g_pGlobals->Time() + 20.0f + RandomFloat(0, 40);
	return TRUE;
}

CTargetDrudge::CTargetDrudge()
{
	m_dwModel = 0x02000034;
	m_fScale = 0.95f;

	m_strName = "Oak Target Drudge";

	m_dwAnimationSet = 0x0900008A;
	m_dwEffectSet = 0x3400006B;
	m_dwSoundSet = 0x20000051;

	m_miBaseModel.SetBasePalette(0x01B9);
	m_miBaseModel.ReplacePalette(0x08B4, 0x00, 0x00);
	m_miBaseModel.ReplaceTexture(0x00, 0x0036, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x01, 0x0031, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x02, 0x0030, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x03, 0x0030, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x04, 0x0D33, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x05, 0x0030, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x06, 0x0030, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x07, 0x0D33, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x08, 0x0030, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x09, 0x0030, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x0A, 0x0035, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x0B, 0x0030, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x0C, 0x0030, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x0D, 0x0035, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x0E, 0x0D33, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x0E, 0x0EE8, 0x0EE8);
	m_miBaseModel.ReplaceTexture(0x0F, 0x0035, 0x0D33);
	m_miBaseModel.ReplaceTexture(0x10, 0x0035, 0x0D33);
	m_miBaseModel.ReplaceModel(0x00, 0x005D);
	m_miBaseModel.ReplaceModel(0x01, 0x005E);
	m_miBaseModel.ReplaceModel(0x02, 0x006E);
	m_miBaseModel.ReplaceModel(0x03, 0x0064);
	m_miBaseModel.ReplaceModel(0x04, 0x18D9);
	m_miBaseModel.ReplaceModel(0x05, 0x006F);
	m_miBaseModel.ReplaceModel(0x06, 0x0316);
	m_miBaseModel.ReplaceModel(0x07, 0x18D9);
	m_miBaseModel.ReplaceModel(0x08, 0x006D);
	m_miBaseModel.ReplaceModel(0x09, 0x006B);
	m_miBaseModel.ReplaceModel(0x0A, 0x005F);
	m_miBaseModel.ReplaceModel(0x0B, 0x006C);
	m_miBaseModel.ReplaceModel(0x0C, 0x0068);
	m_miBaseModel.ReplaceModel(0x0D, 0x0060);
	m_miBaseModel.ReplaceModel(0x0E, 0x18D7);
	m_miBaseModel.ReplaceModel(0x0F, 0x0067);
	m_miBaseModel.ReplaceModel(0x10, 0x0060);
}


