Kill scoring and respawn
Score each kill, bring the fallen back and end the round at a goal.
In a deathmatch, the first player to ten kills wins, and everyone who falls comes back into the fight.
Your mod scores each kill the game reports, and brings the fallen hero back:
import { after, onKill, onPlayerLeave, players, type Player } from 'modlock'
const goal = 10
const kills = new Map<Player, number>()
onKill(({ victimPlayer, attackerPlayer }) => {
if (victimPlayer.slot < 0) {
return // a unit, not a hero
}
after(3, () => victimPlayer.respawn())
if (attackerPlayer.slot < 0 || attackerPlayer.slot === victimPlayer.slot) {
return // a hazard, a unit or the hero's own hit
}
const name = attackerPlayer.connection()?.name ?? 'Someone'
const total = (kills.get(attackerPlayer) ?? 0) + 1
kills.set(attackerPlayer, total)
const won = total >= goal
for (const { player } of players()) {
if (won) {
player.announce(`${name} wins`, 'A new round starts now.')
} else {
player.centerText(`${name}: ${total} / ${goal}`)
}
}
if (won) {
kills.clear()
}
})
onPlayerLeave(({ connection }) => {
kills.delete(connection.player)
})local modlock = require("@modlock")
local goal = 10
local kills: { [modlock.Player]: number } = {}
modlock.onKill(function(kill)
local victim, scorer = kill.victimPlayer, kill.attackerPlayer
if victim.slot < 0 then
return -- a unit, not a hero
end
modlock.after(3, function()
victim:respawn()
end)
if scorer.slot < 0 or scorer.slot == victim.slot then
return -- a hazard, a unit or the hero's own hit
end
local connection = scorer:connection()
local name = if connection then connection.name else "Someone"
local total = (kills[scorer] or 0) + 1
kills[scorer] = total
local won = total >= goal
for _, other in modlock.players() do
if won then
other.player:announce(`{name} wins`, "A new round starts now.")
else
other.player:centerText(`{name}: {total} / {goal}`)
end
end
if won then
kills = {}
end
end)
modlock.onPlayerLeave(function(left)
kills[left.connection.player] = nil
end)import modlock
GOAL = 10
kills: dict[modlock.Player, int] = {}
@modlock.on_kill
def scored(kill: modlock.KillEvent) -> None:
victim, scorer = kill.victim_player, kill.attacker_player
if victim.slot < 0:
return # a unit, not a hero
modlock.after(3, victim.respawn)
if scorer.slot < 0 or scorer.slot == victim.slot:
return # a hazard, a unit or the hero's own hit
connection = scorer.connection()
name = connection.name if connection is not None else "Someone"
total = kills.get(scorer, 0) + 1
kills[scorer] = total
won = total >= GOAL
for other in modlock.players():
if won:
other.player.announce(f"{name} wins", "A new round starts now.")
else:
other.player.center_text(f"{name}: {total} / {GOAL}")
if won:
kills.clear()
@modlock.on_player_leave
def left(event: modlock.PlayerLeftEvent) -> None:
kills.pop(event.connection.player, None)package main
import (
"fmt"
"time"
"github.com/paralin/modlock/mod"
)
const goal = 10
var kills = map[mod.Player]int{}
func init() {
mod.OnKill(func(kill *mod.KillEvent) {
victim := mod.PlayerOf(kill.GetVictimPlayer())
scorer := mod.PlayerOf(kill.GetAttackerPlayer())
if victim.Slot() < 0 {
return // a unit, not a hero
}
mod.After(3*time.Second, func() { _ = victim.Respawn() })
if scorer.Slot() < 0 || scorer.Slot() == victim.Slot() {
return // a hazard, a unit or the hero's own hit
}
name := "Someone"
if c := scorer.Connection(); c != nil {
name = c.GetName()
}
kills[scorer]++
total := kills[scorer]
won := total >= goal
connections, _ := mod.Players()
for _, c := range connections {
p := mod.PlayerOf(c.GetPlayer())
if won {
_ = p.Announce(name+" wins", "A new round starts now.")
} else {
_ = p.CenterText(fmt.Sprintf("%s: %d / %d", name, total, goal))
}
}
if won {
clear(kills)
}
})
mod.OnPlayerLeave(func(left *mod.PlayerLeftEvent) {
delete(kills, mod.PlayerOf(left.GetConnection().GetPlayer()))
})
}
func main() {}Bring a second player or a bot into the game and defeat them.
The kill gives the player on each side, with a slot of -1 where no player's
hero stands: a unit that died, or a unit or hazard that killed. A hero that
killed itself is its own attacker, so it scores nothing. Each point shows every
player the scorer's name and total, such as Ana: 4 / 10, in the middle of the
screen, and at ten every player sees the announcement "name wins".
Variations
- Keep a score through a reconnect by keying it by Steam ID instead of player. The sample keys scores by player and drops them when the player leaves.
- Pay the scorer with
adjustSoulsor heal them to reward a streak. - Count kills across sessions with a metric, or rank players with a board.
- The
bountyexample builds on this. The leader carries a marker, and whoever defeats them takes it.