forked from Mirrors/openclonk
Merge branch 'hotice-rounds'
commit
d0ee605728
|
@ -7,10 +7,17 @@
|
|||
|
||||
static g_player_spawn_positions;
|
||||
static g_map_width;
|
||||
static g_no_map, g_seed;
|
||||
|
||||
// Called be the engine: draw the complete map here.
|
||||
public func InitializeMap(proplist map)
|
||||
{
|
||||
// Don't draw a map when switching to the empty scenario section.
|
||||
if (g_no_map) return true;
|
||||
// Reloading the scenario section also resets the RNG. Call Random() a few times to get a new map each round.
|
||||
var i = g_seed++;
|
||||
while (i--) Random(2);
|
||||
|
||||
// Map type 0: One big island; more small islands above
|
||||
// Map type 1: Only many small islands
|
||||
var t = SCENPAR_MapType;
|
||||
|
|
|
@ -33,3 +33,31 @@ Default=0
|
|||
Name=$WeaponsExplosive$
|
||||
Description=$DescWeaponsExplosive$
|
||||
Value=1
|
||||
|
||||
[ParameterDef]
|
||||
Name=$Rounds$
|
||||
Description=$DescRounds$
|
||||
ID=Rounds
|
||||
Default=1
|
||||
|
||||
[Options]
|
||||
|
||||
[Option]
|
||||
Name=1
|
||||
Value=1
|
||||
|
||||
[Option]
|
||||
Name=2
|
||||
Value=2
|
||||
|
||||
[Option]
|
||||
Name=3
|
||||
Value=3
|
||||
|
||||
[Option]
|
||||
Name=5
|
||||
Value=5
|
||||
|
||||
[Option]
|
||||
Name=7
|
||||
Value=7
|
||||
|
|
|
@ -1,7 +1,61 @@
|
|||
/* Hot ice */
|
||||
|
||||
static g_remaining_rounds, g_winners, g_check_victory_effect;
|
||||
static g_gameover;
|
||||
|
||||
func Initialize()
|
||||
{
|
||||
g_remaining_rounds = SCENPAR_Rounds;
|
||||
g_winners = [];
|
||||
InitializeRound();
|
||||
|
||||
Scoreboard->Init([
|
||||
// Invisible team column for sorting players under their teams.
|
||||
{key = "team", title = "", sorted = true, desc = false, default = "", priority = 90},
|
||||
{key = "wins", title = "Wins", sorted = true, desc = true, default = 0, priority = 100},
|
||||
{key = "death", title = "", sorted = false, default = "", priority = 0},
|
||||
]);
|
||||
}
|
||||
|
||||
// Resets the scenario, redrawing the map.
|
||||
func ResetRound()
|
||||
{
|
||||
// Retrieve all Clonks.
|
||||
var clonks = FindObjects(Find_OCF(OCF_CrewMember));
|
||||
for (var clonk in clonks)
|
||||
{
|
||||
var container = clonk->Contained();
|
||||
if (container)
|
||||
{
|
||||
clonk->Exit();
|
||||
container->RemoveObject();
|
||||
}
|
||||
clonk->SetObjectStatus(C4OS_INACTIVE);
|
||||
}
|
||||
// Clear and redraw the map.
|
||||
g_no_map = true;
|
||||
LoadScenarioSection("Empty");
|
||||
g_no_map = false;
|
||||
LoadScenarioSection("main");
|
||||
InitializeRound();
|
||||
// Re-enable the players.
|
||||
for (var clonk in clonks)
|
||||
{
|
||||
clonk->SetObjectStatus(C4OS_NORMAL);
|
||||
SetCursor(clonk->GetOwner(), clonk);
|
||||
// Select the first item. This fixes item ordering.
|
||||
clonk->SetHandItemPos(0, 0);
|
||||
InitPlayerRound(clonk->GetOwner());
|
||||
}
|
||||
}
|
||||
|
||||
func InitializeRound()
|
||||
{
|
||||
// Checking for victory: Only active after a Clonk dies.
|
||||
g_check_victory_effect = AddEffect("CheckVictory", nil, 1, 0);
|
||||
g_player_spawn_index = 0;
|
||||
ShuffleArray(g_player_spawn_positions);
|
||||
|
||||
// Materials: Chests
|
||||
var i,pos;
|
||||
var ls_wdt = LandscapeWidth(), ls_hgt = LandscapeHeight();
|
||||
|
@ -46,10 +100,28 @@ func Initialize()
|
|||
|
||||
static g_player_spawn_positions, g_map_width, g_player_spawn_index;
|
||||
|
||||
global func ScoreboardTeam(int team) { return team * 100; }
|
||||
|
||||
func InitializePlayer(int plr)
|
||||
{
|
||||
// Add the player and their team to the scoreboard.
|
||||
Scoreboard->NewPlayerEntry(plr);
|
||||
Scoreboard->SetPlayerData(plr, "wins", "");
|
||||
var team = GetPlayerTeam(plr);
|
||||
Scoreboard->NewEntry(ScoreboardTeam(team), GetTeamName(team));
|
||||
Scoreboard->SetData(ScoreboardTeam(team), "team", "", ScoreboardTeam(team));
|
||||
Scoreboard->SetPlayerData(plr, "team", "", ScoreboardTeam(team) + 1);
|
||||
|
||||
return InitPlayerRound(plr);
|
||||
}
|
||||
|
||||
func InitPlayerRound(int plr)
|
||||
{
|
||||
// Unmark death on scoreboard.
|
||||
Scoreboard->SetPlayerData(plr, "death", "");
|
||||
// everything visible
|
||||
SetFoW(false, plr);
|
||||
SetPlayerViewLock(plr, true);
|
||||
// Player positioning.
|
||||
var ls_wdt = LandscapeWidth(), ls_hgt = LandscapeHeight();
|
||||
var crew = GetCrew(plr), start_pos;
|
||||
|
@ -93,6 +165,156 @@ func InitializePlayer(int plr)
|
|||
return true;
|
||||
}
|
||||
|
||||
func OnClonkDeath(object clonk)
|
||||
{
|
||||
var plr = clonk->GetOwner();
|
||||
// Mark death on scoreboard.
|
||||
Scoreboard->SetPlayerData(plr, "death", "{{Scoreboard_Death}}");
|
||||
// Skip eliminated players, NO_OWNER, etc.
|
||||
if (GetPlayerName(plr))
|
||||
{
|
||||
var crew = CreateObject(Clonk, 0, 0, plr);
|
||||
crew->MakeCrewMember(plr);
|
||||
var relaunch = CreateObject(RelaunchContainer, LandscapeWidth() / 2, LandscapeHeight() / 2, plr);
|
||||
// We just use the relaunch object as a dumb container.
|
||||
crew->Enter(relaunch);
|
||||
// Allow scrolling around the landscape.
|
||||
SetPlayerViewLock(plr, false);
|
||||
}
|
||||
|
||||
// Check for victory after three seconds to allow stalemates.
|
||||
if (!g_gameover)
|
||||
g_check_victory_effect.Interval = 36 * 5;
|
||||
}
|
||||
|
||||
// Returns a list of colored player names, for example "Sven2, Maikel, Luchs"
|
||||
global func GetTeamPlayerNames(int team)
|
||||
{
|
||||
var str = "";
|
||||
for (var i = 0; i < GetPlayerCount(); i++)
|
||||
{
|
||||
var plr = GetPlayerByIndex(i);
|
||||
if (GetPlayerTeam(plr) == team)
|
||||
{
|
||||
var comma = "";
|
||||
if (str != "") comma = ", ";
|
||||
str = Format("%s%s<c %x>%s</c>", str, comma, GetPlayerColor(plr), GetPlayerName(plr));
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
global func FxCheckVictoryTimer(_, proplist effect)
|
||||
{
|
||||
var find_living = Find_And(Find_OCF(OCF_CrewMember), Find_NoContainer());
|
||||
var clonk = FindObject(find_living);
|
||||
var msg;
|
||||
if (!clonk)
|
||||
{
|
||||
// Stalemate!
|
||||
msg = "$Stalemate$";
|
||||
Log(msg);
|
||||
GameCall("ResetRound");
|
||||
}
|
||||
else if (!FindObject(find_living, Find_Hostile(clonk->GetOwner())))
|
||||
{
|
||||
// We have a winner!
|
||||
var team = GetPlayerTeam(clonk->GetOwner());
|
||||
PushBack(g_winners, team);
|
||||
// Announce the winning team.
|
||||
msg = Format("$WinningTeam$", GetTeamPlayerNames(team));
|
||||
Log(msg);
|
||||
|
||||
// Update the scoreboard.
|
||||
UpdateScoreboardWins(team);
|
||||
|
||||
if (--g_remaining_rounds > 0 || GetLeadingTeam() == nil)
|
||||
{
|
||||
var msg2 = CurrentRoundStr();
|
||||
Log(msg2);
|
||||
msg = Format("%s|%s", msg, msg2);
|
||||
GameCall("ResetRound");
|
||||
}
|
||||
else
|
||||
{
|
||||
GameCall("EliminateLosers");
|
||||
}
|
||||
}
|
||||
// Switching scenario sections makes the Log() messages hard to see, so announce them using a message as well.
|
||||
CustomMessage(msg);
|
||||
// Go to sleep again.
|
||||
effect.Interval = 0;
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
global func CurrentRoundStr()
|
||||
{
|
||||
if (g_remaining_rounds == 1)
|
||||
return "$LastRound$";
|
||||
else if (g_remaining_rounds > 1)
|
||||
return Format("$RemainingRounds$", g_remaining_rounds);
|
||||
else
|
||||
return "$Tiebreak$";
|
||||
}
|
||||
|
||||
global func UpdateScoreboardWins(int team)
|
||||
{
|
||||
var wins = GetTeamWins(team);
|
||||
Scoreboard->SetData(ScoreboardTeam(team), "wins", wins, wins);
|
||||
// We have to update each player as well to make the sorting work.
|
||||
for (var i = 0; i < GetPlayerCount(); i++)
|
||||
{
|
||||
var plr = GetPlayerByIndex(i);
|
||||
if (GetPlayerTeam(plr) == team)
|
||||
{
|
||||
Scoreboard->SetPlayerData(plr, "wins", "", wins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
global func GetTeamWins(int team)
|
||||
{
|
||||
var wins = 0;
|
||||
for (var w in g_winners)
|
||||
if (w == team)
|
||||
wins++;
|
||||
return wins;
|
||||
}
|
||||
|
||||
// Returns the team which won the most rounds, or nil if there is a tie.
|
||||
global func GetLeadingTeam()
|
||||
{
|
||||
var teams = [], winning_team = g_winners[0];
|
||||
for (var w in g_winners)
|
||||
{
|
||||
teams[w] += 1;
|
||||
if (teams[w] > teams[winning_team])
|
||||
winning_team = w;
|
||||
}
|
||||
// Detect a tie.
|
||||
for (var i = 0; i < GetLength(teams); i++)
|
||||
{
|
||||
if (i != winning_team && teams[i] == teams[winning_team])
|
||||
return nil;
|
||||
}
|
||||
return winning_team;
|
||||
}
|
||||
|
||||
func EliminateLosers()
|
||||
{
|
||||
g_gameover = true;
|
||||
// Determine the winning team.
|
||||
var winning_team = GetLeadingTeam();
|
||||
// Eliminate everybody who isn't on the winning team.
|
||||
for (var i = 0; i < GetPlayerCount(); i++)
|
||||
{
|
||||
var plr = GetPlayerByIndex(i);
|
||||
if (GetPlayerTeam(plr) != winning_team)
|
||||
EliminatePlayer(plr);
|
||||
}
|
||||
// The scenario goal will end the scenario.
|
||||
}
|
||||
|
||||
/* Called periodically in grenade launcher */
|
||||
func ReplenishLauncherAmmo()
|
||||
{
|
||||
|
|
|
@ -10,3 +10,10 @@ WeaponsClassic=Klassisch
|
|||
DescWeaponsClassic=Bögen, Speere, Keulen und einige Feuersteine
|
||||
WeaponsExplosive=Explosiv
|
||||
DescWeaponsExplosive=Nur Granatwerfer mit Endlosmunition
|
||||
Rounds=Rundenzahl
|
||||
DescRounds=Mehrere Runden spielen
|
||||
Stalemate=Unentschieden!
|
||||
WinningTeam=Gewinner: %s
|
||||
RemainingRounds=Noch %d Runden.
|
||||
LastRound=Letzte Runde!
|
||||
Tiebreak=Entscheidende Runde!
|
||||
|
|
|
@ -10,3 +10,10 @@ WeaponsClassic=Classic
|
|||
DescWeaponsClassic=Bows, spears and clubs available in chests
|
||||
WeaponsExplosive=Explosive
|
||||
DescWeaponsExplosive=Only grenade lauchers and wind bags available
|
||||
Rounds=Number of rounds
|
||||
DescRounds=Play for multiple rounds
|
||||
Stalemate=Stalemate!
|
||||
WinningTeam=Winning team: %s
|
||||
RemainingRounds=%d rounds remaining.
|
||||
LastRound=Last round!
|
||||
Tiebreak=Tiebreak!
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#appendto Goal_Melee
|
||||
|
||||
public func GetDescription(int plr)
|
||||
{
|
||||
// Count active enemy clonks.
|
||||
var hostile_count = ObjectCount(Find_OCF(OCF_CrewMember), Find_NoContainer(), Find_Hostile(plr));
|
||||
var message;
|
||||
if (!hostile_count)
|
||||
message = "$MsgGoalFulfilled$";
|
||||
else
|
||||
message = Format("$MsgGoalUnfulfilled$", hostile_count);
|
||||
|
||||
// Also report the remaining rounds.
|
||||
message = Format("%s|%s", message, CurrentRoundStr());
|
||||
|
||||
return message;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
MsgGoalFulfilled=Eure Gegner sind eliminiert.
|
||||
MsgGoalUnfulfilled=Es sind noch %d Gegner im Spiel.
|
|
@ -0,0 +1,2 @@
|
|||
MsgGoalFulfilled=All opponents eliminated.
|
||||
MsgGoalUnfulfilled=There are still %d opponents in the game.
|
Loading…
Reference in New Issue