-
Notifications
You must be signed in to change notification settings - Fork 150
/
player.py
205 lines (175 loc) · 5.01 KB
/
player.py
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
import random
from itertools import chain
from .actions import Draw, Give, Steal, Summon
from .card import Card
from .deck import Deck
from .entity import Entity
from .enums import CardType, PlayState, Zone
from .entity import slot_property
from .managers import PlayerManager
from .targeting import *
from .utils import CardList
class Player(Entity):
Manager = PlayerManager
extra_deathrattles = slot_property("extra_deathrattles")
healing_double = slot_property("healing_double", sum)
hero_power_double = slot_property("hero_power_double", sum)
outgoing_healing_adjustment = slot_property("outgoing_healing_adjustment")
spellpower_double = slot_property("spellpower_double", sum)
type = CardType.PLAYER
def __init__(self, name):
self.data = None
super().__init__()
self.name = name
self.deck = Deck()
self.hand = CardList()
self.field = CardList()
self.graveyard = CardList()
self.secrets = CardList()
self.buffs = []
self.slots = []
self.choice = None
self.start_hand_size = 4
self.max_hand_size = 10
self.max_resources = 10
self.cant_draw = False
self.cant_fatigue = False
self.fatigue_counter = 0
self.hero = None
self.last_card_played = None
self.overloaded = 0
self._max_mana = 0
self.playstate = PlayState.INVALID
self.temp_mana = 0
self.timeout = 75
self.times_hero_power_used_this_game = 0
self.minions_killed_this_turn = 0
self.weapon = None
self.zone = Zone.INVALID
def __str__(self):
return self.name
def __repr__(self):
return "%s(name=%r, hero=%r)" % (self.__class__.__name__, self.name, self.hero)
@property
def current_player(self):
return self.game.current_player is self
@property
def controller(self):
return self
@property
def mana(self):
mana = max(0, self.max_mana - self.used_mana - self.overload_locked) + self.temp_mana
return mana
@property
def heropower_damage(self):
return sum(minion.heropower_damage for minion in self.field)
@property
def spellpower(self):
return sum(minion.spellpower for minion in self.field)
@property
def characters(self):
return CardList(chain([self.hero] if self.hero else [], self.field))
@property
def entities(self):
ret = []
for entity in self.field:
ret += entity.entities
ret += self.secrets
return CardList(chain(list(self.hero.entities) if self.hero else [], ret, [self]))
@property
def live_entities(self):
ret = self.field[:]
if self.hero:
ret.append(self.hero)
if self.weapon:
ret.append(self.weapon)
return ret
@property
def actionable_entities(self):
ret = CardList(chain(self.characters, self.hand))
if self.hero.power:
ret.append(self.hero.power)
return ret
@property
def minion_slots(self):
return max(0, self.game.MAX_MINIONS_ON_FIELD - len(self.field))
def card(self, id, source=None, zone=Zone.SETASIDE):
card = Card(id)
card.controller = self
card.zone = zone
if source is not None:
card.creator = source
self.game.manager.new_entity(card)
return card
def get_spell_damage(self, amount: int) -> int:
"""
Returns the amount of damage \a amount will do, taking
SPELLPOWER and SPELLPOWER_DOUBLE into account.
"""
amount += self.spellpower
amount *= (self.controller.spellpower_double + 1)
return amount
def give(self, id):
cards = self.game.queue_actions(self, [Give(self, id)])[0]
return cards[0][0]
def prepare_deck(self, cards, hero):
self.starting_deck = cards
self.starting_hero = hero
def discard_hand(self):
self.log("%r discards their entire hand!", self)
# iterate the list in reverse so we don't skip over cards in the process
# yes it's stupid.
for card in self.hand[::-1]:
card.discard()
def draw(self, count=1):
if self.cant_draw:
self.log("%s tries to draw %i cards, but can't draw", self, count)
return None
ret = self.game.queue_actions(self, [Draw(self) * count])[0]
if count == 1:
if not ret[0]: # fatigue
return None
return ret[0][0]
return ret
def mill(self, count=1):
if count == 1:
if not self.deck:
return
else:
card = self.deck[-1]
self.log("%s mills %r", self, card)
card.discard()
return card
else:
ret = []
while count:
ret.append(self.mill())
count -= 1
return ret
def fatigue(self):
if self.cant_fatigue:
self.log("%s can't fatigue and does not take damage", self)
return
self.fatigue_counter += 1
self.log("%s takes %i fatigue damage", self, self.fatigue_counter)
self.hero.hit(self.hero, self.fatigue_counter)
@property
def max_mana(self):
return self._max_mana
@max_mana.setter
def max_mana(self, amount):
self._max_mana = min(self.max_resources, max(0, amount))
self.log("%s is now at %i mana crystals", self, self._max_mana)
def steal(self, card):
return self.game.queue_actions(self, [Steal(card)])
def shuffle_deck(self):
self.log("%r shuffles their deck", self)
random.shuffle(self.deck)
def summon(self, card):
"""
Puts \a card in the PLAY zone
"""
if isinstance(card, str):
card = self.card(card, zone=Zone.PLAY)
self.game.queue_actions(self, [Summon(self, card)])
return card