/*-- Klippenschubsen --*/ #strict 2 static const MODE_Classic = 0, MODE_SuddenDeath = 1, MODE_Magic = 2, MODE_Apocalyptic = 3; static section, mode; static numRelaunches; static deathmatchEnabled, deathmatchWinScore; static playerDeaths, playerScore, teamScore; static ambienceEnabled; static loadingSection; static gameStartMessage, countdown, gameStarted, gameOver; func Initialize() { ShowLobby(); // Initial values deathmatchWinScore = 20; playerDeaths = CreateArray(); playerScore = CreateArray(); teamScore = CreateArray(); countdown = 5; // Create setup menu var menu = CreateObject(SPMU, 0, 0, NO_OWNER); menu->LocalN("extinguisherEnabled") = false; menu->LocalN("rotateInJumpEnabled") = true; menu->LocalN("numRelaunches") = 10; menu->LocalN("deathmatchWinScore") = 25; menu->LocalN("ambienceEnabled") = true; ScriptGo(true); } func TeamRow(int team) { return 1 + team * 1000; } func PlayerRow(int player) { return TeamRow(GetPlayerTeam(player)) + GetPlayerID(player); } func InitializePlayer(int player) { if (LobbyActive()) return; var team = GetPlayerTeam(player); playerDeaths[GetPlayerID(player)] = 0; if (team) SetScoreboardData(TeamRow(team), SBRD_Caption, Format("%s", GetTeamColor(team), GetTeamName(team)), TeamRow(team)); SetScoreboardData(PlayerRow(player), SBRD_Caption, GetTaggedPlayerName(player), PlayerRow(player)); UpdateScoreboard(player); SortScoreboard(SBRD_Caption); LaunchClonk(player, GetCrew(player)); } func RemovePlayer(int player) { if (!LobbyActive()) { // Leaver? var relaunchesLeft = numRelaunches - playerDeaths[GetPlayerID(player)]; if (!deathmatchEnabled && relaunchesLeft >= 0 || deathmatchEnabled && !gameOver) SetScoreboardData(PlayerRow(player), 0, "{{SLVR}}"); } } func UpdateScoreboard(int player) { if (!GetPlayerID(player)) return; if (!deathmatchEnabled) { var relaunchesLeft = numRelaunches - playerDeaths[GetPlayerID(player)]; SetScoreboardData(PlayerRow(player), 0, Format("%d", IIf(relaunchesLeft < 0, "{{SKUL}}", relaunchesLeft))); } else { SetScoreboardData(PlayerRow(player), 0, Format("%d", playerScore[GetPlayerID(player)])); var team = GetPlayerTeam(player); if (team) SetScoreboardData(TeamRow(team), 0, Format("%d", teamScore[team])); } } func ShowLobby() { LoadScenarioSection("Lobby"); } func StartGame(object menu, string message) { // Copy settings from menu var sectionID = menu->LocalN("section"); mode = menu->LocalN("mode"); var extinguisherEnabled = menu->LocalN("extinguisherEnabled"); var friendlyPushingEnabled = menu->LocalN("friendlyPushingEnabled"); var rotateInJumpEnabled = menu->LocalN("rotateInJumpEnabled"); ambienceEnabled = menu->LocalN("ambienceEnabled"); numRelaunches = menu->LocalN("numRelaunches"); deathmatchEnabled = menu->LocalN("deathmatchEnabled"); deathmatchWinScore = menu->LocalN("deathmatchWinScore"); menu->RemoveObject(); // Change scenario section loadingSection = true; //Log("Before LoadScenarioSection()"); LoadScenarioSection(DefinitionCall(sectionID, "SectionName")); //Log("After LoadScenarioSection()"); loadingSection = false; section = CreateObject(sectionID, 0, 0, NO_OWNER); // Create spawnpoints if (mode != MODE_Apocalyptic) { //Log("Creating spawnpoints"); var spawnPointSpawner = CreateObject(SPSR, 0, 0, NO_OWNER); spawnPointSpawner->SetLocations(section->SpawnpointLocations()); if (mode != MODE_Magic) { spawnPointSpawner->SetDefinitions([[ROCK, 9], [SCRL, 9], [FLNT, 9], [SFLN, 9], [STFN, 4], [EFLN, 4], [FBMP, 4]]); spawnPointSpawner->SetSpawnInterval(750); } else { spawnPointSpawner->SetDefinitions([[SCRL, 14], [GBLT, 1]]); spawnPointSpawner->SetSpawnInterval(1000); spawnPointSpawner->SetSpawnpointGamma(RGB(5, 5, 10), RGB(80, 80, 150), RGB(200, 200, 255)); } spawnPointSpawner->CreateSpawnPoints(); } // Effects for apocalypse mode if (mode == MODE_Apocalyptic) { AddEffect("CreateTeraFlints", 0, 20, 90); AddEffect("ShakeScreen", 0, 20, 50); AddEffect("Bottom", 0, 20, 2); AddEffect("SkyAdjust", 0, 20, 1); } // Create melee goal //Log("Creating melee goal"); CreateObject(MELE, 0, 0, NO_OWNER); // Create rules //Log("Creating rules"); if (extinguisherEnabled) CreateObject(_ETG, 0, 0, NO_OWNER); if (friendlyPushingEnabled) CreateObject(FYPG, 0, 0, NO_OWNER); if (rotateInJumpEnabled) CreateObject(RIJP, 0, 0, NO_OWNER); //Log("Creating mode rules"); if (mode == MODE_SuddenDeath) { CreateObject(SDDT, 0, 0, NO_OWNER); } else if (mode == MODE_Magic) { CreateObject(MLPG, 0, 0, NO_OWNER); } else if (mode == MODE_Apocalyptic) { CreateObject(APCE, 0, 0, NO_OWNER); } // Deathmatch? if (deathmatchEnabled) { //Log("Creating deathmatch rule"); CreateObject(DTHM, 0, 0, NO_OWNER); SetScoreboardData(SBRD_Caption, 0, "{{DTHM}}"); SetScoreboardData(0, SBRD_Caption, "$WinScore$"); SetScoreboardData(0, 0, Format("%d", deathmatchWinScore)); } else { SetScoreboardData(SBRD_Caption, 0, "{{SKUL}}"); } // Initialize players //Log("Initializing players"); for (var i = 0; i < GetPlayerCount(); ++i) { InitializePlayer(GetPlayerByIndex(i)); } //Log("Starting countdown"); gameStartMessage = message; ShowCountdown(); //Log("StartGame() done"); } func ShowCountdown() { if (countdown == 0) { gameStartMessage = 0; Message(""); Schedule("SetMaxPlayer(0)", 60 * 38); // Reenable crew for (var i = 0; i < GetPlayerCount(); ++i) { var player = GetPlayerByIndex(i); var clonk = GetCrew(player); if (!clonk) continue; // Happens if player still in team choice menu // Relaunch if clonk does not stand. if (clonk->GetAction() != "Walk") { clonk->Kill(); clonk = GetCrew(player); } clonk->SetCrewEnabled(true); SelectCrew(player, clonk, true); // Make sure all clonks start with equal health clonk->Extinguish(); ResetHealth(clonk); } gameStarted = true; } else { Message("@%d|%s", 0, countdown, gameStartMessage); Schedule("GameCall(\"ShowCountdown\")", 38); } --countdown; } func LobbyActive() { return !section; } func HandleKill(int killed, int killer) { // Assume suicide if killer cannot be determined if (killer == NO_OWNER) killer = killed; var killedEliminated = false; var killedID = GetPlayerID(killed), killerID = GetPlayerID(killer); var killedTeam = GetPlayerTeam(killed), killerTeam = GetPlayerTeam(killer); var teamKill = killer == killed || killedTeam != 0 && killedTeam == killerTeam; ++playerDeaths[killedID]; // Update kill score if (!teamKill) { ++playerScore[killerID]; if (killerTeam) ++teamScore[killerTeam]; } else // Decrement score on suicide or team kill { if (playerScore[killerID] > 0) { --playerScore[killerID]; if (killerTeam) --teamScore[killerTeam]; } } // Show relaunch message or eliminate player if no relaunches left var relaunchesLeft; if (!deathmatchEnabled) { relaunchesLeft = numRelaunches - playerDeaths[killedID]; if (relaunchesLeft < 0) { EliminatePlayer(killed); killedEliminated = true; } else if (relaunchesLeft == 0) { PlayerMessage(killed, "$MsgLastRelaunch$"); } else if (relaunchesLeft == 1) { PlayerMessage(killed, "$MsgOneRelaunch$"); } else // More than one relaunch left { PlayerMessage(killed, "$MsgRelaunch$", 0, relaunchesLeft); } } // Check for deathmatch winner if (deathmatchEnabled) { // Teams enabled? if (killerTeam) { // Winner? if (teamScore[killerTeam] >= deathmatchWinScore) { // Eliminate all players of losing teams for (var player in GetPlayers()) { if (GetPlayerTeam(player) != killerTeam) EliminatePlayer(player); } gameOver = true; killedEliminated = true; } } else // No teams? { // Winner? if (playerScore[killerID] >= deathmatchWinScore) { // Eliminate all losing players for (var player in GetPlayers()) { if (player != killer) EliminatePlayer(player); } gameOver = true; killedEliminated = true; } } } UpdateScoreboard(killed); UpdateScoreboard(killer); return killedEliminated; } func GetPlayers() { var players = CreateArray(GetPlayerCount()); for (var i = 0; i < GetPlayerCount(); ++i) { players[i] = GetPlayerByIndex(i); } return players; } func OnClonkDeath(object clonk, int killedBy) { if (loadingSection) return; var player = clonk->GetOwner(); // Do nothing if Clonk does not belong to a player if (GetPlayerID(player) == 0) return; // Handle kill and return if player got eliminated if (gameStarted && HandleKill(player, killedBy)) return; // Relaunch if (GetPlayerID(player)) LaunchClonk(player, clonk, true); } func LaunchClonk(int player, object clonk, bool forceCreate) { if (!clonk || forceCreate) { var newClonk = CreateObject(CLNK, 0, 0, player); if (clonk) { newClonk->GrabObjectInfo(clonk); } else { MakeCrewMember(newClonk, player); } clonk = newClonk; } ResetHealth(clonk); SelectCrew(player, clonk, true); // Move clonk to random position var NumCheckPos = 10; var positions = CreateArray(NumCheckPos); for (var i = 0; i < NumCheckPos; ++i) { var wipf = PlaceAnimal(WIPF); positions[i] = IIf(wipf, [wipf->GetX(), wipf->GetY()], [LandscapeWidth() / 2, LandscapeHeight() / 2]); if (wipf) wipf->RemoveObject(); } // Prevent spawning too close to an enemy var bestPosition = positions[0], bestDistance = 0; for (var pos in positions) { var closestHostileClonk = FindObject2(Find_OCF(OCF_CrewMember | OCF_Alive), Find_Hostile(player), Sort_Distance(pos[0], pos[1])); if (!closestHostileClonk) break; var distance = Distance(pos[0], pos[1], closestHostileClonk->GetX(), closestHostileClonk->GetY()); if (distance > bestDistance) { bestPosition = pos; bestDistance = distance; } } clonk->SetPosition(bestPosition[0], bestPosition[1]); // Still in countdown? if (!LobbyActive() && !gameStarted) { clonk->SetCrewEnabled(false); } // No corpses in apocalopyse mode if (mode == MODE_Apocalyptic) clonk->LocalN("removeOnDeath") = true; if (FindObject(RIJP)) clonk->LocalN("rotateInJump") = true; SetPlrView(player, clonk); } func ResetHealth(object clonk) { if (mode == MODE_SuddenDeath) { clonk->DoEnergy(1 - clonk->GetEnergy()); } else { clonk->DoEnergy(100); } } func CheckDeathmatchKillCount() { if (GetTeamCount() == 0) { var winner = NO_OWNER; // Check if a player has reached the kill limit for (var i = 0; i < GetPlayerCount(); ++i) { var plr = GetPlayerByIndex(i); if (playerScore[plr] >= deathmatchWinScore) { winner = plr; break; } } // Eliminate other players if there is a winner for (var i = 0; i < GetPlayerCount(); ++i) { var plr = GetPlayerByIndex(i); if (plr != winner) EliminatePlayer(plr); } } else { var winnerTeam = 0; // Clear team score array teamScore = CreateArray(GetTeamCount()); // Calculate team score and check if kill limit is reached for (var i = 0; i < GetPlayerCount(); ++i) { var plr = GetPlayerByIndex(i), team = GetPlayerTeam(plr); teamScore[team] += playerScore[plr]; if (teamScore >= deathmatchWinScore) { winnerTeam = team; break; } } // Do we have a winner? if (winnerTeam != 0) { for (var i = 0; i < GetPlayerCount(); ++i) { var plr = GetPlayerByIndex(i); if (GetPlayerTeam(plr) != winnerTeam) EliminatePlayer(plr); } } } }