#include "scripts/Math.txt"
#include "scripts/common.txt"
#include "scripts/debug/debug.txt"
#include "scripts/debug/levelcreate.txt"

const kVec3 PressurePlate2Offset = kVec3(60.0f, -60.0f, 0.0f);
const kVec3 PressurePlate2Size = kVec3(70.0f, 75.0f, 100.0f);

const float NormalGravity = 0.45f;
const float JumpPowerGravity = 0.25f;

float KnifeRadiusMultiplier = 1.0f;

//actor.ScriptObject()
//array<kActor@> enemiesList;
/*
int closestEnemy = 0;
float closestEnemyDistance = 999999.0f;
bool findClosestEnemy = false;
bool warpClosestEnemy = false;
*/
kActor @actorWorldTest = null;
int tidTest = -1;

//------------------------------------------------------------------------------------------------------------------------
bool CanUseWeapon(int weaponType) {
	int enabledWeaponType;
	GameVariables.GetInt("BP.EnabledWeaponType", enabledWeaponType);
	if (enabledWeaponType == -1) {
		return true;
	} else {
		return enabledWeaponType == weaponType;
	}
}
//------------------------------------------------------------------------------------------------------------------------
void SetOnlyEnabledWeapon(int weaponType) {
	GameVariables.SetValue("BP.EnabledWeaponType", "" + weaponType);
}
//------------------------------------------------------------------------------------------------------------------------
void EnableAllWeapons() {
	SetOnlyEnabledWeapon(-1);
}
//------------------------------------------------------------------------------------------------------------------------
void UpdateGeneralGame() {
	
	// if (Debug::IsActorEditorOn()) {
		// DebugLevelCreate::Update();
		// return;
	// }
	// //int t = Sys.Mouse_X();
	// // Game.PrintLine("" + Sys.Mouse_X(), 0, 30);
	// uint16 buttons = Player.Buttons();
	// if ((buttons & (BC_WEAPONLEFT)) != 0) {
		// // Game.PlayMusic("music/test.ogg", false); //string filename, bool loop
		// // PlayLoop.ChangeMap("levels/level" + (Game.GetCurrentMapID() < 10 ? "0" : "") + Game.GetCurrentMapID() + ".map");
		// // return;
	// }
	// if ((buttons & (BC_WEAPONRIGHT)) != 0) {
		// Player.GiveWeapon(TW_WEAPON_BOW, 999);
		// Player.GiveWeapon(TW_WEAPON_PISTOL, 999);
		// // Player.GiveWeapon(TW_WEAPON_SHOTGUN, 999);
		// Player.GiveWeapon(TW_WEAPON_LASERRIFLE, 999);
		// Player.GiveWeapon(TW_WEAPON_MINIGUN, 999);
		// Player.GiveWeapon(TW_WEAPON_GRENADE, 999);
		// Player.GiveWeapon(TW_WEAPON_MISSILE, 999);
		// Player.GiveWeapon(TW_WEAPON_CANNON, 999);
		// Player.GiveWeapon(TW_WEAPON_CHRONO, 999);

		// Player.GiveWeapon(TW_WEAPON_ASHOTGUN, 1);
		// Player.GiveWeapon(TW_WEAPON_RIFLE, 999);
		// Player.GiveWeapon(TW_WEAPON_PULSERIFLE, 999);
		// Player.GiveWeapon(TW_WEAPON_ALIENGUN, 999);
		// Player.GiveWeapon(TW_WEAPON_ACCELERATOR, 999);
		
		// //give
		// Player.GiveWeapon(TW_WEAPON_ASHOTGUN, -4);

		// Sys.Print("Current Position - X:" + Player.Actor().Origin().x + ", Y:" + Player.Actor().Origin().y + ", Z:" + Player.Actor().Origin().z + ", SectorIndex: " + Player.Actor().SectorIndex() + ", Yaw: " + Math::Rad2Deg(Player.Actor().Yaw()) + ", " + Player.Actor().Yaw() + ", MapID: " + Game.GetCurrentMapID() + ", AreaID: " + Player.Actor().AreaID());
	// }
}
//------------------------------------------------------------------------------------------------------------------------
void ActorInWorldTestUpdate() {
	// uint16 buttons = Player.Buttons();
	// if ((buttons & (BC_WEAPONLEFT)) != 0) {
		// //get the actor in the world near me
		// tidTest = -1;
		// float closest = 99999.0f;
		// for (int i = 0; i < 10000; i++) {
			// kActor @newActor = World.GetActorByTID(i);
			// if (newActor !is null) {
				// float d = newActor.Origin().Distance(Player.Actor().Origin());
				// if (d < closest) {
					// closest = d;
					// @actorWorldTest = @newActor;
					// tidTest = i;
				// }
			// }
		// }
		// if (actorWorldTest !is null and tidTest >= 0) {
			// Game.PrintLine("ActorTID " + tidTest + " - Dist " + closest, 1, 60);
		// }
	// }
	// if ((buttons & (BC_WEAPONRIGHT)) != 0) {
		// //trigger that actor
		// if (actorWorldTest !is null and tidTest >= 0) {
			// World.TriggerActorsByTID(Player.Actor().CastToActor(), tidTest);
			// //World.TriggerActorsByTID(instigator, tidTest);
			// Sys.Print("Tried to activate actor " + tidTest);
		// } else {
			// Sys.Print("No actor found");
		// }
	// }	
}

