Merge branch 'main' into dev

This commit is contained in:
Giulio 2023-02-10 00:07:00 +01:00
commit 31bdeb3436
17 changed files with 203 additions and 77 deletions

View File

@ -1,4 +1,5 @@
from typing import List, Set, Dict, Tuple, Optional
from __future__ import annotations
from typing import List, Set, Dict, Tuple, Optional, TYPE_CHECKING
import bang.expansions.fistful_of_cards.card_events as ce
import bang.expansions.high_noon.card_events as ceh
from abc import ABC, abstractmethod
@ -6,11 +7,16 @@ from enum import IntEnum
import bang.roles as r
from globals import G
if TYPE_CHECKING:
from bang.players import Player
from bang.game import Game
class Suit(IntEnum):
DIAMONDS = 0 # ♦
CLUBS = 1 # ♣
HEARTS = 2 # ♥
SPADES = 3 # ♠
GOLD = 4 # 🤑
class Card(ABC):
@ -47,14 +53,14 @@ class Card(ABC):
def __str__(self):
if str(self.suit).isnumeric():
char = ['♦️', '♣️', '♥️', '♠️'][int(self.suit)]
char = ['♦️', '♣️', '♥️', '♠️', '🤑'][int(self.suit)]
else:
char = self.suit
return f'{self.name} {char}{self.number}'
return super().__str__()
def num_suit(self):
return f"{['♦️', '♣️', '♥️', '♠️'][int(self.suit)]}{self.number}"
return f"{['♦️', '♣️', '♥️', '♠️', '🤑'][int(self.suit)]}{self.number}"
def reset_card(self):
if self.usable_next_turn:
@ -64,7 +70,7 @@ class Card(ABC):
if self.must_be_used:
self.must_be_used = False
def play_card(self, player, against=None, _with=None):#self --> carta
def play_card(self, player:Player, against:str=None, _with:int=None):#self --> carta
if (player.game.check_event(ce.IlGiudice)) and self.usable_next_turn and not self.can_be_used_now:
return False
if self.is_equipment:
@ -98,10 +104,10 @@ class Card(ABC):
def use_card(self, player):
pass
def is_duplicate_card(self, player):
return self.name in [c.name for c in player.equipment] or self.name in [c.name for c in player.gold_rush_equipment]
def is_duplicate_card(self, player:Player):
return any(c.name==self.name for c in player.equipment) or any(c.name==self.name for c in player.gold_rush_equipment)
def check_suit(self, game, accepted):
def check_suit(self, game:Game, accepted:List[Suit]):
if game.check_event(ceh.Benedizione):
return Suit.HEARTS in accepted
elif game.check_event(ceh.Maledizione):
@ -226,7 +232,7 @@ class Bang(Card):
elif against is not None:
import bang.characters as chars
super().play_card(player, against=against)
if not self.number == 42: # 42 gold rush
if not (self.number == 42 and self.suit == Suit.GOLD): # 42 gold rush
player.bang_used += 1
player.has_played_bang = True if not player.game.check_event(ceh.Sparatoria) else player.bang_used > 1
if player.character.check(player.game, chars.WillyTheKid):

View File

@ -1,8 +1,13 @@
from __future__ import annotations
from abc import ABC, abstractmethod
from bang.expansions import *
from typing import List
from typing import List, TYPE_CHECKING
from globals import G
if TYPE_CHECKING:
from bang.players import Player
from bang.game import Game
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 = ''):
super().__init__()
@ -16,13 +21,13 @@ class Character(ABC):
self.icon = '🤷‍♂️'
self.number = ''.join(['❤️']*self.max_lives)
def check(self, game, character):
def check(self, game:Game, character:Character):
import bang.expansions.high_noon.card_events as ceh
if game.check_event(ceh.Sbornia):
return False
return isinstance(self, character)
def special(self, player, data):
def special(self, player:Player, data):
import bang.expansions.high_noon.card_events as ceh
if player.game.check_event(ceh.Sbornia):
return False

View File

