bang-mancato

This commit is contained in:
Alberto Xamin 2020-11-21 12:19:20 +01:00
parent d861a1869a
commit 1e98d4a1dd
No known key found for this signature in database
GPG Key ID: 4F026F48309500A2
11 changed files with 204 additions and 49 deletions

View File

@ -81,6 +81,11 @@ def draw(sid):
ses = sio.get_session(sid) ses = sio.get_session(sid)
ses.draw() ses.draw()
@sio.event
def pick(sid):
ses = sio.get_session(sid)
ses.pick()
@sio.event @sio.event
def end_turn(sid): def end_turn(sid):
ses = sio.get_session(sid) ses = sio.get_session(sid)
@ -91,5 +96,10 @@ def play_card(sid, data):
ses = sio.get_session(sid) ses = sio.get_session(sid)
ses.play_card(data['index'], data['against']) ses.play_card(data['index'], data['against'])
@sio.event
def respond(sid, data):
ses = sio.get_session(sid)
ses.respond(data)
if __name__ == '__main__': if __name__ == '__main__':
eventlet.wsgi.server(eventlet.listen(('', 5001)), app) eventlet.wsgi.server(eventlet.listen(('', 5001)), app)

View File

View File

@ -29,6 +29,7 @@ class Card(ABC):
self.sight_mod = sight_mod self.sight_mod = sight_mod
self.range = range self.range = range
self.desc = desc self.desc = desc
self.need_target = False
def __str__(self): def __str__(self):
char = ['♦️','♣️','♥️','♠️'][int(self.suit)] char = ['♦️','♣️','♥️','♠️'][int(self.suit)]
@ -64,6 +65,7 @@ class Prigione(Card):
super().__init__(suit, 'Prigione', number, is_equipment=False) super().__init__(suit, 'Prigione', number, is_equipment=False)
self.icon = '' self.icon = ''
self.desc = "Equipaggia questa carta a un altro giocatore, tranne lo Sceriffo. Il giocatore scelto all'inizio del suo turno, prima di pescare dovrà estrarre: se esce Cuori scarta questa carta e gioca normalmente il turno, altrimenti scarta questa carta e salta il turno" self.desc = "Equipaggia questa carta a un altro giocatore, tranne lo Sceriffo. Il giocatore scelto all'inizio del suo turno, prima di pescare dovrà estrarre: se esce Cuori scarta questa carta e gioca normalmente il turno, altrimenti scarta questa carta e salta il turno"
self.need_target = True
class Remington(Card): class Remington(Card):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -100,6 +102,7 @@ class Bang(Card):
super().__init__(suit, 'Bang!', number) super().__init__(suit, 'Bang!', number)
self.icon = '💥' self.icon = '💥'
self.desc = "Spara a un giocatore a distanta raggiungibile. Se non hai armi la distanza di default è 1" self.desc = "Spara a un giocatore a distanta raggiungibile. Se non hai armi la distanza di default è 1"
self.need_target = True
class Birra(Card): class Birra(Card):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -112,6 +115,7 @@ class CatBalou(Card):
super().__init__(suit, 'Cat Balou', number) super().__init__(suit, 'Cat Balou', number)
self.icon = '💃' self.icon = '💃'
self.desc = "Fai scartare una carta a un qualsiasi giocatore, scegli a caso dalla mano, oppure fra quelle che ha in gioco" self.desc = "Fai scartare una carta a un qualsiasi giocatore, scegli a caso dalla mano, oppure fra quelle che ha in gioco"
self.need_target = True
class Diligenza(Card): class Diligenza(Card):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -148,6 +152,7 @@ class Panico(Card):
def __init__(self, suit, number): def __init__(self, suit, number):
super().__init__(suit, 'Panico!', number, range=1) super().__init__(suit, 'Panico!', number, range=1)
self.icon = '😱' self.icon = '😱'
self.need_target = True
class Saloon(Card): class Saloon(Card):
def __init__(self, suit, number): def __init__(self, suit, number):

View File

