Skip to content

Commit dce9203

Browse files
committed
common: add helper functions for Player and TeamState
fixes #115
1 parent d03a884 commit dce9203

File tree

5 files changed

+187
-27
lines changed

5 files changed

+187
-27
lines changed

common/common.go

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"math/rand"
66
"time"
77

8-
r3 "github.com/golang/geo/r3"
8+
"github.com/golang/geo/r3"
99
)
1010

1111
// Team is the type for the various TeamXYZ constants.
@@ -110,7 +110,8 @@ func (b Bomb) Position() r3.Vector {
110110

111111
// TeamState contains a team's ID, score, clan name & country flag.
112112
type TeamState struct {
113-
team Team
113+
team Team
114+
membersCallback func(Team) []*Player
114115

115116
// ID stays the same even after switching sides.
116117
ID int
@@ -132,6 +133,55 @@ func (ts TeamState) Team() Team {
132133
return ts.team
133134
}
134135

135-
func NewTeamState(team Team) TeamState {
136-
return TeamState{team: team}
136+
// Members returns the members of the team.
137+
func (ts TeamState) Members() []*Player {
138+
return ts.membersCallback(ts.team)
139+
}
140+
141+
// CurrentEquipmentValue returns the cumulative value of all equipment currently owned by the members of the team.
142+
func (ts TeamState) CurrentEquipmentValue() (value int) {
143+
for _, pl := range ts.Members() {
144+
value += pl.CurrentEquipmentValue
145+
}
146+
return
147+
}
148+
149+
// RoundStartEquipmentValue returns the cumulative value of all equipment owned by the members of the team at the start of the current round.
150+
func (ts TeamState) RoundStartEquipmentValue() (value int) {
151+
for _, pl := range ts.Members() {
152+
value += pl.RoundStartEquipmentValue
153+
}
154+
return
155+
}
156+
157+
// FreezeTimeEndEquipmentValue returns the cumulative value of all equipment owned by the members of the team at the end of the freeze-time of the current round.
158+
func (ts TeamState) FreezeTimeEndEquipmentValue() (value int) {
159+
for _, pl := range ts.Members() {
160+
value += pl.FreezetimeEndEquipmentValue
161+
}
162+
return
163+
}
164+
165+
// CashSpentThisRound returns the total amount of cash spent by the whole team in the current round.
166+
func (ts TeamState) CashSpentThisRound() (value int) {
167+
for _, pl := range ts.Members() {
168+
value += pl.CashSpentThisRound()
169+
}
170+
return
171+
}
172+
173+
// CashSpentThisRound returns the total amount of cash spent by the whole team during the whole game up to the current point.
174+
func (ts TeamState) CashSpentTotal() (value int) {
175+
for _, pl := range ts.Members() {
176+
value += pl.CashSpentTotal()
177+
}
178+
return
179+
}
180+
181+
// NewTeamState creates a new TeamState with the given Team and members callback function.
182+
func NewTeamState(team Team, membersCallback func(Team) []*Player) TeamState {
183+
return TeamState{
184+
team: team,
185+
membersCallback: membersCallback,
186+
}
137187
}

common/common_test.go

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66

77
"github.com/golang/geo/r3"
88
"github.com/stretchr/testify/assert"
9+
10+
"github.com/markus-wa/demoinfocs-golang/sendtables"
911
)
1012

1113
func TestBombPosition(t *testing.T) {
@@ -43,7 +45,55 @@ func TestDemoHeader_FrameTime_PlaybackFrames_Zero(t *testing.T) {
4345
assert.Zero(t, DemoHeader{}.FrameTime())
4446
}
4547

46-
func TestTeamState(t *testing.T) {
47-
assert.Equal(t, TeamTerrorists, NewTeamState(TeamTerrorists).Team())
48-
assert.Equal(t, TeamCounterTerrorists, NewTeamState(TeamCounterTerrorists).Team())
48+
func TestTeamState_Team(t *testing.T) {
49+
assert.Equal(t, TeamTerrorists, NewTeamState(TeamTerrorists, nil).Team())
50+
assert.Equal(t, TeamCounterTerrorists, NewTeamState(TeamCounterTerrorists, nil).Team())
51+
}
52+
53+
func TestTeamState_Members(t *testing.T) {
54+
members := []*Player{new(Player), new(Player)}
55+
state := NewTeamState(TeamTerrorists, func(Team) []*Player { return members })
56+
57+
assert.Equal(t, members, state.Members())
58+
}
59+
60+
func TestTeamState_CurrentEquipmentValue(t *testing.T) {
61+
members := []*Player{{CurrentEquipmentValue: 100}, {CurrentEquipmentValue: 200}}
62+
state := NewTeamState(TeamTerrorists, func(Team) []*Player { return members })
63+
64+
assert.Equal(t, 300, state.CurrentEquipmentValue())
65+
}
66+
67+
func TestTeamState_RoundStartEquipmentValue(t *testing.T) {
68+
members := []*Player{{RoundStartEquipmentValue: 100}, {RoundStartEquipmentValue: 200}}
69+
state := NewTeamState(TeamTerrorists, func(Team) []*Player { return members })
70+
71+
assert.Equal(t, 300, state.RoundStartEquipmentValue())
72+
}
73+
74+
func TestTeamState_FreezeTimeEndEquipmentValue(t *testing.T) {
75+
members := []*Player{{FreezetimeEndEquipmentValue: 100}, {FreezetimeEndEquipmentValue: 200}}
76+
state := NewTeamState(TeamTerrorists, func(Team) []*Player { return members })
77+
78+
assert.Equal(t, 300, state.FreezeTimeEndEquipmentValue())
79+
}
80+
81+
func TestTeamState_CashSpentThisRound(t *testing.T) {
82+
members := []*Player{
83+
playerWithProperty("m_iCashSpentThisRound", sendtables.PropertyValue{IntVal: 100}),
84+
playerWithProperty("m_iCashSpentThisRound", sendtables.PropertyValue{IntVal: 200}),
85+
}
86+
state := NewTeamState(TeamTerrorists, func(Team) []*Player { return members })
87+
88+
assert.Equal(t, 300, state.CashSpentThisRound())
89+
}
90+
91+
func TestTeamState_CashSpentTotal(t *testing.T) {
92+
members := []*Player{
93+
playerWithProperty("m_iTotalCashSpent", sendtables.PropertyValue{IntVal: 100}),
94+
playerWithProperty("m_iTotalCashSpent", sendtables.PropertyValue{IntVal: 200}),
95+
}
96+
state := NewTeamState(TeamTerrorists, func(Team) []*Player { return members })
97+
98+
assert.Equal(t, 300, state.CashSpentTotal())
4999
}

common/player.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,36 @@ func (p *Player) HasSpotted(other *Player) bool {
138138
return other.IsSpottedBy(p)
139139
}
140140

141+
// IsInBombZone returns whether the player is currently in the bomb zone or not.
142+
func (p *Player) IsInBombZone() bool {
143+
return p.Entity.FindPropertyI("m_bInBombZone").Value().IntVal == 1
144+
}
145+
146+
// IsInBuyZone returns whether the player is currently in the buy zone or not.
147+
func (p *Player) IsInBuyZone() bool {
148+
return p.Entity.FindPropertyI("m_bInBuyZone").Value().IntVal == 1
149+
}
150+
151+
// IsWalking returns whether the player is currently walking (sneaking) in or not.
152+
func (p *Player) IsWalking() bool {
153+
return p.Entity.FindPropertyI("m_bIsWalking").Value().IntVal == 1
154+
}
155+
156+
// IsScoped returns whether the player is currently scoped in or not.
157+
func (p *Player) IsScoped() bool {
158+
return p.Entity.FindPropertyI("m_bIsScoped").Value().IntVal == 1
159+
}
160+
161+
// CashSpentThisRound returns the amount of cash the player spent in the current round.
162+
func (p *Player) CashSpentThisRound() int {
163+
return p.Entity.FindPropertyI("m_iCashSpentThisRound").Value().IntVal
164+
}
165+
166+
// CashSpentTotal returns the amount of cash the player spent during the whole game up to the current point.
167+
func (p *Player) CashSpentTotal() int {
168+
return p.Entity.FindPropertyI("m_iTotalCashSpent").Value().IntVal
169+
}
170+
141171
// AdditionalPlayerInformation contains mostly scoreboard information.
142172
type AdditionalPlayerInformation struct {
143173
Kills int

common/player_test.go

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,8 @@ func TestPlayer_FlashDurationTimeRemaining_Fallback(t *testing.T) {
125125
}
126126

127127
func TestPlayer_IsSpottedBy_HasSpotted_True(t *testing.T) {
128-
pl := newPlayer(0)
129-
entity := new(fake.Entity)
130-
pl.Entity = entity
128+
pl := playerWithProperty("m_bSpottedByMask.000", sendtables.PropertyValue{IntVal: 2})
131129
pl.EntityID = 1
132-
prop := new(fake.Property)
133-
prop.On("Value").Return(sendtables.PropertyValue{IntVal: 2})
134-
entity.On("FindPropertyI", "m_bSpottedByMask.000").Return(prop)
135130

136131
other := newPlayer(0)
137132
other.EntityID = 2
@@ -141,13 +136,8 @@ func TestPlayer_IsSpottedBy_HasSpotted_True(t *testing.T) {
141136
}
142137

143138
func TestPlayer_IsSpottedBy_HasSpotted_False(t *testing.T) {
144-
pl := newPlayer(0)
145-
entity := new(fake.Entity)
146-
pl.Entity = entity
139+
pl := playerWithProperty("m_bSpottedByMask.000", sendtables.PropertyValue{IntVal: 0})
147140
pl.EntityID = 1
148-
prop := new(fake.Property)
149-
prop.On("Value").Return(sendtables.PropertyValue{IntVal: 0})
150-
entity.On("FindPropertyI", "m_bSpottedByMask.000").Return(prop)
151141

152142
other := newPlayer(0)
153143
other.EntityID = 2
@@ -157,12 +147,7 @@ func TestPlayer_IsSpottedBy_HasSpotted_False(t *testing.T) {
157147
}
158148

159149
func TestPlayer_IsSpottedBy_HasSpotted_BitOver32(t *testing.T) {
160-
pl := newPlayer(0)
161-
entity := new(fake.Entity)
162-
prop := new(fake.Property)
163-
prop.On("Value").Return(sendtables.PropertyValue{IntVal: 1})
164-
entity.On("FindPropertyI", "m_bSpottedByMask.001").Return(prop)
165-
pl.Entity = entity
150+
pl := playerWithProperty("m_bSpottedByMask.001", sendtables.PropertyValue{IntVal: 1})
166151
pl.EntityID = 1
167152

168153
other := newPlayer(0)
@@ -182,10 +167,55 @@ func TestPlayer_IsSpottedBy_EntityNull(t *testing.T) {
182167
assert.False(t, other.HasSpotted(pl))
183168
}
184169

170+
func TestPlayer_IsInBombZone(t *testing.T) {
171+
pl := playerWithProperty("m_bInBombZone", sendtables.PropertyValue{IntVal: 1})
172+
173+
assert.True(t, pl.IsInBombZone())
174+
}
175+
176+
func TestPlayer_IsInBuyZone(t *testing.T) {
177+
pl := playerWithProperty("m_bInBuyZone", sendtables.PropertyValue{IntVal: 1})
178+
179+
assert.True(t, pl.IsInBuyZone())
180+
}
181+
182+
func TestPlayer_IsWalking(t *testing.T) {
183+
pl := playerWithProperty("m_bIsWalking", sendtables.PropertyValue{IntVal: 1})
184+
185+
assert.True(t, pl.IsWalking())
186+
}
187+
188+
func TestPlayer_IsScoped(t *testing.T) {
189+
pl := playerWithProperty("m_bIsScoped", sendtables.PropertyValue{IntVal: 1})
190+
191+
assert.True(t, pl.IsScoped())
192+
}
193+
194+
func TestPlayer_CashSpentThisRound(t *testing.T) {
195+
pl := playerWithProperty("m_iCashSpentThisRound", sendtables.PropertyValue{IntVal: 500})
196+
197+
assert.Equal(t, 500, pl.CashSpentThisRound())
198+
}
199+
200+
func TestPlayer_CashSpentTotal(t *testing.T) {
201+
pl := playerWithProperty("m_iTotalCashSpent", sendtables.PropertyValue{IntVal: 500})
202+
203+
assert.Equal(t, 500, pl.CashSpentTotal())
204+
}
205+
185206
func newPlayer(tick int) *Player {
186207
return NewPlayer(128, tickProvider(tick))
187208
}
188209

189210
func tickProvider(tick int) ingameTickProvider {
190211
return func() int { return tick }
191212
}
213+
214+
func playerWithProperty(propName string, value sendtables.PropertyValue) *Player {
215+
entity := new(fake.Entity)
216+
prop := new(fake.Property)
217+
prop.On("Value").Return(value)
218+
entity.On("FindPropertyI", propName).Return(prop)
219+
pl := &Player{Entity: entity}
220+
return pl
221+
}

game_state.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ func newGameState() *GameState {
123123
grenadeProjectiles: make(map[int]*common.GrenadeProjectile),
124124
infernos: make(map[int]*common.Inferno),
125125
entities: make(map[int]*st.Entity),
126-
tState: common.NewTeamState(common.TeamTerrorists),
127-
ctState: common.NewTeamState(common.TeamCounterTerrorists),
128126
}
129127

128+
gs.tState = common.NewTeamState(common.TeamTerrorists, gs.Participants().TeamMembers)
129+
gs.ctState = common.NewTeamState(common.TeamCounterTerrorists, gs.Participants().TeamMembers)
130130
gs.tState.Opponent = &gs.ctState
131131
gs.ctState.Opponent = &gs.tState
132132

0 commit comments

Comments
 (0)