@ -58,7 +58,9 @@ class Bottiglia(ShopCard):
def play_card(self, player, against=None, _with=None):
# bang, birra, panico
player.available_cards = [Bang(1,42), Birra(1,42), Panico(1,42)]
player.available_cards = [Bang(4,42), Birra(4,42), Panico(4,42)]
if not any((player.get_sight() >= p['dist'] for p in player.game.get_visible_players(player))):
player.available_cards.pop(0)
for i in range(len(player.available_cards)):
player.available_cards[i].must_be_used = True
player.choose_text = 'choose_bottiglia'
@ -73,7 +75,7 @@ class Complice(ShopCard):
def play_card(self, player, against=None, _with=None):
# emporio, duello, Cat balou
player.available_cards = [Emporio(1,42), Duello(1,42), CatBalou(1,42)]
player.available_cards = [Emporio(4,42), Duello(4,42), CatBalou(4,42)]
for i in range(len(player.available_cards)):
player.available_cards[i].must_be_used = True
player.choose_text = 'choose_complice'

View File

@ -33,7 +33,24 @@ class Lemat(Card):
def __init__(self, suit, number):
super().__init__(suit, 'Lemat', number, is_equipment=True, is_weapon=True, range=1)
self.icon = '🔫' # ogni carta può essere usata come bang, conta per il conteggio dei bang per turno
#TODO
def play_card(self, player, against, _with=None):
if (player.game.check_event(ce.IlGiudice) and self.can_be_used_now) or (not self.can_be_used_now and player.game.check_event(ce.Lazo)):
return False
if self.can_be_used_now:
self.can_be_used_now = False
G.sio.emit('chat_message', room=player.game.name,
data=f'_play_card|{player.name}|{self.name}')
player.equipment.append(self)
player.notify_self()
return True
elif not player.has_played_bang and any((player.get_sight() >= p['dist'] for p in player.game.get_visible_players(player))):
from bang.players import PendingAction
player.available_cards = player.hand.copy()
player.pending_action = PendingAction.CHOOSE
player.choose_text = 'choose_play_as_bang'
player.notify_self()
return False
class SerpenteASonagli(Card):
def __init__(self, suit, number):
@ -165,7 +182,7 @@ class Mira(Card):
def play_card(self, player, against, _with=None):
if against is not None and _with is not None:
super().play_card(player, against=against)
super().play_card(player, against=against, _with=_with)
player.game.attack(player, against, card_name=self.name)
return True
return False
@ -218,7 +235,7 @@ def get_starting_deck() -> List[Card]:
cards = [
Fantasma(Suit.SPADES, 9),
Fantasma(Suit.SPADES, 10),
# Lemat(Suit.DIAMONDS, 4),
Lemat(Suit.DIAMONDS, 4),
SerpenteASonagli(Suit.HEARTS, 7),
Shotgun(Suit.SPADES, 'K'),
Taglia(Suit.CLUBS, 9),

View File

@ -9,14 +9,14 @@ class BlackFlower(Character):
self.icon = '🥀'
def special(self, player, data): #fiori = suit.Clubs
if player.special_use_count > 0 and not any((c.suit == cs.Suit.CLUBS for c in player.hand)):
if player.special_use_count > 0 or not any((c.suit == cs.Suit.CLUBS for c in player.hand)):
return False
if super().special(player, data):
if any((player.get_sight() >= p['dist'] for p in player.game.get_visible_players(player))) and super().special(player, data):
from bang.players import PendingAction
player.special_use_count += 1
player.available_cards = [c for c in player.hand if c.suit == cs.Suit.CLUBS]
player.special_use_count += 1
player.pending_action = PendingAction.CHOOSE
player.choose_text = 'blackflower_special'
player.choose_text = 'choose_play_as_bang'
player.notify_self()
class ColoradoBill(Character):

View File

@ -61,7 +61,7 @@ class Game:
self.initial_players = 0
self.password = ''
self.expansions: List[str] = []
self.available_expansions = ['dodge_city', 'fistful_of_cards', 'high_noon', 'gold_rush']
self.available_expansions = ['dodge_city', 'fistful_of_cards', 'high_noon', 'gold_rush', 'the_valley_of_shadows']
self.shutting_down = False
self.is_competitive = False
self.disconnect_bot = True
@ -446,7 +446,7 @@ class Game:
{'name':self.players[self.turn].name,'cards': self.available_cards}, default=lambda o: o.__dict__))
self.players[self.turn].notify_self()
def respond_emporio(self, player, i):
def respond_emporio(self, player:pl.Player, i:int):
card = self.available_cards.pop(i)
G.sio.emit('chat_message', room=self.name, data=f'_choose_emporio|{player.name}|{card.name}')
player.hand.append(card)

