// -----------------------------------------------------------------------------
// localplayer.cpp
// -----------------------------------------------------------------------------
// Implementation of the LocalPlayer wrapper described in localplayer.h.
// -----------------------------------------------------------------------------

#include "localplayer.h"

namespace sdk {

void LocalPlayer::Initialize(const core::ProcessMemory* memory, const core::GameOffsets* offsets, uintptr_t clientBase)
{
	m_memory = memory;
	m_offsets = offsets;
	m_clientBase = clientBase;
}

uintptr_t LocalPlayer::GetLocalPawn() const
{
	if (m_clientBase == 0) {
		return 0;
	}

	const uintptr_t controller = m_memory->Read<uintptr_t>(m_clientBase + m_offsets->localPlayerPawn);
	if (controller == 0 || m_offsets->hPlayerPawn == 0) {
		return 0;
	}

	const uint32_t pawnHandle = m_memory->Read<uint32_t>(controller + m_offsets->hPlayerPawn) & 0x7FFF;
	if (pawnHandle == 0) {
		return 0;
	}

	const uintptr_t outer = m_memory->Read<uintptr_t>(m_clientBase + m_offsets->entityList);
	if (outer == 0) {
		return 0;
	}
	const uintptr_t inner = m_memory->Read<uintptr_t>(outer + static_cast<uintptr_t>(pawnHandle / 512) * 0x8);
	if (inner == 0) {
		return 0;
	}
	const uintptr_t identity = inner + static_cast<uintptr_t>(pawnHandle % 512) * 0x70;
	return m_memory->Read<uintptr_t>(identity);
}

uintptr_t LocalPlayer::GetClientBase() const
{
	return m_clientBase;
}

int LocalPlayer::GetCrosshairId() const
{
	const uintptr_t pawn = GetLocalPawn();
	if (pawn == 0 || m_offsets->idEntIndex == 0) {
		return -1;
	}

	const int id = m_memory->Read<int>(pawn + m_offsets->idEntIndex);
	if (id == 0xFFFFFFFF) {
		return -1;
	}
	return id;
}

int LocalPlayer::GetTeam() const
{
	const uintptr_t pawn = GetLocalPawn();
	if (pawn == 0 || m_offsets->teamNum == 0) {
		return -1;
	}
	return m_memory->Read<int>(pawn + m_offsets->teamNum);
}

bool LocalPlayer::GetPosition(Vec3& outPosition) const
{
	const uintptr_t pawn = GetLocalPawn();
	if (pawn == 0 || m_offsets->oldOrigin == 0) {
		return false;
	}

	m_memory->ReadArray<float>(pawn + m_offsets->oldOrigin, &outPosition.x, 3);
	return true;
}

float LocalPlayer::GetViewOrigin() const
{
	const uintptr_t pawn = GetLocalPawn();
	if (pawn == 0 || m_offsets->vecViewOffset == 0) {
		return 0.0f;
	}

	const float viewOffsetZ = m_memory->Read<float>(pawn + m_offsets->vecViewOffset + 8);
	return viewOffsetZ;
}

void LocalPlayer::SetAngles(const Vec3& angles) const
{
	if (m_clientBase == 0) {
		return;
	}
	m_memory->WriteArray<float>(m_clientBase + m_offsets->viewAngles, &angles.x, 3);
}

bool LocalPlayer::GetAngles(Vec3& outAngles) const
{
	if (m_clientBase == 0) {
		return false;
	}
	m_memory->ReadArray<float>(m_clientBase + m_offsets->viewAngles, &outAngles.x, 3);
	return true;
}

int LocalPlayer::GetShotsFired() const
{
	const uintptr_t pawn = GetLocalPawn();
	if (pawn == 0 || m_offsets->iShotsFired == 0) {
		return 0;
	}
	return m_memory->Read<int>(pawn + m_offsets->iShotsFired);
}

} // namespace sdk