-- name: \\#b85469\\Epitaph -- description: Adds a kill/death counter, enhanced death messages, and an API for developers\n\nAuthor: \\#b85469\\CrazyDany -- version: 1.0.0 local KCObjectsMetas = { [id_bhvGoomba] = { name = 'Goomba', reason = 'was eaten by Goomba', side_reason = 'while trying to escape from Goombas biting', id = id_bhvGoomba, }, [id_bhvExplosion] = { name = 'Bob-omb', reason = 'was blown up by Bob-omb', side_reason = 'after being blown up by Bob-omb', id = id_bhvExplosion, }, [id_bhvKoopa] = { name = 'Koopa', reason = 'was downtrodden by Koopa', side_reason = 'while stood in the Koopas way', id = id_bhvKoopa, }, [id_bhvFlyGuy] = { name = 'Fly Guy', reason = 'was beaten by Fly Guy', side_reason = 'while being targeted by Fly Guy', id = id_bhvFlyGuy, }, [id_bhvMontyMole] = { name = 'Monty Mole', reason = 'was ambushed by Monty Mole', side_reason = 'while running from Monty Mole rocks', id = id_bhvMontyMole, }, [id_bhvSpindrift] = { name = 'Spindrift', reason = 'was downtrodden by Spindrift', side_reason = 'while running from Spindrift', id = id_bhvSpindrift, }, [id_bhvBoo] = { name = 'Boo', reason = 'was scared to death by Boo', side_reason = 'while being shocked by Boo', id = id_bhvBoo, }, [id_bhvGhostHuntBoo] = { name = 'Boo', reason = 'was scared to death by Boo', side_reason = 'while being shocked by Boo', id = id_bhvGhostHuntBoo, }, [id_bhvBooInCastle] = { name = 'Castle Boo', reason = 'was frightened by a Castle Boo', side_reason = 'while exploring the castle', id = id_bhvBooInCastle, }, [id_bhvBooWithCage] = { name = 'Boo', reason = "died in the Big Boo's Haunt", side_reason = "when tried to enter the Big Boo's Haunt", id = id_bhvBooWithCage, }, [id_bhvMerryGoRoundBoo] = { name = 'Boo', reason = 'died while spinning with Boos', side_reason = 'while having fun with Boos', id = id_bhvMerryGoRoundBoo, }, [id_bhvFlyingBookend] = { name = 'Flying Book', reason = 'was mauled to death by Flying Book', side_reason = 'while being ambushed by Flying Book', id = id_bhvFlyingBookend, }, [id_bhvSkeeter] = { name = 'Skeeter', reason = 'was pushed out by Skeeter', side_reason = 'while swimming with Skeeters', id = id_bhvSkeeter, }, [id_bhvMoneybag] = { name = 'Moneybag', reason = 'was fooled by Moneybag', side_reason = 'while chasing Moneybag', id = id_bhvMoneybag, }, [id_bhvSnufit] = { name = 'Snufit', reason = 'was shot by Snufit', side_reason = 'while dodging Snufit', id = id_bhvSnufit, }, [id_bhvSwoop] = { name = 'Swoop', reason = 'was scratched by Swoop', side_reason = 'while being chased by Swoop', id = id_bhvSwoop, }, [id_bhvEnemyLakitu] = { name = 'Lakitu', reason = 'was attacked by Lakitu', side_reason = 'while fleeing from Lakitu', id = id_bhvEnemyLakitu, }, [id_bhvSpiny] = { name = 'Spiny', reason = 'was stambled by Spiny', side_reason = 'while watching for Spinys', id = id_bhvSpiny, }, [id_bhvPokey] = { name = 'Pokey', reason = 'was pricked by Pokey', side_reason = 'while having a Pokey stings', id = id_bhvPokey, }, [id_bhvPokeyBodyPart] = { name = 'Pokey', reason = 'was pricked by Pokey', side_reason = 'while having a Pokey stings', id = id_bhvPokeyBodyPart, }, [id_bhvFirePiranhaPlant] = { name = 'Fire Piranha Plant', reason = 'stambled upon Fire Pirahna Plant', side_reason = 'while having legs burned by Fire Pirahna Plant', id = id_bhvFirePiranhaPlant, }, [id_bhvBalconyBigBoo] = { name = 'Big Boo', reason = 'was scared to death by Big Boo', side_reason = 'while fighting Big Boo', id = id_bhvBalconyBigBoo, }, [id_bhvGhostHuntBigBoo] = { name = 'Big Boo', reason = 'was cursed by Big Boo', side_reason = 'while fighting Big Boo', id = id_bhvGhostHuntBigBoo, }, [id_bhvMerryGoRoundBigBoo] = { name = 'Big Boo', reason = 'was took on a ride by Big Boo', side_reason = 'while having fun with Big Boo', id = id_bhvMerryGoRoundBigBoo, }, [id_bhvChainChomp] = { name = 'Chain Chomp', reason = 'was mauled to death by Chain Chomp', side_reason = 'while pestreing Chain Chomp', id = id_bhvChainChomp, }, [id_bhvWigglerBody] = { name = 'Wiggler', reason = 'was crushed by Wiggler', side_reason = 'while avoiding Wiggler\'s charge', id = id_bhvWigglerBody, }, [id_bhvWigglerHead] = { name = 'Wiggler', reason = 'was crushed by Wiggler', side_reason = 'while avoiding Wiggler\'s charge', id = id_bhvWigglerHead, }, [id_bhvSmallBully] = { name = 'Bully', reason = 'was pushed off by Bully', side_reason = 'while standing near a Bully', id = id_bhvSmallBully, }, [id_bhvBigBully] = { name = 'Big Bully', reason = 'was pushed off by Big Bully', side_reason = 'while standing near a Big Bully', id = id_bhvBigBully, }, [id_bhvSmallChillBully] = { name = 'Chill Bully', reason = 'was pushed off by Chill Bully', side_reason = 'while standing near a Chill Bully', id = id_bhvSmallChillBully, }, [id_bhvBigChillBully] = { name = 'Big Chill Bully', reason = 'was pushed off by Big Chill Bully', side_reason = 'while standing near a Big Chill Bully', id = id_bhvBigChillBully, }, [id_bhvPiranhaPlant] = { name = 'Piranha Plant', reason = 'was bitten by Piranha Plant', side_reason = 'while trying to pass a Piranha Plant', id = id_bhvPiranhaPlant, }, [id_bhvBulletBill] = { name = 'Bullet Bill', reason = 'was hit by Bullet Bill', side_reason = 'while trying to dodge Bullet Bill', id = id_bhvBulletBill, }, [id_bhvChuckya] = { name = 'Chuckya', reason = 'was thrown by Chuckya', side_reason = 'after being grabbed by Chuckya', id = id_bhvChuckya, }, [id_bhvKingBobomb] = { name = 'King Bob-omb', reason = 'was crushed by King Bob-omb', side_reason = 'while fighting King Bob-omb', id = id_bhvKingBobomb, checkFunc = --- comment --- @param o Object function(o) return o.oInteractStatus == 34816 end }, [id_bhvBowser] = { name = 'Bowser', reason = 'was killed by Bowser', side_reason = 'while facing Bowser', id = id_bhvBowser, }, [id_bhvBowserShockWave] = { name = 'Bowser shockwave', reason = 'was shocked by Bowser\'s jump', side_reason = 'while being contused by Bowser\'s shockwave', id = id_bhvBowserShockWave, }, [id_bhvFlame] = { name = 'Flame', reason = 'was burned by a flame', side_reason = 'while stepping into flames', id = id_bhvFlame, }, [id_bhvFlameBouncing] = { name = 'Bouncing Flame', reason = 'was burned by a flame', side_reason = 'while avoiding flames', id = id_bhvFlameBouncing, }, [id_bhvFlameBowser] = { name = 'Bowser\'s Flame', reason = 'was burned alive', side_reason = 'while avoiding flame', id = id_bhvFlameBowser, }, [id_bhvFlamethrowerFlame] = { name = 'Flamethrower Flame', reason = 'was burned alive', side_reason = 'while avoiding flame', id = id_bhvFlamethrowerFlame, }, [id_bhvFlyguyFlame] = { name = 'Fly Guy\'s Flame', reason = 'was burned alive', side_reason = 'while avoiding flame', id = id_bhvFlyguyFlame, }, [id_bhvVolcanoFlames] = { name = 'Volcano Flames', reason = 'was burned alive', side_reason = 'while avoiding flame', id = id_bhvVolcanoFlames, }, [id_bhvSmallPiranhaFlame] = { name = 'Small Piranha Flame', reason = 'was burned alive', side_reason = 'while avoiding flame', id = id_bhvSmallPiranhaFlame, }, [id_bhvMrI] = { name = 'Mr. I', reason = 'was shoot by Mr. I', side_reason = 'while spinning around with Mr. I', id = id_bhvMrI, }, [id_bhvCirclingAmp] = { name = 'Circling Amp', reason = 'was electrocuted by Amp', side_reason = 'while trying to avoid the Amp', id = id_bhvCirclingAmp, }, [id_bhvHomingAmp] = { name = 'Homing Amp', reason = 'was electrocuted by Amp', side_reason = 'while trying to avoid the Amp', id = id_bhvHomingAmp, }, [id_bhvThwomp] = { name = 'Thwomp', reason = 'was smashed by a Thwomp', side_reason = 'while being contused by Thwomp', id = id_bhvHomingAmp, }, [id_bhvBigBoulder] = { name = 'Big Boulder', reason = 'was crushed by a Big Boulder', side_reason = 'while dodging the boulder', id = id_bhvBigBoulder, }, [id_bhvBigBullyWithMinions] = { name = 'Big Bully', reason = 'was pushed into lava by Big Bully', side_reason = 'while fighting Big Bully', id = id_bhvBigBullyWithMinions, }, [id_bhvBlueBowserFlame] = { name = "Bowser's Flame", reason = 'was burned alive', side_reason = 'while avoiding flame', id = id_bhvBlueBowserFlame, }, [id_bhvBouncingFireball] = { name = 'Bouncing Fireball', reason = 'was burned by a bouncing fireball', side_reason = 'while dodging fireballs', id = id_bhvBouncingFireball, }, [id_bhvBouncingFireballFlame] = { name = 'Bouncing Flame', reason = 'was burned by a bouncing flame', side_reason = 'while avoiding the flames', id = id_bhvBouncingFireballFlame, }, [id_bhvBowlingBall] = { name = 'Bowling Ball', reason = 'was crushed by a Bowling Ball', side_reason = 'while trying to avoid the ball', id = id_bhvBowlingBall, }, [id_bhvBubba] = { name = 'Bubba', reason = 'was eaten by Bubba', side_reason = 'while swimming near Bubba', id = id_bhvBubba, }, [id_bhvBub] = { name = 'Bub', reason = 'was hit by Bub', side_reason = 'while swimming with Bubs', id = id_bhvBub, }, [id_bhvGrindel] = { name = 'Grindel', reason = 'was crushed by Grindel', side_reason = 'while dodging Grindel', id = id_bhvGrindel, }, [id_bhvHeaveHo] = { name = 'Heave-Ho', reason = 'was flung by Heave-Ho', side_reason = 'after launch by Heave-Ho', id = id_bhvHeaveHo, }, [id_bhvHeaveHoThrowMario] = { name = 'Heave-Ho', reason = 'was thrown by Heave-Ho', side_reason = 'after launch by Heave-Ho', id = id_bhvHeaveHoThrowMario, }, [id_bhvHorizontalGrindel] = { name = 'Grindel', reason = 'was crushed by a Grindel', side_reason = 'while dodging the Grindel', id = id_bhvHorizontalGrindel, }, [id_bhvKlepto] = { name = 'Klepto', reason = 'was attacked by Klepto', side_reason = 'while trying to get the Star', id = id_bhvKlepto, }, [id_bhvMadPiano] = { name = 'Mad Piano', reason = 'was crushed by Mad Piano', side_reason = 'while approaching the piano', id = id_bhvMadPiano, }, [id_bhvMoneybagHidden] = { name = 'Moneybag', reason = 'was fooled by Moneybag', side_reason = 'while chasing the Moneybag', id = id_bhvMoneybagHidden, }, [id_bhvMontyMoleRock] = { name = 'Monty Mole', reason = 'was hit by a Monty Mole rock', side_reason = 'while dodging Monty Mole rocks', id = id_bhvMontyMoleRock, }, [id_bhvMrBlizzard] = { name = 'Mr. Blizzard', reason = 'was hit by Mr. Blizzard\'s snowball', side_reason = 'while dodging snowballs', id = id_bhvMrBlizzard, }, [id_bhvMrBlizzardSnowball] = { name = 'Mr. Blizzard', reason = 'was hit by a snowball', side_reason = 'while trying to avoid snowballs', id = id_bhvMrBlizzardSnowball, }, [id_bhvScuttlebug] = { name = 'Scuttlebug', reason = 'was attacked by Scuttlebug', side_reason = 'while fighting Scuttlebug', id = id_bhvScuttlebug, }, [id_bhvSmallBomp] = { name = 'Small Bomp', reason = 'was pushed by Small Bomp', side_reason = 'while standing near a Bomp', id = id_bhvSmallBomp, }, [id_bhvSmallWhomp] = { name = 'Small Whomp', reason = 'was crushed by Small Whomp', side_reason = 'while dodging the Whomp', id = id_bhvSmallWhomp, }, [id_bhvSnowBall] = { name = 'Snowball', reason = 'was crushed by a Snowball', side_reason = 'while trying to avoid the snowball', id = id_bhvSnowBall, }, [id_bhvSushiShark] = { name = 'Sushi', reason = 'was eaten by Sushi', side_reason = 'while swimming near Sushi', id = id_bhvSushiShark, }, [id_bhvThwomp2] = { name = 'Thwomp', reason = 'was crushed by Thwomp', side_reason = 'while standing under Thwomp', id = id_bhvThwomp2, }, [id_bhvUnagi] = { name = 'Unagi', reason = 'was eaten by Unagi', side_reason = 'while swimming near Unagi', id = id_bhvUnagi, }, [id_bhvWaterBomb] = { name = 'Water Bomb', reason = 'was hit by a Water Bomb', side_reason = 'while trying to dodge Water Bombs', id = id_bhvWaterBomb, }, [id_bhvWaterBombCannon] = { name = 'Water Bomb Cannon', reason = 'was hit by a Water Bomb', side_reason = 'while trying to avoid the cannon', id = id_bhvWaterBombCannon, }, [id_bhvWhirlpool] = { name = 'Whirlpool', reason = 'was drowned in a Whirlpool', side_reason = 'while swimming near the Whirlpool', id = id_bhvWhirlpool, }, } local KCCustomDeathReasons = { [0] = { reason = 'died from the fall', side_reason = 'while being concussed by a fall' }, [1] = { reason = 'fell into the void', side_reason = 'while falling into the void' }, [2] = { reason = 'drowned into water', side_reason = 'suffocating underwater' }, [3] = { reason = 'handled by higher powers.', side_reason = 'for entertaining higher powers.' } } local KCHazardReasons = { [HAZARD_TYPE_LAVA_FLOOR] = { reason = 'burned in lava', side_reason = 'while burned in lava' }, [HAZARD_TYPE_LAVA_WALL] = { reason = 'burned in lava', side_reason = 'while burning in lava' }, [HAZARD_TYPE_QUICKSAND] = { reason = 'sucked into quicksand', side_reason = 'while sucking into quicksand' } } local resetPrevReasonTimer = 0 local stupidTimer = 0 ---@param objectId number ---@return table { reason: string, side_reason: string, id: number } local function getKCObjectMetaById(objectId) local meta = KCObjectsMetas[objectId] if meta then return meta end return { reason = '', side_reason = '', id = -1 } end ---@param customId number ---@return table { reason: string, side_reason: string } local function getKCCustomDeathMeta(customId) local meta = KCCustomDeathReasons[customId] if meta then return meta end return { reason = '', side_reason = '' } end ---@param hazardType number ---@return table { reason: string, side_reason: string } local function getKCHazardMeta(hazardType) local meta = KCHazardReasons[hazardType] if meta then return meta end return { reason = '', side_reason = '' } end ---@param o Object ---@return table { name: string, reason: string, side_reason: string, id: number } local function getKCObjectMeta(o) local meta = KCObjectsMetas[get_id_from_behavior(o.behavior)] if meta then return meta end return { name = '', reason = '', side_reason = '', id = -1 } end ---@param newType string 'object' | 'player' | 'hazard' | 'custom' ---@param newId number local function updateAttackerInfo(newType, newId) local currentType = gPlayerSyncTable[0].epitaph__player_attacker_t or 'nil' local currentId = gPlayerSyncTable[0].epitaph__player_attacker or -1 if newType == currentType and newId == currentId then return end gPlayerSyncTable[0].epitaph__player_prev_attacker_t = currentType gPlayerSyncTable[0].epitaph__player_prev_attacker = currentId gPlayerSyncTable[0].epitaph__player_attacker_t = newType gPlayerSyncTable[0].epitaph__player_attacker = newId resetPrevReasonTimer = 30 * 20 end --- @class Epitaph Epitaph = Epitaph or {} Epitaph.__index = Epitaph --- Gets the death counter for a given player. ---@param playerIndex number ---@return number function Epitaph.getDeathCounter(playerIndex) return gPlayerSyncTable[playerIndex].epitaph__death_counter or 0 end --- Gets the kill counter for a given player. ---@param playerIndex number ---@return number function Epitaph.getKillCounter(playerIndex) return gPlayerSyncTable[playerIndex].epitaph__kill_counter or 0 end --- Gets the last attacker information for a player. ---@param playerIndex number ---@return table { type: string, id: number } function Epitaph.getAttackerInfo(playerIndex) return { type = gPlayerSyncTable[playerIndex].epitaph__player_attacker_t or 'nil', id = gPlayerSyncTable[playerIndex].epitaph__player_attacker or -1 } end --- Gets the previous attacker information for a player. ---@param playerIndex number ---@return table { type: string, id: number } function Epitaph.getPrevAttackerInfo(playerIndex) return { type = gPlayerSyncTable[playerIndex].epitaph__player_prev_attacker_t or 'nil', id = gPlayerSyncTable[playerIndex].epitaph__player_prev_attacker or -1 } end --- Registers a new object meta for death reason detection. ---@param objectId number ---@param meta table { name: string, reason: string, side_reason: string, id?: number } function Epitaph.registerObjectMeta(objectId, meta) if not meta.id then meta.id = objectId end KCObjectsMetas[objectId] = meta end --- Registers a new custom death reason. ---@param customId number ---@param meta table { reason: string, side_reason: string } function Epitaph.registerCustomDeath(customId, meta) KCCustomDeathReasons[customId] = meta end --- Registers a new hazard type meta. ---@param hazardType number ---@param meta table { reason: string, side_reason: string } function Epitaph.registerHazardMeta(hazardType, meta) KCHazardReasons[hazardType] = meta end --- Builds the death message for a MarioState. ---@param m MarioState ---@return string function Epitaph.getDeathMessage(m) local type = gPlayerSyncTable[m.playerIndex].epitaph__player_attacker_t or 'nil' local attacker = gPlayerSyncTable[m.playerIndex].epitaph__player_attacker or -1 local prevType = gPlayerSyncTable[m.playerIndex].epitaph__player_prev_attacker_t or 'nil' local prevAttacker = gPlayerSyncTable[m.playerIndex].epitaph__player_prev_attacker or -1 local playerName = network_get_player_text_color_string(m.playerIndex) .. gNetworkPlayers[m.playerIndex].name .. '\\#ffffff\\' local mainMessage = '' local extraMessage = '' if type == 'object' then if attacker ~= -1 then local meta = getKCObjectMetaById(attacker) mainMessage = playerName .. ' ' .. meta.reason else mainMessage = playerName .. ' died' end elseif type == 'player' then if attacker ~= -1 then local attackerName = network_get_player_text_color_string(attacker) .. network_player_from_global_index(attacker).name .. '\\#ffffff\\' mainMessage = playerName .. ' was killed by ' .. attackerName else mainMessage = playerName .. ' died' end elseif type == 'hazard' then local meta = getKCHazardMeta(attacker) if meta.reason ~= '' then mainMessage = playerName .. ' ' .. meta.reason end elseif type == 'custom' then local meta = getKCCustomDeathMeta(attacker) mainMessage = playerName .. ' ' .. meta.reason else mainMessage = playerName .. ' died' end if prevType ~= 'nil' and prevAttacker ~= -1 then if prevType == 'player' then local prevName = network_get_player_text_color_string(prevAttacker) .. network_player_from_global_index(prevAttacker).name .. '\\#ffffff\\' extraMessage = 'while trying to escape from ' .. prevName elseif prevType == 'object' then local meta = getKCObjectMetaById(prevAttacker) extraMessage = meta.side_reason elseif prevType == 'hazard' then local meta = getKCHazardMeta(prevAttacker) if meta.reason ~= '' then extraMessage = meta.side_reason end elseif prevType == 'custom' then local meta = getKCCustomDeathMeta(prevAttacker) extraMessage = meta.side_reason end end if extraMessage ~= '' then -- djui_chat_message_create(mainMessage .. ',\n' .. extraMessage) return mainMessage .. ', ' .. extraMessage else -- djui_chat_message_create(mainMessage) return mainMessage end end gPlayerSyncTable[0].epitaph__death_counter = gPlayerSyncTable[0].epitaph__death_counter or 0 gPlayerSyncTable[0].epitaph__kill_counter = gPlayerSyncTable[0].epitaph__kill_counter or 0 gPlayerSyncTable[0].epitaph__player_hitted = gPlayerSyncTable[0].epitaph__player_hitted or -1 gPlayerSyncTable[0].epitaph__player_attacker_t = gPlayerSyncTable[0].epitaph__player_attacker_t or 'nil' gPlayerSyncTable[0].epitaph__player_attacker = gPlayerSyncTable[0].epitaph__player_attacker or -1 gPlayerSyncTable[0].epitaph__player_prev_attacker_t = gPlayerSyncTable[0].epitaph__player_prev_attacker_t or 'nil' gPlayerSyncTable[0].epitaph__player_prev_attacker = gPlayerSyncTable[0].epitaph__player_prev_attacker or -1 hook_event(HOOK_ON_INTERACT, --- comment --- @param interactor MarioState --- @param interactee Object --- @param interactType InteractionType --- @param interactValue boolean function(interactor, interactee, interactType, interactValue) if interactor.playerIndex ~= 0 then return end local objectMeta = getKCObjectMeta(interactee) local checkFunc = objectMeta.checkFunc or function(o) return true end if interactValue and (objectMeta.id ~= -1) and checkFunc(interactee) then updateAttackerInfo('object', objectMeta.id) end end ) hook_event(HOOK_ON_PVP_ATTACK, function(attacker, victim, interaction) if victim.playerIndex ~= 0 then return end local attackerGlobal = network_global_index_from_local(attacker.playerIndex) updateAttackerInfo('player', attackerGlobal) end ) hook_event(HOOK_ALLOW_HAZARD_SURFACE, function(m, hazardType) if m.playerIndex ~= 0 then return end updateAttackerInfo('hazard', hazardType) end ) hook_event(HOOK_MARIO_UPDATE, function(m) if m.playerIndex ~= 0 then return end if m.hurtCounter ~= 0 then if m.peakHeight >= 750 and m.vel.y <= -55 then updateAttackerInfo('custom', 0) end end if m.action == ACT_DROWNING then updateAttackerInfo('custom', 2) end if resetPrevReasonTimer > 0 then resetPrevReasonTimer = resetPrevReasonTimer - 1 if resetPrevReasonTimer == 0 then gPlayerSyncTable[0].epitaph__player_prev_attacker_t = 'nil' gPlayerSyncTable[0].epitaph__player_prev_attacker = -1 end end if stupidTimer > 0 then stupidTimer = stupidTimer - 1 end end ) hook_event(HOOK_ON_DEATH, function(m) if stupidTimer > 0 then return end stupidTimer = 30 * 2 djui_popup_create_global(Epitaph.getDeathMessage(m), 2) gPlayerSyncTable[0].epitaph__death_counter = (gPlayerSyncTable[0].epitaph__death_counter or 0) + 1 if gPlayerSyncTable[0].epitaph__player_prev_attacker_t == 'player' then local attackerIdx = network_local_index_from_global(gPlayerSyncTable[0].epitaph__player_attacker) gPlayerSyncTable[attackerIdx].epitaph__kill_counter = (gPlayerSyncTable[attackerIdx].epitaph__kill_counter or 0) + 1 end gPlayerSyncTable[0].epitaph__player_prev_attacker_t = 'nil' gPlayerSyncTable[0].epitaph__player_prev_attacker = -1 gPlayerSyncTable[0].epitaph__player_attacker_t = 'nil' gPlayerSyncTable[0].epitaph__player_attacker = -1 resetPrevReasonTimer = 1 end ) hook_chat_command('kills-deaths', 'displays player K/D statistics.', function(msg) for i = 0, MAX_PLAYERS - 1 do if gNetworkPlayers[i].connected then local kills = Epitaph.getKillCounter(i) local deaths = Epitaph.getDeathCounter(i) djui_chat_message_create(network_get_player_text_color_string(i) .. gNetworkPlayers[i].name .. '\\#ffffff\\' .. ' - Kills: ' .. kills .. ' | Deaths: ' .. deaths) end end return true end ) -- export --- @type Epitaph _G.Epitaph = Epitaph