/
typeclasses.py
345 lines (296 loc) · 12.4 KB
/
typeclasses.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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
from evennia import DefaultCharacter, DefaultObject
import random
import cardsystem
from cardsystem import helper
from evennia.prototypes import spawner
from evennia.utils import is_iter
from collections import defaultdict
from evennia.utils.utils import list_to_string
class CardUserMixin(object):
def at_object_creation(self):
super(CardUserMixin, self).at_object_creation()
self.db.card_deck = []
self.db.card_hand = []
self.db.card_discard = []
self.db.card_played = []
self.db.card_effects = {}
self.db.stats = {'Strength': {'Max': 10, 'Cur': 10, 'Mod': 0},
'Reflexes': {'Max': 10, 'Cur': 10, 'Mod': 0},
'Health': {'Max': 10, 'Cur': 10, 'Mod': 0},
'Intelligence': {'Max': 10, 'Cur': 10, 'Mod': 0},
}
def shuffle(self, withdiscard=True):
if withdiscard:
self.db.card_deck.extend(self.db.card_discard)
self.db.card_discard = []
random.shuffle(self.db.card_deck)
@property
def deck(self):
return self.db.card_deck
@property
def hand(self):
return self.db.card_hand
@property
def played(self):
return self.db.card_played
@property
def discardpile(self):
return self.db.card_discard
@property
def defense(self):
basedefense = self.db.stats['Strength']['Cur']
defense = int(basedefense)
for card in self.db.card_played:
carddata = helper.get_card_data(card)
if carddata.get("DefenseMult"):
defense = defense * carddata['DefenseMult']
defense = int(defense/10)
return defense
def get_stat(self, stat):
return self.db.stats[stat]['Cur'] + self.db.stats[stat]['Mod'], self.db.stats[stat]['Max']
def fill_deck(self):
""" Remove this """
for i in range(20):
rarity = random.choice(['Common', 'Common', 'Common', 'Uncommon', 'Common', 'Common', 'Common', 'Uncommon', 'Common', 'Common', 'Common', 'Rare'])
cardtitle = random.choice(list(cardsystem.CARDS['Base'][rarity].keys()))
card = f'Base_{rarity}_{cardtitle}'
self.db.card_deck.append(card)
def draw(self, cardcount):
for i in range(0, cardcount):
if len(self.db.card_deck) == 0:
self.msg('Shuffling discard back into deck.')
self.shuffle()
self.db.card_hand.append(self.db.card_deck.pop(0))
def discard(self, index):
self.db.card_discard.append(self.db.card_hand.pop(index))
def play(self, index, fromzone='card_hand'):
from_zone = self.attributes.get(fromzone)
carddata = helper.get_card_data(from_zone[index])
if carddata['Type'] in ['Attack', 'Defend', 'Buff', 'Debuff']:
# Insert card effects here
self.db.card_discard.append(from_zone.pop(index))
else:
for index in range(0, len(self.db.card_played)):
played_carddata = helper.get_card_data(self.db.card_played[index])
if played_carddata['Type'] == carddata['Type']:
self.msg(f"Removing {played_carddata['Name']} from play.")
self.leaveplay(index)
self.msg(f'Playing {carddata["Name"]}')
self.db.card_played.append(from_zone.pop(index))
if carddata.get('Create', None):
for card in carddata['Create']:
self.db.card_deck.append(card)
self.shuffle(withdiscard=False)
self.calculate_stats()
self.check_stats()
def leaveplay(self, index):
carddata = helper.get_card_data(self.db.card_played[index])
if carddata.get('Create', None):
for card in carddata['Create']:
self.remove_card(card)
self.db.card_discard.append(self.db.card_played.pop(index))
self.calculate_stats()
self.check_stats()
def calculate_stats(self):
for key in self.db.stats.keys():
stat = self.db.stats[key]
statdif = stat['Max'] - stat['Cur']
self.db.stats[key]['Max'] = 10
self.db.stats[key]['Cur'] = 10 - statdif
self.db.stats[key]['Mod'] = 0
for card in self.all_cards():
cardinfo = helper.get_card_data(card)
cardmod = cardinfo.get(key, 0)
if cardmod:
self.db.stats[key]['Max'] += cardmod
self.db.stats[key]['Cur'] += cardmod
for effect in self.db.card_effects.values():
if effect['Stat'] == key:
self.db.stats[key]['Mod'] += effect['Amount']
def modify_stat(self, stat, amount):
if stat in self.db.stats.keys():
mystat = self.db.stats[stat]
mystat['Cur'] += amount
mystat['Cur'] = min(mystat['Max'], mystat['Cur'])
self.check_stats()
def check_stats(self):
healthcur, healthmax = self.get_stat('Health')
if healthcur <= 0:
if chandler := self.ndb.combat_handler:
chandler.msg_all(f'COMBAT: {self.key} is knocked out.')
chandler.remove_character(self)
self.die()
def die(self):
self.location.msg_contents(f'GAME: {self.key} dies. If you\'re seeing this, this typeclass has not been set up properly.')
def all_cards(self):
allcards = list(self.db.card_deck) + list(self.db.card_hand) + list(self.db.card_discard) + list(self.db.card_played)
return allcards
def remove_card(self, cardstring):
cardpool, index = helper.find_card(self, cardstring, pools=['card_deck', 'card_hand', 'card_discard', 'card_played'])
if cardpool:
self.attributes.get(cardpool).remove(cardstring)
return True
return False
def return_appearance(self, looker, **kwargs):
"""
This formats a description. It is the hook a 'look' command
should call.
Args:
looker (Object): Object doing the looking.
**kwargs (dict): Arbitrary, optional arguments for users
overriding the call (unused by default).
"""
if not looker:
return ""
# get and identify all objects
visible = (con for con in self.contents if con != looker and con.access(looker, "view"))
exits, users, things = [], [], defaultdict(list)
for con in visible:
key = con.get_display_name(looker)
if con.destination:
exits.append(key)
elif con.has_account:
users.append("|c%s|n" % key)
else:
# things can be pluralized
things[key].append(con)
# get description, build string
string = ""
# string = "|c%s|n\n" % self.get_display_name(looker)
desc = helper.carduser_desc(self, looker)
if desc:
string += "%s" % desc
if exits:
string += "\n|wExits:|n " + list_to_string(exits)
if users or things:
# handle pluralization of things (never pluralize users)
thing_strings = []
for key, itemlist in sorted(things.items()):
nitem = len(itemlist)
if nitem == 1:
key, _ = itemlist[0].get_numbered_name(nitem, looker, key=key)
else:
key = [item.get_numbered_name(nitem, looker, key=key)[1] for item in itemlist][
0
]
thing_strings.append(key)
string += "\n|wYou see:|n " + list_to_string(users + thing_strings)
return string
def addeffect(self, stat, amount, duration=-1, source=None):
if not source:
source = self
id = random.randint(0, 10000)
self.db.card_effects[id] = {'Stat': stat, 'Amount': amount, 'Duration': duration, 'Source': source}
self.calculate_stats()
self.check_stats()
def countdowneffects(self):
for effectkey in self.db.card_effects.keys():
effect = self.db.card_effects[effectkey]
if effect['Duration'] > 0:
effect['Duration'] -= 1
if effect['Duration'] == 0:
del self.db.card_effects[effectkey]
self.calculate_stats()
self.check_stats()
def cleareffects(self):
self.db.card_effects = {}
self.calculate_stats()
self.check_stats()
class CardCharacter(CardUserMixin, DefaultCharacter):
"""
"""
def at_object_creation(self):
super(CardCharacter, self).at_object_creation()
self.db.hand_size = 4
def die(self):
self.location.msg_contents(f'{self.key} is unconscious.')
# TODO: Add cmdset to remove basic commands like move.
class CardObject(DefaultObject):
"""
"""
def at_object_creation(self):
super(CardObject, self).at_object_creation()
self.db.card_combatok = False
self.db.card = None
self.db.component = None
class NPC(CardUserMixin, DefaultCharacter):
"""
"""
def at_object_creation(self):
super(NPC, self).at_object_creation()
self.db.card_combatok = True
self.db.hand_size = 3
self.db.death_message = 'died.'
self.db.card_equipped = []
def basetype_posthook_setup(self):
super(NPC, self).basetype_posthook_setup()
self.execute_cmd('say Test')
for count in range(0, len(self.db.card_equipped)):
self.play(0, fromzone='card_equipped')
self.calculate_stats()
self.shuffle()
def consider_invite(self):
if self.ndb.party_invite:
invite = self.ndb.party_invite
accept = random.choice([True, False])
if accept:
invite.add_character(self)
invite.msg_all(f'PARTY: {self.key} has joined the party.')
else:
invite.uninvite_character(character=self)
invite.db.party_leader.msg(f'{self.key} has declined your party invite.')
def spawn_loot(self, cardstring):
carddata = helper.get_card_data(cardstring)
if loot := carddata.get("Loot"):
loot['location'] = self
spawner.spawn(loot)
def die(self):
for i in range(0, len(self.db.card_hand)):
self.discard(0)
for i in range(0, len(self.db.card_played)):
self.leaveplay(0)
self.shuffle()
self.spawn_loot(self.db.card_deck[0])
self.for_contents(self.drop)
if is_iter(self.db.death_message):
death_message = random.choice(self.db.death_message)
else:
death_message = self.db.death_message
self.location.msg_contents(f'{self.key} {death_message}')
self.delete()
def drop(self, obj, **kwargs):
obj.move_to(self.location, quiet=True)
self.location.msg_contents(f'{self.key} dropped {obj.get_numbered_name(1, self)[0]}.')
def combat_action(self):
drawcount = self.db.hand_size - len(self.db.card_hand)
self.draw(drawcount)
chandler = self.ndb.combat_handler
group = chandler.get_groups(self)
card = self.db.card_hand[0] # Add logic here to choose card.
card_details = helper.get_card_data(card)
if card_details['Type'] in ['Attack', 'Debuff']:
if len(group['Foe']) == 1:
target = group['Foe']
chandler.add_action(card, self, target)
elif card_details.get('Target') == 'Group':
target = group['Foe']
chandlder.add_action(card, self, target)
else:
target = [group['Foe'][0]] # Add logic here to choose target.
chandler.add_action(card, self, target)
elif card_details['Type'] in ['Heal', 'Buff']:
if len(group['Friend']) == 1:
target = group['Friend']
chandler.add_action(card, self, target)
elif card_details.get('Target') == 'Group':
target = group['Friend']
chandler.add_action(card, self, target)
else:
target = [group['Friend'][0]] # Add logic here to choose target.
chandler.msg_all(target)
chandler.add_action(card, self, target)
chandler.msg_all(target)
else:
target = [self]
chandler.add_action(card, self, target)
chandler.check_end_turn()