@ -23,6 +23,7 @@ class Deck:
def pick_and_scrap(self) -> Card: def pick_and_scrap(self) -> Card:
card = self.cards.pop(0) card = self.cards.pop(0)
self.scrap_pile.append(card) self.scrap_pile.append(card)
self.game.notify_scrap_pile()
return card return card
def draw(self) -> Card: def draw(self) -> Card:

View File

@ -4,6 +4,7 @@ import socketio
import players import players
from characters import all_characters from characters import all_characters
from deck import Deck from deck import Deck
from players import Player
import roles import roles
class Game: class Game:
@ -25,6 +26,7 @@ class Game:
return True return True
self.sio.emit('room', room=self.name, data={'name': self.name, 'started': self.started, 'players': [p.name for p in self.players]}) self.sio.emit('room', room=self.name, data={'name': self.name, 'started': self.started, 'players': [p.name for p in self.players]})
self.sio.emit('chat_message', room=self.name, data=f'{player.name} si è disconnesso.') self.sio.emit('chat_message', room=self.name, data=f'{player.name} si è disconnesso.')
self.players_map = {c.name: i for i, c in enumerate(self.players)}
return False return False
def add_player(self, player: players.Player): def add_player(self, player: players.Player):
@ -50,6 +52,7 @@ class Game:
print('GAME IS STARING') print('GAME IS STARING')
if self.started: if self.started:
return return
self.players_map = {c.name: i for i, c in enumerate(self.players)}
self.sio.emit('chat_message', room=self.name, data=f'La partita sta iniziando...') self.sio.emit('chat_message', room=self.name, data=f'La partita sta iniziando...')
self.sio.emit('start', room=self.name) self.sio.emit('start', room=self.name)
self.started = True self.started = True
@ -74,8 +77,22 @@ class Game:
def get_visible_players(self, player): def get_visible_players(self, player):
i = self.players.index(player) i = self.players.index(player)
sight = player.get_sight() sight = player.get_sight()
return [{'name': self.players[j].name, 'dist': min(abs(i - j) - 1, abs(i - len(self.players) - j)) + self.players[j].get_visibility()} return [{
for j in range(len(self.players)) if i != j and min(abs(i - j) - 1, abs(i - len(self.players) - j)) + self.players[j].get_visibility() <= sight] 'name': self.players[j].name,
'dist': min(abs(i - j), abs(i - len(self.players) - j)) + self.players[j].get_visibility(),
'lives': self.players[j].lives,
'max_lives': self.players[j].max_lives,
} for j in range(len(self.players)) if i != j]
def attack(self, attacker:Player, target_username:str):
self.sio.emit('chat_message', room=self.name, data=f'{attacker.name} ha fatto Bang contro {target_username}.')
if self.players[self.players_map[target_username]].get_banged():
attacker.pending_action = players.PendingAction.WAIT
attacker.notify_self()
def responders_did_respond(self):
self.players[self.turn].pending_action = players.PendingAction.PLAY
self.players[self.turn].notify_self()
def next_player(self): def next_player(self):
return self.players[(self.turn + 1) % len(self.players)] return self.players[(self.turn + 1) % len(self.players)]

View File

