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.draw()
@sio.event
def pick(sid):
ses = sio.get_session(sid)
ses.pick()
@sio.event
def end_turn(sid):
ses = sio.get_session(sid)
@ -91,5 +96,10 @@ def play_card(sid, data):
ses = sio.get_session(sid)
ses.play_card(data['index'], data['against'])
@sio.event
def respond(sid, data):
ses = sio.get_session(sid)
ses.respond(data)
if __name__ == '__main__':
eventlet.wsgi.server(eventlet.listen(('', 5001)), app)

View File

View File

@ -29,6 +29,7 @@ class Card(ABC):
self.sight_mod = sight_mod
self.range = range
self.desc = desc
self.need_target = False
def __str__(self):
char = ['♦️','♣️','♥️','♠️'][int(self.suit)]
@ -64,6 +65,7 @@ class Prigione(Card):
super().__init__(suit, 'Prigione', number, is_equipment=False)
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.need_target = True
class Remington(Card):
def __init__(self, suit, number):
@ -100,6 +102,7 @@ class Bang(Card):
super().__init__(suit, 'Bang!', number)
self.icon = '💥'
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):
def __init__(self, suit, number):
@ -112,6 +115,7 @@ class CatBalou(Card):
super().__init__(suit, 'Cat Balou', number)
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.need_target = True
class Diligenza(Card):
def __init__(self, suit, number):
@ -148,6 +152,7 @@ class Panico(Card):
def __init__(self, suit, number):
super().__init__(suit, 'Panico!', number, range=1)
self.icon = '😱'
self.need_target = True
class Saloon(Card):
def __init__(self, suit, number):

View File

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

View File

@ -4,6 +4,7 @@ import socketio
import players
from characters import all_characters
from deck import Deck
from players import Player
import roles
class Game:
@ -25,6 +26,7 @@ class Game:
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('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
def add_player(self, player: players.Player):
@ -50,6 +52,7 @@ class Game:
print('GAME IS STARING')
if self.started:
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('start', room=self.name)
self.started = True
@ -74,8 +77,22 @@ class Game:
def get_visible_players(self, player):
i = self.players.index(player)
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()}
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]
return [{
'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):
return self.players[(self.turn + 1) % len(self.players)]

View File

@ -1,6 +1,7 @@
from enum import IntEnum
import json
import socketio
from cards import Mancato
import roles
import cards
@ -32,6 +33,9 @@ class Player:
self.pending_action: PendingAction = None
self.available_characters = []
self.was_shot = False
self.on_pick_cb = None
self.on_response_cb = None
self.expected_response = None
def join_game(self, game):
self.game = game
@ -69,6 +73,9 @@ class Player:
ser.pop('game')
ser.pop('sio')
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_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.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):
if self.pending_action != PendingAction.DRAW:
return
for i in range(2):
self.hand.append(self.game.deck.draw())
self.pending_action = PendingAction.PLAY
self.notify_self()
def pick(self):
if self.pending_action != PendingAction.PICK:
return
pickable_cards = 1 + self.character.pick_mod
for i in range(len(self.equipment)):
if isinstance(self.equipment[i], cards.Dinamite):
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.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0:
self.lives -= 3
self.game.deck.scrap(self.equipment.pop(i))
print(f'{self.name} Boom, -3 hp')
else:
self.game.next_player().equipment.append(self.equipment.pop(i))
if any([isinstance(c, cards.Dinamite) or isinstance(c, cards.Prigione) for c in self.equipment]):
return
for i in range(len(self.equipment)):
if isinstance(self.equipment[i], cards.Prigione):
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 and pickable_cards == 0:
self.game.deck.scrap(self.equipment.pop(i))
self.end_turn(forced=True)
else:
break
break
self.pending_action = PendingAction.DRAW
if self.is_my_turn:
for i in range(len(self.equipment)):
if isinstance(self.equipment[i], cards.Dinamite):
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.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0:
self.lives -= 3
self.game.deck.scrap(self.equipment.pop(i))
print(f'{self.name} Boom, -3 hp')
else:
self.game.next_player().equipment.append(self.equipment.pop(i))
self.game.next_player().notify_self()
if any([isinstance(c, cards.Dinamite) or isinstance(c, cards.Prigione) for c in self.equipment]):
self.notify_self()
return
for i in range(len(self.equipment)):
if isinstance(self.equipment[i], cards.Prigione):
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 and pickable_cards == 0:
self.game.deck.scrap(self.equipment.pop(i))
self.end_turn(forced=True)
else:
break
break
self.pending_action = PendingAction.DRAW
self.notify_self()
else:
self.on_pick_cb()
def get_playable_cards(self):
playable_cards = []
@ -163,10 +175,64 @@ class Player:
self.equipment.append(card)
else:
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.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):
aim = 0
for card in self.equipment:

View File

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

View File

@ -2,6 +2,7 @@
<div :class="{ card: true, equipment: card.is_equipment, character:card.is_character }">
<h4>{{card.name}}</h4>
<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>
</template>
@ -86,4 +87,17 @@ export default {
bottom: 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>

View File

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

View File

@ -1,7 +1,7 @@
<template>
<div>
<h1>Lobby: {{ lobbyName }}</h1>
<h3>Giocatori</h3>
<h3>Giocatori (tu sei {{username}})</h3>
<div style="display:flex">
<!-- <div style="position: relative;width:260pt;height:400pt;"> -->
<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(vis)
this.players = JSON.parse(vis)
}
},
},
computed: {
startGameCard() {
@ -100,7 +100,8 @@ export default {
return {
name: player.name,
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,
}
},

View File

@ -18,16 +18,20 @@
</transition-group>
</div>
<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>
</template>
<script>
import Card from '@/components/Card.vue'
import Chooser from '@/components/Chooser.vue'
export default {
name: 'Player',
components: {
Card
Card,
Chooser,
},
data: () => ({
my_role: null,
@ -37,7 +41,9 @@ export default {
lives: 0,
max_lives: 0,
hint: '',
pending_action: null
pending_action: null,
card_against: null,
visiblePlayers: []
}),
sockets: {
role(role) {
@ -52,7 +58,18 @@ export default {
this.equipment = self.equipment
this.lives = self.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:{
instruction() {
@ -64,6 +81,17 @@ export default {
canEndTurn() {
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: {
end_turn(){
@ -72,14 +100,28 @@ export default {
},
play_card(card) {
if (this.pending_action == 2) {
let card_data = {
index: this.hand.indexOf(card),
against: null
if (card.need_target) {
this.card_against = card
} 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() {
this.$socket.emit('refresh')