diff --git a/backend/bang/cards.py b/backend/bang/cards.py index ce84677..f7a9a08 100644 --- a/backend/bang/cards.py +++ b/backend/bang/cards.py @@ -188,6 +188,9 @@ class Birra(Card): if len(player.game.players) != 2: super().play_card(player, against=against) player.lives = min(player.lives+1, player.max_lives) + import bang.expansions.dodge_city.characters as chd + if isinstance(player.character, chd.TequilaJoe): + player.lives = min(player.lives+1, player.max_lives) return True elif len(player.game.players) == 2: player.sio.emit('chat_message', room=player.game.name, diff --git a/backend/bang/characters.py b/backend/bang/characters.py index 23d4728..97b6c3b 100644 --- a/backend/bang/characters.py +++ b/backend/bang/characters.py @@ -1,4 +1,5 @@ -from abc import ABC, abstractmethod +from abc import ABC, abstractmethod +from typing import List class Character(ABC): def __init__(self, name: str, max_lives: int, sight_mod: int = 0, visibility_mod: int = 0, pick_mod: int = 0, desc: str = ''): @@ -33,7 +34,6 @@ class BartCassidy(Character): super().__init__("Bart Cassidy", max_lives=4) self.desc = "Ogni volta che viene ferito, pesca una carta" self.icon = '💔' - #una sola carta per ogni gruppo di danni. es: dinamite -> 1 carta def on_hurt(self, dmg): pass @@ -133,8 +133,9 @@ class WillyTheKid(Character): self.desc = "Questo personaggio può giocare quanti bang vuole nel suo turno" self.icon = '🎉' -def all_characters(): - return [ +def all_characters(expansions: List[str]): + from bang.expansions import DodgeCity + base_chars = [ BartCassidy(), BlackJack(), CalamityJanet(), @@ -151,4 +152,7 @@ def all_characters(): SuzyLafayette(), VultureSam(), WillyTheKid(), - ] \ No newline at end of file + ] + if 'dodge_city' in expansions: + base_chars.extend(DodgeCity.get_characters()) + return base_chars \ No newline at end of file diff --git a/backend/bang/deck.py b/backend/bang/deck.py index e8aaf33..f3924f6 100644 --- a/backend/bang/deck.py +++ b/backend/bang/deck.py @@ -10,6 +10,10 @@ class Deck: for c in self.cards: if isinstance(c, cs.Mancato) and c.name not in self.mancato_cards: self.mancato_cards.append(c.name) + self.all_cards_str: List[str] = [] + for c in self.cards: + if c.name not in self.all_cards_str: + self.all_cards_str.append(c.name) self.game = game random.shuffle(self.cards) self.scrap_pile: List[cs.Card] = [] diff --git a/backend/bang/expansions/__init__.py b/backend/bang/expansions/__init__.py index aebf978..4409025 100644 --- a/backend/bang/expansions/__init__.py +++ b/backend/bang/expansions/__init__.py @@ -1,5 +1,7 @@ -from bang.expansions.dodge_city import cards +from bang.expansions.dodge_city import cards, characters class DodgeCity(): + def get_characters(): + return characters.all_characters() def get_cards(): return cards.get_starting_deck() \ No newline at end of file diff --git a/backend/bang/expansions/dodge_city/cards.py b/backend/bang/expansions/dodge_city/cards.py index a821ce5..2d75e39 100644 --- a/backend/bang/expansions/dodge_city/cards.py +++ b/backend/bang/expansions/dodge_city/cards.py @@ -211,17 +211,19 @@ class Derringer(Pugnale): player.equipment.append(self) return True -class Borraccia(Birra): +class Borraccia(Card): def __init__(self, suit, number): - super().__init__(suit, number) - self.name = 'Borraccia' + super().__init__(suit, 'Borraccia', number) self.icon = '🍼' self.usable_next_turn = True self.can_be_used_now = False def play_card(self, player, against, _with=None): if self.can_be_used_now: - return super().play_card(player, against) + super().play_card(player, against) + player.lives = min(player.lives+1, player.max_lives) + player.notify_self() + return True else: player.equipment.append(self) return True diff --git a/backend/bang/expansions/dodge_city/characters.py b/backend/bang/expansions/dodge_city/characters.py new file mode 100644 index 0000000..f45a2a7 --- /dev/null +++ b/backend/bang/expansions/dodge_city/characters.py @@ -0,0 +1,48 @@ +from typing import List +from bang.characters import * + +class PixiePete(Character): + def __init__(self): + super().__init__("Pixie Pete", max_lives=3) + self.desc = "Pesca 3 carte invece che 2" + self.icon = '☘️' + +class TequilaJoe(Character): + def __init__(self): + super().__init__("Tequila Joe", max_lives=4) + self.desc = "Le birre gli fanno recuperare 2 vite" + self.icon = '🍻' + +class GregDigger(Character): + def __init__(self): + super().__init__("Greg Digger", max_lives=4) + self.desc = "Quando un giocatore muore, recupera 2 vite" + self.icon = '🦴' + +class HerbHunter(Character): + def __init__(self): + super().__init__("HerbHunter", max_lives=4) + self.desc = "Quando un giocatore muore, ottiene 2 carte" + self.icon = '⚰️' + +class ElenaFuente(Character): + def __init__(self): + super().__init__("Elena Fuente", max_lives=3) + self.desc = "Può usare una carta qualsiasi come mancato" + self.icon = '🧘‍♀️' + +class BillNoface(Character): + def __init__(self): + super().__init__("Bill Noface", max_lives=4) + self.desc = "Pesca 1 carta + 1 carta per ogni ferita" + self.icon = '🙈' + +def all_characters() -> List[Character]: + return [ + PixiePete(), + TequilaJoe(), + GregDigger(), + HerbHunter(), + ElenaFuente(), + BillNoface(), + ] \ No newline at end of file diff --git a/backend/bang/game.py b/backend/bang/game.py index b0679bb..5fd896c 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -74,7 +74,7 @@ class Game: self.players[self.turn].play_turn() def choose_characters(self): - char_cards = random.sample(characters.all_characters(), len(self.players)*2) + char_cards = random.sample(characters.all_characters(self.expansions), len(self.players)*2) for i in range(len(self.players)): self.players[i].set_available_character(char_cards[i * 2 : i * 2 + 2]) @@ -209,6 +209,7 @@ class Game: else: return False def player_death(self, player: players.Player): + import bang.expansions.dodge_city.characters as chd print(player.attacker) if player.attacker and isinstance(player.attacker, roles.Sheriff) and isinstance(player.role, roles.Vice): for i in range(len(player.attacker.hand)): @@ -223,6 +224,7 @@ class Game: print(f'player {player.name} died') if (self.waiting_for > 0): self.responders_did_respond_resume_turn() + vulture = [p for p in self.players if isinstance(p.character, characters.VultureSam)] if len(vulture) == 0: for i in range(len(player.hand)): @@ -234,6 +236,15 @@ class Game: vulture[0].hand.append(player.hand.pop()) for i in range(len(player.equipment)): vulture[0].hand.append(player.equipment.pop()) + vulture[0].notify_self() + greg = [p for p in self.players if isinstance(p.character, chd.GregDigger)] + if len(greg) > 0: + greg[0].lives = min(greg[0].lives+2, greg[0].max_lives) + herb = [p for p in self.players if isinstance(p.character, chd.HerbHunter)] + if len(herb) > 0: + herb[0].hand.append(self.deck.draw()) + herb[0].hand.append(self.deck.draw()) + index = self.players.index(player) died_in_his_turn = self.started and index == self.turn if self.started and index <= self.turn: diff --git a/backend/bang/players.py b/backend/bang/players.py index 6b316e5..df78d28 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -7,6 +7,7 @@ import bang.roles as r import bang.cards as cs import bang.expansions.dodge_city.cards as csd import bang.characters as chars +import bang.expansions.dodge_city.characters as chd class PendingAction(IntEnum): PICK = 0 @@ -164,6 +165,10 @@ class Player: self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha pescato la prima carta dalla mano di {pile}.') self.hand.append(self.game.deck.draw()) + elif isinstance(self.character, chd.BillNoface): + self.hand.append(self.game.deck.draw()) + for i in range(self.max_lives-self.lives): + self.hand.append(self.game.deck.draw()) else: for i in range(2): card: cs.Card = self.game.deck.draw() @@ -174,6 +179,8 @@ class Player: p.notify_card(self, card) if card.suit == cs.Suit.HEARTS or card.suit == cs.Suit.DIAMONDS: self.hand.append(self.game.deck.draw()) + if isinstance(self.character, chd.PixiePete): + self.hand.append(self.game.deck.draw()) self.notify_self() def pick(self): @@ -327,13 +334,15 @@ class Player: if self.mancato_needed <= 0: self.game.responders_did_respond_resume_turn() return - if len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang))]) == 0\ + if len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang)) or isinstance(self.character, chd.ElenaFuente)]) == 0\ and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 0: self.take_damage_response() self.game.responders_did_respond_resume_turn() else: self.pending_action = PendingAction.RESPOND self.expected_response = self.game.deck.mancato_cards + if isinstance(self.character, chd.ElenaFuente): + self.expected_response = self.game.deck.all_cards_str self.on_failed_response_cb = self.take_damage_response self.notify_self() @@ -344,7 +353,7 @@ class Player: if self.equipment[i].can_be_used_now: print('usable', self.equipment[i]) if len([c for c in self.equipment if isinstance(c, cs.Barile)]) == 0 and not isinstance(self.character, chars.Jourdonnais)\ - and len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang))]) == 0\ + and len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang)) or isinstance(self.character, chd.ElenaFuente)]) == 0\ and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 0: print('Cant defend') self.take_damage_response() @@ -358,6 +367,8 @@ class Player: print('has mancato') self.pending_action = PendingAction.RESPOND self.expected_response = self.game.deck.mancato_cards + if isinstance(self.character, chd.ElenaFuente): + self.expected_response = self.game.deck.all_cards_str self.on_failed_response_cb = self.take_damage_response self.notify_self() return True diff --git a/frontend/src/components/Player.vue b/frontend/src/components/Player.vue index 6a59c50..57532d8 100644 --- a/frontend/src/components/Player.vue +++ b/frontend/src/components/Player.vue @@ -197,7 +197,7 @@ export default { this.hand.filter(x => x.can_be_used_now && this.expected_response.indexOf(x.name) !== -1).forEach(x=>{ cc.push(x) }) - this.equipment.filter(x => x.can_be_used_now && this.expected_response.indexOf(x.name) !== -1).forEach(x=>{ + this.equipment.filter(x => x.usable_next_turn && x.can_be_used_now && this.expected_response.indexOf(x.name) !== -1).forEach(x=>{ cc.push(x) }) return cc