View File

@ -1,3 +1,4 @@
from __future__ import annotations
from enum import IntEnum
import json
from random import random, randrange, sample, uniform
@ -14,11 +15,14 @@ import bang.expansions.gold_rush.shop_cards as grc
import bang.expansions.gold_rush.characters as grch
import bang.expansions.the_valley_of_shadows.cards as tvosc
import bang.expansions.the_valley_of_shadows.characters as tvosch
from typing import List
from typing import List, TYPE_CHECKING
from metrics import Metrics
from globals import G
import sys
if TYPE_CHECKING:
from bang.game import Game
robot_pictures = [
'https://i.imgur.com/40rAFIb.jpg',
'https://i.imgur.com/gG77VRR.jpg',
@ -50,7 +54,7 @@ class Player:
def is_admin(self):
return self.discord_id in {'244893980960096266', '539795574019457034'}
def get_avatar(self):
def _get_avatar(self):
import requests
headers = {
'Authorization': 'Bearer ' + self.discord_token,
@ -78,7 +82,6 @@ class Player:
print(r)
def __init__(self, name, sid, bot=False, discord_token=None):
import bang.game as g
super().__init__()
self.name = name
self.sid = sid
@ -89,8 +92,8 @@ class Player:
if self.is_bot:
self.avatar = robot_pictures[randrange(len(robot_pictures))]
if self.discord_token:
G.sio.start_background_task(self.get_avatar)
self.game: g = None
G.sio.start_background_task(self._get_avatar)
self.game: Game = None
self.reset()
def reset(self):
@ -187,7 +190,6 @@ class Player:
self.pending_action = PendingAction.DRAW
self.notify_self()
def prepare(self):
self.max_lives = self.character.max_lives + self.role.health_mod
self.lives = self.max_lives
@ -717,6 +719,7 @@ class Player:
print('which is a gold rush black card')
card: grc.ShopCard = self.gold_rush_equipment[hand_index - len(self.hand) - len(self.equipment)]
return card.play_card(self)
from_hand = hand_index < len(self.hand)
card: cs.Card = self.hand.pop(hand_index) if hand_index < len(self.hand) else self.equipment.pop(hand_index-len(self.hand))
withCard: cs.Card = None
if _with is not None:
@ -744,7 +747,10 @@ class Player:
self.equipment.insert(hand_index-len(self.hand), card)
elif card.is_equipment or (card.usable_next_turn and not card.can_be_used_now):
if not did_play_card:
self.hand.insert(hand_index, card)
if from_hand:
self.hand.insert(hand_index, card)
else:
self.equipment.insert(hand_index-len(self.hand), card)
else:
did_play_card = True
if not self.game.is_replay:
@ -870,11 +876,11 @@ class Player:
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{self.name}|Sventagliata|{player.name}')
self.pending_action = PendingAction.PLAY
self.notify_self()
elif 'blackflower_special' in self.choose_text:
elif 'choose_play_as_bang' in self.choose_text:
if card_index <= len(self.available_cards):
self.hand.remove(self.available_cards[card_index])
self.game.deck.scrap(self.available_cards[card_index], player=self)
self.hand.append(cs.Bang(cs.Suit.CLUBS,42))
self.hand.append(cs.Bang(self.available_cards[card_index].suit, 42))
self.pending_action = PendingAction.PLAY
self.notify_self()
elif 'choose_tornado' in self.choose_text:

View File

@ -56,12 +56,12 @@ HASTEBIN_HEADERS = {
}
app = socketio.WSGIApp(sio, static_files=static_files)
games: List[Game] = []
games: dict[str, Game] = {}
online_players = 0
blacklist: List[str] = []
def send_to_debug(error):
for g in games:
for g in games.values():
if g.debug:
sio.emit('chat_message', room=g.name, data={'color': f'red','text':json.dumps({'ERROR':error}), 'type':'json'})
elif any((p.is_admin() for p in g.players)):
@ -85,9 +85,10 @@ def bang_handler(func):
return wrapper_func
def advertise_lobbies():
sio.emit('lobbies', room='lobby', data=[{'name': g.name, 'players': len(g.players), 'locked': g.password != ''} for g in games if not g.started and len(g.players) < 10 and not g.is_hidden])
sio.emit('spectate_lobbies', room='lobby', data=[{'name': g.name, 'players': len(g.players), 'locked': g.password != ''} for g in games if g.started and not g.is_hidden and len(g.players) > 0])
Metrics.send_metric('lobbies', points=[sum(not g.is_replay for g in games)])
open_lobbies = [g for g in games.values() if 0 < len(g.players) < 10 and not g.is_hidden][-10:]
sio.emit('lobbies', room='lobby', data=[{'name': g.name, 'players': len(g.players), 'locked': g.password != ''} for g in open_lobbies if not g.started])
sio.emit('spectate_lobbies', room='lobby', data=[{'name': g.name, 'players': len(g.players), 'locked': g.password != ''} for g in open_lobbies if g.started])
Metrics.send_metric('lobbies', points=[sum(not g.is_replay for g in games.values())])
Metrics.send_metric('online_players', points=[online_players])
@sio.event
@ -137,7 +138,7 @@ def set_username(sid, username):
ses = sio.get_session(sid)
if not isinstance(ses, Player):
dt = username["discord_token"] if 'discord_token' in username else None
sio.save_session(sid, Player(username["name"], sid, discord_token=dt))
sio.save_session(sid, Player(username.get('name', 'player'), sid, discord_token=dt))
print(f'{sid} is now {username}')
advertise_lobbies()
elif ses.game is None or not ses.game.started:
@ -178,7 +179,7 @@ def get_me(sid, data):
else:
sid.game.replay(log, speed=0, fast_forward=int(data['ffw']))
return
if (room := next((g for g in games if g.name == data['name']), None)) is not None:
if data['name'] in games and (room := games[data['name']]) is not None:
if not room.started:
join_room(sid, data)
elif room.started:
@ -233,8 +234,7 @@ def disconnect(sid):
sio.emit('players', room='lobby', data=online_players)
if p.game and p.disconnect():
sio.close_room(p.game.name)
if p.game in games:
games.pop(games.index(p.game))
games.pop(p.game.name)
print('disconnect ', sid)
advertise_lobbies()
Metrics.send_metric('online_players', points=[online_players])
@ -243,15 +243,15 @@ def disconnect(sid):
@bang_handler
def create_room(sid, room_name):
if (p := sio.get_session(sid)).game is None:
while any((g.name == room_name for g in games)):
room_name += f'_{random.randint(0,100)}'
while room_name in games:
room_name += f'_{random.randint(0, 10000)}'
sio.leave_room(sid, 'lobby')
sio.enter_room(sid, room_name)
g = Game(room_name)
g.add_player(p)
if room_name in blacklist:
g.is_hidden = True
games.append(g)
games[room_name] = g
print(f'{sid} created a room named {room_name}')
advertise_lobbies()
@ -282,27 +282,26 @@ def toggle_replace_with_bot(sid):
@bang_handler
def join_room(sid, room):
room_name = room['name']
i = [g.name for g in games].index(room_name)
if games[i].password != '' and games[i].password != room.get('password', '').upper():
if games[room_name].password != '' and games[room_name].password != room.get('password', '').upper():
return
if not games[i].started:
if not games[room_name].started:
print(f'{sid} joined a room named {room_name}')
sio.leave_room(sid, 'lobby')
sio.enter_room(sid, room_name)
while any((p.name == sio.get_session(sid).name and not p.is_bot for p in games[i].players)):
while any((p.name == sio.get_session(sid).name and not p.is_bot for p in games[room_name].players)):
sio.get_session(sid).name += f'_{random.randint(0,100)}'
sio.emit('me', data=sio.get_session(sid).name, room=sid)
games[i].add_player(sio.get_session(sid))
games[room_name].add_player(sio.get_session(sid))
advertise_lobbies()
else:
games[i].spectators.append(sio.get_session(sid))
sio.get_session(sid).game = games[i]
games[room_name].spectators.append(sio.get_session(sid))
sio.get_session(sid).game = games[room_name]
sio.get_session(sid).pending_action = PendingAction.WAIT
sio.enter_room(sid, games[0].name)
games[i].notify_room(sid)
sio.enter_room(sid, games[room_name].name)
games[room_name].notify_room(sid)
eventlet.sleep(0.5)
games[i].notify_room(sid)
games[i].notify_all()
games[room_name].notify_room(sid)
games[room_name].notify_all()
"""
Sockets for the status page
@ -324,7 +323,7 @@ def get_all_rooms(sid, deploy_key):
'incremental_turn': g.incremental_turn,
'debug': g.debug,
'spectators': len(g.spectators)
} for g in games])
} for g in games.values()])
@sio.event
@bang_handler
@ -339,16 +338,16 @@ def reset(sid, data):
global games
ses = sio.get_session(sid)
if ('DEPLOY_KEY' in os.environ and 'key' in data and data['key'] == os.environ['DEPLOY_KEY']) or (isinstance(ses, Player) and ses.is_admin()):
for g in games:
for g in games.values():
sio.emit('kicked', room=g.name)
games = []
games = {}
@sio.event
@bang_handler
def hide_toogle(sid, data):
ses = sio.get_session(sid)
if ('DEPLOY_KEY' in os.environ and 'key' in data and data['key'] == os.environ['DEPLOY_KEY']) or (isinstance(ses, Player) and ses.is_admin()):
game = [g for g in games if g.name==data['room']]
game = games['room']
if len(games) > 0:
game[0].is_hidden = not game[0].is_hidden
if game[0].is_hidden:
@ -797,7 +796,7 @@ def discord_auth(sid, data):
def pool_metrics():
while True:
sio.sleep(60)
Metrics.send_metric('lobbies', points=[sum(not g.is_replay for g in games)])
Metrics.send_metric('lobbies', points=[sum(not g.is_replay for g in games.values())])
Metrics.send_metric('online_players', points=[online_players])
import urllib.parse
@ -830,14 +829,15 @@ def save_games():
if not os.path.exists("save"):
os.mkdir("save")
with open('./save/games.pickle', 'wb') as f:
pickle.dump([g for g in games if g.started and not g.is_replay and not g.is_hidden and len(g.players) > 0], f)
pickle.dump([g for g in games.values() if g.started and not g.is_replay and not g.is_hidden and len(g.players) > 0], f)
if __name__ == '__main__':
if os.path.exists('./save/games.pickle'):
try:
with open('./save/games.pickle', 'rb') as file:
games = pickle.load(file)
for g in games:
temp_g = pickle.load(file)
games = {g.name: g for g in temp_g}
for g in games.values():
g.spectators = []
for p in g.players:
if p.sid != 'bot':

View File

@ -50,3 +50,22 @@ def test_ColoradoBill():
assert p1.lives == 3
p.play_card(0, p1.name)
assert p1.pending_action == PendingAction.RESPOND
# test BlackFlower
def test_BlackFlower():
g = Game('test')
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
for p in ps:
g.add_player(p)
g.start_game()
for p in ps:
p.available_characters = [BlackFlower()]
p.set_character(p.available_characters[0].name)
p = g.players[g.turn]
p.draw('')
p.hand = [cs.Volcanic(cs.Suit.DIAMONDS,0)]
p.special('')
assert p.pending_action == PendingAction.PLAY
p.hand = [cs.Volcanic(cs.Suit.CLUBS,0)]
p.special('')
assert p.pending_action == PendingAction.CHOOSE

View File

@ -6,9 +6,16 @@
<div v-else class="center-stuff">
<h2>{{$t("warning")}}</h2>
<p>{{$t("connection_error")}}</p>
<ul v-if="shouldShowBackendSuggestions">
Connect to one of these backends:
<li v-for="suggestion in backendSuggestions" :key="suggestion.name" @click="changeBackend(suggestion)">
{{suggestion.name}}
</li>
</ul>
</div>
<help v-if="showHelp"/>
<div style="position:fixed;bottom:4pt;right:4pt;display:flex;z-index:10">
<input v-if="connect_dev" type=button class="btn" style="min-width:28pt;cursor:pointer;" @click="resetConnection" :value="'💚'+connect_dev" />
<input type=button class="btn" style="min-width:28pt;cursor:pointer;" @click="()=>{sending_report = true}" :value=" $t('report') " />
<input type="button" class="btn" value="" style="min-width:28pt;cursor:pointer;background-position:center;background-image:url('https://img.icons8.com/color/48/discord-logo.png');background-size:1.5em;background-repeat: no-repeat;" @click="joinDiscord"/>
<input type="button" class="btn" :value="(showHelp?'X':'?')" style="min-width:28pt;border-radius:100%;cursor:pointer;" @click="getHelp"/>
@ -63,8 +70,17 @@ export default {
theme: 'light',
report: '',
sending_report: false,
connect_dev: undefined,
backendSuggestions: [
{ name: 'Bang Xamin', url: 'https://bang.xamin.it' },
{ name: 'Bang Miga', url: 'https://bang.migani.synology.me/' },
{ name: 'Localhost', url: 'http://localhost:5001' },
],
}),
computed: {
shouldShowBackendSuggestions() {
return window.location.origin.indexOf('vercel') !== -1 || window.location.origin.indexOf('localhost') !== -1
},
},
sockets: {
connect() {
@ -98,6 +114,16 @@ export default {
// Send message to SW to skip the waiting and activate the new SW
this.registration.waiting.postMessage({ type: 'SKIP_WAITING' })
},
changeBackend(suggestion) {
this.$socket.disconnect();
window.localStorage.setItem('connect-dev', suggestion.url);
window.location.reload();
},
resetConnection() {
this.$socket.disconnect();
window.localStorage.removeItem('connect-dev');
window.navigation.reload();
},
detectColorScheme() {
if(localStorage.getItem("theme")){
this.theme = localStorage.getItem("theme")
@ -146,6 +172,9 @@ export default {
userLang = 'en';
this.$i18n.locale = userLang.split('-')[0]
}
if (window.localStorage.getItem('connect-dev')) {
this.connect_dev = window.localStorage.getItem('connect-dev')
}
this.detectColorScheme()
if (window.location.origin.indexOf('localhost') !== -1) return;
datadogRum.init({

View File

@ -32,7 +32,7 @@ export default {
},
suit() {
if (this.card && !isNaN(this.card.suit)) {
let x = ['♦️','♣️','♥️','♠️']
let x = ['♦️','♣️','♥️','♠️','🤑']
return x[this.card.suit];
} else if (this.card.suit) {
return this.card.suit;
@ -89,6 +89,19 @@ export default {
#816b45 10px
);
}
.card:not(.back,.fistful-of-cards,.high-noon,.gold-rush):before{
content: "";
background-image: radial-gradient(var(--bg-color) 13%, #0000 5%),
radial-gradient(var(--bg-color) 14%, transparent 5%),
radial-gradient(var(--bg-color) 8%, transparent 5%);
background-position: -12px 0, 12px 14px, 0 -12pt;
background-size: 50px 50px;
position: absolute;
top: -10px;
left: -10px;
bottom: -4px;
right: -4px;
}
.card.equipment {
box-shadow:
0 0 0 3pt #5c5e83,

View File

@ -61,7 +61,7 @@
<div class="tiny-equipment">
<Card v-for="(card, i) in p.equipment" v-bind:key="card.name+card.number"
:card="card" @click.native="selectedInfo = p.equipment"
:style="`margin-top: ${i<1?10:-(Math.min((p.equipment.length+p.gold_rush_equipment.length+1)*12,80))}pt`"/>
:style="`margin-top: ${i < 1 ? 10 : -(Math.min((p.equipment.length + p.gold_rush_equipment.length + 1) * 12, 80))}pt;`"/>
<Card v-for="(card, i) in p.gold_rush_equipment" v-bind:key="card.name+card.number"
:card="card" @click.native="selectedInfo = p.gold_rush_equipment"
:style="`margin-top: ${i+p.equipment.length<1?10:-(Math.min((p.equipment.length+p.gold_rush_equipment.length+1)*12,80))}pt`"/>
@ -531,8 +531,14 @@ export default {
transform: scale(0.8);
margin-bottom: -4pt;
}
.tiny-equipment .card {
transform: rotate(2deg);
}
.tiny-equipment .card:nth-child(odd) {
transform: rotate(-2deg);
}
.tiny-equipment .card:hover {
transform: translateY(10px) scale(1.1);
transform: translateY(10px) scale(1.2);
z-index: 1;
}
.tiny-character {

View File

@ -169,6 +169,10 @@ export default {
'Authorization': 'Bearer ' + localStorage.getItem('discord_token')
}
})
.then((res) => {
if (res.status !== 200) throw new Error(res.status)
return res
})
.then(response => response.json())
.then(data => {
console.log(data)

View File

@ -3,13 +3,13 @@
<p v-if="instruction && (lives > 0 || is_ghost)" class="center-stuff">{{instruction}}</p>
<!-- <button v-if="canEndTurn" @click="end_turn">Termina Turno</button> -->
<div class="equipment-slot">
<Card v-if="my_role" :card="my_role" class="back"
<Card v-if="my_role" :card="my_role" class="back" style="transform:rotate(-2deg)"
@pointerenter.native="desc=($i18n.locale=='it'?my_role.goal:my_role.goal_eng)" @pointerleave.native="desc=''"/>
<Card v-if="character" :card="character" style="margin-left: -30pt;margin-right: 0pt;"
@pointerenter.native="setDesc(character)" @pointerleave.native="desc=''"/>
<transition-group name="list" tag="div" style="display: flex;flex-direction:column; justify-content: space-evenly; margin-left: 12pt;margin-right:-10pt;">
<span v-for="(n, i) in lives" v-bind:key="i" :alt="i"></span>
<span v-for="(n, i) in (max_lives-lives)" v-bind:key="`${i}-sk`" :alt="i">💀</span>
<span v-for="(n, i) in lives" v-bind:key="i" :alt="i"></span>
</transition-group>
<div v-if="gold_nuggets > 0" style="display: flex;align-items: center;margin-left: 12pt;margin-right: -10pt;justify-content: space-evenly;width: 25pt;">
<transition name="list">
@ -17,7 +17,7 @@
</transition>
<span>💵</span>
</div>
<transition-group v-if="lives > 0 || is_ghost" name="list" tag="div" style="margin: 0 0 0 10pt; display:flex;">
<transition-group v-if="lives > 0 || is_ghost" name="list" id="equipment" tag="div" style="margin: 0 0 0 10pt; display:flex;">
<Card v-for="card in equipmentComputed" v-bind:key="card.name+card.number" :card="card"
@pointerenter.native="setDesc(card)" @pointerleave.native="desc=''"
@click.native="play_card(card, true)" :class="{'cant-play':((eventCard && eventCard.name == 'Lazo') || (!card.can_be_used_now && !card.is_equipment))}"/>
@ -390,7 +390,7 @@ export default {
},
play_card(card, from_equipment) {
console.log('play ' + card.name)
if (from_equipment && (!card.can_be_used_now || (this.eventCard && this.eventCard.name == "Lazo"))) return;
if (from_equipment && ((!card.can_be_used_now && !card.name == 'Lemat') || (this.eventCard && this.eventCard.name == "Lazo"))) return;
else if (card.usable_next_turn && !card.can_be_used_now) return this.really_play_card(card, null);
let calamity_special = (card.name === 'Mancato!' && this.character.name === 'Calamity Janet')
let cant_play_bang = (this.has_played_bang && card.number !==42 && this.equipment.filter(x => x.name == 'Volcanic').length == 0)
@ -514,8 +514,12 @@ export default {
margin-left: -30pt;
}
.hand>.card:hover {
margin-right:35pt;
transform: translateY(-15px);
transform: translateY(-15px) translateX(-15px) rotate(-2deg);
z-index: 1;
}
.hand>.card:nth-child(1):hover, .hand>.card:last-child:hover {
transform: translateY(-15px) translateX(0) rotate(2deg);
z-index: 1;
}
#hand_text{
color: var(--muted-color);
@ -531,6 +535,12 @@ export default {
margin: 10pt 0pt;
overflow:auto;
}
#equipment .card:nth-child(even) {
transform: rotate(1deg);
}
#equipment .card:nth-child(odd) {
transform: rotate(-1deg);
}
.hurt-notify {
pointer-events: none;
animation: disappear 0.5s ease-in forwards;

View File

@ -75,6 +75,7 @@
"choose_complice": "Choose how you will play Pardner!",
"choose_ricercato": "Choose who you will play Wanted against.",
"choose_birra_function": "Choose between getting 1 gold nugget by discarding beer or if you want to play the beer.",
"choose_play_as_bang": "Choose which card to play as Bang!",
"emporio_others": "{0} is choosing which card to get from the General Store",
"you_died": "YOU DIED",
"spectate": "SPECTATE",
@ -694,7 +695,7 @@
},
"Lemat": {
"name": "Lemat",
"desc": "During your turn you can use any card as BANG!."
"desc": "During your turn you can use any card as BANG! (Click on the card once equipped)."
},
"SerpenteASonagli": {
"name": "Serpente a Sonagli",

View File

@ -75,6 +75,7 @@
"choose_complice": "Scegli come giocare Complice!",
"choose_ricercato": "Scegli il giocatore su cui vuoi giocare Ricercato",
"choose_birra_function": "Scegli tra ottenere 1 pepita scartando la birra oppure giocare la birra.",
"choose_play_as_bang": "Scegli che carta giocare come Bang!",
"emporio_others": "{0} sta scegliendo che carta prendere dall'emporio",
"you_died": "SEI MORTO",
"spectate": "SPETTATORE",
@ -694,7 +695,7 @@
},
"Lemat": {
"name": "Lemat",
"desc": "Puoi usare ogni carta in mano come BANG!."
"desc": "Puoi usare ogni carta in mano come BANG! (Clicca la carta una volta equipaggiata)."
},
"SerpenteASonagli": {
"name": "Serpente a Sonagli",

View File

@ -3,10 +3,17 @@ import App from './App.vue'
Vue.config.productionTip = false
import VueSocketIO from 'bang-vue-socket.io'
Vue.use(new VueSocketIO({
debug: Vue.config.devtools,
connection: Vue.config.devtools ? `http://${window.location.hostname}:5001` : window.location.origin,
}))
if (window.localStorage.getItem('connect-dev')) {
Vue.use(new VueSocketIO({
debug: true,
connection: window.localStorage.getItem('connect-dev'),
}))
} else {
Vue.use(new VueSocketIO({
debug: Vue.config.devtools,
connection: (Vue.config.devtools) ? `http://${window.location.hostname}:5001` : window.location.origin,
}))
}
import PrettyCheckbox from 'pretty-checkbox-vue';
Vue.use(PrettyCheckbox)