Skip to content

Commit 3643290

Browse files
authored
Merge pull request #166 from markus-wa/issue/164-identify-bots-controlled-by-players
add Player bot utility functions
2 parents 59fbe07 + 6e8450d commit 3643290

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

common/player.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ type Player struct {
4343
FlashTick int // In-game tick at which the player was last flashed
4444
TeamState *TeamState // When keeping the reference make sure you notice when the player changes teams
4545
Team Team
46-
IsBot bool
46+
IsBot bool // True if this is a bot-entity. See also IsControllingBot and ControlledBot().
4747
IsConnected bool
4848
IsDucking bool
4949
IsDefusing bool
@@ -204,6 +204,28 @@ func (p *Player) CashSpentTotal() int {
204204
return p.AdditionalPlayerInformation.TotalCashSpent
205205
}
206206

207+
// IsControllingBot returns true if the player is currently controlling a bot.
208+
// See also ControlledBot().
209+
func (p *Player) IsControllingBot() bool {
210+
if p.Entity == nil {
211+
return false
212+
}
213+
214+
return p.Entity.FindPropertyI("m_bIsControllingBot").Value().IntVal != 0
215+
}
216+
217+
// ControlledBot returns the player instance of the bot that the player is controlling, if any.
218+
// Returns nil if the player is not controlling a bot.
219+
func (p *Player) ControlledBot() *Player {
220+
if p.Entity == nil {
221+
return nil
222+
}
223+
224+
botHandle := p.Entity.FindPropertyI("m_iControlledBotEntIndex").Value().IntVal
225+
226+
return p.demoInfoProvider.FindPlayerByHandle(botHandle)
227+
}
228+
207229
// AdditionalPlayerInformation contains mostly scoreboard information.
208230
type AdditionalPlayerInformation struct {
209231
Kills int

common/player_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,50 @@ func TestPlayer_IsAirborne(t *testing.T) {
206206
assert.True(t, pl.IsAirborne())
207207
}
208208

209+
func TestPlayer_IsControllingBot_NilEntity(t *testing.T) {
210+
pl := new(Player)
211+
212+
assert.False(t, pl.IsControllingBot())
213+
}
214+
215+
func TestPlayer_IsControllingBot(t *testing.T) {
216+
pl := playerWithProperty("m_bIsControllingBot", st.PropertyValue{IntVal: 0})
217+
218+
assert.False(t, pl.IsControllingBot())
219+
220+
pl = playerWithProperty("m_bIsControllingBot", st.PropertyValue{IntVal: 1})
221+
222+
assert.True(t, pl.IsControllingBot())
223+
}
224+
225+
func TestPlayer_ControlledBot_NilEntity(t *testing.T) {
226+
pl := new(Player)
227+
228+
assert.Nil(t, pl.ControlledBot())
229+
}
230+
231+
func TestPlayer_ControlledBot(t *testing.T) {
232+
dave := &Player{
233+
Name: "Dave",
234+
IsBot: true,
235+
}
236+
demoInfoProvider := &demoInfoProviderMock{
237+
playersByHandle: map[int]*Player{
238+
12: dave,
239+
},
240+
}
241+
242+
pl := playerWithProperty("m_iControlledBotEntIndex", st.PropertyValue{IntVal: 0})
243+
pl.demoInfoProvider = demoInfoProvider
244+
245+
assert.Nil(t, pl.ControlledBot())
246+
247+
pl = playerWithProperty("m_iControlledBotEntIndex", st.PropertyValue{IntVal: 12})
248+
pl.demoInfoProvider = demoInfoProvider
249+
250+
assert.Same(t, dave, pl.ControlledBot())
251+
}
252+
209253
func newPlayer(tick int) *Player {
210254
return NewPlayer(mockDemoInfoProvider(128, tick))
211255
}

game_events.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func newGameEventHandler(parser *Parser) gameEventHandler {
109109
"bomb_exploded": geh.bombExploded, // Bomb exploded
110110
"bomb_pickup": geh.bombPickup, // Bomb picked up
111111
"bomb_planted": geh.bombPlanted, // Plant finished
112-
"bot_takeover": geh.botTakeover, // Bot got taken over
112+
"bot_takeover": delay(geh.botTakeover), // Bot got taken over
113113
"buytime_ended": nil, // Not actually end of buy time, seems to only be sent once per game at the start
114114
"cs_match_end_restart": nil, // Yawn
115115
"cs_pre_restart": nil, // Not sure, doesn't seem to be important
@@ -252,8 +252,14 @@ func (geh gameEventHandler) roundMVP(data map[string]*msg.CSVCMsg_GameEventKeyT)
252252
}
253253

254254
func (geh gameEventHandler) botTakeover(data map[string]*msg.CSVCMsg_GameEventKeyT) {
255+
taker := geh.playerByUserID32(data["userid"].GetValShort())
256+
257+
unassert.True(!taker.IsBot)
258+
unassert.True(taker.IsControllingBot())
259+
unassert.NotNil(taker.ControlledBot())
260+
255261
geh.dispatch(events.BotTakenOver{
256-
Taker: geh.playerByUserID32(data["userid"].GetValShort()),
262+
Taker: taker,
257263
})
258264
}
259265

0 commit comments

Comments
 (0)