//-1 sector makes the object not collide with anything
//------------------------------------------------------------------------------------------------------------------------
kActor@ SpawnSolidActor(const kStr &in name, const float x, const float y, const float z, float yaw = 0) {
	kActor @actor = SpawnActor(name, x, y, z, yaw);
	actor.Flags() |= AF_SOLID;
	return @actor;
}
//------------------------------------------------------------------------------------------------------------------------
kActor@ SpawnActor(const kStr &in name, const float x, const float y, const float z, float yaw = 0) {
	int sectorIndex = Player.Actor().GetSectorIndexAtLocation(kVec3(x, y, z));
	return ActorFactory.Spawn(name, x, y, z, yaw, sectorIndex);
}
//------------------------------------------------------------------------------------------------------------------------
kActor@ SpawnSolidActor(const kStr &in name, const float x, const float y, const float z, int sectorIndex, float yaw = 0) {
	kActor @actor = SpawnActor(name, x, y, z, sectorIndex, yaw);
	actor.Flags() |= AF_SOLID;
	return @actor;
}
//------------------------------------------------------------------------------------------------------------------------
kActor@ SpawnActor(const kStr &in name, const float x, const float y, const float z, int sectorIndex, float yaw = 0) {
	return ActorFactory.Spawn(name, x, y, z, yaw, sectorIndex);
}

