forked from AY2425S2-CG4002-Team-8/External-comms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgame_state.py
More file actions
208 lines (171 loc) · 6.6 KB
/
game_state.py
File metadata and controls
208 lines (171 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
from logger import get_logger
logger = get_logger(__name__)
class GameState:
def __init__(self):
self.player_1 = Player()
self.player_2 = Player()
def __str__(self):
return str(self.to_dict())
def to_dict(self) -> dict[str, dict[str, int]]:
data = {'p1': self.player_1.to_dict(), 'p2': self.player_2.to_dict()}
return data
def _init_player (self, player_id, bullets_remaining, bombs_remaining, hp,
num_deaths, num_unused_shield, shield_health):
if player_id == 1:
player = self.player_1
else:
player = self.player_2
player.set_state(bullets_remaining, bombs_remaining, hp, num_deaths,
num_unused_shield, shield_health)
def perform_action(self, action, player_id, fov, snow_number) -> bool:
"""use the user sent action to alter the game state"""
if player_id == 1:
attacker = self.player_1
opponent = self.player_2
else:
attacker = self.player_2
opponent = self.player_1
# Using visualiser fov for gun
attacker.rain_damage(opponent, fov, snow_number)
action_possible = True
# perform the actual action
if action == "miss":
action_possible = attacker.miss()
return False, action_possible
elif action == "gun" or action == "miss":
action_possible = attacker.shoot(opponent, fov)
elif action == "shield":
action_possible = attacker.shield()
elif action == "reload":
action_possible = attacker.reload()
elif action == "bomb":
action_possible = attacker.bomb(opponent, fov)
elif action in {"badminton", "golf", "fencing", "boxing"}:
attacker.harm_AI(opponent, fov)
else:
# logout & invalid action we do nothing
pass
return fov, action_possible
class VisualiserState:
"""
Manages the FOV data of the opponent.
Visualiser periodically updates with opponent FOV data which will be reflected as an encapsulated attribute of this class.
"""
def __init__(self):
self.fov = False
self.snow_number = 0
def set_fov(self, fov: bool):
self.fov = fov
def set_snow_number(self, snow_number: int):
self.snow_number = snow_number
def get_fov(self):
return self.fov
def get_snow_number(self):
return self.snow_number
def handle_fov(self, fov_data: str) -> None:
if not int(fov_data):
self.set_fov(False)
else:
self.set_fov(True)
class Player:
def __init__(self):
# Constants
self.max_bombs = 2
self.max_shields = 3
self.hp_bullet = 5
self.hp_AI = 10
self.hp_bomb = 5
self.hp_rain = 5
self.max_shield_health = 30
self.max_bullets = 6
self.max_hp = 100
# Initial state
self.hp = self.max_hp
self.num_bullets = self.max_bullets
self.num_bombs = self.max_bombs
self.hp_shield = 0
self.num_deaths = 0
self.num_shield = self.max_shields
def __str__(self):
return str(self.to_dict())
def to_dict(self) -> dict[str, int]:
data = dict()
data['hp'] = self.hp
data['bullets'] = self.num_bullets
data['bombs'] = self.num_bombs
data['shield_hp'] = self.hp_shield
data['deaths'] = self.num_deaths
data['shields'] = self.num_shield
return data
def set_state(self, bullets_remaining: int, bombs_remaining: int, hp: int, num_deaths: int, num_unused_shield: int, shield_health: int) -> None:
self.hp = hp
self.num_bullets = bullets_remaining
self.num_bombs = bombs_remaining
self.hp_shield = shield_health
self.num_shield = num_unused_shield
self.num_deaths = num_deaths
def can_shoot(self):
if self.num_bullets <= 0:
return False
return True
#TODO: Attain ammo data from the gun packet + health from health packet
def shoot(self, opponent, fov) -> bool:
if not self.can_shoot():
return False
self.num_bullets -= 1
if fov:
opponent.damage(self.hp_bullet)
return True
def miss(self) -> bool:
if not self.can_shoot():
return False
self.num_bullets -= 1
return True
def damage(self, hp_reduction: int) -> None:
# use the shield to protect the player
if self.hp_shield > 0:
new_hp_shield = max(0, self.hp_shield - hp_reduction)
# If damage is more than the shield, induce the remaining damage
hp_reduction = max(0, hp_reduction - self.hp_shield)
self.hp_shield = new_hp_shield
# reduce the player HP
self.hp = max(0, self.hp - hp_reduction)
if self.hp == 0:
# if we die, we spawn immediately
self.num_deaths += 1
self.set_state(self.max_bullets, self.max_bombs, self.max_hp, self.num_deaths, self.max_shields, 0)
def shield(self) -> bool:
"""Activate shield"""
if self.num_shield <= 0 or self.hp_shield > 0:
return False
self.hp_shield = self.max_shield_health
self.num_shield -= 1
return True
#TODO: Implement bomb, add the start to a rain/snow in the quadrant of the opponent
def bomb(self, opponent, fov: bool) -> bool:
"""Throw a bomb at opponent"""
if self.num_bombs <= 0:
return False
self.num_bombs -= 1
if fov:
opponent.damage(self.hp_bomb)
return True
#TODO: Implement rain_damage
def rain_damage(self, opponent, fov: bool, snow_number: int) -> None:
"""
Whenever an opponent walks into a quadrant we need to reduce the health
based on the number of rains/snow
"""
while fov and snow_number > 0:
opponent.damage(self.hp_rain)
snow_number -= 1
def harm_AI(self, opponent, fov):
""" We can harm am opponent based on our AI action if we can see them"""
if fov:
opponent.damage(self.hp_AI)
def reload(self) -> bool:
""" perform reload only if the magazine is empty"""
if self.num_bullets <= 0:
self.num_bullets = self.max_bullets
return True
return False