@ -1,6 +1,7 @@
from enum import IntEnum from enum import IntEnum
import json import json
import socketio import socketio
from cards import Mancato
import roles import roles
import cards import cards
@ -32,6 +33,9 @@ class Player:
self.pending_action: PendingAction = None self.pending_action: PendingAction = None
self.available_characters = [] self.available_characters = []
self.was_shot = False self.was_shot = False
self.on_pick_cb = None
self.on_response_cb = None
self.expected_response = None
def join_game(self, game): def join_game(self, game):
self.game = game self.game = game
@ -69,6 +73,9 @@ class Player:
ser.pop('game') ser.pop('game')
ser.pop('sio') ser.pop('sio')
ser.pop('sid') ser.pop('sid')
ser.pop('on_pick_cb')
ser.pop('on_response_cb')
ser.pop('expected_response')
self.sio.emit('self', room=self.sid, data=json.dumps(ser, default=lambda o: o.__dict__)) self.sio.emit('self', room=self.sid, data=json.dumps(ser, default=lambda o: o.__dict__))
self.sio.emit('self_vis', room=self.sid, data=json.dumps(self.game.get_visible_players(self), default=lambda o: o.__dict__)) self.sio.emit('self_vis', room=self.sid, data=json.dumps(self.game.get_visible_players(self), default=lambda o: o.__dict__))
@ -84,46 +91,51 @@ class Player:
self.pending_action = PendingAction.DRAW self.pending_action = PendingAction.DRAW
self.notify_self() self.notify_self()
# # print(f'lives: {self.lives}/{self.max_lives} hand: {[str(c) for c in self.hand]}')
# print(f'I {self.name} can see {[p.get_public_description() for p in self.game.get_visible_players(self)]}')
# ser = self.__dict__.copy()
# ser.pop('game')
# print(json.dumps(ser, default=lambda o: o.__dict__, indent=4))
def draw(self): def draw(self):
if self.pending_action != PendingAction.DRAW:
return
for i in range(2): for i in range(2):
self.hand.append(self.game.deck.draw()) self.hand.append(self.game.deck.draw())
self.pending_action = PendingAction.PLAY self.pending_action = PendingAction.PLAY
self.notify_self() self.notify_self()
def pick(self): def pick(self):
if self.pending_action != PendingAction.PICK:
return
pickable_cards = 1 + self.character.pick_mod pickable_cards = 1 + self.character.pick_mod
for i in range(len(self.equipment)): if self.is_my_turn:
if isinstance(self.equipment[i], cards.Dinamite): for i in range(len(self.equipment)):
while pickable_cards > 0: if isinstance(self.equipment[i], cards.Dinamite):
pickable_cards -= 1 while pickable_cards > 0:
picked: cards.Card = self.game.deck.pick_and_scrap() pickable_cards -= 1
print(f'Did pick {picked}') picked: cards.Card = self.game.deck.pick_and_scrap()
if picked.suit == cards.Suit.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0: print(f'Did pick {picked}')
self.lives -= 3 if picked.suit == cards.Suit.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0:
self.game.deck.scrap(self.equipment.pop(i)) self.lives -= 3
print(f'{self.name} Boom, -3 hp') self.game.deck.scrap(self.equipment.pop(i))
else: print(f'{self.name} Boom, -3 hp')
self.game.next_player().equipment.append(self.equipment.pop(i)) else:
if any([isinstance(c, cards.Dinamite) or isinstance(c, cards.Prigione) for c in self.equipment]): self.game.next_player().equipment.append(self.equipment.pop(i))
return self.game.next_player().notify_self()
for i in range(len(self.equipment)): if any([isinstance(c, cards.Dinamite) or isinstance(c, cards.Prigione) for c in self.equipment]):
if isinstance(self.equipment[i], cards.Prigione): self.notify_self()
while pickable_cards > 0: return
pickable_cards -= 1 for i in range(len(self.equipment)):
picked: cards.Card = self.game.deck.pick_and_scrap() if isinstance(self.equipment[i], cards.Prigione):
print(f'Did pick {picked}') while pickable_cards > 0:
if picked.suit != cards.Suit.HEARTS and pickable_cards == 0: pickable_cards -= 1
self.game.deck.scrap(self.equipment.pop(i)) picked: cards.Card = self.game.deck.pick_and_scrap()
self.end_turn(forced=True) print(f'Did pick {picked}')
else: if picked.suit != cards.Suit.HEARTS and pickable_cards == 0:
break self.game.deck.scrap(self.equipment.pop(i))
break self.end_turn(forced=True)
self.pending_action = PendingAction.DRAW else:
break
break
self.pending_action = PendingAction.DRAW
self.notify_self()
else:
self.on_pick_cb()
def get_playable_cards(self): def get_playable_cards(self):
playable_cards = [] playable_cards = []
@ -163,10 +175,64 @@ class Player:
self.equipment.append(card) self.equipment.append(card)
else: else:
if isinstance(card, cards.Bang) and self.has_played_bang and not any([isinstance(c, cards.Volcanic) for c in self.equipment]): if isinstance(card, cards.Bang) and self.has_played_bang and not any([isinstance(c, cards.Volcanic) for c in self.equipment]):
print('you retard') return
if isinstance(card, cards.Bang) and againts != None:
self.game.attack(self, againts)
self.game.deck.scrap(card) self.game.deck.scrap(card)
self.notify_self() self.notify_self()
def barrel_pick(self):
pickable_cards = 1 + self.character.pick_mod
while pickable_cards > 0:
pickable_cards -= 1
picked: cards.Card = self.game.deck.pick_and_scrap()
print(f'Did pick {picked}')
if picked.suit == cards.Suit.HEARTS:
self.pending_action = PendingAction.WAIT
self.notify_self()
self.game.responders_did_respond()
return
if len([c for c in self.hand if isinstance(c, cards.Mancato)]) == 0:
self.take_damage_response()
self.game.responders_did_respond()
else:
self.pending_action = PendingAction.RESPOND
self.expected_response = cards.Mancato
self.on_response_cb = self.take_damage_response()
self.notify_self()
def get_banged(self):
if len([c for c in self.hand if isinstance(c, cards.Mancato) or isinstance(c, cards.Barile)]) == 0:
print('Cant defend')
self.take_damage_response()
return False
else:
if len([c for c in self.hand if isinstance(c, cards.Barile)]) > 0:
print('has barrel')
self.pending_action = PendingAction.PICK
self.on_pick_cb = self.barrel_pick
else:
print('has mancato')
self.pending_action = PendingAction.RESPOND
self.expected_response = cards.Mancato
self.on_response_cb = self.take_damage_response()
self.notify_self()
return True
def take_damage_response(self):
self.lives -= 1
self.notify_self()
def respond(self, hand_index):
self.pending_action = PendingAction.WAIT
if hand_index != -1 and isinstance(self.hand[hand_index], self.expected_response):
self.game.deck.scrap(self.hand.pop(hand_index))
self.notify_self()
self.game.responders_did_respond()
else:
self.on_response_cb()
self.game.responders_did_respond()
def get_sight(self): def get_sight(self):
aim = 0 aim = 0
for card in self.equipment: for card in self.equipment:

View File

@ -92,8 +92,7 @@ export default {
return { return {
name: lobby.name, name: lobby.name,
icon: "💥", icon: "💥",
number: lobby.players, number: `${lobby.players}🤠`,
suit: '🤠',
is_equipment: true, is_equipment: true,
} }
}, },

View File

@ -2,6 +2,7 @@
<div :class="{ card: true, equipment: card.is_equipment, character:card.is_character }"> <div :class="{ card: true, equipment: card.is_equipment, character:card.is_character }">
<h4>{{card.name}}</h4> <h4>{{card.name}}</h4>
<div class="emoji">{{card.icon}}</div> <div class="emoji">{{card.icon}}</div>
<div v-if="card.is_character" class="alt_text">{{card.alt_text}}</div>
<div class="suit">{{card.number}}{{suit}}</div> <div class="suit">{{card.number}}{{suit}}</div>
</div> </div>
</template> </template>
@ -86,4 +87,17 @@ export default {
bottom: 3pt; bottom: 3pt;
left:3pt; left:3pt;
} }
.card.character .suit {
font-size: x-small;
right: 3pt;
text-align: center;
}
.card.character .alt_text {
right: 3pt;
text-align: center;
position: absolute;
font-size: small;
bottom: 16pt;
left: 3pt;
}
</style> </style>

View File