//------------------------------------------------------------------------------------------------------------------------
void SpawnMonkey(int monkeyID, const float x, const float y, const float z, const float yawDegrees) {
	if (!HasFoundMonkey(monkeyID)) {
		SpawnActor("BPMonkey", x, y, z, -1, Math::Deg2Rad(yawDegrees)).Health() = monkeyID;
	}
}
//------------------------------------------------------------------------------------------------------------------------
kActor@ MapSpawnItem(const kStr &in itemName, const float x, const float y, const float z) {
	kActor @item = SpawnActor(itemName, x, y, z);
	item.Scale() = kVec3(0.35f, 0.35f, 0.35f);
	return @item;
}
//------------------------------------------------------------------------------------------------------------------------
kActor@ MapSpawnBeamTrapVert(const kVec3 p1, const kVec3 p2, const float moveTime, const int sectorIndex) {
	kActor @beam = ActorFactory.Spawn("BP_BeamTrap", p1.x, p1.y, p1.z, 0, sectorIndex);
	// kVec3 v = p2;
	// v.z = moveTime;
	// beam.Velocity() = v;
	beam.Velocity() = p2;
	beam.Health() = int(moveTime * 100.0f);
	return @beam;
}
//------------------------------------------------------------------------------------------------------------------------
kActor@ MapSpawnBeamTrapHorzX(const kVec3 p1, const kVec3 p2, const float moveTime, const int sectorIndex) {
	kActor @beam = ActorFactory.Spawn("BP_BeamTrapHorzX", p1.x, p1.y, p1.z, 0, sectorIndex);
	beam.Velocity() = p2;
	beam.Health() = int(moveTime * 100.0f);
	return @beam;
}
//------------------------------------------------------------------------------------------------------------------------
kActor@ MapSpawnBeamTrapHorzY(const kVec3 p1, const kVec3 p2, const float moveTime, const int sectorIndex) {
	kActor @beam = ActorFactory.Spawn("BP_BeamTrapHorzY", p1.x, p1.y, p1.z, 0, sectorIndex);
	beam.Velocity() = p2;
	beam.Health() = int(moveTime * 100.0f);
	return @beam;
}
//------------------------------------------------------------------------------------------------------------------------
void PlayRandomSound(const array<kStr> sounds) {
	Game.PlaySound(sounds[Math::RandMax(sounds.length())]);
}
//------------------------------------------------------------------------------------------------------------------------
void BlockRadius(const kVec3 pos, const float radius) {
	if (Player.Actor().Origin().Distance(pos) < radius) {
		kVec3 dir = (Player.Actor().Origin() - pos).Normalize() * 20.0f;
		dir.z = Player.Actor().Velocity().z;
		Player.Actor().Velocity() = dir;
	}
}
//------------------------------------------------------------------------------------------------------------------------
// pos is the bottom center of the area. Width is half the total width.
//------------------------------------------------------------------------------------------------------------------------
void BlockArea(const kVec3 pos, const float width, const float height) {
	kVec3 areaMin = kVec3(pos.x - width, pos.y - width, pos.z);
	kVec3 areaMax = kVec3(pos.x + width, pos.y + width, pos.z + height);
	if (PointInArea(Player.Actor().Origin(), areaMin, areaMax)) {
		kVec3 dir = (Player.Actor().Origin() - pos).Normalize() * 50.0f;
		dir.z = Player.Actor().Velocity().z;
		Player.Actor().Velocity() = dir;
	}
}
//------------------------------------------------------------------------------------------------------------------------
void BlockAreaMinMax(const kVec3 min, const kVec3 max) {
	if (PointInArea(Player.Actor().Origin(), min, max)) {
		//kVec3 center = (max - min) / 2;
		kVec3 center = kVec3(0.0f, 0.0f, 0.0f); //max;
		center.x = (max.x - min.x) / 2.0f;
		center.y = (max.y - min.y) / 2.0f;
		center.z = 0.0f;
		kVec3 dir = (Player.Actor().Origin() - center).Normalize() * 50.0f;
		dir.z = Player.Actor().Velocity().z;
		Player.Actor().Velocity() = dir;
	}
}
//------------------------------------------------------------------------------------------------------------------------
// Takes a vector for direction to push player away on XY axis only (since opposite dir is not always good)
//------------------------------------------------------------------------------------------------------------------------
void BlockAreaMinMax(const kVec3 min, const kVec3 max, const kVec3 pushDir) {
	if (PointInArea(Player.Actor().Origin(), min, max)) {
		//Sys.Print("In Area");
		kVec3 dir = kVec3(0.0f, 0.0f, 0.0f); //pushDir;
		dir.x = pushDir.x * 50.0f;
		dir.y = pushDir.y * 50.0f;
		dir.z = Player.Actor().Velocity().z;
		Player.Actor().Velocity() = dir;
	}
}
//------------------------------------------------------------------------------------------------------------------------
// Takes a vector for direction to push player away on XY axis only (since opposite dir is not always good)
//------------------------------------------------------------------------------------------------------------------------
void BlockAreaMinMaxArena(const kVec3 min, const kVec3 max, const kVec3 pushDir) {
	if ((Player.Actor().PlayerFlags() & PF_NOCLIP) != 0) {
		return;
	}
	
	kVec3 newMin = min;
	kVec3 newMax = max;
	newMin.x -= Player.Actor().Radius();
	newMin.y -= Player.Actor().Radius();
	newMax.x += Player.Actor().Radius();
	newMax.y += Player.Actor().Radius();
	
	if (PointInArea(Player.Actor().Origin(), newMin, newMax)) {
		kVec3 pos = Player.Actor().Origin();
		kVec3 prevPos = Player.Actor().PrevOrigin();
		if (pushDir.x != 0) {
			pos.x = prevPos.x;
		}
		if (pushDir.y != 0) {
			pos.y = prevPos.y;
		}
		if (pushDir.z != 0) {
			pos.z = prevPos.z;
		}
		Player.Actor().Origin() = pos;
		BlockAreaMinMax(newMin, newMax, pushDir);
	}
}
//------------------------------------------------------------------------------------------------------------------------
bool InRadius(const kVec3 pos, const float radius) {
	return Player.Actor().Origin().Distance(pos) < radius;
}
//------------------------------------------------------------------------------------------------------------------------
// pos is the bottom center of the area. Width is half the actual width.
//------------------------------------------------------------------------------------------------------------------------
bool InArea(const kVec3 pos, const float width, const float height) {
	kVec3 areaMin = kVec3(pos.x - width, pos.y - width, pos.z);
	kVec3 areaMax = kVec3(pos.x + width, pos.y + width, pos.z + height);
	return PointInArea(Player.Actor().Origin(), areaMin, areaMax);
}
//------------------------------------------------------------------------------------------------------------------------
// pos is the bottom center of the area. size.xy is half the actual size.
//------------------------------------------------------------------------------------------------------------------------
bool InArea(const kVec3 pos, const kVec3 size) {
	kVec3 areaMin = kVec3(pos.x - size.x, pos.y - size.y, pos.z);
	kVec3 areaMax = kVec3(pos.x + size.x, pos.y + size.y, pos.z + size.z);
	return PointInArea(Player.Actor().Origin(), areaMin, areaMax);
}
//------------------------------------------------------------------------------------------------------------------------
bool InAreaMinMax(const kVec3 min, const kVec3 max) {
	return PointInArea(Player.Actor().Origin(), min, max);
}
//------------------------------------------------------------------------------------------------------------------------
// Returns true if point is inside a Area
//------------------------------------------------------------------------------------------------------------------------
bool PointInArea(const kVec3 point, const kVec3 rMin, const kVec3 rMax) {
	return (point.x >= rMin.x and point.x <= rMax.x) and (point.y >= rMin.y and point.y <= rMax.y) and (point.z >= rMin.z and point.z <= rMax.z);
}
//------------------------------------------------------------------------------------------------------------------------
bool CanPlayerMove() {
	return (Player.Actor().CastToActor().Flags() & AF_STATIONARY) == 0;
}
//------------------------------------------------------------------------------------------------------------------------
// pos is the position to keep the player
//------------------------------------------------------------------------------------------------------------------------
void SetPlayerFlagNoMovement(const bool value) {	
	kVec3 pos = Player.Actor().Origin();
	GameVariables.SetValue("BP.NoMovePos", pos.ToString());
	if (value == true) {
		Player.Actor().CastToActor().Flags() |= AF_STATIONARY;
	} else {
		Player.Actor().CastToActor().Flags() &= ~AF_STATIONARY; //no movement flag gives an error here
	}
	//Sys.Print("No Movement setting to " + value + ", stationaryflag = " + (Player.Actor().CastToActor().Flags() & AF_STATIONARY));
}
//------------------------------------------------------------------------------------------------------------------------
void SetPlayerPosToNoMovementPos() {
	kVec3 pos;
	GameVariables.GetVector("BP.NoMovePos", pos);
	Player.Actor().Origin() = pos;
	Player.Actor().Velocity() = Math::vecZero;
	Player.Actor().Movement() = Math::vecZero;
}
//------------------------------------------------------------------------------------------------------------------------
void LoseMoney(const int amount) {
	int money = 0;
	GameVariables.GetInt("BP.Money", money);
	money -= amount;
	SetMoney(money);
}
//------------------------------------------------------------------------------------------------------------------------
void GainMoney(const int amount, const bool showMoney) {
	int money = 0;
	GameVariables.GetInt("BP.Money", money);
	money += amount;
	SetMoney(money);
	if (showMoney) {
		Game.PrintLine("" + money + " Spirits", 5, 60);
	}
}
//------------------------------------------------------------------------------------------------------------------------
int GetMoney() {
	int money = 0;
	GameVariables.GetInt("BP.Money", money);
	return money;
}
//------------------------------------------------------------------------------------------------------------------------
void SetMoney(const int money) {
	//Sys.Print("" + money);
	GameVariables.SetValue("BP.Money", "" + money);
}
//------------------------------------------------------------------------------------------------------------------------
bool HasMoney(const int amount) {
	int money = 0;
	GameVariables.GetInt("BP.Money", money);
	return money >= amount;
}
//------------------------------------------------------------------------------------------------------------------------
bool HasJumpPower() {
	bool hasJumpPower = false;
	GameVariables.GetBool("BP.JumpPower", hasJumpPower);
	return hasJumpPower;
}
//------------------------------------------------------------------------------------------------------------------------
void SetJumpPower(const bool value) {
	GameVariables.SetValue("BP.JumpPower", value ? "1" : "0");
	Player.Actor().Gravity() = value ? JumpPowerGravity : NormalGravity;
}
//------------------------------------------------------------------------------------------------------------------------
bool HasKey1A() {
	bool haskey = false;
	GameVariables.GetBool("BP.GotKey1a", haskey);
	return haskey;
}
//------------------------------------------------------------------------------------------------------------------------
void SetKey1A(const bool value) {
	GameVariables.SetValue("BP.GotKey1a", value ? "1" : "0");
	//didn't have key but has it now and on level 4
	if (value and Game.GetCurrentMapID() == 4) {
		Game.CallDelayedMapScript(2, Player.Actor().CastToActor(), 0);
	}
}
//------------------------------------------------------------------------------------------------------------------------
bool HasPPKey1A() {
	bool haskey = false;
	GameVariables.GetBool("BP.PPKey1a", haskey);
	return haskey;
}
//------------------------------------------------------------------------------------------------------------------------
void SetPPKey1A(const bool value) {
	GameVariables.SetValue("BP.PPKey1a", value ? "1" : "0");
	if (value and Game.GetCurrentMapID() == 4) {
		Game.CallDelayedMapScript(3, Player.Actor().CastToActor(), 0);
	}
}
//------------------------------------------------------------------------------------------------------------------------
bool HasPlayedIntro1() {
	bool played = false;
	GameVariables.GetBool("BP.intro1", played);
	return played;
}
//------------------------------------------------------------------------------------------------------------------------
void SetPlayedIntro1(const bool value) {
	GameVariables.SetValue("BP.intro1", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasPlayedArenaEnterCin(const int num) {
	bool played = false;
	GameVariables.GetBool("BP.ArenaEnterCin" + num, played);
	return played;
}
//------------------------------------------------------------------------------------------------------------------------
void SetPlayedArenaEnterCin(const int num, const bool value) {
	GameVariables.SetValue("BP.ArenaEnterCin" + num, value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasPlayedShopIntro() {
	bool played = false;
	GameVariables.GetBool("BP.shopintro", played);
	return played;
}
//------------------------------------------------------------------------------------------------------------------------
void SetPlayedShopIntro(const bool value) {
	GameVariables.SetValue("BP.shopintro", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasPlayedChallengeIntro() {
	bool played = false;
	GameVariables.GetBool("BP.challengeintro", played);
	return played;
}
//------------------------------------------------------------------------------------------------------------------------
void SetPlayedChallengeIntro(const bool value) {
	GameVariables.SetValue("BP.challengeintro", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasChallengeKey(const int num) {
	bool hasKey = false;
	GameVariables.GetBool("BP.ChallengeKey" + num, hasKey);
	return hasKey;
}
//------------------------------------------------------------------------------------------------------------------------
void SetChallengeKey(const int num, const bool value) {
	GameVariables.SetValue("BP.ChallengeKey" + num, value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
void EnterChallengeWarp(int id) {
	kVec3 pos = Player.Actor().Origin();
	pos.z = Player.Actor().FloorHeight();
	int sector = Player.Actor().GetSectorIndexAtLocation(pos);
	GameVariables.SetValue("BP.ChallengeWarpSector", "" + sector);
	GameVariables.SetValue("BP.ChallengeWarpPos", pos.ToString());
	GameVariables.SetValue("BP.ChallengeWarpYaw", "" + Player.Actor().Yaw());
	GameVariables.SetValue("BP.ChallengeWarpMap", "" + Game.GetCurrentMapID());
	GameVariables.SetValue("BP.ChallengeID", "" + id);
	
	switch (id) {
		case 3:
			PlayLoop.StartFreeWarp(Player.Actor().CastToActor(), kVec3(-3124, 2753, 102), Math::Deg2Rad(46), 3878, 56);
			break;
		case 2:
			PlayLoop.StartFreeWarp(Player.Actor().CastToActor(), kVec3(4271, -8044, 1424), Math::Deg2Rad(-90), 2857, 55);
			break;
		case 1:
		default:
			PlayLoop.StartFreeWarp(Player.Actor().CastToActor(), kVec3(-5389, -3516, 307), Math::Deg2Rad(-90), 1313, 54);
			break;
	}
}
//------------------------------------------------------------------------------------------------------------------------
void ExitChallengeWarp() {
	int sector;
	kVec3 pos;
	float yaw;
	int mapID;
	GameVariables.GetInt("BP.ChallengeWarpSector", sector);
	GameVariables.GetVector("BP.ChallengeWarpPos", pos);
	GameVariables.GetFloat("BP.ChallengeWarpYaw", yaw);
	GameVariables.GetInt("BP.ChallengeWarpMap", mapID);
	PlayLoop.StartFreeWarp(Player.Actor().CastToActor(), pos, yaw, sector, mapID);
}
//------------------------------------------------------------------------------------------------------------------------
bool HasUpgradeKnife() {
	bool hasUpgrade = false;
	GameVariables.GetBool("BP.UpgradeKnife", hasUpgrade);
	return hasUpgrade;
}
//------------------------------------------------------------------------------------------------------------------------
void SetUpgradeKnife(const bool value) {
	GameVariables.SetValue("BP.UpgradeKnife", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasUpgradeBow() {
	bool hasUpgrade = false;
	GameVariables.GetBool("BP.UpgradeBow", hasUpgrade);
	return hasUpgrade;
}
//------------------------------------------------------------------------------------------------------------------------
void SetUpgradeBow(const bool value) {
	GameVariables.SetValue("BP.UpgradeBow", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasUpgradePistol() {
	bool hasUpgrade = false;
	GameVariables.GetBool("BP.UpgradePistol", hasUpgrade);
	return hasUpgrade;
}
//------------------------------------------------------------------------------------------------------------------------
void SetUpgradePistol(const bool value) {
	GameVariables.SetValue("BP.UpgradePistol", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasUpgradeShotgun() {
	return true;
	// bool hasUpgrade = false;
	// GameVariables.GetBool("BP.UpgradeShotgun", hasUpgrade);
	// return hasUpgrade;
}
//------------------------------------------------------------------------------------------------------------------------
void SetUpgradeShotgun(const bool value) {
	GameVariables.SetValue("BP.UpgradeShotgun", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasUpgradeMinigun() {
	return true;
	// bool hasUpgrade = false;
	// GameVariables.GetBool("BP.UpgradeMinigun", hasUpgrade);
	// return hasUpgrade;
}
//------------------------------------------------------------------------------------------------------------------------
void SetUpgradeMinigun(const bool value) {
	GameVariables.SetValue("BP.UpgradeMinigun", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasUpgradeGrenade() {
	return true;
	// bool hasUpgrade = false;
	// GameVariables.GetBool("BP.UpgradeGrenade", hasUpgrade);
	// return hasUpgrade;
}
//------------------------------------------------------------------------------------------------------------------------
void SetUpgradeGrenade(const bool value) {
	GameVariables.SetValue("BP.UpgradeGrenade", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasUpgradeLaser() {
	return true;
	// bool hasUpgrade = false;
	// GameVariables.GetBool("BP.UpgradeLaser", hasUpgrade);
	// return hasUpgrade;
}
//------------------------------------------------------------------------------------------------------------------------
void SetUpgradeLaser(const bool value) {
	GameVariables.SetValue("BP.UpgradeLaser", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasUpgradeRocket() {
	return true;
	// bool hasUpgrade = false;
	// GameVariables.GetBool("BP.UpgradeRocket", hasUpgrade);
	// return hasUpgrade;
}
//------------------------------------------------------------------------------------------------------------------------
void SetUpgradeRocket(const bool value) {
	GameVariables.SetValue("BP.UpgradeRocket", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
bool HasDoneMonkeyIntro() {
	bool hasUpgrade = false;
	GameVariables.GetBool("BP.MonkeyIntro", hasUpgrade);
	return hasUpgrade;
}
//------------------------------------------------------------------------------------------------------------------------
void SetMonkeyIntro(const bool value) {
	GameVariables.SetValue("BP.MonkeyIntro", value ? "1" : "0");
}
//------------------------------------------------------------------------------------------------------------------------
int GetMonkeyLevel() {
	switch (Game.GetCurrentMapID()) {
		case 4:
		case 5:
			return 1;
		case 6:
		case 7:
			return 2;
		case 8:
		case 9:
			return 3;
		case 10:
		case 11:
			return 4;
		case 12:
		case 13:
			return 5;
		case 14:
		case 15:
		case 16:
			return 6;
		default: //(17,18,19,20)
			return 7;
	}
	return 7;
}
//------------------------------------------------------------------------------------------------------------------------
int GetMaxMonkeysOnLevel() {
	return GetMaxMonkeysOnLevel(GetMonkeyLevel());
}
//------------------------------------------------------------------------------------------------------------------------
int GetMaxMonkeysOnLevel(int level) {
	switch (level) {
		case 2: //Jungle
			return 18;
		case 1: //Hub
			return 15;
		default:
			return 0;
	}
	return 0;
}
//------------------------------------------------------------------------------------------------------------------------
int GetMonkeysFoundOnLevel() {
	return GetMonkeysFoundOnLevel(GetMonkeyLevel());
}
//------------------------------------------------------------------------------------------------------------------------
int GetMonkeysFoundOnLevel(int level) {
	int flags;
	GameVariables.GetInt("BP.MonkeysL" + level, flags);
	int count = 0;
	for (int i = 0; i < GetMaxMonkeysOnLevel(level); i++) {
		if ((flags & (1 << i)) != 0) {
			count++;
		}
	}
	return count;
}
//------------------------------------------------------------------------------------------------------------------------
bool HasFoundMonkey(int monkeyID) {
	int flags;
	GameVariables.GetInt("BP.MonkeysL" + GetMonkeyLevel(), flags);
	return (flags & (1 << monkeyID)) != 0;
}
//------------------------------------------------------------------------------------------------------------------------
void SetMonkeyFound(int monkeyID, const bool value) {
	kStr key = "BP.MonkeysL" + GetMonkeyLevel();
	int flags;
	GameVariables.GetInt(key, flags);
	if (value) {
		flags |= (1 << monkeyID);
	} else {
		flags &= ~(1 << monkeyID);
	}
	GameVariables.SetValue(key, "" + flags);
}
//------------------------------------------------------------------------------------------------------------------------
