Skip to content

Commit 9e73278

Browse files
authored
Bomb Damage Detection (+Fall Damage) (#205)
bakuretsu
1 parent 4df89e0 commit 9e73278

File tree

1 file changed

+45
-6
lines changed

1 file changed

+45
-6
lines changed

pkg/demoinfocs/game_events.go

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ func (p *parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
5151
}
5252

5353
type gameEventHandler struct {
54-
parser *parser
55-
gameEventNameToHandler map[string]gameEventHandlerFunc
54+
parser *parser
55+
gameEventNameToHandler map[string]gameEventHandlerFunc
56+
userIDToFallDamageFrame map[int32]int
57+
frameToRoundEndReason map[int]events.RoundEndReason
5658
}
5759

5860
func (geh gameEventHandler) dispatch(event interface{}) {
@@ -75,7 +77,11 @@ type gameEventHandlerFunc func(map[string]*msg.CSVCMsg_GameEventKeyT)
7577

7678
//nolint:funlen
7779
func newGameEventHandler(parser *parser) gameEventHandler {
78-
geh := gameEventHandler{parser: parser}
80+
geh := gameEventHandler{
81+
parser: parser,
82+
userIDToFallDamageFrame: make(map[int32]int),
83+
frameToRoundEndReason: make(map[int]events.RoundEndReason),
84+
}
7985

8086
// some events need to be delayed until their data is available
8187
// some events can't be delayed because the required state is lost by the end of the tick
@@ -147,7 +153,7 @@ func newGameEventHandler(parser *parser) gameEventHandler {
147153
"player_connect_full": nil, // Connecting finished
148154
"player_death": delayIfNoPlayers(geh.playerDeath), // Player died
149155
"player_disconnect": geh.playerDisconnect, // Player disconnected (kicked, quit, timed out etc.)
150-
"player_falldamage": nil, // Falldamage
156+
"player_falldamage": geh.playerFallDamage, // Falldamage
151157
"player_footstep": delayIfNoPlayers(geh.playerFootstep), // Footstep sound.- Delayed because otherwise Player might be nil
152158
"player_hurt": geh.playerHurt, // Player got hurt
153159
"player_jump": geh.playerJump, // Player jumped
@@ -216,9 +222,12 @@ func (geh gameEventHandler) roundEnd(data map[string]*msg.CSVCMsg_GameEventKeyT)
216222
loserState = winnerState.Opponent
217223
}
218224

225+
reason := events.RoundEndReason(data["reason"].GetValByte())
226+
geh.frameToRoundEndReason[geh.parser.currentFrame] = reason
227+
219228
geh.dispatch(events.RoundEnd{
220229
Message: data["message"].GetValString(),
221-
Reason: events.RoundEndReason(data["reason"].GetValByte()),
230+
Reason: reason,
222231
Winner: winner,
223232
WinnerState: winnerState,
224233
LoserState: loserState,
@@ -313,6 +322,8 @@ func (geh gameEventHandler) weaponReload(data map[string]*msg.CSVCMsg_GameEventK
313322
func (geh gameEventHandler) playerDeath(data map[string]*msg.CSVCMsg_GameEventKeyT) {
314323
killer := geh.playerByUserID32(data["attacker"].GetValShort())
315324
wepType := common.MapEquipment(data["weapon"].GetValString())
325+
victimUserID := data["userid"].GetValShort()
326+
wepType = geh.attackerWeaponType(wepType, victimUserID)
316327

317328
geh.dispatch(events.Kill{
318329
Victim: geh.playerByUserID32(data["userid"].GetValShort()),
@@ -327,9 +338,11 @@ func (geh gameEventHandler) playerDeath(data map[string]*msg.CSVCMsg_GameEventKe
327338
func (geh gameEventHandler) playerHurt(data map[string]*msg.CSVCMsg_GameEventKeyT) {
328339
attacker := geh.playerByUserID32(data["attacker"].GetValShort())
329340
wepType := common.MapEquipment(data["weapon"].GetValString())
341+
userID := data["userid"].GetValShort()
342+
wepType = geh.attackerWeaponType(wepType, userID)
330343

331344
geh.dispatch(events.PlayerHurt{
332-
Player: geh.playerByUserID32(data["userid"].GetValShort()),
345+
Player: geh.playerByUserID32(userID),
333346
Attacker: attacker,
334347
Health: int(data["health"].GetValByte()),
335348
Armor: int(data["armor"].GetValByte()),
@@ -340,6 +353,10 @@ func (geh gameEventHandler) playerHurt(data map[string]*msg.CSVCMsg_GameEventKey
340353
})
341354
}
342355

356+
func (geh gameEventHandler) playerFallDamage(data map[string]*msg.CSVCMsg_GameEventKeyT) {
357+
geh.userIDToFallDamageFrame[data["userid"].GetValShort()] = geh.parser.currentFrame
358+
}
359+
343360
func (geh gameEventHandler) playerBlind(data map[string]*msg.CSVCMsg_GameEventKeyT) {
344361
attacker := geh.gameState().lastFlash.player
345362
projectile := geh.gameState().lastFlash.projectileByPlayer[attacker]
@@ -694,6 +711,28 @@ func (geh gameEventHandler) deleteThrownGrenade(p *common.Player, wepType common
694711
unassert.Samef(wepType, common.EqSmoke, "trying to delete non-existing grenade from gameState.thrownGrenades")
695712
}
696713

714+
func (geh gameEventHandler) attackerWeaponType(wepType common.EquipmentType, victimUserID int32) common.EquipmentType {
715+
// if the player took falldamage in this frame we set the weapon type to world damage
716+
if wepType == common.EqUnknown && geh.userIDToFallDamageFrame[victimUserID] == geh.parser.currentFrame {
717+
wepType = common.EqWorld
718+
}
719+
720+
// if the round ended in the current frame with reason 1 or 0 we assume it was bomb damage
721+
// unfortunately RoundEndReasonTargetBombed isn't enough and sometimes we need to check for 0 as well
722+
if wepType == common.EqUnknown {
723+
switch geh.frameToRoundEndReason[geh.parser.currentFrame] {
724+
case 0:
725+
fallthrough
726+
case events.RoundEndReasonTargetBombed:
727+
wepType = common.EqBomb
728+
}
729+
}
730+
731+
unassert.NotSame(wepType, common.EqUnknown)
732+
733+
return wepType
734+
}
735+
697736
func (geh gameEventHandler) getEquipmentInstance(player *common.Player, wepType common.EquipmentType) *common.Equipment {
698737
isGrenade := wepType.Class() == common.EqClassGrenade
699738
if isGrenade {

0 commit comments

Comments
 (0)