text: #include "csgostructs.hpp"
  #include "../Helpers/Math.hpp"
  #include "../Helpers/Utils.hpp"
  
  bool C_BaseEntity::IsPlayer()
  {
  	//index: 152
  	//ref: "effects/nightvision"
  	//sig: 8B 92 ? ? ? ? FF D2 84 C0 0F 45 F7 85 F6
  	return CallVFunction<bool(__thiscall*)(C_BaseEntity*)>(this, 152)(this);
  }
  
  bool C_BaseEntity::IsWeapon()
  {
  	//index: 160
  	//ref: "CNewParticleEffect::DrawModel"
  	//sig: 8B 80 ? ? ? ? FF D0 84 C0 74 6F 8B 4D A4
  	return CallVFunction<bool(__thiscall*)(C_BaseEntity*)>(this, 160)(this);
  }
  
  
  bool C_BaseEntity::IsPlantedC4()
  {
  	return GetClientClass()->m_ClassID == ClassId_CPlantedC4;
  }
  
  bool C_BaseEntity::IsDefuseKit()
  {
  	return GetClientClass()->m_ClassID == ClassId_CBaseAnimating;
  }
  
  CCSWeaponInfo* C_BaseCombatWeapon::GetCSWeaponData()
  {
  	return CallVFunction<CCSWeaponInfo*(__thiscall*)(void*)>(this, 444)(this);
  	/*
  	static auto fnGetWpnData
  	= reinterpret_cast<CCSWeaponInfo*(__thiscall*)(void*)>(
  	Utils::PatternScan(GetModuleHandleW(L"client_panorama.dll"), "55 8B EC 81 EC ? ? ? ? 53 8B D9 56 57 8D 8B")
  	);
  	return fnGetWpnData(this);*/
  }
  
  bool C_BaseCombatWeapon::HasBullets()
  {
  	return !IsReloading() && m_iClip1() > 0;
  }
  
  bool C_BaseCombatWeapon::CanFire()
  {
  	static decltype(this) stored_weapon = nullptr;
  	static auto stored_tick = 0;
  	if (stored_weapon != this || stored_tick >= g_LocalPlayer->m_nTickBase()) {
  		stored_weapon = this;
  		stored_tick = g_LocalPlayer->m_nTickBase();
  		return false; //cannot shoot first tick after switch
  	}
  
  	if (IsReloading() || m_iClip1() <= 0 || !g_LocalPlayer)
  		return false;
  
  	auto flServerTime = g_LocalPlayer->m_nTickBase() * g_GlobalVars->interval_per_tick;
  
  	return m_flNextPrimaryAttack() <= flServerTime;
  }
  
  bool C_BaseCombatWeapon::IsGrenade()
  {
  	return GetCSWeaponData()->iWeaponType == WEAPONTYPE_GRENADE;
  }
  
  bool C_BaseCombatWeapon::IsGun()
  {
  	switch (GetCSWeaponData()->iWeaponType)
  	{
  	case WEAPONTYPE_C4:
  		return false;
  	case WEAPONTYPE_GRENADE:
  		return false;
  	case WEAPONTYPE_KNIFE:
  		return false;
  	case WEAPONTYPE_UNKNOWN:
  		return false;
  	default:
  		return true;
  	}
  }
  
  bool C_BaseCombatWeapon::IsKnife()
  {
  	if (this->m_Item().m_iItemDefinitionIndex() == WEAPON_TASER) return false;
  	return GetCSWeaponData()->iWeaponType == WEAPONTYPE_KNIFE;
  }
  
  bool C_BaseCombatWeapon::IsRifle()
  {
  	switch (GetCSWeaponData()->iWeaponType)
  	{
  	case WEAPONTYPE_RIFLE:
  		return true;
  	case WEAPONTYPE_SUBMACHINEGUN:
  		return true;
  	case WEAPONTYPE_SHOTGUN:
  		return true;
  	case WEAPONTYPE_MACHINEGUN:
  		return true;
  	default:
  		return false;
  	}
  }
  
  bool C_BaseCombatWeapon::IsPistol()
  {
  	switch (GetCSWeaponData()->iWeaponType)
  	{
  	case WEAPONTYPE_PISTOL:
  		return true;
  	default:
  		return false;
  	}
  }
  
  bool C_BaseCombatWeapon::IsSniper()
  {
  	switch (GetCSWeaponData()->iWeaponType)
  	{
  	case WEAPONTYPE_SNIPER_RIFLE:
  		return true;
  	default:
  		return false;
  	}
  }
  
  bool C_BaseCombatWeapon::IsReloading()
  {
  	static auto inReload = *(uint32_t*)(Utils::PatternScan(GetModuleHandleW(L"client_panorama.dll"), "C6 87 ? ? ? ? ? 8B 06 8B CE FF 90") + 2);
  	return *(bool*)((uintptr_t)this + inReload);
  }
  
  float C_BaseCombatWeapon::GetInaccuracy()
  {
  	return CallVFunction<float(__thiscall*)(void*)>(this, 467)(this);
  }
  
  float C_BaseCombatWeapon::GetSpread()
  {
  	return CallVFunction<float(__thiscall*)(void*)>(this, 436)(this);
  }
  
  void C_BaseCombatWeapon::UpdateAccuracyPenalty()
  {
  	CallVFunction<void(__thiscall*)(void*)>(this, 467)(this);
  }
  
  CUtlVector<IRefCounted*>& C_BaseCombatWeapon::m_CustomMaterials()
  {	static auto inReload = *(uint32_t*)(Utils::PatternScan(GetModuleHandleW(L"client_panorama.dll"), "83 BE ? ? ? ? ? 7F 67") + 2) - 12;
  	return *(CUtlVector<IRefCounted*>*)((uintptr_t)this + inReload);
  }
  
  bool* C_BaseCombatWeapon::m_bCustomMaterialInitialized()
  {
  	static auto currentCommand = *(uint32_t*)(Utils::PatternScan(GetModuleHandleW(L"client_panorama.dll"), "C6 86 ? ? ? ? ? FF 50 04") + 2);
  	return (bool*)((uintptr_t)this + currentCommand);
  }
  
  CUserCmd*& C_BasePlayer::m_pCurrentCommand()
  {
  	static auto currentCommand = *(uint32_t*)(Utils::PatternScan(GetModuleHandleW(L"client_panorama.dll"), "89 BE ? ? ? ? E8 ? ? ? ? 85 FF") + 2);
  	return *(CUserCmd**)((uintptr_t)this + currentCommand);
  }
  
  int C_BasePlayer::GetNumAnimOverlays()
  {
  	return *(int*)((DWORD)this + 0x297C);
  }
  
  AnimationLayer *C_BasePlayer::GetAnimOverlays()
  {
  	// to find offset: use 9/12/17 dll
  	// sig: 55 8B EC 51 53 8B 5D 08 33 C0
  	return *(AnimationLayer**)((DWORD)this + 10608);
  }
  
  AnimationLayer *C_BasePlayer::GetAnimOverlay(int i)
  {
  	if (i < 15)
  		return &GetAnimOverlays()[i];
  	return nullptr;
  }
  
  int C_BasePlayer::GetSequenceActivity(int sequence)
  {
  	auto hdr = g_MdlInfo->GetStudiomodel(this->GetModel());
  
  	if (!hdr)
  		return -1;
  
  	// sig for stuidohdr_t version: 53 56 8B F1 8B DA 85 F6 74 55
  	// sig for C_BaseAnimating version: 55 8B EC 83 7D 08 FF 56 8B F1 74 3D
  	// c_csplayer vfunc 242, follow calls to find the function.
  
  	static auto get_sequence_activity = reinterpret_cast<int(__fastcall*)(void*, studiohdr_t*, int)>(Utils::PatternScan(GetModuleHandle(L"client_panorama.dll"), "55 8B EC 83 7D 08 FF 56 8B F1 74 3D"));
  
  	return get_sequence_activity(this, hdr, sequence);
  }
  
  CBasePlayerAnimState *C_BasePlayer::GetBasePlayerAnimState()
  {
  	static int basePlayerAnimStateOffset = 0x3874;
  	return *(CBasePlayerAnimState**)((DWORD)this + basePlayerAnimStateOffset);
  }
  
  CCSPlayerAnimState *C_BasePlayer::GetPlayerAnimState()
  {
  	return *(CCSPlayerAnimState**)((DWORD)this + 0x3870);
  }
  
  void C_BasePlayer::UpdateAnimationState(CCSGOPlayerAnimState *state, QAngle angle)
  {
  	static auto UpdateAnimState = Utils::PatternScan(
  		GetModuleHandle(L"client_panorama.dll"), "55 8B EC 83 E4 F8 83 EC 18 56 57 8B F9 F3 0F 11 54 24");
  	/*static auto UpdateAnimState = Utils::PatternScan(
  	GetModuleHandle(L"client_panorama.dll"), "55 8B EC 83 E4 F8 83 EC 18 56 57 8B F9 F3 0F 11 54 24");
  	*/
  	if (!UpdateAnimState)
  		return;
  
  	__asm {
  		push 0
  	}
  
  	__asm
  	{
  		mov ecx, state
  
  		movss xmm1, dword ptr[angle + 4]
  		movss xmm2, dword ptr[angle]
  
  		call UpdateAnimState
  	}
  }
  
  void C_BasePlayer::ResetAnimationState(CCSGOPlayerAnimState *state)
  {
  	using ResetAnimState_t = void(__thiscall*)(CCSGOPlayerAnimState*);
  	static auto ResetAnimState = (ResetAnimState_t)Utils::PatternScan(GetModuleHandle(L"client_panorama.dll"), "56 6A 01 68 ? ? ? ? 8B F1");
  	if (!ResetAnimState)
  		return;
  
  	ResetAnimState(state);
  }
  
  void C_BasePlayer::CreateAnimationState(CCSGOPlayerAnimState *state)
  {
  	using CreateAnimState_t = void(__thiscall*)(CCSGOPlayerAnimState*, C_BasePlayer*);
  	static auto CreateAnimState = (CreateAnimState_t)Utils::PatternScan(GetModuleHandle(L"client_panorama.dll"), "55 8B EC 56 8B F1 B9 ? ? ? ? C7 46");
  	if (!CreateAnimState)
  		return;
  
  	CreateAnimState(state, this);
  }
  
  Vector C_BasePlayer::GetEyePos()
  {
  	return m_vecOrigin() + m_vecViewOffset();
  }
  
  player_info_t C_BasePlayer::GetPlayerInfo()
  {
  	player_info_t info;
  	g_EngineClient->GetPlayerInfo(EntIndex(), &info);
  	return info;
  }
  
  bool C_BasePlayer::IsAlive()
  {
  	return m_lifeState() == LIFE_ALIVE;
  }
  
  bool C_BasePlayer::IsFlashed()
  {
  	if (m_flFlashDuration() > 0.f) return true;
  	return false;
  }
  
  bool C_BasePlayer::HasC4()
  {
  	static auto fnHasC4
  		= reinterpret_cast<bool(__thiscall*)(void*)>(
  			Utils::PatternScan(GetModuleHandleW(L"client_panorama.dll"), "56 8B F1 85 F6 74 31")
  			);
  
  	return fnHasC4(this);
  }
  
  Vector C_BasePlayer::GetHitboxPos(int hitbox_id)
  {
  	matrix3x4_t boneMatrix[MAXSTUDIOBONES];
  
  	if (SetupBones(boneMatrix, MAXSTUDIOBONES, BONE_USED_BY_HITBOX, 0.0f)) {
  		auto studio_model = g_MdlInfo->GetStudiomodel(GetModel());
  		if (studio_model) {
  			auto hitbox = studio_model->GetHitboxSet(0)->GetHitbox(hitbox_id);
  			if (hitbox) {
  				auto
  					min = Vector{},
  					max = Vector{};
  
  				Math::VectorTransform(hitbox->bbmin, boneMatrix[hitbox->bone], min);
  				Math::VectorTransform(hitbox->bbmax, boneMatrix[hitbox->bone], max);
  
  				return (min + max) / 2.0f;
  			}
  		}
  	}
  	return Vector{};
  }
  
  mstudiobbox_t* C_BasePlayer::GetHitbox(int hitbox_id)
  {
  	matrix3x4_t boneMatrix[MAXSTUDIOBONES];
  
  	if (SetupBones(boneMatrix, MAXSTUDIOBONES, BONE_USED_BY_HITBOX, 0.0f)) {
  		auto studio_model = g_MdlInfo->GetStudiomodel(GetModel());
  		if (studio_model) {
  			auto hitbox = studio_model->GetHitboxSet(0)->GetHitbox(hitbox_id);
  			if (hitbox) {
  				return hitbox;
  				//auto
  				//	min = Vector{},
  				//	max = Vector{};
  
  				//Math::VectorTransform(hitbox->bbmin, boneMatrix[hitbox->bone], min);
  				//Math::VectorTransform(hitbox->bbmax, boneMatrix[hitbox->bone], max);
  
  				//return (min + max) / 2.0f;
  			}
  		}
  	}
  	return nullptr;
  }
  
  bool C_BasePlayer::GetHitboxPos(int hitbox, Vector &output)
  {
  	if (hitbox >= HITBOX_MAX)
  		return false;
  
  	const model_t *model = this->GetModel();
  	if (!model)
  		return false;
  
  	studiohdr_t *studioHdr = g_MdlInfo->GetStudiomodel(model);
  	if (!studioHdr)
  		return false;
  
  	matrix3x4_t matrix[MAXSTUDIOBONES];
  	if (!this->SetupBones(matrix, MAXSTUDIOBONES, 0x100, 0))
  		return false;
  
  	mstudiobbox_t *studioBox = studioHdr->GetHitboxSet(0)->GetHitbox(hitbox);
  	if (!studioBox)
  		return false;
  
  	Vector min, max;
  
  	Math::VectorTransform(studioBox->bbmin, matrix[studioBox->bone], min);
  	Math::VectorTransform(studioBox->bbmax, matrix[studioBox->bone], max);
  
  	output = (min + max) * 0.5f;
  
  	return true;
  }
  
  Vector C_BasePlayer::GetBonePos(int bone)
  {
  	matrix3x4_t boneMatrix[MAXSTUDIOBONES];
  	if (SetupBones(boneMatrix, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, 0.0f)) {
  		return boneMatrix[bone].at(3);
  	}
  	return Vector{};
  }
  
  bool C_BasePlayer::CanSeePlayer(C_BasePlayer* player, int hitbox)
  {
  	CGameTrace tr;
  	Ray_t ray;
  	CTraceFilter filter;
  	filter.pSkip = this;
  
  	auto endpos = player->GetHitboxPos(hitbox);
  
  	ray.Init(GetEyePos(), endpos);
  	g_EngineTrace->TraceRay(ray, MASK_SHOT | CONTENTS_GRATE, &filter, &tr);
  
  	return tr.hit_entity == player || tr.fraction > 0.97f;
  }
  
  bool C_BasePlayer::CanSeePlayer(C_BasePlayer* player, const Vector& pos)
  {
  	CGameTrace tr;
  	Ray_t ray;
  	CTraceFilter filter;
  	filter.pSkip = this;
  
  	//auto start = GetEyePos();
  	//auto dir = (pos - start).Normalized();
  
  	ray.Init(GetEyePos(), pos);
  	g_EngineTrace->TraceRay(ray, MASK_SHOT | CONTENTS_GRATE, &filter, &tr);
  
  	return tr.hit_entity == player || tr.fraction > 0.97f;
  }
  
  void C_BasePlayer::UpdateClientSideAnimation()
  {
  	return CallVFunction<void(__thiscall*)(void*)>(this, 218)(this);
  }
  
  void C_BasePlayer::SetAngle2(QAngle wantedang)
  {
  	typedef void(__thiscall* SetAngleFn)(void*, const QAngle &);
  	static SetAngleFn SetAngle2 = reinterpret_cast<SetAngleFn>(Utils::PatternScan(GetModuleHandleA("client_panorama.dll"), "55 8B EC 83 E4 F8 83 EC 64 53 56 57 8B F1"));
  	SetAngle2(this, wantedang);
  }
  
  void C_BasePlayer::InvalidateBoneCache()
  {
  	static auto InvalidateBoneCacheFn = Utils::PatternScan(GetModuleHandleA("client_panorama.dll"), "80 3D ?? ?? ?? ?? ?? 74 16 A1 ?? ?? ?? ?? 48 C7 81");
  	reinterpret_cast<void(__fastcall*)(void*)>(InvalidateBoneCacheFn)(this);
  }
  
  int C_BasePlayer::m_nMoveType()
  {
  	return *(int*)((uintptr_t)this + 0x258);
  }
  
  QAngle* C_BasePlayer::GetVAngles()
  {
  	static auto deadflag = NetvarSys::Get().GetOffset("DT_BasePlayer", "deadflag");
  	return (QAngle*)((uintptr_t)this + deadflag + 0x4);
  }
  
  void C_BaseAttributableItem::SetGloveModelIndex(int modelIndex)
  {
  	return CallVFunction<void(__thiscall*)(void*, int)>(this, 75)(this, modelIndex);
  }
  
  float C_BasePlayer::GetFlashBangTime()
  {
  
  	static uint32_t m_flFlashBangTime = *(uint32_t*)((uint32_t)Utils::PatternScan(GetModuleHandleA("client_panorama.dll"),
  		"F3 0F 10 86 ?? ?? ?? ?? 0F 2F 40 10 76 30") + 4);
  	return *(float*)(this + m_flFlashBangTime);
  	//return *(float*)((uintptr_t)this + 0xa308);
  }
  
  void C_BaseViewModel::SendViewModelMatchingSequence(int sequence)
  {
  	return CallVFunction<void(__thiscall*)(void*, int)>(this, 241)(this, sequence);
  }
  
  CUtlVector<IRefCounted*>& C_EconItemView::m_CustomMaterials()
  {
  	return *(CUtlVector<IRefCounted*>*)((uintptr_t)this + 0x14);
  }
  
  CUtlVector<IRefCounted*>& C_EconItemView::m_VisualsDataProcessors()
  {
  	static auto inReload = *(uint32_t*)(Utils::PatternScan(GetModuleHandleW(L"client_panorama.dll"), "81 C7 ? ? ? ? 8B 4F 0C 8B 57 04 89 4C 24 0C") + 2);
  	return *(CUtlVector<IRefCounted*>*)((uintptr_t)this + inReload);
  }
  
  float_t C_BasePlayer::m_flSpawnTime()
  {
  	return *(float_t*)((uintptr_t)this + 0xA290);
  }