@ -36,7 +36,7 @@ export default {
}, },
methods: { methods: {
action() { action() {
if (this.pending_action && this.pending_action < 2) { if (this.pending_action !== false && this.pending_action < 2) {
console.log('action') console.log('action')
if (this.pending_action == 0) if (this.pending_action == 0)
this.$socket.emit('pick') this.$socket.emit('pick')

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<h1>Lobby: {{ lobbyName }}</h1> <h1>Lobby: {{ lobbyName }}</h1>
<h3>Giocatori</h3> <h3>Giocatori (tu sei {{username}})</h3>
<div style="display:flex"> <div style="display:flex">
<!-- <div style="position: relative;width:260pt;height:400pt;"> --> <!-- <div style="position: relative;width:260pt;height:400pt;"> -->
<Card v-for="p in playersTable" v-bind:key="p.card.name" :card="p.card"/> <Card v-for="p in playersTable" v-bind:key="p.card.name" :card="p.card"/>
@ -68,7 +68,7 @@ export default {
console.log('received visibility update') console.log('received visibility update')
console.log(vis) console.log(vis)
this.players = JSON.parse(vis) this.players = JSON.parse(vis)
} },
}, },
computed: { computed: {
startGameCard() { startGameCard() {
@ -100,7 +100,8 @@ export default {
return { return {
name: player.name, name: player.name,
number: ((this.username == player.name) ? 'YOU' : (this.players[0].name == player.name) ? 'OWNER' :'') + (player.dist ? `${player.dist}` : ''), number: ((this.username == player.name) ? 'YOU' : (this.players[0].name == player.name) ? 'OWNER' :'') + (player.dist ? `${player.dist}` : ''),
icon: '🤠', icon: (player.lives === undefined || player.lives > 0) ? '🤠' : '☠️',
alt_text: player.lives !== undefined ? Array(player.lives).join('❤️')+Array(player.max_lives-player.lives).join('💀') : '',
is_character: true, is_character: true,
} }
}, },

View File

@ -18,16 +18,20 @@
</transition-group> </transition-group>
</div> </div>
<p>{{hint}}</p> <p>{{hint}}</p>
<Chooser v-if="card_against" text="Contro chi vuoi giocare la carta" :cards="visiblePlayers" :select="selectAgainst"/>
<Chooser v-if="pending_action == 3" text="Scegli come rispondere" :cards="respondCards" :select="respond"/>
</div> </div>
</template> </template>
<script> <script>
import Card from '@/components/Card.vue' import Card from '@/components/Card.vue'
import Chooser from '@/components/Chooser.vue'
export default { export default {
name: 'Player', name: 'Player',
components: { components: {
Card Card,
Chooser,
}, },
data: () => ({ data: () => ({
my_role: null, my_role: null,
@ -37,7 +41,9 @@ export default {
lives: 0, lives: 0,
max_lives: 0, max_lives: 0,
hint: '', hint: '',
pending_action: null pending_action: null,
card_against: null,
visiblePlayers: []
}), }),
sockets: { sockets: {
role(role) { role(role) {
@ -52,7 +58,18 @@ export default {
this.equipment = self.equipment this.equipment = self.equipment
this.lives = self.lives this.lives = self.lives
this.max_lives = self.max_lives this.max_lives = self.max_lives
} },
self_vis(vis) {
console.log('received visibility update')
console.log(vis)
this.visiblePlayers = JSON.parse(vis).map(player => {
return {
name: player.name,
number: player.dist !== undefined ? `${player.dist}` : '',
icon: '🤠',
is_character: true,
}})
},
}, },
computed:{ computed:{
instruction() { instruction() {
@ -64,6 +81,17 @@ export default {
canEndTurn() { canEndTurn() {
return (this.pending_action == 2 && this.hand.length <= this.lives) return (this.pending_action == 2 && this.hand.length <= this.lives)
}, },
respondCards() {
let cc = [{
name: 'Prendi Danno',
icon: '❌',
is_equipment: true,
}]
this.hand.filter(x => x.name == 'Mancato!').forEach(x=>{
cc.push(x)
})
return cc
}
}, },
methods: { methods: {
end_turn(){ end_turn(){
@ -72,14 +100,28 @@ export default {
}, },
play_card(card) { play_card(card) {
if (this.pending_action == 2) { if (this.pending_action == 2) {
let card_data = { if (card.need_target) {
index: this.hand.indexOf(card), this.card_against = card
against: null } else {
this.really_play_card(card, null)
} }
console.log(card_data)
this.$socket.emit('play_card', card_data)
} }
}, },
respond(card) {
this.$socket.emit('respond', this.hand.indexOf(card))
},
selectAgainst(player) {
this.really_play_card(this.card_against, player.name)
this.card_against = null
},
really_play_card(card, against) {
let card_data = {
index: this.hand.indexOf(card),
against: against
}
console.log(card_data)
this.$socket.emit('play_card', card_data)
}
}, },
mounted() { mounted() {
this.$socket.emit('refresh') this.$socket.emit('refresh')