-- Copyright (C) 2011 and beyond by Gregory Smith, Jeremiah Morris, -- and the "Aleph One" developers. -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- This license is contained in the file "COPYING", -- which is included with this source code; it is available online at -- http://www.gnu.org/licenses/gpl.html Triggers = {} function Triggers.init(restored) for p in Players() do if p.local_ then local_player = p end end stats = {} stats["start tick"] = Game.ticks stats["player color"] = local_player.color.mnemonic if #Players > 1 then stats["player name"] = local_player.name stats["player team"] = local_player.team.mnemonic end stats["difficulty"] = Game.difficulty.mnemonic stats["game type"] = Game.type.mnemonic stats["level"] = Level.name stats["level index"] = Level.index stats["map checksum"] = Level.map_checksum stats["players"] = # Players stats["scenario name"] = "Marathon Infinity" stats["engine version"] = Game.version if restored then stats["restored"] = 1 end establish_session(restored) end function Triggers.cleanup() stats["end tick"] = Game.ticks if Level.completed then stats["level completed"] = 1 -- count monsters left alive on map for m in Monsters() do if not m.player and (m.vitality > 0 or not m.visible) then increment(m.type.mnemonic .. "s spared") end end end if #Players > 1 then stats["player index"] = local_player.index if Game.type ~= "kill monsters" and Game.type ~= "cooperative play" then stats["points"] = local_player.points end -- only check multiplayer wins if the game finishes -- corollary: untimed games with no kill limit never count as wins! local find_winner = false if Players[0].disconnected then -- gatherer went away, game was interrupted stats["interrupted"] = 1 elseif Game.type == "cooperative play" then -- Lua doesn't provide monster damage to replicate scoring find_winner = false elseif Game.time_remaining == 0 then -- Kill limit games convert to timed games when limit is -- reached, so this check conveniently covers both find_winner = true end if find_winner then -- send kills, deaths, suicides for complete game stats["game suicides"] = local_player.kills[local_player] stats["game deaths"] = local_player.deaths stats["game kills"] = 0 for p in Players() do stats["game deaths"] = stats["game deaths"] + p.kills[local_player] if p ~= local_player then stats["game deaths by player " .. p.index] = p.kills[local_player] stats["game kills"] = stats["game kills"] + local_player.kills[p] stats["game kills of player " .. p.index] = local_player.kills[p] end end -- determine scores and rankings local scores = {} if Game.type == "kill monsters" then -- emfh for p in Players() do -- emfh score = total kills (excluding suicides) - total deaths scores[p] = 0 -- count up all the player's kills for pp in Players() do if p ~= pp then scores[p] = scores[p] + p.kills[pp] end end -- subtract times he was killed (by other players and himself) for pp in Players() do scores[p] = scores[p] - pp.kills[p] end -- subtract times he died for other reasons scores[p] = scores[p] - p.deaths end else local mult = 1 if Game.type == "tag" or (Game.type == "netscript" and (Game.scoring_mode == "least points" or Game.scoring_mode == "least_time")) then mult = -1 end for p in Players() do scores[p] = p.points * mult end end stats["score"] = scores[local_player] stats["ranking"] = 1 local tied = 0 for p in Players() do if scores[p] > scores[local_player] then increment("ranking") elseif p ~= local_player and scores[p] == scores[local_player] then tied = 1 end end if stats["ranking"] == 1 and tied == 0 then stats["winner"] = 1 end end -- find_winner end -- #Players > 1 -- count polygons and lines counted_lines = {} for p in Polygons() do increment("polygons") if p.visible_on_automap then increment("visible polygons") end for l in p.lines() do if not counted_lines[l.index] then increment("lines") if l.visible_on_automap then increment("visible lines") end counted_lines[l.index] = 1 end end end Statistics = {} Statistics.parameters = stats end function Triggers.projectile_created(projectile) if projectile.type ~= "fist" and projectile.owner == local_player.monster then increment(projectile.type.mnemonic .. "s fired") end end function Triggers.monster_killed(monster, aggressor, projectile) if aggressor == local_player then increment(monster.type.mnemonic .. " kills") if projectile.type == "fist" then increment(monster.type.mnemonic .. " punch kills") end end end function Triggers.monster_damaged(_, aggressor_monster, _, _, projectile) if aggressor_monster == local_player.monster and projectile then if projectile.type ~= "fist" and not projectile._hit then projectile._hit = true increment(projectile.type.mnemonic .. "s hit") end end end function Triggers.player_damaged(_, aggressor_player, _, _, _, projectile) if aggressor_player == local_player and projectile then if projectile.type ~= "fist" and not projectile._hit then projectile._hit = true increment(projectile.type.mnemonic .. "s hit") end end end function Triggers.projectile_switch(projectile, side) if projectile.type == "fist" and projectile.owner == local_player.monster then increment("switches punched") end end function Triggers.tag_switch(_, player, side) if player == local_player and side.control_panel and side.control_panel.uses_item then increment("chips inserted") end end function Triggers.terminal_enter(_, player) if player == local_player then increment("terminals activated") end end function Triggers.player_killed(victim, aggressor) if victim == local_player then increment("deaths") if aggressor == local_player then increment("suicides") elseif aggressor then increment("deaths by player " .. aggressor.index) end -- kill zones if stats["death locations"] == nil then stats["death locations"] = "" end stats["death locations"] = stats["death locations"] .. string.format(" %.1f,%.1f,%.1f,%d", victim.x, victim.y, victim.z, victim.polygon.index) elseif aggressor == local_player then increment("kills") increment("kills of player " .. victim.index) end end function increment(key) if stats[key] then stats[key] = stats[key] + 1 else stats[key] = 1 end end function establish_session(restored) if Game.ticks == 0 then Game._initial_level = Level.index Game._saves_loaded = 0 elseif restored then Game.restore_saved() if Game._saves_loaded ~= nil then Game._saves_loaded = Game._saves_loaded + 1 end else Game.restore_passed() end if Game._stat_session ~= nil then Game._parent_session = Game._stat_session end Game._stat_session = create_session_id() if Game._initial_level ~= nil then stats["initial level"] = Game._initial_level end if Game._parent_session ~= nil then stats["parent session"] = Game._parent_session end if Game._stat_session ~= nil then stats["stat session"] = Game._stat_session end if Game._saves_loaded ~= nil then stats["saves loaded"] = Game._saves_loaded end end function create_session_id() return string.sub(tostring(math.random()), 3) end