Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7571eda9e2 | ||
![]() |
05fd0c8062 | ||
![]() |
9d9cd8fa75 |
111
.github/workflows/docker-image.yml
vendored
111
.github/workflows/docker-image.yml
vendored
@ -4,68 +4,69 @@ on:
|
||||
branches: main
|
||||
|
||||
jobs:
|
||||
build-platform:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [linux/amd64, linux/arm/v7, linux/arm64/v8]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v4
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: crazy-max/ghaction-docker-buildx@v3
|
||||
-
|
||||
name: Cache Docker layers
|
||||
uses: actions/cache@v3
|
||||
id: cache
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Prepare Platform Tag
|
||||
id: platform_tag
|
||||
run: echo "platform_tag=$(echo ${{ matrix.platform }} | sed 's|/|-|g')" >> $GITHUB_ENV
|
||||
|
||||
- name: Build and push platform-specific image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: true
|
||||
tags: albertoxamin/bang:${{ env.platform_tag }}
|
||||
cache-from: type=registry,ref=albertoxamin/bang:${{ env.platform_tag }}
|
||||
cache-to: type=inline
|
||||
|
||||
create-manifest:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-platform
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Create and push multi-arch manifest
|
||||
-
|
||||
name: Docker Buildx (build amd64 arm64)
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
docker buildx build \
|
||||
--cache-from "type=local,src=/tmp/.buildx-cache" \
|
||||
--cache-to "type=local,dest=/tmp/.buildx-cache" \
|
||||
--platform linux/amd64 \
|
||||
--output "type=image,push=false" \
|
||||
--tag albertoxamin/bang:latest \
|
||||
albertoxamin/bang:linux-amd64 \
|
||||
albertoxamin/bang:linux-arm-v7 \
|
||||
albertoxamin/bang:linux-arm64-v8
|
||||
--file ./Dockerfile ./
|
||||
-
|
||||
name: Docker Buildx (build armv-7)
|
||||
run: |
|
||||
docker buildx build \
|
||||
--cache-from "type=local,src=/tmp/.buildx-cache" \
|
||||
--cache-to "type=local,dest=/tmp/.buildx-cache" \
|
||||
--platform linux/arm/v7 \
|
||||
--output "type=image,push=false" \
|
||||
--tag albertoxamin/bang:latest \
|
||||
--file ./Dockerfile ./
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
-
|
||||
name: Docker Buildx (push all)
|
||||
run: |
|
||||
docker buildx build \
|
||||
--cache-from "type=local,src=/tmp/.buildx-cache" \
|
||||
--platform linux/amd64,linux/arm/v7 \
|
||||
--output "type=image,push=true" \
|
||||
--tag albertoxamin/bang:latest \
|
||||
--file ./Dockerfile ./
|
||||
-
|
||||
name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect albertoxamin/bang:latest
|
||||
|
||||
- name: Notify discord
|
||||
uses: th0th/notify-discord@v0.4.1
|
||||
if: ${{ always() }}
|
||||
env:
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
GITHUB_ACTOR: ${{ github.actor }}
|
||||
GITHUB_JOB_NAME: "Docker image main :latest"
|
||||
GITHUB_JOB_STATUS: ${{ job.status }}
|
||||
|
@ -6,9 +6,3 @@ BANG! is a trademark owned by DVGiochi.
|
||||
[Frontend Readme](./frontend/README.md)
|
||||
|
||||
[Backend Readme](./backend/Readme.md)
|
||||
|
||||
|
||||
<img width="1326" alt="bang-lobby" src="https://github.com/albertoxamin/bang/assets/6067659/853a4182-aace-4f5d-92c3-ad63f309c37a">
|
||||
|
||||
|
||||
<img width="1316" alt="bang-in-game" src="https://github.com/albertoxamin/bang/assets/6067659/fa4ad9f3-2012-4a38-b3eb-97fd0b4b8f2b">
|
||||
|
@ -20,7 +20,6 @@ class Suit(IntEnum):
|
||||
HEARTS = 2 # ♥
|
||||
SPADES = 3 # ♠
|
||||
GOLD = 4 # 🤑
|
||||
TRAIN = 5 # 🚂
|
||||
|
||||
|
||||
class Card(ABC):
|
||||
@ -67,7 +66,7 @@ class Card(ABC):
|
||||
|
||||
def __str__(self) -> str:
|
||||
if str(self.suit).isnumeric():
|
||||
char = ["♦️", "♣️", "♥️", "♠️", "🤑", "🚋"][int(self.suit)]
|
||||
char = ["♦️", "♣️", "♥️", "♠️", "🤑"][int(self.suit)]
|
||||
else:
|
||||
char = self.suit
|
||||
return f"{self.name} {char}{self.number}"
|
||||
@ -125,13 +124,13 @@ class Card(ABC):
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_against{'_with' if _with else ''}|{player.name}|{self.name}|{against}|{_with.name if _with else ''}",
|
||||
data=f"_play_card_against|{player.name}|{self.name}|{against}",
|
||||
)
|
||||
else:
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card{'_with' if _with else ''}|{player.name}|{self.name}|{_with.name if _with else ''}",
|
||||
data=f"_play_card|{player.name}|{self.name}",
|
||||
)
|
||||
return True
|
||||
|
||||
@ -219,10 +218,8 @@ class Prigione(Card):
|
||||
) -> bool:
|
||||
if player.game.check_event(ce.IlGiudice):
|
||||
return False
|
||||
if (
|
||||
against is not None
|
||||
and not isinstance(player.game.get_player_named(against).role, r.Sheriff)
|
||||
and not self.is_duplicate_card(player.game.get_player_named(against))
|
||||
if against is not None and not isinstance(
|
||||
player.game.get_player_named(against).role, r.Sheriff
|
||||
):
|
||||
self.can_be_used_now = False
|
||||
G.sio.emit(
|
||||
@ -371,18 +368,14 @@ class Birra(Card):
|
||||
player.game.deck.draw(True, player=p)
|
||||
p.notify_self()
|
||||
if "gold_rush" in player.game.expansions and self.number != 42:
|
||||
player.set_choose_action(
|
||||
"choose_birra_function",
|
||||
[
|
||||
{
|
||||
"name": "Pepita",
|
||||
"icon": "💵️",
|
||||
"alt_text": "1",
|
||||
"noDesc": True,
|
||||
},
|
||||
from bang.players import PendingAction
|
||||
|
||||
player.available_cards = [
|
||||
{"name": "Pepita", "icon": "💵️", "alt_text": "1", "noDesc": True},
|
||||
self,
|
||||
],
|
||||
)
|
||||
]
|
||||
player.choose_text = "choose_birra_function"
|
||||
player.pending_action = PendingAction.CHOOSE
|
||||
player.notify_self()
|
||||
return True
|
||||
if (
|
||||
|
@ -1,17 +1,15 @@
|
||||
from typing import List, Set, Dict, Tuple, Optional, TYPE_CHECKING
|
||||
import random
|
||||
import bang.cards as cs
|
||||
import bang.expansions.fistful_of_cards.card_events as ce
|
||||
import bang.expansions.high_noon.card_events as ceh
|
||||
import bang.expansions.wild_west_show.card_events as cew
|
||||
import bang.expansions.wild_west_show.characters as chw
|
||||
import bang.expansions.gold_rush.shop_cards as grc
|
||||
import bang.expansions.train_robbery.stations as trs
|
||||
import bang.expansions.train_robbery.trains as trt
|
||||
from globals import G
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bang.game import Game
|
||||
from bang.players import Player
|
||||
|
||||
|
||||
class Deck:
|
||||
@ -37,9 +35,6 @@ class Deck:
|
||||
self.game = game
|
||||
self.event_cards: List[ce.CardEvent] = []
|
||||
self.event_cards_wildwestshow: List[ce.CardEvent] = []
|
||||
self.stations: List[trs.StationCard] = []
|
||||
self.train_pile: List[trt.TrainCard] = []
|
||||
self.current_train: List[trt.TrainCard] = []
|
||||
endgame_cards: List[ce.CardEvent] = []
|
||||
if "fistful_of_cards" in game.expansions:
|
||||
self.event_cards.extend(ce.get_all_events(game.rng))
|
||||
@ -52,12 +47,6 @@ class Deck:
|
||||
game.rng.shuffle(self.event_cards_wildwestshow)
|
||||
self.event_cards_wildwestshow.insert(0, None)
|
||||
self.event_cards_wildwestshow.append(cew.get_endgame_card())
|
||||
if "train_robbery" in game.expansions:
|
||||
self.stations = game.rng.sample(trs.get_all_stations(), len(game.players))
|
||||
self.train_pile = trt.get_all_cards(game.rng)
|
||||
self.current_train = [trt.get_locomotives(game.rng)[0]] + self.train_pile[
|
||||
:3
|
||||
]
|
||||
if len(self.event_cards) > 0:
|
||||
game.rng.shuffle(self.event_cards)
|
||||
self.event_cards = self.event_cards[:12]
|
||||
@ -117,21 +106,12 @@ class Deck:
|
||||
self.shop_cards[i].reset_card()
|
||||
self.game.notify_gold_rush_shop()
|
||||
|
||||
def move_train_forward(self):
|
||||
if len(self.stations) == 0:
|
||||
return
|
||||
if len(self.current_train) == len(self.stations) + 4:
|
||||
return
|
||||
if len(self.current_train) > 0:
|
||||
self.current_train.append(None)
|
||||
self.game.notify_stations()
|
||||
|
||||
def peek(self, n_cards: int) -> list:
|
||||
return self.cards[:n_cards]
|
||||
|
||||
def peek_scrap_pile(self, n_cards: int=1) -> List[cs.Card]:
|
||||
def peek_scrap_pile(self) -> cs.Card:
|
||||
if len(self.scrap_pile) > 0:
|
||||
return self.scrap_pile[-n_cards:]
|
||||
return self.scrap_pile[-1]
|
||||
else:
|
||||
return None
|
||||
|
||||
@ -161,15 +141,7 @@ class Deck:
|
||||
and len(self.scrap_pile) > 0
|
||||
and not ignore_event
|
||||
):
|
||||
card = self.draw_from_scrap_pile()
|
||||
if player is not None and self.game.replay_speed > 0:
|
||||
G.sio.emit(
|
||||
"card_drawn",
|
||||
room=self.game.name,
|
||||
data={"player": player.name, "pile": "scrap"},
|
||||
)
|
||||
player.hand.append(card)
|
||||
return card
|
||||
return self.draw_from_scrap_pile()
|
||||
card = self.cards.pop(0)
|
||||
if len(self.cards) == 0:
|
||||
self.reshuffle()
|
||||
@ -196,7 +168,7 @@ class Deck:
|
||||
else:
|
||||
return self.draw()
|
||||
|
||||
def scrap(self, card: cs.Card, ignore_event:bool=False, player:'Player'=None):
|
||||
def scrap(self, card: cs.Card, ignore_event=False, player=None):
|
||||
if card.number == 42:
|
||||
return
|
||||
card.reset_card()
|
||||
|
@ -9,61 +9,11 @@ class DodgeCity():
|
||||
from bang.expansions.dodge_city import cards
|
||||
return cards.get_starting_deck()
|
||||
|
||||
def get_expansion_info(self):
|
||||
return {
|
||||
"id": "dodge_city",
|
||||
"name": "Dodge City",
|
||||
"cards": [
|
||||
{"type": "characters", "cards": DodgeCity.get_characters()},
|
||||
{"type": "cards", "cards": DodgeCity.get_cards()}
|
||||
]
|
||||
}
|
||||
|
||||
class HighNoon():
|
||||
def get_events():
|
||||
from bang.expansions.high_noon import card_events
|
||||
return card_events.get_all_events() + [card_events.get_endgame_card()]
|
||||
|
||||
def get_expansion_info(self):
|
||||
return {
|
||||
"id": "high_noon",
|
||||
"name": "High Noon",
|
||||
"cards": [
|
||||
{"type": "events", "cards": HighNoon.get_events()}
|
||||
]
|
||||
}
|
||||
class FistfulOfCards():
|
||||
def get_events():
|
||||
from bang.expansions.fistful_of_cards import card_events
|
||||
return card_events.get_all_events() + [card_events.get_endgame_card()]
|
||||
|
||||
def get_expansion_info(self):
|
||||
return {
|
||||
"id": "fistful_of_cards",
|
||||
"name": "Fistful of Cards",
|
||||
"cards": [
|
||||
{"type": "events", "cards": FistfulOfCards.get_events()}
|
||||
]
|
||||
}
|
||||
class GoldRush():
|
||||
def get_characters():
|
||||
from bang.expansions.gold_rush import characters
|
||||
return characters.all_characters()
|
||||
|
||||
def get_shop_cards():
|
||||
from bang.expansions.gold_rush import shop_cards
|
||||
return shop_cards.get_cards()
|
||||
|
||||
def get_expansion_info(self):
|
||||
return {
|
||||
"id": "gold_rush",
|
||||
"name": "Gold Rush",
|
||||
"cards": [
|
||||
{"type": "characters", "cards": GoldRush.get_characters()},
|
||||
{"type": "cards", "cards": GoldRush.get_shop_cards()}
|
||||
]
|
||||
}
|
||||
|
||||
class TheValleyOfShadows():
|
||||
def get_characters():
|
||||
from bang.expansions.the_valley_of_shadows import characters
|
||||
@ -73,74 +23,7 @@ class TheValleyOfShadows():
|
||||
from bang.expansions.the_valley_of_shadows import cards
|
||||
return cards.get_starting_deck()
|
||||
|
||||
def get_expansion_info(self):
|
||||
return {
|
||||
"id": "the_valley_of_shadows",
|
||||
"name": "The Valley of Shadows",
|
||||
"cards": [
|
||||
{"type": "characters", "cards": TheValleyOfShadows.get_characters()},
|
||||
{"type": "cards", "cards": TheValleyOfShadows.get_cards()}
|
||||
]
|
||||
}
|
||||
|
||||
class WildWestShow():
|
||||
def get_characters():
|
||||
from bang.expansions.wild_west_show import characters
|
||||
return characters.all_characters()
|
||||
|
||||
def get_events():
|
||||
from bang.expansions.wild_west_show import card_events
|
||||
return card_events.get_all_events() + [card_events.get_endgame_card()]
|
||||
|
||||
def get_expansion_info(self):
|
||||
return {
|
||||
"id": "wild_west_show",
|
||||
"name": "Wild West Show",
|
||||
"cards": [
|
||||
{"type": "characters", "cards": WildWestShow.get_characters()},
|
||||
{"type": "events", "cards": WildWestShow.get_events()}
|
||||
]
|
||||
}
|
||||
|
||||
class TrainRobbery():
|
||||
def get_stations():
|
||||
from bang.expansions.train_robbery import stations
|
||||
return stations.get_all_stations()
|
||||
|
||||
def get_trains():
|
||||
from bang.expansions.train_robbery import trains
|
||||
return trains.get_all_cards() + trains.get_locomotives()
|
||||
|
||||
def get_expansion_info(self):
|
||||
return {
|
||||
"id": "train_robbery",
|
||||
"name": "Train Robbery",
|
||||
"cards": [
|
||||
{"type": "stations", "cards": TrainRobbery.get_stations()},
|
||||
{"type": "trains", "cards": TrainRobbery.get_trains()}
|
||||
]
|
||||
}
|
||||
|
||||
def get_expansion_info(expansion_id):
|
||||
expansion_map = {
|
||||
"dodge_city": DodgeCity(),
|
||||
"high_noon": HighNoon(),
|
||||
"fistful_of_cards": FistfulOfCards(),
|
||||
"gold_rush": GoldRush(),
|
||||
"the_valley_of_shadows": TheValleyOfShadows(),
|
||||
"wild_west_show": WildWestShow(),
|
||||
"train_robbery": TrainRobbery()
|
||||
}
|
||||
|
||||
expansion_info = expansion_map[expansion_id].get_expansion_info()
|
||||
|
||||
for section in expansion_info["cards"]:
|
||||
unique_cards = []
|
||||
seen_card = set()
|
||||
for card in section["cards"]:
|
||||
if card.name not in seen_card:
|
||||
unique_cards.append(card)
|
||||
seen_card.add(card.name)
|
||||
section["cards"] = unique_cards
|
||||
|
||||
return expansion_info
|
@ -2,25 +2,22 @@ from bang.cards import *
|
||||
import bang.expansions.fistful_of_cards.card_events as ce
|
||||
from globals import G
|
||||
|
||||
|
||||
class Binocolo(Mirino):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Binocolo"
|
||||
self.icon = "🔍"
|
||||
|
||||
self.name = 'Binocolo'
|
||||
self.icon = '🔍'
|
||||
|
||||
class Riparo(Mustang):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Riparo"
|
||||
self.icon = "⛰"
|
||||
|
||||
self.name = 'Riparo'
|
||||
self.icon = '⛰'
|
||||
|
||||
class Pugno(Card):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, "Pugno!", number, range=1)
|
||||
self.icon = "👊"
|
||||
super().__init__(suit, 'Pugno!', number, range=1)
|
||||
self.icon = '👊'
|
||||
self.alt_text = "1🔎 💥"
|
||||
# self.desc = "Spara a un giocatore a distanza 1"
|
||||
# self.desc_eng = "Shoot a player at distance 1"
|
||||
@ -33,12 +30,11 @@ class Pugno(Card):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Schivata(Mancato):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Schivata"
|
||||
self.icon = "🙅♂️"
|
||||
self.name = 'Schivata'
|
||||
self.icon = '🙅♂️'
|
||||
# self.desc += " e poi pesca una carta"
|
||||
# self.desc_eng += " and then draw a card."
|
||||
self.alt_text = "😅 | 🎴"
|
||||
@ -50,44 +46,37 @@ class Schivata(Mancato):
|
||||
player.game.deck.draw(True, player=player)
|
||||
player.notify_self()
|
||||
|
||||
|
||||
class RagTime(Panico):
|
||||
def __init__(self, suit, number):
|
||||
Card.__init__(self, suit, "Rag Time", number)
|
||||
self.icon = "🎹"
|
||||
Card.__init__(self, suit, 'Rag Time', number)
|
||||
self.icon = '🎹'
|
||||
# self.desc = "Ruba 1 carta da un giocatore a prescindere dalla distanza"
|
||||
# self.desc_eng = "Steal a card from another player at any distance"
|
||||
self.need_target = True
|
||||
self.need_with = True
|
||||
self.alt_text = "2🃏 | 👤😱"
|
||||
self.alt_text = '2🃏 | 👤😱'
|
||||
|
||||
def play_card(self, player, against, _with):
|
||||
if against is not None and _with is not None:
|
||||
player.game.deck.scrap(_with)
|
||||
super().play_card(player, against=against, _with=_with)
|
||||
super().play_card(player, against=against)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Rissa(CatBalou):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Rissa"
|
||||
self.icon = "🥊"
|
||||
self.name = 'Rissa'
|
||||
self.icon = '🥊'
|
||||
# self.desc = "Fai scartare una carta a tutti gli altri giocatori, scegli a caso dalla mano, oppure fra quelle che hanno in gioco"
|
||||
# self.desc_eng = "Choose a card to discard from the hand/equipment of all the other players"
|
||||
self.need_with = True
|
||||
self.need_target = False
|
||||
self.alt_text = "2🃏 | 👤💃"
|
||||
self.alt_text = '2🃏 | 👤💃'
|
||||
|
||||
def play_card(self, player, against, _with):
|
||||
if _with is not None:
|
||||
if not any(
|
||||
(
|
||||
p != player and (len(p.hand) + len(p.equipment)) > 0
|
||||
for p in player.game.players
|
||||
)
|
||||
):
|
||||
if not any((p != player and (len(p.hand)+len(p.equipment)) > 0 for p in player.game.players)):
|
||||
return False
|
||||
#se sono qui vuol dire che ci sono giocatori con carte in mano oltre a me
|
||||
player.rissa_targets = []
|
||||
@ -97,43 +86,35 @@ class Rissa(CatBalou):
|
||||
player.rissa_targets.append(target)
|
||||
target = player.game.get_player_named(target.name, next=True)
|
||||
player.game.deck.scrap(_with)
|
||||
player.event_type = "rissa"
|
||||
print(f"rissa targets: {player.rissa_targets}")
|
||||
super().play_card(
|
||||
player, against=player.rissa_targets.pop(0).name, _with=_with
|
||||
)
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card|{player.name}|{self.name}",
|
||||
)
|
||||
player.event_type = 'rissa'
|
||||
print(f'rissa targets: {player.rissa_targets}')
|
||||
super().play_card(player, against=player.rissa_targets.pop(0).name)
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card|{player.name}|{self.name}')
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class SpringField(Card):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, "Springfield", number)
|
||||
self.icon = "🌵"
|
||||
super().__init__(suit, 'Springfield', number)
|
||||
self.icon = '🌵'
|
||||
# self.desc = "Spara a un giocatore a prescindere dalla distanza"
|
||||
# self.desc_eng = "Shoot a player at any distance"
|
||||
self.need_target = True
|
||||
self.need_with = True
|
||||
self.alt_text = "2🃏 | 👤💥"
|
||||
self.alt_text = '2🃏 | 👤💥'
|
||||
|
||||
def play_card(self, player, against, _with=None):
|
||||
if against is not None and _with is not None:
|
||||
player.game.deck.scrap(_with)
|
||||
super().play_card(player, against=against, _with=_with)
|
||||
super().play_card(player, against=against)
|
||||
player.game.attack(player, against, card_name=self.name)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Tequila(Card):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, "Tequila", number)
|
||||
self.icon = "🍹"
|
||||
super().__init__(suit, 'Tequila', number)
|
||||
self.icon = '🍹'
|
||||
# self.desc = "Fai recuperare 1 vita a un giocatore a tua scelta, anche te stesso"
|
||||
# self.desc_eng = "Heal 1 HP to a player of your choice (can be you)"
|
||||
self.need_target = True
|
||||
@ -143,45 +124,36 @@ class Tequila(Card):
|
||||
|
||||
def play_card(self, player, against, _with=None):
|
||||
if against is not None and _with is not None:
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_for|{player.name}|{self.name}|{against}",
|
||||
)
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card_for|{player.name}|{self.name}|{against}')
|
||||
player.game.deck.scrap(_with)
|
||||
player.game.get_player_named(against).lives = min(
|
||||
player.game.get_player_named(against).lives + 1,
|
||||
player.game.get_player_named(against).max_lives,
|
||||
)
|
||||
player.game.get_player_named(against).lives = min(player.game.get_player_named(against).lives+1, player.game.get_player_named(against).max_lives)
|
||||
player.game.get_player_named(against).notify_self()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Whisky(Card):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, "Whisky", number)
|
||||
self.icon = "🥃"
|
||||
super().__init__(suit, 'Whisky', number)
|
||||
self.icon = '🥃'
|
||||
# self.desc = "Gioca questa carta per recuperare fino a 2 punti vita"
|
||||
# self.desc_eng = "Heal 2 HP"
|
||||
self.need_with = True
|
||||
self.alt_text = "2🃏 | 🍺🍺"
|
||||
self.alt_text = '2🃏 | 🍺🍺'
|
||||
|
||||
def play_card(self, player, against, _with=None):
|
||||
if _with is not None:
|
||||
super().play_card(player, against=against, _with=_with)
|
||||
super().play_card(player, against=against)
|
||||
player.game.deck.scrap(_with)
|
||||
player.lives = min(player.lives+2, player.max_lives)
|
||||
player.notify_self()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Bibbia(Schivata):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Bibbia"
|
||||
self.icon = "📖"
|
||||
self.name = 'Bibbia'
|
||||
self.icon = '📖'
|
||||
self.usable_next_turn = True
|
||||
self.can_be_used_now = False
|
||||
|
||||
@ -190,26 +162,18 @@ class Bibbia(Schivata):
|
||||
pass
|
||||
return False
|
||||
else:
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class Cappello(Mancato):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Cappello"
|
||||
self.icon = "🧢"
|
||||
self.name = 'Cappello'
|
||||
self.icon = '🧢'
|
||||
self.usable_next_turn = True
|
||||
self.can_be_used_now = False
|
||||
self.alt_text = "😅"
|
||||
@ -220,40 +184,30 @@ class Cappello(Mancato):
|
||||
return False
|
||||
else:
|
||||
self.reset_card()
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class PlaccaDiFerro(Cappello):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Placca Di Ferro"
|
||||
self.icon = "🛡"
|
||||
|
||||
self.name = 'Placca Di Ferro'
|
||||
self.icon = '🛡'
|
||||
|
||||
class Sombrero(Cappello):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Sombrero"
|
||||
self.icon = "👒"
|
||||
|
||||
self.name = 'Sombrero'
|
||||
self.icon = '👒'
|
||||
|
||||
class Pugnale(Pugno):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Pugnale"
|
||||
self.icon = "🗡"
|
||||
self.name = 'Pugnale'
|
||||
self.icon = '🗡'
|
||||
self.usable_next_turn = True
|
||||
self.can_be_used_now = False
|
||||
|
||||
@ -262,27 +216,19 @@ class Pugnale(Pugno):
|
||||
return super().play_card(player, against=against)
|
||||
else:
|
||||
self.reset_card()
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class Derringer(Pugnale):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Derringer"
|
||||
self.icon = "🚬"
|
||||
self.alt_text += " 🎴"
|
||||
self.name = 'Derringer'
|
||||
self.icon = '🚬'
|
||||
self.alt_text += ' 🎴'
|
||||
# self.desc += ' e poi pesca una carta'
|
||||
# self.desc_eng += ' and then draw a card.'
|
||||
|
||||
@ -291,15 +237,8 @@ class Derringer(Pugnale):
|
||||
player.game.deck.draw(True, player=player)
|
||||
return super().play_card(player, against=against)
|
||||
else:
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
@ -309,11 +248,10 @@ class Derringer(Pugnale):
|
||||
player.game.deck.draw(True, player=player)
|
||||
player.notify_self()
|
||||
|
||||
|
||||
class Borraccia(Card):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, "Borraccia", number)
|
||||
self.icon = "🍼"
|
||||
super().__init__(suit, 'Borraccia', number)
|
||||
self.icon = '🍼'
|
||||
# self.desc = 'Recupera 1 vita'
|
||||
# self.desc_eng = 'Regain 1 HP'
|
||||
self.alt_text = "🍺"
|
||||
@ -327,26 +265,18 @@ class Borraccia(Card):
|
||||
player.notify_self()
|
||||
return True
|
||||
else:
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class PonyExpress(WellsFargo):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Pony Express"
|
||||
self.icon = "🦄"
|
||||
self.name = 'Pony Express'
|
||||
self.icon = '🦄'
|
||||
self.alt_text = "🎴🎴🎴"
|
||||
self.usable_next_turn = True
|
||||
self.can_be_used_now = False
|
||||
@ -355,26 +285,18 @@ class PonyExpress(WellsFargo):
|
||||
if self.can_be_used_now:
|
||||
return super().play_card(player, against)
|
||||
else:
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class Howitzer(Gatling):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Howitzer"
|
||||
self.icon = "📡"
|
||||
self.name = 'Howitzer'
|
||||
self.icon = '📡'
|
||||
self.alt_text = "👥💥"
|
||||
self.usable_next_turn = True
|
||||
self.can_be_used_now = False
|
||||
@ -383,21 +305,13 @@ class Howitzer(Gatling):
|
||||
if self.can_be_used_now:
|
||||
return super().play_card(player, against)
|
||||
else:
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class CanCan(CatBalou):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
@ -411,24 +325,16 @@ class CanCan(CatBalou):
|
||||
if self.can_be_used_now:
|
||||
return super().play_card(player, against)
|
||||
else:
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class Conestoga(Panico):
|
||||
def __init__(self, suit, number):
|
||||
Card.__init__(self, suit, "Conestoga", number)
|
||||
Card.__init__(self, suit, 'Conestoga', number)
|
||||
self.icon = "🏕"
|
||||
# self.desc = "Ruba 1 carta da un giocatore a prescindere dalla distanza"
|
||||
# self.desc_eng = "Steal a card from another player at any distance"
|
||||
@ -441,26 +347,18 @@ class Conestoga(Panico):
|
||||
if self.can_be_used_now:
|
||||
return super().play_card(player, against)
|
||||
else:
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class Pepperbox(Bang):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, number)
|
||||
self.name = "Pepperbox"
|
||||
self.icon = "🌶"
|
||||
self.name = 'Pepperbox'
|
||||
self.icon = '🌶'
|
||||
self.alt_text = "💥"
|
||||
self.usable_next_turn = True
|
||||
self.can_be_used_now = False
|
||||
@ -473,25 +371,17 @@ class Pepperbox(Bang):
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class FucileDaCaccia(Card):
|
||||
def __init__(self, suit, number):
|
||||
super().__init__(suit, "Fucile Da Caccia", number)
|
||||
self.icon = "🌂"
|
||||
super().__init__(suit, 'Fucile Da Caccia', number)
|
||||
self.icon = '🌂'
|
||||
# self.desc = "Spara a un giocatore a prescindere dalla distanza"
|
||||
self.alt_text = "👤💥"
|
||||
self.need_target = True
|
||||
@ -506,66 +396,58 @@ class FucileDaCaccia(Card):
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(
|
||||
ce.IlGiudice
|
||||
):
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
self.reset_card()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=player.game.name,
|
||||
data=f"_play_card_green|{player.name}|{self.name}",
|
||||
)
|
||||
player.equipment.append(self)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# pylint: disable=function-redefined
|
||||
def get_starting_deck() -> List[Card]:
|
||||
cards = [
|
||||
Barile(Suit.CLUBS, "A"),
|
||||
Barile(Suit.CLUBS, 'A'),
|
||||
Binocolo(Suit.DIAMONDS, 10),
|
||||
Dinamite(Suit.CLUBS, 10),
|
||||
Mustang(Suit.HEARTS, 5),
|
||||
Remington(Suit.DIAMONDS, 6),
|
||||
RevCarabine(Suit.SPADES, 5),
|
||||
Riparo(Suit.DIAMONDS, "K"),
|
||||
Riparo(Suit.DIAMONDS, 'K'),
|
||||
Bang(Suit.SPADES, 8),
|
||||
Bang(Suit.CLUBS, 5),
|
||||
Bang(Suit.CLUBS, 6),
|
||||
Bang(Suit.CLUBS, "K"),
|
||||
Bang(Suit.CLUBS, 'K'),
|
||||
Birra(Suit.HEARTS, 6),
|
||||
Birra(Suit.SPADES, 6),
|
||||
CatBalou(Suit.CLUBS, 8),
|
||||
Emporio(Suit.SPADES, "A"),
|
||||
Emporio(Suit.SPADES, 'A'),
|
||||
Indiani(Suit.DIAMONDS, 5),
|
||||
Mancato(Suit.DIAMONDS, 8),
|
||||
Panico(Suit.HEARTS, "J"),
|
||||
Panico(Suit.HEARTS, 'J'),
|
||||
Pugno(Suit.SPADES, 10),
|
||||
RagTime(Suit.HEARTS, 9),
|
||||
Rissa(Suit.SPADES, "J"),
|
||||
Rissa(Suit.SPADES, 'J'),
|
||||
Schivata(Suit.DIAMONDS, 7),
|
||||
Schivata(Suit.HEARTS, "K"),
|
||||
SpringField(Suit.SPADES, "K"),
|
||||
Schivata(Suit.HEARTS, 'K'),
|
||||
SpringField(Suit.SPADES, 'K'),
|
||||
Tequila(Suit.CLUBS, 9),
|
||||
Whisky(Suit.HEARTS, "Q"),
|
||||
Whisky(Suit.HEARTS, 'Q'),
|
||||
Bibbia(Suit.HEARTS, 10),
|
||||
Cappello(Suit.DIAMONDS, "J"),
|
||||
PlaccaDiFerro(Suit.DIAMONDS, "A"),
|
||||
PlaccaDiFerro(Suit.SPADES, "Q"),
|
||||
Cappello(Suit.DIAMONDS, 'J'),
|
||||
PlaccaDiFerro(Suit.DIAMONDS, 'A'),
|
||||
PlaccaDiFerro(Suit.SPADES, 'Q'),
|
||||
Sombrero(Suit.CLUBS, 7),
|
||||
Pugnale(Suit.HEARTS, 8),
|
||||
Derringer(Suit.SPADES, 7),
|
||||
Borraccia(Suit.HEARTS, 7),
|
||||
CanCan(Suit.CLUBS, "J"),
|
||||
CanCan(Suit.CLUBS, 'J'),
|
||||
Conestoga(Suit.DIAMONDS, 9),
|
||||
FucileDaCaccia(Suit.CLUBS, "Q"),
|
||||
PonyExpress(Suit.DIAMONDS, "Q"),
|
||||
Pepperbox(Suit.HEARTS, "A"),
|
||||
FucileDaCaccia(Suit.CLUBS, 'Q'),
|
||||
PonyExpress(Suit.DIAMONDS, 'Q'),
|
||||
Pepperbox(Suit.HEARTS, 'A'),
|
||||
Howitzer(Suit.SPADES, 9),
|
||||
]
|
||||
for c in cards:
|
||||
c.expansion_icon = "🐄️"
|
||||
c.expansion = "dodge_city"
|
||||
c.expansion_icon = '🐄️'
|
||||
c.expansion = 'dodge_city'
|
||||
return cards
|
||||
|
@ -1,6 +1,5 @@
|
||||
from typing import List
|
||||
from bang.characters import Character
|
||||
from globals import PendingAction
|
||||
|
||||
|
||||
class PixiePete(Character):
|
||||
@ -166,6 +165,8 @@ class DocHolyday(Character):
|
||||
|
||||
def special(self, player, data):
|
||||
if super().special(player, data):
|
||||
from bang.players import PendingAction
|
||||
|
||||
if (
|
||||
player.special_use_count < 1
|
||||
and player.pending_action == PendingAction.PLAY
|
||||
|
@ -1,4 +1,3 @@
|
||||
from typing import TYPE_CHECKING
|
||||
from abc import ABC, abstractmethod
|
||||
import random
|
||||
import bang.players as players
|
||||
@ -7,9 +6,6 @@ import bang.cards as cs
|
||||
|
||||
from globals import G
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bang.game import Game
|
||||
|
||||
|
||||
class CardEvent(ABC):
|
||||
"""Base class for all event cards"""
|
||||
@ -18,7 +14,7 @@ class CardEvent(ABC):
|
||||
self.name = name
|
||||
self.icon = icon
|
||||
|
||||
def on_flipped(self, game: "Game"):
|
||||
def on_flipped(self, game):
|
||||
"""Default on flipped event
|
||||
|
||||
Args:
|
||||
|
@ -1,26 +1,23 @@
|
||||
from typing import List
|
||||
from bang.characters import Character
|
||||
|
||||
|
||||
class DonBell(Character):
|
||||
def __init__(self):
|
||||
super().__init__("Don Bell", max_lives=4)
|
||||
# A fine turno estrae, ❤️ o ♦️ gioca di nuovo
|
||||
self.icon = "🔔️"
|
||||
|
||||
self.icon = '🔔️'
|
||||
|
||||
class DutchWill(Character):
|
||||
def __init__(self):
|
||||
super().__init__("Dutch Will", max_lives=4)
|
||||
# Pesca 2 ne scarta 1 e prende 1 pepita
|
||||
self.icon = "🧐️"
|
||||
|
||||
self.icon = '🧐️'
|
||||
|
||||
class JackyMurieta(Character):
|
||||
def __init__(self):
|
||||
super().__init__("Jacky Murieta", max_lives=4)
|
||||
# puo pagare 2 pepite per sparare 1 bang extra
|
||||
self.icon = "💆♂️️"
|
||||
self.icon = '💆♂️️'
|
||||
|
||||
def special(self, player, data):
|
||||
if super().special(player, data):
|
||||
@ -32,55 +29,45 @@ class JackyMurieta(Character):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class JoshMcCloud(Character):
|
||||
def __init__(self):
|
||||
super().__init__("Josh McCloud", max_lives=4)
|
||||
# puo pagare 2 pepite per pescare il primo equipaggiamento dalla pila gold rush
|
||||
self.icon = "⛅️"
|
||||
self.icon = '⛅️'
|
||||
|
||||
def special(self, player, data):
|
||||
if super().special(player, data):
|
||||
if player.gold_nuggets >= 2 and player.is_my_turn:
|
||||
player.gold_nuggets -= 2
|
||||
card = player.game.deck.shop_deck.pop(0)
|
||||
print(
|
||||
f"{player.name} ha comprato usando la abilità speciale {card.name}"
|
||||
)
|
||||
print(f'{player.name} ha comprato usando la abilità speciale {card.name}')
|
||||
if card.play_card(player):
|
||||
player.game.deck.shop_deck.append(card)
|
||||
player.notify_self()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class MadamYto(Character):
|
||||
def __init__(self):
|
||||
super().__init__("Madam Yto", max_lives=4)
|
||||
# quando viene giocata 1 birra pesca 1 carta
|
||||
self.icon = "💃️"
|
||||
|
||||
self.icon = '💃️'
|
||||
|
||||
class PrettyLuzena(Character):
|
||||
def __init__(self):
|
||||
super().__init__("Pretty Luzena", max_lives=4)
|
||||
# una volta per turno ha 1 sconto di 1 pepita sugli equipaggiamenti
|
||||
self.icon = "👛️"
|
||||
|
||||
self.icon = '👛️'
|
||||
|
||||
class RaddieSnake(Character):
|
||||
def __init__(self):
|
||||
super().__init__("Raddie Snake", max_lives=4)
|
||||
# può scartare 1 pepita per pescare 1 carta (2 volte per turno)
|
||||
self.icon = "🐍️"
|
||||
self.icon = '🐍️'
|
||||
|
||||
def special(self, player, data):
|
||||
if super().special(player, data):
|
||||
if (
|
||||
player.gold_nuggets >= 1
|
||||
and player.is_my_turn
|
||||
and player.special_use_count < 2
|
||||
):
|
||||
if player.gold_nuggets >= 1 and player.is_my_turn and player.special_use_count < 2:
|
||||
player.gold_nuggets -= 1
|
||||
player.special_use_count += 1
|
||||
player.game.deck.draw(True, player=player)
|
||||
@ -88,12 +75,11 @@ class RaddieSnake(Character):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class SimeonPicos(Character):
|
||||
def __init__(self):
|
||||
super().__init__("Simeon Picos", max_lives=4)
|
||||
# ottiene 1 pepita ogni volta che perde 1 punto vita
|
||||
self.icon = "🥲"
|
||||
self.icon = '🥲'
|
||||
|
||||
|
||||
def all_characters() -> List[Character]:
|
||||
@ -108,6 +94,6 @@ def all_characters() -> List[Character]:
|
||||
SimeonPicos(),
|
||||
]
|
||||
for c in cards:
|
||||
c.expansion_icon = "🤑️"
|
||||
c.expansion = "gold_rush"
|
||||
c.expansion_icon = '🤑️'
|
||||
c.expansion = 'gold_rush'
|
||||
return cards
|
||||
|
@ -1,7 +1,7 @@
|
||||
from bang.cards import *
|
||||
import bang.roles as r
|
||||
import bang.players as pl
|
||||
from globals import G, PendingAction
|
||||
from globals import G
|
||||
|
||||
class ShopCardKind(IntEnum):
|
||||
BROWN = 0 # Se l’equipaggiamento ha il bordo marrone, applicane subito l’effetto e poi scartalo.
|
||||
@ -47,7 +47,7 @@ class Bicchierino(ShopCard):
|
||||
'is_player': True
|
||||
} for p in player.game.get_alive_players()]
|
||||
player.choose_text = 'choose_bicchierino'
|
||||
player.pending_action = PendingAction.CHOOSE
|
||||
player.pending_action = pl.PendingAction.CHOOSE
|
||||
player.notify_self()
|
||||
return super().play_card(player, against, _with)
|
||||
|
||||
@ -64,7 +64,7 @@ class Bottiglia(ShopCard):
|
||||
for i in range(len(player.available_cards)):
|
||||
player.available_cards[i].must_be_used = True
|
||||
player.choose_text = 'choose_bottiglia'
|
||||
player.pending_action = PendingAction.CHOOSE
|
||||
player.pending_action = pl.PendingAction.CHOOSE
|
||||
player.notify_self()
|
||||
return super().play_card(player, against, _with)
|
||||
|
||||
@ -79,7 +79,7 @@ class Complice(ShopCard):
|
||||
for i in range(len(player.available_cards)):
|
||||
player.available_cards[i].must_be_used = True
|
||||
player.choose_text = 'choose_complice'
|
||||
player.pending_action = PendingAction.CHOOSE
|
||||
player.pending_action = pl.PendingAction.CHOOSE
|
||||
player.notify_self()
|
||||
return super().play_card(player, against, _with)
|
||||
|
||||
@ -175,7 +175,7 @@ class Ricercato(ShopCard):
|
||||
} for p in player.game.get_alive_players() if p != player and not isinstance(p.role, r.Sheriff)]
|
||||
player.available_cards.append({'name': player.name, 'number':0,'icon': 'you', 'is_character': True})
|
||||
player.choose_text = 'choose_ricercato'
|
||||
player.pending_action = PendingAction.CHOOSE
|
||||
player.pending_action = pl.PendingAction.CHOOSE
|
||||
player.notify_self()
|
||||
return True
|
||||
# la giochi su un altro giocatore, ricompensa di 2 carte e 1 pepita a chi lo uccide
|
||||
|
@ -3,7 +3,7 @@ import bang.roles as r
|
||||
import bang.players as pl
|
||||
from bang.cards import Card, Suit, Bang, Mancato
|
||||
import bang.expansions.fistful_of_cards.card_events as ce
|
||||
from globals import G, PendingAction
|
||||
from globals import G
|
||||
|
||||
|
||||
class Fantasma(Card):
|
||||
@ -15,7 +15,7 @@ class Fantasma(Card):
|
||||
if (player.game.check_event(ce.IlGiudice)) or not self.can_be_used_now:
|
||||
return False
|
||||
if len(player.game.get_dead_players(include_ghosts=False)) > 0:
|
||||
player.pending_action = PendingAction.CHOOSE
|
||||
player.pending_action = pl.PendingAction.CHOOSE
|
||||
player.choose_text = "choose_fantasma"
|
||||
player.available_cards = [
|
||||
{
|
||||
@ -60,7 +60,11 @@ class Lemat(Card):
|
||||
for p in player.game.get_visible_players(player)
|
||||
)
|
||||
):
|
||||
player.set_choose_action("choose_play_as_bang", player.hand.copy())
|
||||
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
|
||||
|
||||
@ -181,7 +185,7 @@ class Sventagliata(
|
||||
if p["name"] != player.name and p["name"] != t.name and p["dist"]
|
||||
]
|
||||
if len(player.available_cards) > 0:
|
||||
player.pending_action = PendingAction.CHOOSE
|
||||
player.pending_action = pl.PendingAction.CHOOSE
|
||||
player.choose_text = "choose_sventagliata"
|
||||
else:
|
||||
player.available_cards = []
|
||||
|
@ -21,11 +21,12 @@ class BlackFlower(Character):
|
||||
for p in player.game.get_visible_players(player)
|
||||
)
|
||||
) and super().special(player, data):
|
||||
from bang.players import PendingAction
|
||||
|
||||
player.available_cards = [c for c in player.hand if c.suit == cs.Suit.CLUBS]
|
||||
player.special_use_count += 1
|
||||
player.set_choose_action(
|
||||
"choose_play_as_bang",
|
||||
[c for c in player.hand if c.suit == cs.Suit.CLUBS],
|
||||
)
|
||||
player.pending_action = PendingAction.CHOOSE
|
||||
player.choose_text = "choose_play_as_bang"
|
||||
player.notify_self()
|
||||
|
||||
|
||||
|
@ -1,315 +0,0 @@
|
||||
from typing import TYPE_CHECKING
|
||||
import bang.cards as cs
|
||||
from globals import PendingAction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bang.players import Player
|
||||
|
||||
|
||||
class StationCard:
|
||||
def __init__(self, name: str):
|
||||
self.name = name
|
||||
self.expansion = "train_robbery"
|
||||
self.price: list[dict] = []
|
||||
self.attached_train = None
|
||||
|
||||
def discard_and_buy_train(self, player: "Player", card_index: int):
|
||||
"""Discard the card and buy the train"""
|
||||
if self.attached_train is None:
|
||||
return
|
||||
card = player.available_cards.pop(card_index)
|
||||
for i, card in enumerate(player.hand):
|
||||
if card == self:
|
||||
player.hand.pop(i)
|
||||
break
|
||||
else:
|
||||
player.lives -= 1
|
||||
card = player.hand.pop(card_index)
|
||||
player.game.deck.scrap(card, True, player=player)
|
||||
player.equipment.append(self.attached_train)
|
||||
self.attached_train = None
|
||||
player.pending_action = PendingAction.PLAY
|
||||
|
||||
def check_price(self, player: "Player") -> bool:
|
||||
"""Check if the card can be used to rob the train"""
|
||||
return len(player.hand) > 0
|
||||
|
||||
|
||||
class BoomTown(StationCard):
|
||||
"""Discard a Bang! to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Boom Town")
|
||||
self.price = [cs.Bang(0, 0).__dict__]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
not isinstance(c, cs.Bang) for c in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[c for c in player.hand if isinstance(c, cs.Bang)],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class Caticor(StationCard):
|
||||
"""Discard a Cat Balou or Panico to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Caticor")
|
||||
self.price = [cs.CatBalou(0, 0).__dict__, cs.Panico(0, 0).__dict__]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
not (isinstance(card, cs.CatBalou) or isinstance(card, cs.Panico))
|
||||
for card in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[
|
||||
c
|
||||
for c in player.hand
|
||||
if isinstance(c, cs.CatBalou) or isinstance(c, cs.Panico)
|
||||
],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class CreepyCreek(StationCard):
|
||||
"""Discard a card of spades to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Creepy Creek")
|
||||
self.price = [{"icon": "♠️"}]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
card.suit != cs.Suit.SPADES for card in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[c for c in player.hand if c.suit == cs.Suit.SPADES],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class CrownsHole(StationCard):
|
||||
"""Discard a beer to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Crowns Hole")
|
||||
self.price = [cs.Birra(0, 0).__dict__]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
not isinstance(card, cs.Birra) for card in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[c for c in player.hand if isinstance(c, cs.Birra)],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class Deadwood(StationCard):
|
||||
"""Discard an equipment card to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Deadwood")
|
||||
self.price = [{"is_equipment": True}]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
not card.is_equipment for card in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[c for c in player.hand if c.is_equipment],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class Dodgeville(StationCard):
|
||||
"""Discard a Missed! to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Dodgeville")
|
||||
self.price = [cs.Mancato(0, 0).__dict__]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
not isinstance(card, cs.Mancato) for card in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[c for c in player.hand if isinstance(c, cs.Mancato)],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class FortWorth(StationCard):
|
||||
"""Discard a card with number 10, J, Q, K, A to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Fort Worth")
|
||||
self.price = [{"icon": "10\nJ\nQ\nK\nA"}]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
card.number not in {1, 10, 11, 12, 13} for card in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[c for c in player.hand if c.number in {1, 10, 11, 12, 13}],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class Frisco(StationCard):
|
||||
"""Discard a card of clubs to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Frisco")
|
||||
self.price = [{"icon": "♣️"}]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
card.suit != cs.Suit.CLUBS for card in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[c for c in player.hand if c.suit == cs.Suit.CLUBS],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class MinersOath(StationCard):
|
||||
"""Discard a card of diamonds to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Miners Oath")
|
||||
self.price = [{"icon": "♦️"}]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
card.suit != cs.Suit.DIAMONDS for card in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[c for c in player.hand if c.suit == cs.Suit.DIAMONDS],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class SanTafe(StationCard):
|
||||
"""Discard a card of hearts to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("San Tafe")
|
||||
self.price = [{"icon": "♥️"}]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
card.suit != cs.Suit.HEARTS for card in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[c for c in player.hand if c.suit == cs.Suit.HEARTS],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class Tombrock(StationCard):
|
||||
"""Lose 1 life point to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Tombrock")
|
||||
self.price = [{"icon": "💔"}]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if player.lives <= 1:
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[{"icon": "💔"}],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class Yooma(StationCard):
|
||||
"""Discard a card with number between 2 and 9 to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Yooma")
|
||||
self.price = [{"icon": "2-9"}]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and all(
|
||||
not (2 <= card.number <= 9) for card in player.hand
|
||||
):
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
[c for c in player.hand if 2 <= c.number <= 9],
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class VirginiaTown(StationCard):
|
||||
"""Discard two cards to rob the train"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Virginia Town")
|
||||
self.price = [{}, {}]
|
||||
|
||||
def check_price(self, player: "Player"):
|
||||
if super().check_price(player) and len(player.hand) < 2:
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_buy_train",
|
||||
player.hand.copy(),
|
||||
self.discard_and_buy_train,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def get_all_stations():
|
||||
"""Return a list of all the station cards"""
|
||||
return [
|
||||
BoomTown(),
|
||||
Caticor(),
|
||||
CreepyCreek(),
|
||||
CrownsHole(),
|
||||
Deadwood(),
|
||||
Dodgeville(),
|
||||
FortWorth(),
|
||||
Frisco(),
|
||||
MinersOath(),
|
||||
SanTafe(),
|
||||
Tombrock(),
|
||||
Yooma(),
|
||||
VirginiaTown(),
|
||||
]
|
@ -1,406 +0,0 @@
|
||||
import random
|
||||
from bang.cards import Card, Bang, Panico, CatBalou, Mancato
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from globals import G, PendingAction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bang.players import Player
|
||||
|
||||
|
||||
class TrainCard(Card):
|
||||
def __init__(self, name: str, is_locomotive: bool = False):
|
||||
super().__init__(suit=5, number=0, name=name)
|
||||
self.expansion_icon = "🚂"
|
||||
self.is_equipment = True
|
||||
self.is_locomotive = is_locomotive
|
||||
self.expansion = "train_robbery"
|
||||
self.type = "train"
|
||||
self.implemented = True
|
||||
|
||||
|
||||
# Circus Wagon: gli altri giocatori
|
||||
# scartano una carta, in senso orario, a
|
||||
# partire dal giocatore alla tua sinistra.
|
||||
# Express Car: non puoi svolgere
|
||||
# un altro turno extra dopo quello
|
||||
# ottenuto da questo effetto, anche se
|
||||
# riesci a giocare di nuovo Express Car.
|
||||
|
||||
# Ghost Car: giocabile su un
|
||||
# qualsiasi giocatore, anche se già
|
||||
# eliminato, te compreso. Non può
|
||||
# essere giocato sullo Sceriffo.
|
||||
# Se quel giocatore è/viene eliminato,
|
||||
# invece ritorna/resta in gioco, senza
|
||||
# punti vita. Non può guadagnare né
|
||||
# perdere punti vita, e viene considerato
|
||||
# un personaggio in gioco per tutti gli
|
||||
# effetti (condizioni di vittoria, distanza
|
||||
# tra giocatori, abilità dei personaggi,
|
||||
# ecc.). Non avendo punti vita, deve
|
||||
# scartare la sua intera mano alla fine
|
||||
# del turno, ma può tenere qualsiasi
|
||||
# carta in gioco di fronte a sé, incluso
|
||||
# Ghost Car. Tuttavia, è eliminato
|
||||
# dal gioco non appena Ghost Car
|
||||
# viene scartato: nessuna ricompensa
|
||||
# viene assegnata in questo caso se il
|
||||
# giocatore è un Fuorilegge, e le abilità
|
||||
# dei personaggi (ad es. Vulture Sam)
|
||||
# non si attivano
|
||||
|
||||
# Lounge Car: i vagoni che peschi
|
||||
# non contano per il normale limite di
|
||||
# acquisizione di 1 vagone per turno. Se
|
||||
# sei lo Sceriffo e peschi Ghost Car, devi
|
||||
# darlo a un altro giocatore.
|
||||
|
||||
# Lumber Flatcar: gioca su un
|
||||
# qualsiasi giocatore (compreso te).
|
||||
# Finché questa carta è in gioco, quel
|
||||
# giocatore vede gli altri giocatori a
|
||||
# distanza aumentata di 1.
|
||||
|
||||
# Private Car: questo effetto non
|
||||
# ti protegge da Gatling, Knife Revolver,
|
||||
# l’abilità di Evan Babbit, e così via.
|
||||
# Sleeper Car: puoi anche usare
|
||||
# l’effetto una volta per turno con
|
||||
# Indiani!, Duello, ecc.
|
||||
|
||||
|
||||
class Ironhorse(TrainCard):
|
||||
"""LOCOMOTIVA:
|
||||
Ogni giocatore, incluso colui che ha attivato l'effetto, è bersaglio di un BANG!
|
||||
Nessun giocatore è responsabile dell'eventuale perdita di punti vita.
|
||||
Se tutti i giocatori vengono eliminati allo stesso tempo, i Fuorilegge vincono.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Ironhorse", is_locomotive=True)
|
||||
self.icon = "🚂"
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
player.game.attack(player, player.name, card_name=self.name)
|
||||
player.game.attack_others(player, card_name=self.name)
|
||||
return True
|
||||
|
||||
|
||||
class Leland(TrainCard):
|
||||
"""
|
||||
LOCOMOTIVA: svolgi l'effetto dell'Emporio, cominciando dal giocatore di turno e procedendo in senso orario.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Leland", is_locomotive=True)
|
||||
self.icon = "🚂"
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
player.game.emporio(player)
|
||||
return True
|
||||
|
||||
|
||||
class BaggageCar(TrainCard):
|
||||
"""Scartalo: ottieni l'effetto di un Mancato!, Panico!, Cat Balou o di un BANG! extra.
|
||||
Discard this for a Missed! Panic!, Cat Balou, or an extra BANG!"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Baggage Car")
|
||||
self.icon = "🚋🛄"
|
||||
|
||||
def choose_callback(self, player: 'Player', card_index):
|
||||
player.hand.append(player.available_cards[card_index])
|
||||
player.pending_action = PendingAction.PLAY
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
player.set_choose_action(
|
||||
"choose_baggage_car",
|
||||
[Bang(4, 42), Mancato(4, 42), CatBalou(4, 42), Panico(4, 42)],
|
||||
self.choose_callback,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class Caboose(TrainCard):
|
||||
"""Puoi scartare un altra tua carta bordo blu incuso un vagone come se fosse un Mancato!"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Caboose")
|
||||
self.icon = "🚋"
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class CattleTruck(TrainCard):
|
||||
"""Scartalo: guarda le 3 carte in cima agli scarti e pescane I"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Cattle Truck")
|
||||
self.icon = "🚋🐄"
|
||||
|
||||
def choose_card_callback(self, player: 'Player', card_index):
|
||||
chosen_card = player.available_cards.pop(card_index)
|
||||
player.game.deck.scrap_pile.pop(-card_index)
|
||||
player.hand.append(chosen_card)
|
||||
player.pending_action = PendingAction.PLAY
|
||||
player.notify_self()
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
drawn_cards = player.game.deck.peek_scrap_pile(n_cards=3)
|
||||
player.set_choose_action(
|
||||
"choose_cattle_truck",
|
||||
drawn_cards,
|
||||
self.choose_card_callback,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class CircusWagon(TrainCard):
|
||||
"""Scartalo: ogni altro giocatore deve scartare una carta che ha in gioco."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Circus Wagon", is_locomotive=True)
|
||||
self.icon = "🚋🎪"
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
player.game.discard_others(player, card_name=self.name)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def choose_circus_wagon(cls, player: 'Player', card_index):
|
||||
player.game.deck.scrap(player.hand.pop(card_index), player=player)
|
||||
player.pending_action = PendingAction.WAIT
|
||||
player.game.responders_did_respond_resume_turn()
|
||||
player.notify_self()
|
||||
|
||||
|
||||
|
||||
class CoalHopper(TrainCard):
|
||||
"""Scartalo: pesca una carta e scarta un vagone in gioco davanti a un giocatore a tua scelta."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Coal Hopper")
|
||||
self.icon = "🚋🔥"
|
||||
self.need_target = True
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
if against is not None and len(player.game.get_player_named(against).equipment) > 0:
|
||||
player.game.steal_discard(player, against, self)
|
||||
return True
|
||||
|
||||
|
||||
class DiningCar(TrainCard):
|
||||
"""A inizio turno, "estrai!": se è Cuori, recuperi I punto vita."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Dining Car")
|
||||
self.icon = "🚋🍽"
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class ExpressCar(TrainCard):
|
||||
"""Scarta tutte le carte in mano, poi gioca un altro turno"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Express Car")
|
||||
self.icon = "🚋⚡"
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
while len(player.hand) > 0:
|
||||
player.game.deck.scrap(player.hand.pop(0), player=player)
|
||||
player.notify_self()
|
||||
player.play_turn()
|
||||
return True
|
||||
|
||||
|
||||
class GhostCar(TrainCard):
|
||||
"""Giocalo su chiunque tranne lo Sceritfo. Se vieni eliminato, invece resta in gioco, ma non puo guadagnare ne perdere punti vita."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Ghost Car")
|
||||
self.icon = "🚋👻"
|
||||
self.implemented = False
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class LoungeCar(TrainCard):
|
||||
"""Scartalo: pesca 2 vagoni dal mazzo, mettine I in gioco di fronte a te e 1 di fronte a un altro giocatore."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Lounge Car")
|
||||
self.icon = "🚋🛋"
|
||||
self.implemented = False
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
class LumberFlatcar(TrainCard):
|
||||
"""Giocalo su un qualsiasi giocatore (compreso te). Finché questa carta è in gioco, quel giocatore vede gli altri giocatori a distanza aumentata di 1."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Lumber Flatcar")
|
||||
self.icon = "🚋🪵"
|
||||
self.sight_mod = -1
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class MailCar(TrainCard):
|
||||
"""Scartalo: pesca 3 carte e dai 1 di esse a un altro giocatore a tua scelta."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Mail Car")
|
||||
self.icon = "🚋📮"
|
||||
|
||||
def choose_card_callback(self, player: 'Player', card_index):
|
||||
chosen_card = player.available_cards.pop(card_index)
|
||||
player.hand.extend(player.available_cards)
|
||||
player.set_choose_action(
|
||||
"choose_other_player",
|
||||
player.game.get_other_players(player),
|
||||
lambda p, other_player_index: self.choose_player_callback(p, other_player_index, chosen_card)
|
||||
)
|
||||
|
||||
def choose_player_callback(self, player: 'Player', other_player_index, chosen_card):
|
||||
pl_name = player.game.get_other_players(player)[other_player_index]["name"]
|
||||
other_player = player.game.get_player_named(pl_name)
|
||||
other_player.hand.append(chosen_card)
|
||||
G.sio.emit(
|
||||
"card_drawn",
|
||||
room=player.game.name,
|
||||
data={"player": pl_name, "pile": player.name},
|
||||
)
|
||||
other_player.notify_self()
|
||||
player.pending_action = PendingAction.PLAY
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
drawn_cards = [player.game.deck.draw(player=player) for _ in range(3)]
|
||||
player.set_choose_action(
|
||||
"choose_mail_car",
|
||||
drawn_cards,
|
||||
self.choose_card_callback,
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class ObservationCar(TrainCard):
|
||||
"""Tu vedi gli altri a distanza -1. Gli altri a vedono a distanza +1."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Observation Car")
|
||||
self.icon = "🚋👀"
|
||||
self.sight_mod = 1
|
||||
self.vis_mod = 1
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class PassengerCar(TrainCard):
|
||||
"""Scartalo: pesca una carta (o in mano o in gioco) da un altro giocatore"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Passenger Car")
|
||||
self.icon = "🚋🚶"
|
||||
self.range = 99
|
||||
self.need_target = True
|
||||
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
if (
|
||||
against is not None
|
||||
and (len(player.equipment) > 0 or len(player.equipment) > 0)
|
||||
):
|
||||
player.game.steal_discard(player, against, self)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class PrisonerCar(TrainCard):
|
||||
"""Le carte Duello e Indiani! giocate dagli altri giocatori non hanno effetto su di te."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Prisoner Car")
|
||||
self.icon = "🚋👮🏻♂️"
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class PrivateCar(TrainCard):
|
||||
"""Se non hai carte in mano, non puoi essere bersaglio di carte BANG"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Private Car")
|
||||
self.icon = "🚋💁🏻"
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class SleeperCar(TrainCard):
|
||||
"""Una volta per turno, puoi scartare un'altra tua carta a bordo blu incluso."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Sleeper Car")
|
||||
self.icon = "🚋🛌"
|
||||
|
||||
def choose_card_callback(self, player: 'Player', card_index):
|
||||
player.game.deck.scrap(player.equipment.pop(card_index), player=player)
|
||||
player.pending_action = PendingAction.PLAY
|
||||
self.usable_next_turn = True
|
||||
self.can_be_used_now = False
|
||||
player.notify_self()
|
||||
|
||||
def play_card(self, player, against=None, _with=None) -> bool:
|
||||
if not self.can_be_used_now:
|
||||
return False
|
||||
player.set_choose_action(
|
||||
"choose_sleeper_car",
|
||||
player.equipment,
|
||||
self.choose_card_callback,
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def get_all_cards(rng=random):
|
||||
"""Return a list of all train cards in the expansion"""
|
||||
cars = [
|
||||
BaggageCar(),
|
||||
Caboose(),
|
||||
CattleTruck(),
|
||||
CircusWagon(),
|
||||
CoalHopper(),
|
||||
DiningCar(),
|
||||
ExpressCar(),
|
||||
GhostCar(),
|
||||
LoungeCar(),
|
||||
LumberFlatcar(),
|
||||
MailCar(),
|
||||
ObservationCar(),
|
||||
PassengerCar(),
|
||||
PrisonerCar(),
|
||||
PrivateCar(),
|
||||
SleeperCar(),
|
||||
]
|
||||
cars = [c for c in cars if c.implemented]
|
||||
rng.shuffle(cars)
|
||||
return cars
|
||||
|
||||
|
||||
def get_locomotives(rng=random):
|
||||
"""Return a list of all locomotive cards in the expansion"""
|
||||
locs = [
|
||||
Ironhorse(),
|
||||
Leland(),
|
||||
]
|
||||
rng.shuffle(locs)
|
||||
return locs
|
@ -7,16 +7,6 @@ from globals import G
|
||||
from bang.expansions.fistful_of_cards.card_events import CardEvent
|
||||
|
||||
|
||||
class WildWestShowCardEvent(CardEvent):
|
||||
"""
|
||||
Base class for all card events in the Wild West Show expansion
|
||||
"""
|
||||
|
||||
def __init__(self, name, icon):
|
||||
super().__init__(name, icon)
|
||||
self.expansion = "wild-west-show"
|
||||
|
||||
|
||||
# class Bavaglio(CardEvent):
|
||||
# def __init__(self):
|
||||
# super().__init__("Bavaglio", "🤐")
|
||||
@ -24,7 +14,7 @@ class WildWestShowCardEvent(CardEvent):
|
||||
# # NOT IMPLEMENTED
|
||||
|
||||
|
||||
class Camposanto(WildWestShowCardEvent):
|
||||
class Camposanto(CardEvent):
|
||||
"""
|
||||
All'inizio del proprio turno, ogni giocatore eliminato torna in gioco con 1 punto vita. Pesca il ruolo a caso fra quelli dei giocatori eliminati.
|
||||
"""
|
||||
@ -33,7 +23,7 @@ class Camposanto(WildWestShowCardEvent):
|
||||
super().__init__("Camposanto", "⚰")
|
||||
|
||||
|
||||
class DarlingValentine(WildWestShowCardEvent):
|
||||
class DarlingValentine(CardEvent):
|
||||
"""
|
||||
All'inizio del proprio turno, ogni giocatore scarta le carte in mano e ne pesca dal mazzo altrettante.
|
||||
"""
|
||||
@ -42,7 +32,7 @@ class DarlingValentine(WildWestShowCardEvent):
|
||||
super().__init__("Darling Valentine", "💋")
|
||||
|
||||
|
||||
class DorothyRage(WildWestShowCardEvent):
|
||||
class DorothyRage(CardEvent):
|
||||
"""
|
||||
Nel proprio turno, ogni giocatore può obbligarne un altro a giocare una carta.
|
||||
"""
|
||||
@ -51,7 +41,7 @@ class DorothyRage(WildWestShowCardEvent):
|
||||
super().__init__("Dorothy Rage", "👩⚖️")
|
||||
|
||||
|
||||
class HelenaZontero(WildWestShowCardEvent):
|
||||
class HelenaZontero(CardEvent):
|
||||
"""
|
||||
Quando Helena entra in gioco, "estrai!": se esce Cuori o Quadri, rimescola i ruoli attivi tranne lo Sceriffo, e ridistribuiscili a caso.
|
||||
"""
|
||||
@ -74,14 +64,14 @@ class HelenaZontero(WildWestShowCardEvent):
|
||||
)
|
||||
pls = [p for p in game.players if not isinstance(p.role, roles.Sheriff)]
|
||||
newroles = [p.role for p in pls]
|
||||
game.rng.shuffle(newroles)
|
||||
random.shuffle(newroles)
|
||||
for p in pls:
|
||||
p.set_role(newroles.pop(game.rng.randint(0, len(newroles) - 1)))
|
||||
p.set_role(newroles.pop(random.randint(0, len(newroles) - 1)))
|
||||
|
||||
return super().on_flipped(game)
|
||||
|
||||
|
||||
class LadyRosaDelTexas(WildWestShowCardEvent):
|
||||
class LadyRosaDelTexas(CardEvent):
|
||||
"""
|
||||
Nel proprio turno, ogni giocatore può scambiarsi di posto con quello alla sua destra, il quale salta il prossimo turno.
|
||||
"""
|
||||
@ -99,7 +89,7 @@ class LadyRosaDelTexas(WildWestShowCardEvent):
|
||||
game.notify_all()
|
||||
|
||||
|
||||
class MissSusanna(WildWestShowCardEvent):
|
||||
class MissSusanna(CardEvent):
|
||||
"""
|
||||
Nel proprio turno ogni giocatore deve giocare almeno 3 carte. Se non lo fa, perde 1 punto vita.
|
||||
"""
|
||||
@ -108,7 +98,7 @@ class MissSusanna(WildWestShowCardEvent):
|
||||
super().__init__("Miss Susanna", "👩🎤")
|
||||
|
||||
|
||||
class RegolamentoDiConti(WildWestShowCardEvent):
|
||||
class RegolamentoDiConti(CardEvent):
|
||||
"""
|
||||
Tutte le carte possono essere giocate come se fossero BANG!. Le carte BANG! come se fossero Mancato!
|
||||
"""
|
||||
@ -118,15 +108,12 @@ class RegolamentoDiConti(WildWestShowCardEvent):
|
||||
|
||||
def on_clicked(self, game, player):
|
||||
super().on_clicked(game, player)
|
||||
if (
|
||||
len(player.hand) > 0
|
||||
and not player.has_played_bang
|
||||
and any(
|
||||
if len(player.hand) > 0:
|
||||
if not player.has_played_bang and any(
|
||||
(
|
||||
player.get_sight() >= p["dist"]
|
||||
for p in game.get_visible_players(player)
|
||||
)
|
||||
)
|
||||
):
|
||||
player.available_cards = player.hand.copy()
|
||||
player.pending_action = players.PendingAction.CHOOSE
|
||||
@ -134,7 +121,7 @@ class RegolamentoDiConti(WildWestShowCardEvent):
|
||||
player.notify_self()
|
||||
|
||||
|
||||
class Sacagaway(WildWestShowCardEvent):
|
||||
class Sacagaway(CardEvent):
|
||||
"""
|
||||
Tutti i giocatori giocano a carte scoperte (tranne il ruolo!).
|
||||
"""
|
||||
@ -143,7 +130,7 @@ class Sacagaway(WildWestShowCardEvent):
|
||||
super().__init__("Sacagaway", "🌄")
|
||||
|
||||
|
||||
class WildWestShow(WildWestShowCardEvent):
|
||||
class WildWestShow(CardEvent):
|
||||
"""
|
||||
L'obiettivo di ogni giocatore diventa: "Rimani l'ultimo in gioco!"
|
||||
"""
|
||||
@ -158,12 +145,12 @@ class WildWestShow(WildWestShowCardEvent):
|
||||
|
||||
|
||||
def get_endgame_card():
|
||||
"""Return the endgame card for this expansion"""
|
||||
return WildWestShow()
|
||||
end_game = WildWestShow()
|
||||
end_game.expansion = "wild-west-show"
|
||||
return end_game
|
||||
|
||||
|
||||
def get_all_events(rng=random):
|
||||
"""Return all the events for this expansion shuffled, excluding the endgame card"""
|
||||
cards = [
|
||||
Camposanto(),
|
||||
DarlingValentine(),
|
||||
@ -175,4 +162,6 @@ def get_all_events(rng=random):
|
||||
Sacagaway(),
|
||||
]
|
||||
rng.shuffle(cards)
|
||||
for c in cards:
|
||||
c.expansion = "wild-west-show"
|
||||
return cards
|
||||
|
@ -123,22 +123,17 @@ class YoulGrinner(Character):
|
||||
|
||||
|
||||
def all_characters() -> List[Character]:
|
||||
"""
|
||||
Returns a list of all characters in this expansion.
|
||||
"""
|
||||
cards = [
|
||||
BigSpencer(),
|
||||
FlintWestwood(),
|
||||
GaryLooter(),
|
||||
# GaryLooter(),
|
||||
# GreygoryDeckard(),
|
||||
JohnPain(),
|
||||
LeeVanKliff(),
|
||||
TerenKill(),
|
||||
YoulGrinner(),
|
||||
]
|
||||
for card in cards:
|
||||
card.expansion_icon = "🎪" # pylint: disable=attribute-defined-outside-init
|
||||
card.expansion = ( # pylint: disable=attribute-defined-outside-init
|
||||
"wild_west_show"
|
||||
)
|
||||
for c in cards:
|
||||
c.expansion_icon = "🎪"
|
||||
c.expansion = "wild_west_show"
|
||||
return cards
|
||||
|
@ -8,7 +8,6 @@ import bang.players as pl
|
||||
import bang.cards as cs
|
||||
import bang.characters as characters
|
||||
import bang.expansions.dodge_city.characters as chd
|
||||
import bang.expansions.wild_west_show.characters as chwws
|
||||
from bang.deck import Deck
|
||||
import bang.roles as roles
|
||||
import bang.expansions.fistful_of_cards.card_events as ce
|
||||
@ -17,9 +16,8 @@ import bang.expansions.wild_west_show.card_events as cew
|
||||
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.train_robbery.trains as trt
|
||||
from metrics import Metrics
|
||||
from globals import G, PendingAction
|
||||
from globals import G
|
||||
|
||||
|
||||
debug_commands = [
|
||||
@ -58,11 +56,8 @@ debug_commands = [
|
||||
"help": "Remove a card from hand/equip - sample /removecard 0",
|
||||
},
|
||||
{"cmd": "/getcard", "help": "Get a brand new card - sample /getcard Birra"},
|
||||
{"cmd": "/equipcard", "help": "Equip a brand new card - sample /getcard Barile"},
|
||||
{"cmd": "/meinfo", "help": "Get player data"},
|
||||
{"cmd": "/gameinfo", "help": "Get game data"},
|
||||
{"cmd": "/deckinfo", "help": "Get deck data"},
|
||||
{"cmd": "/trainfw", "help": "move train forward"},
|
||||
{"cmd": "/playerinfo", "help": "Get player data - sample /playerinfo player"},
|
||||
{"cmd": "/cardinfo", "help": "Get card data - sample /cardinfo handindex"},
|
||||
{"cmd": "/mebot", "help": "Toggles bot mode"},
|
||||
@ -97,7 +92,6 @@ class Game:
|
||||
"gold_rush",
|
||||
"the_valley_of_shadows",
|
||||
"wild_west_show",
|
||||
"train_robbery",
|
||||
]
|
||||
self.shutting_down = False
|
||||
self.is_competitive = False
|
||||
@ -116,13 +110,13 @@ class Game:
|
||||
self.characters_to_distribute = 2 # personaggi da dare a inizio partita
|
||||
self.debug = self.name == "debug"
|
||||
self.dead_roles: List[roles.Role] = []
|
||||
self.mouse_positions = {}
|
||||
self.is_changing_pwd = False
|
||||
self.is_hidden = False
|
||||
self.rng = random.Random()
|
||||
self.rpc_log = []
|
||||
self.is_replay = False
|
||||
self.replay_speed = 1
|
||||
self.owner: str | None = None
|
||||
|
||||
def shuffle_players(self):
|
||||
if not self.started:
|
||||
@ -231,7 +225,6 @@ class Game:
|
||||
self.reset()
|
||||
|
||||
def notify_room(self, sid=None):
|
||||
"""Notify all players in the room of the room's state."""
|
||||
if any((p.character is None for p in self.players)) or sid:
|
||||
G.sio.emit(
|
||||
"room",
|
||||
@ -254,8 +247,6 @@ class Game:
|
||||
"expansions": self.expansions,
|
||||
"available_expansions": self.available_expansions,
|
||||
"is_replay": self.is_replay,
|
||||
"characters_to_distribute": self.characters_to_distribute,
|
||||
"owner": self.owner,
|
||||
},
|
||||
)
|
||||
G.sio.emit("debug", room=self.name, data=self.debug)
|
||||
@ -274,7 +265,6 @@ class Game:
|
||||
G.sio.emit("spectators", room=self.name, data=len(self.spectators))
|
||||
|
||||
def toggle_expansion(self, expansion_name):
|
||||
"""Toggles an expansion on or off."""
|
||||
if not self.started:
|
||||
print(f"{self.name}: toggling", expansion_name)
|
||||
if expansion_name in self.expansions:
|
||||
@ -284,12 +274,10 @@ class Game:
|
||||
self.notify_room()
|
||||
|
||||
def toggle_competitive(self):
|
||||
"""Toggles the competitive mode on or off."""
|
||||
self.is_competitive = not self.is_competitive
|
||||
self.notify_room()
|
||||
|
||||
def toggle_disconnect_bot(self):
|
||||
"""Toggles the disconnect bot on or off."""
|
||||
self.disconnect_bot = not self.disconnect_bot
|
||||
self.notify_room()
|
||||
|
||||
@ -306,16 +294,14 @@ class Game:
|
||||
return
|
||||
if player in self.players or len(self.players) >= 10:
|
||||
return
|
||||
if len(self.players) > 7:
|
||||
if "dodge_city" not in self.expansions:
|
||||
self.expansions.append("dodge_city")
|
||||
player.join_game(self)
|
||||
if player.is_admin():
|
||||
self.feature_flags()
|
||||
self.players.append(player)
|
||||
if len(self.players) == 1:
|
||||
self.owner = player.name
|
||||
if len(self.players) > 7:
|
||||
if "dodge_city" not in self.expansions:
|
||||
self.expansions.append("dodge_city")
|
||||
print(f"{self.name}: Added player {player.name} to game; {len(self.players)=}")
|
||||
print(f"{self.name}: Added player {player.name} to game")
|
||||
self.notify_room()
|
||||
G.sio.emit("chat_message", room=self.name, data=f"_joined|{player.name}")
|
||||
|
||||
@ -324,7 +310,7 @@ class Game:
|
||||
self.is_changing_pwd = True
|
||||
if self.password == "":
|
||||
self.password = "".join(
|
||||
random.choice("AEOUJKZT123456789") for x in range(6)
|
||||
random.choice("AEIOUJKZT123456789") for x in range(6)
|
||||
)
|
||||
print(self.name, "is now private pwd", self.password)
|
||||
else:
|
||||
@ -346,12 +332,7 @@ class Game:
|
||||
data=f"_choose_character|{player.name}|{player.character.name}",
|
||||
)
|
||||
player.prepare()
|
||||
cards_to_draw = (
|
||||
player.max_lives
|
||||
if not player.character.check(self, chwws.BigSpencer)
|
||||
else 5
|
||||
)
|
||||
for _ in range(cards_to_draw):
|
||||
for _ in range(player.max_lives):
|
||||
self.deck.draw(player=player)
|
||||
player.notify_self()
|
||||
self.players_map = {c.name: i for i, c in enumerate(self.players)}
|
||||
@ -363,14 +344,12 @@ class Game:
|
||||
roles_str += f"|{role}|{str(current_roles.count(role))}"
|
||||
G.sio.emit("chat_message", room=self.name, data=f"_allroles{roles_str}")
|
||||
self.play_turn()
|
||||
self.notify_stations()
|
||||
|
||||
def choose_characters(self):
|
||||
n = self.characters_to_distribute
|
||||
all_chars = characters.all_characters(self.expansions)
|
||||
if len(all_chars) // len(self.players) < n:
|
||||
n = len(all_chars) // len(self.players)
|
||||
char_cards = self.rng.sample(all_chars, len(self.players) * n)
|
||||
char_cards = self.rng.sample(
|
||||
characters.all_characters(self.expansions), len(self.players) * n
|
||||
)
|
||||
for i, player in enumerate(self.players):
|
||||
player.set_available_character(char_cards[i * n : i * n + n])
|
||||
|
||||
@ -469,7 +448,7 @@ class Game:
|
||||
|
||||
def discard_others(self, attacker: pl.Player, card_name: str = None):
|
||||
self.attack_in_progress = True
|
||||
attacker.pending_action = PendingAction.WAIT
|
||||
attacker.pending_action = pl.PendingAction.WAIT
|
||||
attacker.notify_self()
|
||||
self.waiting_for = 0
|
||||
self.ready_count = 0
|
||||
@ -478,12 +457,8 @@ class Game:
|
||||
if p.get_discarded(attacker=attacker, card_name=card_name):
|
||||
self.waiting_for += 1
|
||||
p.notify_self()
|
||||
elif card_name == "Tornado" and len(p.hand) == 0:
|
||||
self.deck.draw(player=p)
|
||||
self.deck.draw(player=p)
|
||||
p.notify_self()
|
||||
if self.waiting_for == 0:
|
||||
attacker.pending_action = PendingAction.PLAY
|
||||
attacker.pending_action = pl.PendingAction.PLAY
|
||||
attacker.notify_self()
|
||||
self.attack_in_progress = False
|
||||
elif card_name == "Poker":
|
||||
@ -491,7 +466,7 @@ class Game:
|
||||
|
||||
def attack_others(self, attacker: pl.Player, card_name: str = None):
|
||||
self.attack_in_progress = True
|
||||
attacker.pending_action = PendingAction.WAIT
|
||||
attacker.pending_action = pl.PendingAction.WAIT
|
||||
attacker.notify_self()
|
||||
self.waiting_for = 0
|
||||
self.ready_count = 0
|
||||
@ -501,7 +476,7 @@ class Game:
|
||||
self.waiting_for += 1
|
||||
p.notify_self()
|
||||
if self.waiting_for == 0:
|
||||
attacker.pending_action = PendingAction.PLAY
|
||||
attacker.pending_action = pl.PendingAction.PLAY
|
||||
attacker.notify_self()
|
||||
self.attack_in_progress = False
|
||||
if self.pending_winners and not self.someone_won:
|
||||
@ -509,7 +484,7 @@ class Game:
|
||||
|
||||
def indian_others(self, attacker: pl.Player):
|
||||
self.attack_in_progress = True
|
||||
attacker.pending_action = PendingAction.WAIT
|
||||
attacker.pending_action = pl.PendingAction.WAIT
|
||||
attacker.notify_self()
|
||||
self.waiting_for = 0
|
||||
self.ready_count = 0
|
||||
@ -519,7 +494,7 @@ class Game:
|
||||
self.waiting_for += 1
|
||||
p.notify_self()
|
||||
if self.waiting_for == 0:
|
||||
attacker.pending_action = PendingAction.PLAY
|
||||
attacker.pending_action = pl.PendingAction.PLAY
|
||||
attacker.notify_self()
|
||||
self.attack_in_progress = False
|
||||
if self.pending_winners and not self.someone_won:
|
||||
@ -556,26 +531,26 @@ class Game:
|
||||
self.attack_in_progress = True
|
||||
self.ready_count = 0
|
||||
self.waiting_for = 1
|
||||
attacker.pending_action = PendingAction.WAIT
|
||||
attacker.pending_action = pl.PendingAction.WAIT
|
||||
attacker.notify_self()
|
||||
self.get_player_named(target_username).notify_self()
|
||||
elif not attacker.is_my_turn or len(self.attack_queue) == 0:
|
||||
self.players[self.turn].pending_action = PendingAction.PLAY
|
||||
self.players[self.turn].pending_action = pl.PendingAction.PLAY
|
||||
|
||||
def steal_discard(self, attacker: pl.Player, target_username: str, card: cs.Card):
|
||||
p = self.get_player_named(target_username)
|
||||
if p != attacker and p.get_discarded(
|
||||
attacker,
|
||||
card_name=card.name,
|
||||
action="steal" if (isinstance(card, cs.Panico) or isinstance(card, trt.PassengerCar)) else "discard",
|
||||
action="steal" if isinstance(card, cs.Panico) else "discard",
|
||||
):
|
||||
self.ready_count = 0
|
||||
self.waiting_for = 1
|
||||
attacker.pending_action = PendingAction.WAIT
|
||||
attacker.pending_action = pl.PendingAction.WAIT
|
||||
attacker.notify_self()
|
||||
self.get_player_named(target_username).notify_self()
|
||||
else:
|
||||
attacker.pending_action = PendingAction.CHOOSE
|
||||
attacker.pending_action = pl.PendingAction.CHOOSE
|
||||
attacker.target_p = target_username
|
||||
if isinstance(card, cs.CatBalou):
|
||||
attacker.choose_action = "discard"
|
||||
@ -589,7 +564,7 @@ class Game:
|
||||
):
|
||||
self.ready_count = 0
|
||||
self.waiting_for = 1
|
||||
attacker.pending_action = PendingAction.WAIT
|
||||
attacker.pending_action = pl.PendingAction.WAIT
|
||||
attacker.notify_self()
|
||||
self.get_player_named(target_username).notify_self()
|
||||
|
||||
@ -597,14 +572,14 @@ class Game:
|
||||
if self.get_player_named(target_username).get_dueled(attacker=attacker):
|
||||
self.ready_count = 0
|
||||
self.waiting_for = 1
|
||||
attacker.pending_action = PendingAction.WAIT
|
||||
attacker.pending_action = pl.PendingAction.WAIT
|
||||
attacker.notify_self()
|
||||
self.get_player_named(target_username).notify_self()
|
||||
|
||||
def emporio(self):
|
||||
pls = self.get_alive_players()
|
||||
self.available_cards = [self.deck.draw(True) for i in range(len(pls))]
|
||||
self.players[self.turn].pending_action = PendingAction.CHOOSE
|
||||
self.players[self.turn].pending_action = pl.PendingAction.CHOOSE
|
||||
self.players[self.turn].choose_text = "choose_card_to_get"
|
||||
self.players[self.turn].available_cards = self.available_cards
|
||||
G.sio.emit(
|
||||
@ -626,10 +601,10 @@ class Game:
|
||||
)
|
||||
player.hand.append(card)
|
||||
player.available_cards = []
|
||||
player.pending_action = PendingAction.WAIT
|
||||
player.pending_action = pl.PendingAction.WAIT
|
||||
player.notify_self()
|
||||
pls = self.get_alive_players()
|
||||
next_player = pls[
|
||||
nextPlayer = pls[
|
||||
(
|
||||
pls.index(self.players[self.turn])
|
||||
+ (len(pls) - len(self.available_cards))
|
||||
@ -637,33 +612,28 @@ class Game:
|
||||
% len(pls)
|
||||
]
|
||||
if len(self.available_cards) == 1:
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=self.name,
|
||||
data=f"_choose_emporio|{next_player.name}|{self.available_cards[0].name}",
|
||||
)
|
||||
next_player.hand.append(self.available_cards.pop())
|
||||
next_player.notify_self()
|
||||
nextPlayer.hand.append(self.available_cards.pop())
|
||||
nextPlayer.notify_self()
|
||||
G.sio.emit("emporio", room=self.name, data='{"name":"","cards":[]}')
|
||||
self.players[self.turn].pending_action = PendingAction.PLAY
|
||||
self.players[self.turn].pending_action = pl.PendingAction.PLAY
|
||||
self.players[self.turn].notify_self()
|
||||
elif next_player == self.players[self.turn]:
|
||||
elif nextPlayer == self.players[self.turn]:
|
||||
G.sio.emit("emporio", room=self.name, data='{"name":"","cards":[]}')
|
||||
self.players[self.turn].pending_action = PendingAction.PLAY
|
||||
self.players[self.turn].pending_action = pl.PendingAction.PLAY
|
||||
self.players[self.turn].notify_self()
|
||||
else:
|
||||
next_player.pending_action = PendingAction.CHOOSE
|
||||
next_player.choose_text = "choose_card_to_get"
|
||||
next_player.available_cards = self.available_cards
|
||||
nextPlayer.pending_action = pl.PendingAction.CHOOSE
|
||||
nextPlayer.choose_text = "choose_card_to_get"
|
||||
nextPlayer.available_cards = self.available_cards
|
||||
G.sio.emit(
|
||||
"emporio",
|
||||
room=self.name,
|
||||
data=json.dumps(
|
||||
{"name": next_player.name, "cards": self.available_cards},
|
||||
{"name": nextPlayer.name, "cards": self.available_cards},
|
||||
default=lambda o: o.__dict__,
|
||||
),
|
||||
)
|
||||
next_player.notify_self()
|
||||
nextPlayer.notify_self()
|
||||
|
||||
def get_player_named(self, name: str, next=False) -> pl.Player:
|
||||
if next:
|
||||
@ -671,7 +641,6 @@ class Game:
|
||||
return self.players[self.players_map[name]]
|
||||
|
||||
def responders_did_respond_resume_turn(self, did_lose=False):
|
||||
"""Called when all Players have responded to an event/attack."""
|
||||
print(f"{self.name}: did_lose", did_lose)
|
||||
if self.player_bangs > 0 and self.check_event(ce.PerUnPugnoDiCarte):
|
||||
self.player_bangs -= 1
|
||||
@ -738,7 +707,7 @@ class Game:
|
||||
elif self.poker_on and not any(
|
||||
c.number == 1 for c in self.deck.scrap_pile[-tmp:]
|
||||
):
|
||||
self.players[self.turn].pending_action = PendingAction.CHOOSE
|
||||
self.players[self.turn].pending_action = pl.PendingAction.CHOOSE
|
||||
self.players[
|
||||
self.turn
|
||||
].choose_text = f"choose_from_poker;{min(2, tmp)}"
|
||||
@ -749,15 +718,14 @@ class Game:
|
||||
print("attack completed, next attack")
|
||||
atk = self.attack_queue.pop(0)
|
||||
self.attack(atk[0], atk[1], atk[2], atk[3], skip_queue=True)
|
||||
elif self.players[self.turn].pending_action == PendingAction.CHOOSE:
|
||||
elif self.players[self.turn].pending_action == pl.PendingAction.CHOOSE:
|
||||
self.players[self.turn].notify_self()
|
||||
else:
|
||||
self.players[self.turn].pending_action = PendingAction.PLAY
|
||||
self.players[self.turn].pending_action = pl.PendingAction.PLAY
|
||||
self.poker_on = False
|
||||
self.players[self.turn].notify_self()
|
||||
|
||||
def announces_winners(self, winners=None):
|
||||
"""Announces the winners of the game in the chat"""
|
||||
if winners is None:
|
||||
print(f"{self.name}: WE HAVE A WINNER - pending winners")
|
||||
else:
|
||||
@ -791,12 +759,10 @@ class Game:
|
||||
return self.reset()
|
||||
|
||||
def next_player(self):
|
||||
"""Returns the next player in turn order"""
|
||||
pls = self.get_alive_players()
|
||||
return pls[(pls.index(self.players[self.turn]) + 1) % len(pls)]
|
||||
|
||||
def play_turn(self):
|
||||
"""Starts the turn of the current player"""
|
||||
self.incremental_turn += 1
|
||||
if not self.is_replay:
|
||||
Metrics.send_metric(
|
||||
@ -818,7 +784,7 @@ class Game:
|
||||
elif self.check_event(cew.Camposanto):
|
||||
pl.lives = 1
|
||||
pl.set_role = self.dead_roles.pop(
|
||||
self.rng.randint(0, len(self.dead_roles) - 1)
|
||||
random.randint(0, len(self.dead_roles) - 1)
|
||||
)
|
||||
pl.is_dead = False
|
||||
pl.is_ghost = False
|
||||
@ -856,7 +822,6 @@ class Game:
|
||||
)
|
||||
):
|
||||
self.deck.flip_event()
|
||||
self.deck.move_train_forward()
|
||||
if self.check_event(ce.RouletteRussa):
|
||||
self.is_russian_roulette_on = True
|
||||
if self.players[self.turn].get_banged(self.deck.event_cards[0]):
|
||||
@ -932,31 +897,17 @@ class Game:
|
||||
data=json.dumps(self.deck.shop_cards, default=lambda o: o.__dict__),
|
||||
)
|
||||
|
||||
def notify_stations(self, sid=None):
|
||||
if "train_robbery" in self.expansions:
|
||||
room = self.name if sid is None else sid
|
||||
G.sio.emit(
|
||||
"stations",
|
||||
room=room,
|
||||
data=json.dumps(
|
||||
{
|
||||
"stations": self.deck.stations,
|
||||
"current_train": self.deck.current_train,
|
||||
},
|
||||
default=lambda o: o.__dict__,
|
||||
),
|
||||
)
|
||||
|
||||
def notify_scrap_pile(self, sid=None):
|
||||
print(f"{self.name}: scrap")
|
||||
room = self.name if sid is None else sid
|
||||
if self.deck.peek_scrap_pile():
|
||||
G.sio.emit("scrap", room=room, data=self.deck.peek_scrap_pile()[0].__dict__)
|
||||
G.sio.emit("scrap", room=room, data=self.deck.peek_scrap_pile().__dict__)
|
||||
else:
|
||||
G.sio.emit("scrap", room=room, data=None)
|
||||
|
||||
def handle_disconnect(self, player: pl.Player):
|
||||
print(f"{self.name}: player {player.name} left the game")
|
||||
self.mouse_positions.pop(player.name, None)
|
||||
if player in self.spectators:
|
||||
self.spectators.remove(player)
|
||||
G.sio.emit("spectators", room=self.name, data=len(self.spectators))
|
||||
@ -993,8 +944,6 @@ class Game:
|
||||
self.deck = None
|
||||
return True
|
||||
else:
|
||||
self.owner = next((p.name for p in self.players if not p.is_bot), None)
|
||||
self.notify_room()
|
||||
return False
|
||||
|
||||
def player_death(self, player: pl.Player, disconnected=False):
|
||||
@ -1047,9 +996,9 @@ class Game:
|
||||
self.deck.draw(True, player=player.attacker)
|
||||
player.attacker.notify_self()
|
||||
print(f"{self.name}: player {player.name} died")
|
||||
if self.waiting_for > 0 and player.pending_action == PendingAction.RESPOND:
|
||||
if self.waiting_for > 0 and player.pending_action == pl.PendingAction.RESPOND:
|
||||
self.responders_did_respond_resume_turn()
|
||||
player.pending_action = PendingAction.WAIT
|
||||
player.pending_action = pl.PendingAction.WAIT
|
||||
|
||||
if player.is_dead:
|
||||
return
|
||||
@ -1252,29 +1201,6 @@ class Game:
|
||||
def get_alive_players(self):
|
||||
return [p for p in self.players if not p.is_dead or p.is_ghost]
|
||||
|
||||
def get_other_players(self, player:pl.Player):
|
||||
return [{
|
||||
"name": p.name,
|
||||
"dist": 0,
|
||||
"lives": p.lives,
|
||||
"max_lives": p.max_lives,
|
||||
"is_sheriff": isinstance(p.role, roles.Sheriff),
|
||||
"cards": len(p.hand) + len(p.equipment),
|
||||
"is_ghost": p.is_ghost,
|
||||
"is_bot": p.is_bot,
|
||||
"icon": p.role.icon
|
||||
if (
|
||||
p.role is not None
|
||||
and (
|
||||
self.initial_players == 3
|
||||
or isinstance(p.role, roles.Sheriff)
|
||||
)
|
||||
)
|
||||
else "🤠",
|
||||
"avatar": p.avatar,
|
||||
"role": p.role,
|
||||
} for p in self.get_alive_players() if p != player]
|
||||
|
||||
def get_dead_players(self, include_ghosts=True):
|
||||
return [
|
||||
p for p in self.players if p.is_dead and (include_ghosts or not p.is_ghost)
|
||||
|
@ -1,6 +1,9 @@
|
||||
from __future__ import annotations
|
||||
from enum import IntEnum
|
||||
import json
|
||||
from random import randrange, sample, uniform, randint
|
||||
from random import random, randrange, sample, uniform, randint
|
||||
import socketio
|
||||
import bang.deck as deck
|
||||
import bang.roles as r
|
||||
import bang.cards as cs
|
||||
import bang.expansions.dodge_city.cards as csd
|
||||
@ -14,11 +17,9 @@ 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
|
||||
import bang.expansions.train_robbery.stations as trs
|
||||
import bang.expansions.train_robbery.trains as trt
|
||||
from typing import List, TYPE_CHECKING, Callable
|
||||
from typing import List, TYPE_CHECKING
|
||||
from metrics import Metrics
|
||||
from globals import G, PendingAction
|
||||
from globals import G
|
||||
import sys
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -44,6 +45,15 @@ robot_pictures = [
|
||||
]
|
||||
|
||||
|
||||
class PendingAction(IntEnum):
|
||||
PICK = 0
|
||||
DRAW = 1
|
||||
PLAY = 2
|
||||
RESPOND = 3
|
||||
WAIT = 4
|
||||
CHOOSE = 5
|
||||
|
||||
|
||||
class Player:
|
||||
def is_admin(self):
|
||||
return self.discord_id in {"244893980960096266", "539795574019457034"}
|
||||
@ -92,7 +102,6 @@ class Player:
|
||||
self.is_bot = bot
|
||||
self.discord_token = discord_token
|
||||
self.discord_id = None
|
||||
self.did_choose_callback = None
|
||||
self.played_cards = 0
|
||||
self.avatar = ""
|
||||
self.last_played_card: cs.Card = None
|
||||
@ -271,25 +280,25 @@ class Player:
|
||||
if self.pending_action == PendingAction.DRAW and self.game.check_event(
|
||||
ce.Peyote
|
||||
):
|
||||
self.is_drawing = True
|
||||
self.set_choose_action(
|
||||
"choose_guess",
|
||||
[
|
||||
self.available_cards = [
|
||||
{"icon": "🔴", "noDesc": True},
|
||||
{"icon": "⚫", "noDesc": True},
|
||||
],
|
||||
)
|
||||
]
|
||||
self.is_drawing = True
|
||||
self.choose_text = "choose_guess"
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
elif (
|
||||
self.can_play_ranch
|
||||
and self.pending_action == PendingAction.PLAY
|
||||
and self.game.check_event(ce.Ranch)
|
||||
):
|
||||
self.can_play_ranch = False
|
||||
self.available_cards = [c for c in self.hand]
|
||||
self.discarded_cards = []
|
||||
self.available_cards.append({"icon": "✅", "noDesc": True})
|
||||
self.is_playing_ranch = True
|
||||
self.set_choose_action(
|
||||
"choose_ranch", [c for c in self.hand] + [{"icon": "✅", "noDesc": True}]
|
||||
)
|
||||
self.choose_text = "choose_ranch"
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
elif (
|
||||
self.character
|
||||
and self.character.check(self.game, chars.SuzyLafayette)
|
||||
@ -303,9 +312,9 @@ class Player:
|
||||
if self.gold_nuggets >= 2 and any(
|
||||
(isinstance(c, grc.Zaino) for c in self.gold_rush_equipment)
|
||||
):
|
||||
for card in self.gold_rush_equipment:
|
||||
if isinstance(card, grc.Zaino):
|
||||
card.play_card(self, None)
|
||||
for i in range(len(self.gold_rush_equipment)):
|
||||
if isinstance(self.gold_rush_equipment[i], grc.Zaino):
|
||||
self.gold_rush_equipment[i].play_card(self, None)
|
||||
return # play card will notify the player
|
||||
if self.character.check(self.game, chw.TerenKill):
|
||||
picked: cs.Card = self.game.deck.pick_and_scrap()
|
||||
@ -329,7 +338,9 @@ class Player:
|
||||
self.game.players[self.game.turn].notify_self()
|
||||
self.scrapped_cards = 0
|
||||
self.previous_pending_action = self.pending_action
|
||||
self.set_choose_action("choose_sid_scrap", self.hand)
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
self.choose_text = "choose_sid_scrap"
|
||||
self.available_cards = self.hand
|
||||
self.lives += 1
|
||||
|
||||
ser = self.__dict__.copy()
|
||||
@ -413,12 +424,6 @@ class Player:
|
||||
self.game.rpc_log.append(f"{self.name};draw;")
|
||||
self.draw("")
|
||||
elif self.pending_action == PendingAction.PLAY:
|
||||
must_play_cards = [
|
||||
c
|
||||
for c in self.hand
|
||||
if c.must_be_used and c.can_be_used_now
|
||||
and self.game.check_event(ce.LeggeDelWest)
|
||||
]
|
||||
non_blocked_cards = [
|
||||
card
|
||||
for card in self.hand
|
||||
@ -518,8 +523,8 @@ class Player:
|
||||
if self.gold_nuggets > 0 and any(
|
||||
(c.number <= self.gold_nuggets for c in self.game.deck.shop_cards)
|
||||
):
|
||||
for i, card in enumerate(self.game.deck.shop_cards):
|
||||
if card.number <= self.gold_nuggets:
|
||||
for i in range(len(self.game.deck.shop_cards)):
|
||||
if self.game.deck.shop_cards[i].number <= self.gold_nuggets:
|
||||
self.game.rpc_log.append(f"{self.name};buy_gold_rush_card;{i}")
|
||||
self.buy_gold_rush_card(i)
|
||||
return
|
||||
@ -671,19 +676,19 @@ class Player:
|
||||
self.end_turn()
|
||||
elif self.pending_action == PendingAction.RESPOND:
|
||||
did_respond = False
|
||||
for i, card in enumerate(self.hand):
|
||||
if card.can_be_used_now and (
|
||||
card.name in self.expected_response
|
||||
for i in range(len(self.hand)):
|
||||
if self.hand[i].can_be_used_now and (
|
||||
self.hand[i].name in self.expected_response
|
||||
or self.character.check(self.game, chd.ElenaFuente)
|
||||
):
|
||||
self.game.rpc_log.append(f"{self.name};respond;{i}")
|
||||
self.respond(i)
|
||||
did_respond = True
|
||||
break
|
||||
for i, card in enumerate(self.equipment):
|
||||
for i in range(len(self.equipment)):
|
||||
if (
|
||||
not self.game.check_event(ce.Lazo)
|
||||
and card.name in self.expected_response
|
||||
and self.equipment[i].name in self.expected_response
|
||||
):
|
||||
self.game.rpc_log.append(f"{self.name};respond;{len(self.hand)+i}")
|
||||
self.respond(len(self.hand) + i)
|
||||
@ -737,9 +742,6 @@ class Player:
|
||||
self.has_played_bang = False
|
||||
self.special_use_count = 0
|
||||
self.bang_used = 0
|
||||
if any((isinstance(c, trt.DiningCar) for c in self.equipment)):
|
||||
if self.game.deck.pick_and_scrap().suit == cs.Suit.HEARTS:
|
||||
self.lives = min(self.lives + 1, self.max_lives)
|
||||
if self.game.check_event(cew.DarlingValentine):
|
||||
hand = len(self.hand)
|
||||
for _ in range(hand):
|
||||
@ -774,9 +776,7 @@ class Player:
|
||||
for p in self.game.get_alive_players()
|
||||
)
|
||||
):
|
||||
self.set_choose_action(
|
||||
"choose_fratelli_di_sangue",
|
||||
[
|
||||
self.available_cards = [
|
||||
{
|
||||
"name": p.name,
|
||||
"icon": p.role.icon
|
||||
@ -793,17 +793,18 @@ class Player:
|
||||
for p in self.game.get_alive_players()
|
||||
if p != self and p.lives < p.max_lives
|
||||
]
|
||||
+ [{"icon": "❌", "noDesc": True}],
|
||||
)
|
||||
self.available_cards.append({"icon": "❌", "noDesc": True})
|
||||
self.choose_text = "choose_fratelli_di_sangue"
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
self.is_giving_life = True
|
||||
elif (
|
||||
self.game.check_event(ceh.NuovaIdentita)
|
||||
and self.not_chosen_character is not None
|
||||
and not again
|
||||
):
|
||||
self.set_choose_action(
|
||||
"choose_nuova_identita", [self.character, self.not_chosen_character]
|
||||
)
|
||||
self.available_cards = [self.character, self.not_chosen_character]
|
||||
self.choose_text = "choose_nuova_identita"
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
elif not self.game.check_event(ce.Lazo) and any(
|
||||
(
|
||||
isinstance(c, cs.Dinamite)
|
||||
@ -833,9 +834,7 @@ class Player:
|
||||
and sum((c.name == cs.Bang(0, 0).name for c in self.hand)) >= 2
|
||||
):
|
||||
self.is_using_checchino = True
|
||||
self.set_choose_action(
|
||||
"choose_cecchino",
|
||||
[
|
||||
self.available_cards = [
|
||||
{
|
||||
"name": p["name"],
|
||||
"icon": p["role"].icon
|
||||
@ -851,8 +850,9 @@ class Player:
|
||||
for p in self.game.get_visible_players(self)
|
||||
if p["dist"] <= self.get_sight()
|
||||
]
|
||||
+ [{"icon": "❌", "noDesc": True}],
|
||||
)
|
||||
self.available_cards.append({"icon": "❌", "noDesc": True})
|
||||
self.choose_text = "choose_cecchino"
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
self.notify_self()
|
||||
if (
|
||||
self.is_my_turn
|
||||
@ -878,15 +878,15 @@ class Player:
|
||||
self.notify_self()
|
||||
elif self.character.check(self.game, chars.KitCarlson) and not self.is_ghost:
|
||||
self.is_drawing = True
|
||||
self.set_choose_action(
|
||||
"choose_card_to_get", [self.game.deck.draw() for i in range(3)]
|
||||
)
|
||||
self.available_cards = [self.game.deck.draw() for i in range(3)]
|
||||
self.choose_text = "choose_card_to_get"
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
self.notify_self()
|
||||
elif self.character.check(self.game, grch.DutchWill) and not self.is_ghost:
|
||||
self.is_drawing = True
|
||||
self.set_choose_action(
|
||||
"choose_card_to_get", [self.game.deck.draw() for i in range(2)]
|
||||
)
|
||||
self.available_cards = [self.game.deck.draw() for i in range(2)]
|
||||
self.choose_text = "choose_card_to_get"
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
self.notify_self()
|
||||
elif (
|
||||
self.character.check(self.game, chd.PatBrennan)
|
||||
@ -896,10 +896,10 @@ class Player:
|
||||
and len(self.game.get_player_named(pile).equipment) > 0
|
||||
):
|
||||
self.is_drawing = True
|
||||
self.available_cards = self.game.get_player_named(pile).equipment
|
||||
self.pat_target = pile
|
||||
self.set_choose_action(
|
||||
"choose_card_to_get", self.game.get_player_named(pile).equipment
|
||||
)
|
||||
self.choose_text = "choose_card_to_get"
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
self.notify_self()
|
||||
else:
|
||||
self.pending_action = PendingAction.PLAY
|
||||
@ -998,13 +998,12 @@ class Player:
|
||||
|
||||
def manette(self):
|
||||
if self.game.check_event(ceh.Manette):
|
||||
self.set_choose_action(
|
||||
"choose_manette",
|
||||
[
|
||||
self.choose_text = "choose_manette"
|
||||
self.available_cards = [
|
||||
{"name": "", "icon": "♦♣♥♠"[s], "alt_text": "", "noDesc": True}
|
||||
for s in [0, 1, 2, 3]
|
||||
],
|
||||
)
|
||||
]
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
|
||||
def pick(self):
|
||||
if self.pending_action != PendingAction.PICK:
|
||||
@ -1013,8 +1012,10 @@ class Player:
|
||||
if any((isinstance(c, grc.FerroDiCavallo) for c in self.gold_rush_equipment)):
|
||||
pickable_cards += 1
|
||||
if self.is_my_turn and self.attacker is None:
|
||||
for i, card in enumerate(self.equipment):
|
||||
if i < len(self.equipment) and isinstance(card, cs.Dinamite):
|
||||
for i in range(len(self.equipment)):
|
||||
if i < len(self.equipment) and isinstance(
|
||||
self.equipment[i], cs.Dinamite
|
||||
):
|
||||
while pickable_cards > 0:
|
||||
pickable_cards -= 1
|
||||
picked: cs.Card = self.game.deck.pick_and_scrap()
|
||||
@ -1087,8 +1088,8 @@ class Player:
|
||||
):
|
||||
self.notify_self()
|
||||
return
|
||||
for i, card in enumerate(self.equipment):
|
||||
if isinstance(card, cs.Prigione):
|
||||
for i in range(len(self.equipment)):
|
||||
if isinstance(self.equipment[i], cs.Prigione):
|
||||
while pickable_cards > 0:
|
||||
pickable_cards -= 1
|
||||
picked: cs.Card = self.game.deck.pick_and_scrap()
|
||||
@ -1123,8 +1124,8 @@ class Player:
|
||||
)
|
||||
break
|
||||
break
|
||||
for i, card in enumerate(self.equipment):
|
||||
if isinstance(card, tvosc.SerpenteASonagli):
|
||||
for i in range(len(self.equipment)):
|
||||
if isinstance(self.equipment[i], tvosc.SerpenteASonagli):
|
||||
while pickable_cards > 0:
|
||||
pickable_cards -= 1
|
||||
picked: cs.Card = self.game.deck.pick_and_scrap()
|
||||
@ -1183,7 +1184,8 @@ class Player:
|
||||
|
||||
def get_playable_cards(self):
|
||||
playable_cards = []
|
||||
for i, card in enumerate(self.hand):
|
||||
for i in range(len(self.hand)):
|
||||
card = self.hand[i]
|
||||
if (
|
||||
isinstance(card, cs.Bang)
|
||||
and self.has_played_bang
|
||||
@ -1196,7 +1198,7 @@ class Player:
|
||||
playable_cards.append(i)
|
||||
return playable_cards
|
||||
|
||||
def play_card(self, hand_index: int, against:str=None, _with:int=None):
|
||||
def play_card(self, hand_index: int, against=None, _with=None):
|
||||
if self.is_bot:
|
||||
data = {"index": hand_index, "against": against, "with": _with}
|
||||
self.game.rpc_log.append(f"{self.name};play_card;{json.dumps(data)}")
|
||||
@ -1261,7 +1263,6 @@ class Player:
|
||||
(
|
||||
self.game.check_event(ceh.Manette)
|
||||
and card.suit != self.committed_suit_manette
|
||||
and card.number != 42
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -1394,9 +1395,6 @@ class Player:
|
||||
self.target_p = self.rissa_targets.pop(0).name
|
||||
print(f"rissa targets: {self.rissa_targets}")
|
||||
self.notify_self()
|
||||
elif self.did_choose_callback is not None:
|
||||
self.did_choose_callback(self, card_index)
|
||||
self.notify_self()
|
||||
elif self.choose_text == "choose_ricercato":
|
||||
player = self.game.get_player_named(
|
||||
self.available_cards[card_index]["name"]
|
||||
@ -1532,9 +1530,6 @@ class Player:
|
||||
room=player.game.name,
|
||||
data=f"_play_card_against|{self.name}|Sventagliata|{player.name}",
|
||||
)
|
||||
self.bang_used += 1
|
||||
self.has_played_bang = True
|
||||
if self.pending_action == PendingAction.CHOOSE:
|
||||
self.pending_action = PendingAction.PLAY
|
||||
self.notify_self()
|
||||
elif "choose_play_as_bang" in self.choose_text:
|
||||
@ -1574,10 +1569,6 @@ class Player:
|
||||
self.game.deck.scrap(self.hand.pop(card_index), player=self)
|
||||
self.mancato_needed -= 1
|
||||
else:
|
||||
if self.attacker and "gold_rush" in self.game.expansions and not self.is_ghost:
|
||||
if isinstance(self.attacker, Player):
|
||||
self.attacker.gold_nuggets += 1
|
||||
self.attacker.notify_self()
|
||||
self.lives -= 1
|
||||
self.mancato_needed = 0
|
||||
if self.mancato_needed <= 0:
|
||||
@ -1592,7 +1583,7 @@ class Player:
|
||||
"icon": p.role.icon
|
||||
if (self.game.initial_players == 3)
|
||||
else "⭐️"
|
||||
if isinstance(p.role, r.Sheriff)
|
||||
if p["is_sheriff"]
|
||||
else "🤠",
|
||||
"avatar": p.avatar,
|
||||
"is_character": True,
|
||||
@ -1872,10 +1863,7 @@ class Player:
|
||||
):
|
||||
self.expected_response.append(cs.Bang(0, 0).name)
|
||||
if self.character.check(self.game, chw.BigSpencer):
|
||||
self.expected_response = self.game.deck.mancato_cards.copy()
|
||||
self.expected_response.remove(cs.Mancato(0, 0).name)
|
||||
if any((isinstance(c, trt.Caboose) for c in self.equipment)):
|
||||
self.expected_response.append([c.name for c in self.equipment if not c.usable_next_turn])
|
||||
self.expected_response = []
|
||||
self.on_failed_response_cb = self.take_damage_response
|
||||
self.notify_self()
|
||||
|
||||
@ -1938,7 +1926,7 @@ class Player:
|
||||
self.notify_self()
|
||||
|
||||
def get_discarded(self, attacker=None, card_name=None, action=None):
|
||||
if card_name in {"Tornado", "Poker", "Bandidos", "Circus Wagon"}:
|
||||
if card_name in {"Tornado", "Poker", "Bandidos"}:
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
self.available_cards = self.hand.copy()
|
||||
if card_name == "Tornado":
|
||||
@ -1947,18 +1935,10 @@ class Player:
|
||||
self.choose_text = "choose_poker"
|
||||
if card_name == "Bandidos":
|
||||
self.choose_text = "choose_bandidos"
|
||||
self.attacker = attacker
|
||||
self.mancato_needed = min(2, len(self.hand))
|
||||
self.available_cards.append(
|
||||
{"name": "-1hp", "icon": "💔", "noDesc": True}
|
||||
)
|
||||
if card_name == "Circus Wagon":
|
||||
from bang.expansions.train_robbery.trains import CircusWagon
|
||||
self.set_choose_action(
|
||||
"choose_circus_wagon",
|
||||
self.hand.copy(),
|
||||
CircusWagon.choose_circus_wagon,
|
||||
)
|
||||
return True
|
||||
else:
|
||||
if self.can_escape(card_name) or self.character.check(
|
||||
@ -2008,17 +1988,6 @@ class Player:
|
||||
self.attacker = attacker
|
||||
self.attacking_card = card_name
|
||||
print(f"attacker -> {attacker}")
|
||||
# check for trt.PrivateCar
|
||||
if (card_name == "Bang!" and any(
|
||||
(isinstance(c, trt.PrivateCar) for c in self.equipment)
|
||||
) and len(self.hand) == 0):
|
||||
self.take_no_damage_response()
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=self.game.name,
|
||||
data=f"_in_private_car|{self.name}|{attacker.name}",
|
||||
)
|
||||
return False
|
||||
if (
|
||||
isinstance(attacker, Player)
|
||||
and attacker.character.check(self.game, tvosch.ColoradoBill)
|
||||
@ -2063,7 +2032,7 @@ class Player:
|
||||
)
|
||||
)
|
||||
and not self.can_escape(card_name)
|
||||
):
|
||||
) or card_name == "Mira":
|
||||
print("Cant defend")
|
||||
if not no_dmg:
|
||||
self.take_damage_response()
|
||||
@ -2106,8 +2075,8 @@ class Player:
|
||||
)
|
||||
if (
|
||||
self.character.check(self.game, chars.CalamityJanet)
|
||||
or self.game.check_event(cew.RegolamentoDiConti)
|
||||
) and cs.Bang(0, 0).name not in self.expected_response:
|
||||
and cs.Bang(0, 0).name not in self.expected_response
|
||||
):
|
||||
self.expected_response.append(cs.Bang(0, 0).name)
|
||||
if self.character.check(self.game, chw.BigSpencer):
|
||||
self.expected_response = []
|
||||
@ -2124,7 +2093,9 @@ class Player:
|
||||
if len(equipments) == 0:
|
||||
return False
|
||||
else:
|
||||
self.set_choose_action("choose_dalton", equipments)
|
||||
self.choose_text = "choose_dalton"
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
self.available_cards = equipments
|
||||
return True
|
||||
|
||||
def get_indians(self, attacker):
|
||||
@ -2134,11 +2105,6 @@ class Player:
|
||||
(isinstance(c, grc.Calumet) for c in self.gold_rush_equipment)
|
||||
):
|
||||
return False
|
||||
# check for trt.PrisonerCar
|
||||
if any(
|
||||
(isinstance(c, trt.PrisonerCar) for c in self.equipment)
|
||||
):
|
||||
return False
|
||||
if (
|
||||
not self.game.is_competitive
|
||||
and not any(
|
||||
@ -2172,11 +2138,6 @@ class Player:
|
||||
def get_dueled(self, attacker):
|
||||
self.attacker = attacker
|
||||
self.attacking_card = "Duello"
|
||||
if not self.is_my_turn and any(
|
||||
(isinstance(c, trt.PrisonerCar) for c in self.equipment)
|
||||
):
|
||||
self.take_no_damage_response()
|
||||
return False
|
||||
if (self.game.check_event(ceh.Sermone) and self.is_my_turn) or (
|
||||
not self.game.is_competitive
|
||||
and not any(
|
||||
@ -2234,9 +2195,6 @@ class Player:
|
||||
break
|
||||
|
||||
def take_damage_response(self):
|
||||
if self.attacking_card == "Mira":
|
||||
self.lives -= 2
|
||||
else:
|
||||
self.lives -= 1
|
||||
G.sio.emit("hurt", room=self.sid, data=f"")
|
||||
if self.lives > 0:
|
||||
@ -2372,7 +2330,7 @@ class Player:
|
||||
self.game.deck.scrap(card, True, player=self)
|
||||
self.notify_self()
|
||||
self.mancato_needed -= 1
|
||||
if isinstance(card, tvosc.RitornoDiFiamma) and self.attacker != "Roulette Russa":
|
||||
if isinstance(card, tvosc.RitornoDiFiamma):
|
||||
self.game.attack(self, self.attacker.name, card_name=card.name)
|
||||
if self.mancato_needed <= 0:
|
||||
if self.event_type == "duel":
|
||||
@ -2507,35 +2465,14 @@ class Player:
|
||||
self.game.deck.draw(True, player=self)
|
||||
self.game.deck.draw(True, player=self)
|
||||
self.special_use_count += 1
|
||||
gary_looter = None
|
||||
for p in self.game.players:
|
||||
if p != self and p.character.check(self.game, chw.GaryLooter):
|
||||
gary_looter = p
|
||||
break
|
||||
if gary_looter is not None:
|
||||
G.sio.emit(
|
||||
"card_drawn",
|
||||
room=self.game.name,
|
||||
data={"player": gary_looter.name, "pile": self.name},
|
||||
)
|
||||
gary_looter.hand.append(card)
|
||||
gary_looter.notify_self()
|
||||
else:
|
||||
self.game.deck.scrap(card, player=self)
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=self.game.name,
|
||||
data=f"_scrapped|{self.name}|{card.name}|{card.num_suit()}",
|
||||
)
|
||||
self.notify_self()
|
||||
|
||||
def special(self, data):
|
||||
self.character.special(self, data)
|
||||
|
||||
def gold_rush_discard(self):
|
||||
self.set_choose_action(
|
||||
"gold_rush_discard",
|
||||
[
|
||||
self.available_cards = [
|
||||
{
|
||||
"name": p.name,
|
||||
"icon": p.role.icon
|
||||
@ -2550,12 +2487,11 @@ class Player:
|
||||
}
|
||||
for p in self.game.get_alive_players()
|
||||
if p != self
|
||||
and any(
|
||||
(e.number + 1 <= self.gold_nuggets for e in p.gold_rush_equipment)
|
||||
)
|
||||
and any((e.number + 1 <= self.gold_nuggets for e in p.gold_rush_equipment))
|
||||
]
|
||||
+ [{"icon": "❌", "noDesc": True}],
|
||||
)
|
||||
self.available_cards.append({"icon": "❌", "noDesc": True})
|
||||
self.choose_text = "gold_rush_discard"
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
self.notify_self()
|
||||
|
||||
def buy_gold_rush_card(self, index):
|
||||
@ -2583,59 +2519,8 @@ class Player:
|
||||
self.game.deck.shop_deck.append(card)
|
||||
self.game.deck.shop_cards[index] = None
|
||||
self.game.deck.fill_gold_rush_shop()
|
||||
G.sio.emit(
|
||||
"card_scrapped",
|
||||
room=self.game.name,
|
||||
data={"player": self.name, "pile": "gold_rush", "card": card.__dict__},
|
||||
)
|
||||
self.notify_self()
|
||||
|
||||
def buy_train(self, index):
|
||||
if self.pending_action != PendingAction.PLAY:
|
||||
return
|
||||
print(
|
||||
f"{self.name} wants to buy train card on station index {index} in room {self.game.name}"
|
||||
)
|
||||
station: trs.StationCard = self.game.deck.stations[index]
|
||||
train_index = len(self.game.deck.current_train) - 5 - index
|
||||
if train_index < 0 or train_index >= len(self.game.deck.current_train):
|
||||
return
|
||||
|
||||
train: trt.TrainCard = self.game.deck.current_train[train_index]
|
||||
if train is not None and not train.is_locomotive:
|
||||
if station.check_price(self):
|
||||
print(f"{station=} {train=}")
|
||||
station.attached_train = train
|
||||
G.sio.emit(
|
||||
"chat_message",
|
||||
room=self.game.name,
|
||||
data=f"_bought_train|{self.name}|{station.name}|{train.name}",
|
||||
)
|
||||
G.sio.emit(
|
||||
"card_scrapped",
|
||||
room=self.game.name,
|
||||
data={"player": self.name, "pile": "train_robbery", "card": train.__dict__},
|
||||
)
|
||||
# shift train forward
|
||||
for i in range(train_index, len(self.game.deck.current_train) - 1):
|
||||
self.game.deck.current_train[i] = self.game.deck.current_train[
|
||||
i + 1
|
||||
]
|
||||
self.game.notify_stations()
|
||||
# self.game.deck.current_train[train_index] = None
|
||||
self.notify_self()
|
||||
|
||||
def set_choose_action(
|
||||
self,
|
||||
choose_text: str,
|
||||
available_cards: List,
|
||||
did_choose_callback: Callable[['Player', int], None] = None,
|
||||
):
|
||||
self.pending_action = PendingAction.CHOOSE
|
||||
self.choose_text = choose_text
|
||||
self.available_cards = available_cards
|
||||
self.did_choose_callback = did_choose_callback
|
||||
|
||||
def check_can_end_turn(self):
|
||||
must_be_used_cards = [c for c in self.hand if c.must_be_used]
|
||||
if self.game.check_event(ce.LeggeDelWest) and len(must_be_used_cards) > 0:
|
||||
@ -2745,8 +2630,6 @@ class Player:
|
||||
and not self.equipment[i].can_be_used_now
|
||||
):
|
||||
self.equipment[i].can_be_used_now = True
|
||||
if isinstance(self.equipment[i], trt.TrainCard):
|
||||
self.equipment[i].usable_next_turn = False
|
||||
for i in range(len(self.hand)):
|
||||
if self.hand[i].must_be_used:
|
||||
self.hand[i].must_be_used = False
|
||||
|
@ -1,17 +1,6 @@
|
||||
from enum import IntEnum
|
||||
|
||||
|
||||
class G:
|
||||
sio = None
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
class PendingAction(IntEnum):
|
||||
PICK = 0
|
||||
DRAW = 1
|
||||
PLAY = 2
|
||||
RESPOND = 3
|
||||
WAIT = 4
|
||||
CHOOSE = 5
|
||||
|
@ -1,10 +1,10 @@
|
||||
certifi==2022.12.7
|
||||
dnspython==2.3.0
|
||||
eventlet==0.35.2
|
||||
eventlet==0.33.3
|
||||
python-engineio==4.3.4
|
||||
python-socketio==5.8.0
|
||||
six==1.16.0
|
||||
pytest==7.2.2
|
||||
requests==2.32.0
|
||||
requests==2.31.0
|
||||
discord-webhook==1.1.0
|
||||
datadog==0.45.0
|
@ -16,8 +16,8 @@ import socketio
|
||||
from discord_webhook import DiscordWebhook
|
||||
|
||||
from bang.game import Game
|
||||
from bang.players import Player
|
||||
from globals import G, PendingAction
|
||||
from bang.players import PendingAction, Player
|
||||
from globals import G
|
||||
from metrics import Metrics
|
||||
|
||||
sys.setrecursionlimit(10**6) # this should prevents bots from stopping
|
||||
@ -58,7 +58,7 @@ for file in [f for f in os.listdir(".") if ".js" in f or ".map" in f or ".html"
|
||||
static_files[f"/{file}"] = f"./{file}"
|
||||
|
||||
HASTEBIN_HEADERS = {
|
||||
"Authorization": "Bearer " + os.getenv("HASTEBIN_TOKEN", ""),
|
||||
"Authorization": "Bearer 2cf615e88992970f3396663c5bfb2f599151192bcef5fa99f5569c2e29617ba7cdcfa5df14f90afc61bcf0fe6e475ae49cba98ebded3e0b7b3fdf0c648c76496",
|
||||
"content-type": "text/plain",
|
||||
}
|
||||
|
||||
@ -179,6 +179,32 @@ def get_online_players(sid):
|
||||
sio.emit("players", room="lobby", data=online_players)
|
||||
|
||||
|
||||
@sio.event
|
||||
def mouse_position(sid, data):
|
||||
ses: Player = sio.get_session(sid)
|
||||
if ses.game is not None:
|
||||
if not data or (data["x"] == 0 and data["y"] == 0):
|
||||
print("Mouse position is 0,0, ignoring")
|
||||
else:
|
||||
data["color"] = sid.encode("utf-8").hex()[0:6]
|
||||
ses.game.mouse_positions[ses.name] = data
|
||||
sio.emit(
|
||||
"mouse_positions_update",
|
||||
room=ses.game.name,
|
||||
data=[
|
||||
{
|
||||
"name": x,
|
||||
"data": {
|
||||
"x": data["x"],
|
||||
"y": data["y"],
|
||||
"color": data["color"],
|
||||
},
|
||||
}
|
||||
for x, data in ses.game.mouse_positions.items()
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@sio.event
|
||||
@bang_handler
|
||||
def report(sid, text):
|
||||
@ -262,21 +288,15 @@ def get_me(sid, data):
|
||||
if sio.get_session(sid).game:
|
||||
sio.get_session(sid).game.notify_room()
|
||||
else:
|
||||
dt = data.get("discord_token", None)
|
||||
username = data.get("username", None)
|
||||
if username is None:
|
||||
username = f"player_{random.randint(0,100)}"
|
||||
sio.save_session(sid, Player(username, sid, discord_token=dt))
|
||||
p = sio.get_session(sid)
|
||||
print(f"{sid} is now {username}")
|
||||
dt = data["discord_token"] if "discord_token" in data else None
|
||||
sio.save_session(sid, Player("player", sid, discord_token=dt))
|
||||
if "replay" in data and data["replay"] is not None:
|
||||
create_room(sid, data["replay"])
|
||||
p.game.is_hidden = True
|
||||
sid = sio.get_session(sid)
|
||||
sid.game.is_hidden = True
|
||||
eventlet.sleep(0.5)
|
||||
response = requests.get(
|
||||
f"https://hastebin.com/raw/{data['replay']}",
|
||||
headers=HASTEBIN_HEADERS,
|
||||
timeout=3,
|
||||
f"https://hastebin.com/raw/{data['replay']}", headers=HASTEBIN_HEADERS
|
||||
)
|
||||
if response.status_code != 200:
|
||||
sio.emit(
|
||||
@ -286,20 +306,20 @@ def get_me(sid, data):
|
||||
)
|
||||
return
|
||||
log = response.text.splitlines()
|
||||
p.game.spectators.append(p)
|
||||
sid.game.spectators.append(sid)
|
||||
if "ffw" not in data:
|
||||
p.game.replay(log)
|
||||
sid.game.replay(log)
|
||||
else:
|
||||
p.game.replay(log, speed=0, fast_forward=int(data["ffw"]))
|
||||
sid.game.replay(log, speed=0, fast_forward=int(data["ffw"]))
|
||||
return
|
||||
if data["name"] in games and (room := games[data["name"]]) is not None:
|
||||
if not room.started:
|
||||
join_room(sid, data)
|
||||
elif room.started:
|
||||
print("room exists")
|
||||
if username != "player" and any(
|
||||
if data["username"] is not None and any(
|
||||
(
|
||||
p.name == username
|
||||
p.name == data["username"]
|
||||
for p in room.players
|
||||
if (
|
||||
p.is_bot
|
||||
@ -317,7 +337,7 @@ def get_me(sid, data):
|
||||
or (dt is not None and p.discord_token == dt)
|
||||
or p.sid is None
|
||||
)
|
||||
and p.name == username
|
||||
and p.name == data["username"]
|
||||
][0]
|
||||
bot.sid = sid
|
||||
bot.is_bot = False
|
||||
@ -346,33 +366,29 @@ def get_me(sid, data):
|
||||
room.notify_scrap_pile(sid)
|
||||
room.notify_all()
|
||||
room.notify_gold_rush_shop()
|
||||
room.notify_stations()
|
||||
room.notify_event_card()
|
||||
room.notify_event_card_wildwestshow(sid)
|
||||
else:
|
||||
create_room(sid, data["name"])
|
||||
p: Player = sio.get_session(sid)
|
||||
if p.game is None:
|
||||
if (p := sio.get_session(sid)).game is None:
|
||||
sio.emit("me", data={"error": "Wrong password/Cannot connect"}, room=sid)
|
||||
else:
|
||||
sio.emit("me", data=p.name, room=sid)
|
||||
if username == "player" or any(
|
||||
if data["username"] is None or any(
|
||||
(
|
||||
pl.name == username
|
||||
pl.name == data["username"]
|
||||
for pl in p.game.players
|
||||
if not (
|
||||
(dt is not None and pl.discord_token == dt)
|
||||
or pl.sid is None
|
||||
or pl == p
|
||||
(dt is not None and pl.discord_token == dt) or pl.sid is None
|
||||
)
|
||||
)
|
||||
):
|
||||
sio.emit("change_username", room=sid)
|
||||
elif p.name != username:
|
||||
else:
|
||||
sio.emit(
|
||||
"chat_message",
|
||||
room=p.game.name,
|
||||
data=f"_change_username|{p.name}|{username}",
|
||||
data=f"_change_username|{p.name}|{data['username']}",
|
||||
)
|
||||
p.name = data["username"]
|
||||
sio.emit("me", data=p.name, room=sid)
|
||||
@ -423,11 +439,8 @@ def private(sid):
|
||||
@sio.event
|
||||
@bang_handler
|
||||
def toggle_expansion(sid, expansion_name):
|
||||
game = sio.get_session(sid).game
|
||||
if "suggest" in expansion_name:
|
||||
sio.emit("suggest_expansion", room=game.name, data=expansion_name.split(";")[1])
|
||||
return
|
||||
game.toggle_expansion(expansion_name)
|
||||
g = sio.get_session(sid).game
|
||||
g.toggle_expansion(expansion_name)
|
||||
advertise_lobbies()
|
||||
|
||||
|
||||
@ -447,27 +460,29 @@ def toggle_replace_with_bot(sid):
|
||||
@bang_handler
|
||||
def join_room(sid, room):
|
||||
room_name = room["name"]
|
||||
pwd = room.get("password", "")
|
||||
if pwd is None:
|
||||
pwd = ""
|
||||
if games[room_name].password != "" and games[room_name].password != pwd.upper():
|
||||
if (
|
||||
games[room_name].password != ""
|
||||
and games[room_name].password != room.get("password", "").upper()
|
||||
):
|
||||
return
|
||||
player = sio.get_session(sid)
|
||||
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 == player.name and not p.is_bot for p in games[room_name].players)
|
||||
(
|
||||
p.name == sio.get_session(sid).name and not p.is_bot
|
||||
for p in games[room_name].players
|
||||
)
|
||||
):
|
||||
player.name += f"_{random.randint(0,100)}"
|
||||
sio.emit("me", data=player.name, room=sid)
|
||||
games[room_name].add_player(player)
|
||||
sio.get_session(sid).name += f"_{random.randint(0,100)}"
|
||||
sio.emit("me", data=sio.get_session(sid).name, room=sid)
|
||||
games[room_name].add_player(sio.get_session(sid))
|
||||
advertise_lobbies()
|
||||
else:
|
||||
games[room_name].spectators.append(player)
|
||||
player.game = games[room_name]
|
||||
player.pending_action = PendingAction.WAIT
|
||||
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[room_name].name)
|
||||
games[room_name].notify_room(sid)
|
||||
eventlet.sleep(0.5)
|
||||
@ -679,14 +694,6 @@ def buy_gold_rush_card(sid, data: int):
|
||||
ses.buy_gold_rush_card(data)
|
||||
|
||||
|
||||
@sio.event
|
||||
@bang_handler
|
||||
def buy_train(sid, data: int):
|
||||
ses: Player = sio.get_session(sid)
|
||||
ses.game.rpc_log.append(f"{ses.name};buy_train;{data}")
|
||||
ses.buy_train(data)
|
||||
|
||||
|
||||
@sio.event
|
||||
@bang_handler
|
||||
def chat_message(sid, msg, pl=None):
|
||||
@ -761,12 +768,6 @@ def chat_message(sid, msg, pl=None):
|
||||
if "/togglecomp" in msg and ses.game:
|
||||
ses.game.toggle_competitive()
|
||||
return
|
||||
elif "/set_chars" in msg and not ses.game.started:
|
||||
cmd = msg.split()
|
||||
if len(cmd) == 2 and int(cmd[1]) > 0:
|
||||
ses.game.characters_to_distribute = int(cmd[1])
|
||||
ses.game.notify_room()
|
||||
return
|
||||
if "/debug" in msg:
|
||||
cmd = msg.split()
|
||||
if (
|
||||
@ -800,6 +801,10 @@ def chat_message(sid, msg, pl=None):
|
||||
"text": "debug mode is not active, only the owner of the room can enable it with /debug",
|
||||
},
|
||||
)
|
||||
elif "/set_chars" in msg and not ses.game.started:
|
||||
cmd = msg.split()
|
||||
if len(cmd) == 2 and int(cmd[1]) > 0:
|
||||
ses.game.characters_to_distribute = int(cmd[1])
|
||||
elif "/suicide" in msg and ses.game.started and ses.lives > 0:
|
||||
ses.lives = 0
|
||||
ses.notify_self()
|
||||
@ -1038,9 +1043,7 @@ def chat_message(sid, msg, pl=None):
|
||||
|
||||
cmd = msg.split()
|
||||
if len(cmd) >= 2:
|
||||
import bang.expansions.train_robbery.trains as trt
|
||||
cards = cs.get_starting_deck(ses.game.expansions)
|
||||
cards.extend(trt.get_all_cards())
|
||||
card_names = " ".join(cmd[1:]).split(",")
|
||||
for cn in card_names:
|
||||
ses.equipment.append(
|
||||
@ -1099,21 +1102,6 @@ def chat_message(sid, msg, pl=None):
|
||||
"type": "json",
|
||||
},
|
||||
)
|
||||
elif "/deckinfo" in msg:
|
||||
sio.emit(
|
||||
"chat_message",
|
||||
room=sid,
|
||||
data={
|
||||
"color": "",
|
||||
"text": json.dumps(
|
||||
ses.game.deck.__dict__,
|
||||
default=lambda o: f"<{o.__class__.__name__}() not serializable>",
|
||||
),
|
||||
"type": "json",
|
||||
},
|
||||
)
|
||||
elif "/trainfw" in msg:
|
||||
ses.game.deck.move_train_forward()
|
||||
elif "/status" in msg and ses.is_admin():
|
||||
sio.emit("mount_status", room=sid)
|
||||
elif "/meinfo" in msg:
|
||||
@ -1308,29 +1296,6 @@ def get_wildwestshowcards(sid):
|
||||
"wwscards_info", room=sid, data=json.dumps(chs, default=lambda o: o.__dict__)
|
||||
)
|
||||
|
||||
@sio.event
|
||||
@bang_handler
|
||||
def get_trainrobberycards(sid):
|
||||
print("get_trainrobberycards")
|
||||
import bang.expansions.train_robbery.cards as trc
|
||||
import bang.expansions.train_robbery.stations as trs
|
||||
import bang.expansions.train_robbery.trains as trt
|
||||
|
||||
chs = []
|
||||
chs.extend(trt.get_locomotives())
|
||||
chs.extend(trt.get_all_cards())
|
||||
sio.emit(
|
||||
"trainrobberycards_info", room=sid, data=json.dumps({
|
||||
"cards": chs,
|
||||
"stations": trs.get_all_stations()
|
||||
}, default=lambda o: o.__dict__)
|
||||
)
|
||||
|
||||
@sio.event
|
||||
@bang_handler
|
||||
def get_expansion_info(sid, id):
|
||||
from bang.expansions import get_expansion_info
|
||||
sio.emit("expansion_info", room=sid, data=json.dumps(get_expansion_info(id), default=lambda o: o.__dict__))
|
||||
|
||||
@sio.event
|
||||
@bang_handler
|
||||
@ -1339,7 +1304,7 @@ def discord_auth(sid, data):
|
||||
"https://discord.com/api/oauth2/token",
|
||||
data={
|
||||
"client_id": "1059452581027532880",
|
||||
"client_secret": os.getenv("DISCORD_SECRET", ""),
|
||||
"client_secret": "Mc8ZlMQhayzi1eOqWFtGHs3L0iXCzaEu",
|
||||
"grant_type": "authorization_code",
|
||||
"redirect_uri": data["origin"],
|
||||
"code": data["code"],
|
||||
|
@ -1,4 +1,3 @@
|
||||
from typing import Any, List
|
||||
import pytest
|
||||
from bang.characters import Character
|
||||
from bang.game import Game
|
||||
@ -9,7 +8,7 @@ from globals import G
|
||||
G.sio = DummySocket()
|
||||
|
||||
|
||||
def started_game(expansions=[], players=4, character=Character("test_char", 4)) -> Game:
|
||||
def started_game(expansions, players=4, character=Character("test_char", 4)):
|
||||
g = Game("test")
|
||||
g.expansions = expansions
|
||||
ps = [Player(f"p{i}", f"p{i}") for i in range(players)]
|
||||
@ -24,19 +23,19 @@ def started_game(expansions=[], players=4, character=Character("test_char", 4))
|
||||
return g
|
||||
|
||||
|
||||
def set_events(g: Game, event_cards) -> None:
|
||||
def set_events(g: Game, event_cards):
|
||||
g.deck.event_cards = event_cards
|
||||
|
||||
|
||||
def current_player(g: Game) -> Player:
|
||||
def current_player(g: Game):
|
||||
return g.players[g.turn]
|
||||
|
||||
|
||||
def next_player(g: Game) -> Player:
|
||||
def next_player(g: Game):
|
||||
return g.players[(g.turn + 1) % len(g.players)]
|
||||
|
||||
|
||||
def current_player_with_cards(g: Game, cards: List[Any]) -> Player:
|
||||
def current_player_with_cards(g: Game, cards):
|
||||
p = current_player(g)
|
||||
p.draw("")
|
||||
p.hand = cards
|
||||
|
@ -3,8 +3,7 @@ from bang.characters import Character
|
||||
from bang.cards import *
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player
|
||||
from globals import PendingAction
|
||||
from bang.players import Player, PendingAction
|
||||
|
||||
# test card Barile
|
||||
def test_barile():
|
||||
|
@ -2,8 +2,7 @@ from random import randint
|
||||
from bang.characters import *
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player
|
||||
from globals import PendingAction
|
||||
from bang.players import Player, PendingAction
|
||||
from bang.cards import *
|
||||
|
||||
def test_bartcassidy():
|
||||
|
@ -3,7 +3,7 @@ from bang.characters import Character
|
||||
from bang.expansions.dodge_city.cards import *
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player
|
||||
from bang.players import Player, PendingAction
|
||||
import bang.cards as cs
|
||||
|
||||
# test Borraccia
|
||||
|
@ -1,9 +1,8 @@
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player
|
||||
from bang.players import Player, PendingAction
|
||||
from bang.roles import *
|
||||
from bang.cards import *
|
||||
from globals import PendingAction
|
||||
from tests import started_game
|
||||
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
from bang.characters import Character
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player
|
||||
from globals import PendingAction
|
||||
from bang.players import Player, PendingAction
|
||||
from bang.roles import *
|
||||
from bang.cards import *
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
from tests import started_game, set_events, current_player, next_player, current_player_with_cards
|
||||
|
||||
from bang.expansions.fistful_of_cards.card_events import *
|
||||
import bang.cards as cs
|
||||
|
||||
|
||||
def test_miniera_abbandonata():
|
||||
g = started_game(['fistful_of_cards'])
|
||||
set_events(g, [MinieraAbbandonata()])
|
||||
p = current_player(g)
|
||||
starting_cards = len(p.hand)
|
||||
g.deck.scrap_pile = [
|
||||
cs.Bang(0, 0),
|
||||
cs.Bang(0, 1),
|
||||
cs.Bang(0, 2),
|
||||
cs.Bang(0, 3),
|
||||
]
|
||||
p.draw("")
|
||||
assert len(p.hand) == starting_cards + 2
|
||||
# check the last two cards are the ones from the scrap pile
|
||||
assert p.hand[-2].name == cs.Bang(0, 0).name
|
||||
assert p.hand[-2].number == 3
|
||||
assert p.hand[-1].name == cs.Bang(0, 0).name
|
||||
assert p.hand[-1].number == 2
|
@ -1,24 +0,0 @@
|
||||
from random import randint
|
||||
from bang.characters import Character
|
||||
from bang.expansions.train_robbery.trains import *
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player
|
||||
import bang.cards as cs
|
||||
from globals import PendingAction
|
||||
|
||||
from tests import started_game, set_events, current_player, next_player, current_player_with_cards
|
||||
|
||||
|
||||
def test_cattle_truck():
|
||||
g = started_game()
|
||||
|
||||
g.deck.scrap_pile = [cs.CatBalou(0,1), cs.CatBalou(0,2), cs.CatBalou(0,3)]
|
||||
p = current_player_with_cards(g, [CattleTruck()])
|
||||
p.play_card(0)
|
||||
|
||||
assert p.pending_action == PendingAction.CHOOSE
|
||||
p.choose(0)
|
||||
assert p.pending_action == PendingAction.PLAY
|
||||
assert len(p.hand) == 1
|
||||
assert len(g.deck.scrap_pile) == 2
|
@ -3,9 +3,8 @@ from bang.characters import Character
|
||||
from bang.expansions.the_valley_of_shadows.characters import *
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player
|
||||
from bang.players import Player, PendingAction
|
||||
import bang.cards as cs
|
||||
from globals import PendingAction
|
||||
|
||||
# test TucoFranziskaner
|
||||
def test_TucoFranziskaner():
|
||||
|
@ -3,12 +3,8 @@ from bang.characters import Character
|
||||
from bang.expansions.the_valley_of_shadows.cards import *
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player
|
||||
from bang.players import Player, PendingAction
|
||||
import bang.cards as cs
|
||||
from globals import PendingAction
|
||||
|
||||
from tests import started_game, set_events, current_player, next_player, current_player_with_cards
|
||||
|
||||
|
||||
# test UltimoGiro
|
||||
def test_ultimo_giro():
|
||||
@ -226,29 +222,6 @@ def test_bandidos():
|
||||
assert p1.pending_action == PendingAction.WAIT
|
||||
assert p.pending_action == PendingAction.PLAY
|
||||
|
||||
def test_bandidos_with_gold_rush():
|
||||
g = Game('test')
|
||||
g.expansions = ['gold_rush']
|
||||
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 = [Character('test_char', 4)]
|
||||
p.set_character(p.available_characters[0].name)
|
||||
p = g.players[g.turn]
|
||||
p1 = g.players[(g.turn+1)%3]
|
||||
p.draw('')
|
||||
p.hand = [Bandidos(0,0), Bandidos(0,0)]
|
||||
p.play_card(0)
|
||||
assert len(p.hand) == 1
|
||||
assert p.pending_action == PendingAction.WAIT
|
||||
assert p1.pending_action == PendingAction.CHOOSE
|
||||
p1.choose(len(p1.hand))
|
||||
assert p1.lives == 3
|
||||
assert p.pending_action == PendingAction.PLAY
|
||||
assert p.gold_nuggets == 1
|
||||
|
||||
# test Poker
|
||||
def test_poker():
|
||||
g = Game('test')
|
||||
@ -304,63 +277,3 @@ def test_tornado():
|
||||
assert p.pending_action == PendingAction.PLAY
|
||||
assert len(p.hand) == 2
|
||||
assert len(p1.hand) == 2
|
||||
|
||||
|
||||
def test_sventagliata():
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
for p in ps:
|
||||
p.available_characters = [Character('test_char', 4)]
|
||||
p.set_character(p.available_characters[0].name)
|
||||
|
||||
p = g.players[g.turn]
|
||||
p1 = g.players[(g.turn + 1) % 3]
|
||||
p2 = g.players[(g.turn + 2) % 3]
|
||||
|
||||
p.draw('')
|
||||
p.hand = [Sventagliata('Hearts', 10), Bang('Hearts', 10)]
|
||||
p1.hand = [Mancato('Spades', 2)]
|
||||
p2.hand = [Mancato('Clubs', 5)]
|
||||
|
||||
# Play Sventagliata
|
||||
p.play_card(0, against=p1.name)
|
||||
assert p.pending_action == PendingAction.CHOOSE
|
||||
assert len(p.available_cards) > 0 # Ensure there are available targets
|
||||
|
||||
# Simulate choosing a secondary target
|
||||
secondary_target = p.available_cards[0]['name']
|
||||
assert secondary_target != p.name and secondary_target != p1.name # Ensure the secondary target is correct
|
||||
p.choose(0) # Choose the first available target
|
||||
|
||||
assert p.pending_action == PendingAction.WAIT
|
||||
assert p1.pending_action == PendingAction.RESPOND
|
||||
|
||||
# Simulate p1 responding to the Bang
|
||||
p1.respond(0) # Assuming p1 plays a Mancato card in response
|
||||
assert p1.pending_action == PendingAction.WAIT
|
||||
assert p.pending_action == PendingAction.WAIT
|
||||
|
||||
p2.respond(0) # Assuming p2 plays a Mancato card in response
|
||||
assert p2.pending_action == PendingAction.WAIT
|
||||
assert p.pending_action == PendingAction.PLAY
|
||||
|
||||
# check bang cannot be played
|
||||
assert len(p.hand) == 1
|
||||
p.play_card(0, against=p2.name)
|
||||
assert p.pending_action == PendingAction.PLAY
|
||||
assert len(p.hand) == 1
|
||||
|
||||
|
||||
def test_mira():
|
||||
g = started_game(['the_valley_of_shadows'])
|
||||
p = current_player(g)
|
||||
p.draw('')
|
||||
p.hand = [Mira(0, 0), Bang(0, 0)]
|
||||
target = next_player(g)
|
||||
target.hand = []
|
||||
target_health = target.lives
|
||||
p.play_card(0, against=target.name, _with=1)
|
||||
assert target.lives == target_health - 2
|
||||
|
@ -4,7 +4,7 @@ from tests import started_game, set_events, current_player, next_player, current
|
||||
from bang.expansions.wild_west_show.characters import *
|
||||
from bang.cards import Card, Suit
|
||||
import bang.roles as roles
|
||||
from globals import PendingAction
|
||||
from bang.players import PendingAction
|
||||
|
||||
|
||||
# test TerenKill
|
||||
|
@ -4,7 +4,7 @@ from tests import started_game, set_events, current_player, next_player, current
|
||||
from bang.expansions.wild_west_show.card_events import *
|
||||
from bang.cards import Card, Suit
|
||||
import bang.roles as roles
|
||||
from globals import PendingAction
|
||||
from bang.players import PendingAction
|
||||
|
||||
|
||||
# test Camposanto
|
||||
|
@ -9,11 +9,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@datadog/browser-rum": "^4.36.0",
|
||||
"@vueuse/core": "^9.13.0",
|
||||
"bang-vue-socket.io": "^4.0.0",
|
||||
"caniuse-lite": "^1.0.30001470",
|
||||
"pretty-checkbox-vue": "^1.1.9",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"vue": "^2.7.16",
|
||||
"vue": "^2.7.14",
|
||||
"vue-clipboard2": "^0.3.3",
|
||||
"vue-i18n": "^8.28.2",
|
||||
"vue-json-viewer": "^2.2.22",
|
||||
@ -22,7 +23,7 @@
|
||||
"devDependencies": {
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-plugin-vue": "^9.10.0",
|
||||
"vite": "^4.5.3",
|
||||
"vite": "^4.2.1",
|
||||
"vite-plugin-html": "^3.2.0",
|
||||
"vite-plugin-pwa": "^0.14.6",
|
||||
"vite-plugin-vue2": "^2.0.3",
|
||||
|
@ -29,7 +29,7 @@
|
||||
</select>
|
||||
<select id="lang" class="btn" v-model="$i18n.locale" @change="storeLangPref">
|
||||
<option
|
||||
v-for="(lang, i) in ['it.🇮🇹.Italiano', 'en.🇬🇧.English', 'cs.🇨🇿.Čeština', 'fr.🇫🇷.Français', 'es.🇪🇸.Español', 'ru.🇷🇺.Русский']"
|
||||
v-for="(lang, i) in ['it.🇮🇹.Italiano', 'en.🇬🇧.English', 'cs.🇨🇿.Čeština']"
|
||||
:key="`lang-${i}`"
|
||||
:value="lang.split('.')[0]">
|
||||
{{lang.split('.')[1]}} {{lang.split('.')[2]}}
|
||||
@ -189,7 +189,6 @@ export default {
|
||||
trackResources: true, //non so cosa faccia, proviamo
|
||||
trackLongTasks: true, //non so cosa faccia, proviamo
|
||||
defaultPrivacyLevel: 'allow',
|
||||
enableExperimentalFeatures: ['clickmap'],
|
||||
proxyUrl: (Vue.config.devtools ? `http://${window.location.hostname}:5001` : window.location.origin) + '/ddproxy',
|
||||
});
|
||||
datadogRum.setUser({name: localStorage.getItem('username')})
|
||||
|
@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<p class="animated" :style="style">{{text}}</p>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AnimatedEffect',
|
||||
props: {
|
||||
text: String,
|
||||
startPosition: Object,
|
||||
},
|
||||
data: () => ({
|
||||
style: ''
|
||||
}),
|
||||
computed: {
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
mounted() {
|
||||
let startPosition = {
|
||||
top: this.startPosition.top + Math.random() * 100 - 50,
|
||||
left: this.startPosition.left + Math.random() * 100 - 25,
|
||||
}
|
||||
let endPosition = {
|
||||
top: startPosition.top + Math.random() * 50 - 25,
|
||||
left: startPosition.left + Math.random() * 50 - 25,
|
||||
}
|
||||
this.style = `position: absolute;top:${startPosition.top}px;left: ${startPosition.left}px;`
|
||||
setTimeout(() => {
|
||||
this.style = `position:absolute;;top:${endPosition.top}px;left:${endPosition.left}px;`
|
||||
}, 400)
|
||||
setTimeout(() => {
|
||||
this.style = `position:absolute;;top:${endPosition.top}px;left:${endPosition.left}px;opacity:0;`
|
||||
}, 900)
|
||||
setTimeout(() => {
|
||||
this.style = `display:none;`
|
||||
}, 1500)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.animated {
|
||||
position: absolute;
|
||||
font-size: 26pt;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
</style>
|
@ -11,7 +11,6 @@
|
||||
'gold-rush': card.expansion === 'gold_rush',
|
||||
brown: card.kind === 0,
|
||||
black: card.kind === 1,
|
||||
'train-piece': card.type && card.type === 'train',
|
||||
}"
|
||||
>
|
||||
<h4>{{ cardName }}</h4>
|
||||
@ -21,7 +20,6 @@
|
||||
:style="`background-image: url(${card.avatar});`"
|
||||
></div>
|
||||
<div :class="{ emoji: true, bottomed: card.avatar }">{{ emoji }}</div>
|
||||
<div v-if="card.isMe" :class="{ emoji: true, bottomed: card.avatar, isMe: true }"></div>
|
||||
<div class="alt_text">{{ card.alt_text }}</div>
|
||||
<div class="suit">
|
||||
{{ number
|
||||
@ -65,7 +63,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;
|
||||
@ -116,7 +114,7 @@ export default {
|
||||
#816b45 10px
|
||||
);
|
||||
}
|
||||
.card:not(.back, .fistful-of-cards, .high-noon, .gold-rush, .train-piece):before {
|
||||
.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%),
|
||||
@ -232,18 +230,6 @@ export default {
|
||||
padding: 4pt;
|
||||
border-radius: 12pt;
|
||||
}
|
||||
.wip::after {
|
||||
content: "WIP";
|
||||
position: absolute;
|
||||
bottom: -12pt;
|
||||
right: -12pt;
|
||||
background: red;
|
||||
font-size: 10pt;
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
font-weight: bold;
|
||||
padding: 4pt;
|
||||
border-radius: 12pt;
|
||||
}
|
||||
.avatar {
|
||||
position: absolute;
|
||||
width: 36pt;
|
||||
@ -285,42 +271,10 @@ export default {
|
||||
font-size: 26pt;
|
||||
top: 35%;
|
||||
}
|
||||
.card .emoji.isMe {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 16pt;
|
||||
top: 52%;
|
||||
right: 12pt;
|
||||
}
|
||||
.emoji.isMe::after {
|
||||
content: "🫵";
|
||||
display: block;
|
||||
}
|
||||
.card:HOVER .isMe::after {
|
||||
content: "👋";
|
||||
animation: wave 0.5s infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
@keyframes wave {
|
||||
0% {
|
||||
transform: translate(-5px, 0px) rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: translate(-5px, -5px) rotate(25deg);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-5px, 0) rotate(0deg);
|
||||
}
|
||||
}
|
||||
.emoji.bottomed {
|
||||
top: 45%;
|
||||
left: 8pt;
|
||||
}
|
||||
.emoji.bottomed.emoji.isMe {
|
||||
top: 60%;
|
||||
left: -5pt;
|
||||
}
|
||||
.card.must-be-used {
|
||||
filter: drop-shadow(0 0 5px red);
|
||||
}
|
||||
@ -351,7 +305,6 @@ export default {
|
||||
}
|
||||
.cant-play {
|
||||
filter: brightness(0.5);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.expansion {
|
||||
position: absolute;
|
||||
@ -361,24 +314,4 @@ export default {
|
||||
border-radius: 100%;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
.train-piece {
|
||||
background: linear-gradient(180deg, rgba(218,101,64,1) 0%, rgba(217,197,184,1) 13%, rgba(217,197,184,1) 53%, rgba(235,169,95,1) 61%, rgba(158,81,55,1) 91%, rgba(158,81,55,1) 100%);
|
||||
box-shadow: 0 0 0pt 2pt var(--font-color), 0 0 5pt 2pt #aaa;
|
||||
}
|
||||
.train-piece .emoji {
|
||||
transform: scaleX(-1);
|
||||
/* filter: grayscale(1); */
|
||||
}
|
||||
.train-piece .suit, .train-piece .expansion {
|
||||
display: none;
|
||||
}
|
||||
.train-piece h4 {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
bottom: -10pt;
|
||||
top: unset;
|
||||
font-size: 11pt;
|
||||
color: #FFE27E;
|
||||
}
|
||||
</style>
|
@ -21,8 +21,7 @@
|
||||
@click="fillCmd(msg.cmd)">{{msg.cmd}} <i class="std-text" style="font-size:8pt;">{{msg.help}}</i></p>
|
||||
</div>
|
||||
<form @submit="sendChatMessage" id="msg-form">
|
||||
<input id="my-msg" autocomplete="off" v-model="text" style="flex-grow:2;"
|
||||
@keydown.tab.prevent="tabComplete($event.target.value)"/>
|
||||
<input id="my-msg" autocomplete="off" v-model="text" style="flex-grow:2;"/>
|
||||
<input id="submit-message" type="submit" class="btn" :value="$t('submit')"/>
|
||||
</form>
|
||||
</div>
|
||||
@ -78,22 +77,13 @@ export default {
|
||||
msg = msg.text
|
||||
}
|
||||
let desc = undefined
|
||||
let desc_pos = -1
|
||||
let params = msg.split('|')
|
||||
let type = params.shift().substring(1)
|
||||
if (["flipped", "scrapped", "respond", "play_card", "play_card_green", "play_card_with", "purchase_card", "play_card_against", "play_card_against_with", "play_card_for", "spilled_beer", "diligenza", "wellsfargo", "saloon", "special_calamity", "won", "choose_emporio", "died_role"].indexOf(type) !== -1) {
|
||||
if (type.indexOf("_with") !== -1) {
|
||||
params[params.length - 1] = this.$t(`cards.${params[params.length - 1]}.name`)
|
||||
}
|
||||
if (["flipped", "respond", "play_card", "play_card_against", "play_card_for", "spilled_beer", "diligenza", "wellsfargo", "saloon", "special_calamity", "won", "choose_emporio", "died_role"].indexOf(type) !== -1) {
|
||||
desc = this.$t(`cards.${params[1]}.desc`)
|
||||
desc_pos = 3
|
||||
params[1] = this.$t(`cards.${params[1]}.name`)
|
||||
} else if (type === "choose_character"){
|
||||
params.push(this.$t(`cards.${params[1]}.desc`))
|
||||
} else if (type === "flip_event"){
|
||||
desc = this.$t(`cards.${params[0]}.desc`)
|
||||
params[0] = this.$t(`cards.${params[0]}.name`);
|
||||
desc_pos = 1
|
||||
} else if (type === "allroles") {
|
||||
params.forEach((p,i)=>{
|
||||
if (i%2 === 0) {
|
||||
@ -106,11 +96,10 @@ export default {
|
||||
type += "4"
|
||||
}
|
||||
}
|
||||
let parts = this.$t(`chat.${type}`, params).split(';').map((x, i)=>({text:x, desc:(i===desc_pos&&desc?desc:null)}))
|
||||
if (t_color != null) {
|
||||
this.messages.push({color:t_color, bgcolor: bg_color, text:false, parts: parts})
|
||||
this.messages.push({color:t_color, bgcolor: bg_color, text:false, parts:this.$t(`chat.${type}`, params).split(';').map(x=>({text:x}))});
|
||||
} else {
|
||||
this.messages.push({text:false, parts: parts});
|
||||
this.messages.push({text:false, parts: this.$t(`chat.${type}`, params).split(';').map((x, i)=>({text:x, desc:(i===3&&desc?desc:null)}))});
|
||||
}
|
||||
if (type == 'turn' && params[0] == this.username) {
|
||||
this.playEffects(turn_sfx);
|
||||
@ -165,12 +154,6 @@ export default {
|
||||
this.text = cmd;
|
||||
document.getElementById('my-msg').focus();
|
||||
},
|
||||
tabComplete() {
|
||||
if (this.commandSuggestion.length > 0) {
|
||||
let cmd = this.commandSuggestion[0].cmd;
|
||||
this.text = cmd + ' ';
|
||||
}
|
||||
},
|
||||
playEffects(path) {
|
||||
const promise = (new Audio(path)).play();
|
||||
if(promise !== undefined){
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div >
|
||||
<div class="deck">
|
||||
<div class="deck" id="gold-rush-deck" :style="`position:relative;${goldRushShopOpen?'border: 2px dashed #6a6a6a42;border-radius:8pt':''}`" v-if="goldRushCards.length > 0" >
|
||||
<div class="deck" :style="`position:relative;${goldRushShopOpen?'border: 2px dashed #6a6a6a42;border-radius:8pt':''}`" v-if="goldRushCards.length > 0" >
|
||||
<card @pointerenter.native="()=>{setGoldRushDesc(goldRushCards[0])}" @pointerleave.native="goldRushDesc=null" :style="goldRushShopOpen?``:`position:absolute; top:0; right:0; transform: rotate(95deg) translate(30px, -40px) scale(0.6)`" v-if="goldRushCards.length > 0" :key="goldRushCards[0].name" :card="goldRushCards[0]" :class="{'shop-open':goldRushShopOpen, 'cant-play': pending_action !==2 || gold_nuggets < goldRushCards[0].number - gold_rush_discount}" @click.native="() => {buy_gold_rush_card(0)}"/>
|
||||
<card @pointerenter.native="()=>{setGoldRushDesc(goldRushCards[1])}" @pointerleave.native="goldRushDesc=null" :style="goldRushShopOpen?``:`position:absolute; top:0; right:0; transform: rotate(90deg) translate(0, -40px) scale(0.6)`" v-if="goldRushCards.length > 1" :key="goldRushCards[1].name" :card="goldRushCards[1]" :class="{'shop-open':goldRushShopOpen, 'cant-play': pending_action !==2 || gold_nuggets < goldRushCards[1].number - gold_rush_discount}" @click.native="() => {buy_gold_rush_card(1)}"/>
|
||||
<card @pointerenter.native="()=>{setGoldRushDesc(goldRushCards[2])}" @pointerleave.native="goldRushDesc=null" :style="goldRushShopOpen?``:`position:absolute; top:0; right:0; transform: rotate(85deg) translate(-30px, -40px) scale(0.6)`" v-if="goldRushCards.length > 2" :key="goldRushCards[2].name" :card="goldRushCards[2]" :class="{'shop-open':goldRushShopOpen, 'cant-play': pending_action !==2 || gold_nuggets < goldRushCards[2].number - gold_rush_discount}" @click.native="() => {buy_gold_rush_card(2)}"/>
|
||||
@ -11,10 +11,6 @@
|
||||
<card :card="goldRushCardBack" :donotlocalize="true" class="gold-rush back last-event" @click.native="goldRushShopOpen = !goldRushShopOpen"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="currentStations.length > 0" id="train-robbery-deck" class="deck" :style="`position:relative;border: 2px dashed #6a6a6a42;border-radius:8pt;align-items: flex-end;flex-direction:row;`" >
|
||||
<station-card @click.native="()=>{buyTrain(i)}" v-for="station, i in currentStations" :key="station.name" :card="station" :price="station.price" :trainPiece="trainPieceForStation(i)"
|
||||
@pointerenter.native="()=>{setStationDesc(i)}" @pointerleave.native="stationDesc = null"/>
|
||||
</div>
|
||||
<div v-if="eventCard" style="position:relative">
|
||||
<div class="card fistful-of-cards" style="position:relative; bottom:-3pt;right:-3pt;"/>
|
||||
<div class="card fistful-of-cards" style="position:absolute; bottom:-1.5pt;right:-1.5pt;"/>
|
||||
@ -41,7 +37,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<transition name="list">
|
||||
<p v-if="eventCard" class="center-stuff">🔥 <b>{{eventDesc}}</b> 🎴</p>
|
||||
<p v-if="eventCard" class="center-stuff"><b>{{eventDesc}}</b></p>
|
||||
</transition>
|
||||
<transition name="list">
|
||||
<p v-if="eventCardWildWestShow && !eventCardWildWestShow.back" class="center-stuff">🎪 <b>{{eventDescWildWestShow}}</b> 🎪</p>
|
||||
@ -52,11 +48,6 @@
|
||||
<p class="center-stuff">🤑️ <b>{{goldRushDesc.number - gold_rush_discount}} 💵️</b> 🤑️</p>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="list">
|
||||
<div v-if="stationDesc">
|
||||
<p class="center-stuff"><i>{{stationDesc}}</i></p>
|
||||
</div>
|
||||
</transition>
|
||||
<div style="margin-bottom:6pt;margin-bottom: 6pt;display: flex;flex-direction: column;">
|
||||
<button class="btn" v-if="pending_action == 2 && can_gold_rush_discard" @click="$socket.emit('gold_rush_discard')">{{$t('gold_rush_discard')}}</button>
|
||||
</div>
|
||||
@ -68,7 +59,6 @@
|
||||
|
||||
<script>
|
||||
import Card from '@/components/Card.vue'
|
||||
import StationCard from '@/components/StationCard.vue'
|
||||
|
||||
export default {
|
||||
name: 'Deck',
|
||||
@ -77,7 +67,6 @@ export default {
|
||||
},
|
||||
components: {
|
||||
Card,
|
||||
StationCard
|
||||
},
|
||||
data: () => ({
|
||||
card: {
|
||||
@ -99,11 +88,8 @@ export default {
|
||||
goldRushCards: [],
|
||||
gold_nuggets: 0,
|
||||
goldRushDesc: null,
|
||||
stationDesc: null,
|
||||
can_gold_rush_discard: false,
|
||||
gold_rush_discount: 0,
|
||||
currentStations: [],
|
||||
currentTrain: [],
|
||||
}),
|
||||
sockets: {
|
||||
self(self){
|
||||
@ -137,11 +123,6 @@ export default {
|
||||
console.log('GOLD RUSH:'+ cards)
|
||||
this.goldRushCards = JSON.parse(cards)
|
||||
},
|
||||
stations(stations) {
|
||||
let msg = JSON.parse(stations)
|
||||
this.currentStations = msg.stations
|
||||
this.currentTrain = msg.current_train
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
endTurnCard() {
|
||||
@ -182,15 +163,6 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
trainPieceForStation(i) {
|
||||
let index = this.currentTrain.length-5-i;
|
||||
if (index < 0 || index >= this.currentTrain.length)
|
||||
return null;
|
||||
return this.currentTrain[index];
|
||||
},
|
||||
buyTrain(i) {
|
||||
this.$socket.emit('buy_train', i)
|
||||
},
|
||||
action(pile) {
|
||||
if (this.pending_action !== false && this.pending_action < 2) {
|
||||
// console.log('action')
|
||||
@ -217,14 +189,6 @@ export default {
|
||||
setGoldRushDesc(card) {
|
||||
this.goldRushDesc = card
|
||||
},
|
||||
setStationDesc(index) {
|
||||
console.log('setStationDesc', index)
|
||||
this.stationDesc = this.$t(`cards.${this.currentStations[index].name}.desc`)
|
||||
const trainPiece = this.trainPieceForStation(index)
|
||||
if (trainPiece) {
|
||||
this.stationDesc += '\n\n🚂' + this.$t(`cards.${trainPiece.name}.desc`) + '🚋'
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (window.innerWidth < 1000) {
|
||||
|
@ -1,117 +0,0 @@
|
||||
<template>
|
||||
<div class="popup-overlay" v-if="show" @click="handleOverlayClick">
|
||||
<div class="popup-content" @click.stop>
|
||||
<button class="close-button" @click="close">×</button>
|
||||
<h2>{{ expansion.name }}</h2>
|
||||
<div v-for="section in expansion.cards" :key="section.type" class="section">
|
||||
<h3>{{ section.type }}</h3>
|
||||
<div class="cards-container flexy-cards-wrapper">
|
||||
<div v-for="card in section.cards" :key="card.name" class="flexy-cards">
|
||||
<Card :card="card" v-if="section.type !== 'stations'" :class="getClass(expansion, section)"/>
|
||||
<StationCard :card="card" :price="card.price" v-else-if="section.type === 'stations'"/>
|
||||
<div style="margin-left:6pt;">
|
||||
<p>{{$t(`cards.${card.name}.desc`)}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Card from '@/components/Card.vue';
|
||||
import StationCard from './StationCard.vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
expansion: Object, // Expecting an object with id, name, and cards
|
||||
},
|
||||
components: {
|
||||
Card,
|
||||
StationCard,
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$emit('close');
|
||||
},
|
||||
handleOverlayClick() {
|
||||
this.close();
|
||||
},
|
||||
getClass(expansion, section) {
|
||||
let classes = ''
|
||||
if (section.type == 'events') {
|
||||
classes += 'last-event';
|
||||
}
|
||||
if (expansion.id == 'fistful_of_cards') {
|
||||
classes += ' fistful-of-cards';
|
||||
} else if (expansion.id == 'high_noon') {
|
||||
classes += ' high-noon';
|
||||
} else if (expansion.id == 'gold_rush') {
|
||||
classes += ' gold-rush';
|
||||
} else if (expansion.id == 'train_robbery') {
|
||||
classes += ' train-robbery';
|
||||
} else if (expansion.id == 'the_valley_of_shadows') {
|
||||
classes += ' valley-of-shadows';
|
||||
} else if (expansion.id == 'wild_west_show') {
|
||||
classes += ' wild-west-show';
|
||||
}
|
||||
console.log(classes);
|
||||
return classes;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.popup-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.popup-content {
|
||||
position: relative;
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.close-button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.cards-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
.card {
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.flexy-cards-wrapper {
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
}
|
||||
.flexy-cards {
|
||||
flex: 30%;
|
||||
display:flex;
|
||||
}
|
||||
</style>
|
@ -127,32 +127,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 id="trainrobberycards">{{$t('help.trainrobberycards')}}</h2>
|
||||
<div class="flexy-cards-wrapper">
|
||||
<div v-for="(c, i) in trainrobberycards" v-bind:key="c.name ? (c.name+c.number) : i" class="flexy-cards">
|
||||
<Card :card="c" class="train-robbery" @pointerenter.native="''" @pointerleave.native="''"/>
|
||||
<div style="margin-left:6pt;">
|
||||
<p>{{$t(`cards.${c.name}.desc`)}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(c, i) in trainrobberystations" v-bind:key="c.name ? (c.name+c.number) : i" class="flexy-cards">
|
||||
<StationCard :card="c" class="train-robbery" @pointerenter.native="''" @pointerleave.native="''" :price="c.price"/>
|
||||
<div style="margin-left:6pt;">
|
||||
<p>{{$t(`cards.${c.name}.desc`)}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Card from '@/components/Card.vue'
|
||||
import StationCard from './StationCard.vue'
|
||||
|
||||
export default {
|
||||
name: 'Help',
|
||||
components: {
|
||||
Card,
|
||||
StationCard,
|
||||
},
|
||||
props: {
|
||||
inGame: Boolean
|
||||
@ -169,8 +152,6 @@ export default {
|
||||
goldrushcards: [],
|
||||
valleyofshadowscards: [],
|
||||
wildwestshowcards: [],
|
||||
trainrobberycards: [],
|
||||
trainrobberystations: [],
|
||||
}),
|
||||
computed: {
|
||||
endTurnCard() {
|
||||
@ -215,14 +196,6 @@ export default {
|
||||
...x,
|
||||
}))
|
||||
},
|
||||
trainrobberycards_info(cardsJson) {
|
||||
this.trainrobberycards = JSON.parse(cardsJson).cards.map(x=>({
|
||||
...x,
|
||||
}))
|
||||
this.trainrobberystations = JSON.parse(cardsJson).stations.map(x=>({
|
||||
...x,
|
||||
}))
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$socket.emit('get_cards')
|
||||
@ -232,7 +205,6 @@ export default {
|
||||
this.$socket.emit('get_goldrushcards')
|
||||
this.$socket.emit('get_valleyofshadowscards')
|
||||
this.$socket.emit('get_wildwestshowcards')
|
||||
this.$socket.emit('get_trainrobberycards')
|
||||
document.getElementById('help').scrollIntoView();
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,12 @@
|
||||
:value="$t('copy')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- <div class="players-table"> -->
|
||||
<!-- <div style="position: relative;width:260pt;height:400pt;"> -->
|
||||
<!-- :style="p.style"/> -->
|
||||
<!-- </div> -->
|
||||
<!-- </div> -->
|
||||
<div style="position: relative">
|
||||
<div
|
||||
v-if="showTurnFlow"
|
||||
@ -65,18 +71,26 @@
|
||||
<div
|
||||
v-for="p in playersTable"
|
||||
v-bind:key="p.card.name"
|
||||
:id="p.card.name"
|
||||
style="position: relative"
|
||||
class="player-in-table"
|
||||
>
|
||||
<transition-group
|
||||
v-if="p.gold_nuggets && p.gold_nuggets > 0"
|
||||
name="list"
|
||||
tag="div"
|
||||
style="position: absolute; top: -10pt; font-size: 9pt"
|
||||
>
|
||||
<span v-for="(n, i) in p.gold_nuggets" v-bind:key="i" :alt="i"
|
||||
>💵️</span
|
||||
>
|
||||
</transition-group>
|
||||
<transition-group
|
||||
v-if="p.max_lives && !p.is_ghost"
|
||||
name="list"
|
||||
tag="div"
|
||||
class="tiny-health"
|
||||
>
|
||||
<span v-for="(n, i) in p.lives" v-bind:key="i" :alt="i">
|
||||
{{(!p.is_sheriff || i !== (p.max_lives-1))?'❤️':'💛'}}</span>
|
||||
<span v-for="(n, i) in p.lives" v-bind:key="i" :alt="i">❤️</span>
|
||||
<span
|
||||
v-for="(n, i) in p.max_lives - p.lives"
|
||||
v-bind:key="`${i}-sk`"
|
||||
@ -106,12 +120,6 @@
|
||||
class="character tiny-character"
|
||||
@click.native="selectedInfo = [p.character]"
|
||||
/>
|
||||
<div
|
||||
v-if="p.gold_nuggets && p.gold_nuggets > 0"
|
||||
style="position: absolute; top: 45pt; left: -5pt; font-size: 9pt;"
|
||||
>
|
||||
<h3 style="background:gold;border-radius:15pt;padding:0pt 2pt;color:black"> 💵️ {{ p.gold_nuggets }} </h3>
|
||||
</div>
|
||||
<tiny-hand
|
||||
:id="p.name + '-hand'"
|
||||
:ncards="p.ncards"
|
||||
@ -195,20 +203,17 @@
|
||||
<p v-else style="min-height: 19px"></p>
|
||||
<h3>{{ $t("expansions") }}</h3>
|
||||
<div class="players-table" style="justify-content: flex-start">
|
||||
<div v-for="ex in expansionsStatus" :key="ex.id" class="expansion-card" style="position: relative">
|
||||
<card
|
||||
:id="ex.id"
|
||||
v-for="ex in expansionsStatus"
|
||||
v-bind:key="ex.id"
|
||||
:card="ex.card"
|
||||
:class="{
|
||||
'cant-play': !ex.enabled,
|
||||
...ex.card.classes,
|
||||
}"
|
||||
style="cursor: pointer"
|
||||
:donotlocalize="true"
|
||||
@click.native="toggleExpansions(ex.id)"
|
||||
/>
|
||||
<button class="info-button" @click="showExpansionInfo(ex.id)">?</button>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="isRoomOwner">{{ $t("click_to_toggle") }}</p>
|
||||
<h3>{{ $t("mods") }}</h3>
|
||||
@ -220,57 +225,6 @@
|
||||
style="margin-top: 5px; margin-bottom: 3px"
|
||||
>{{ $t("mod_comp") }}</PrettyCheck
|
||||
>
|
||||
<br/>
|
||||
<br/>
|
||||
<span>{{$t("characters_to_distribute")}}</span>
|
||||
<input
|
||||
type="button"
|
||||
:class="{btn:true, 'small-btn':true, active: characters_to_distribute === 1}"
|
||||
:value="1"
|
||||
:disabled="!isRoomOwner"
|
||||
@click="
|
||||
(e) => {
|
||||
this.$socket.emit('chat_message', '/set_chars 1');
|
||||
e.preventDefault();
|
||||
}
|
||||
"
|
||||
/>
|
||||
<input
|
||||
type="button"
|
||||
:class="{btn:true, 'small-btn':true, active: characters_to_distribute === 2}"
|
||||
:value="2"
|
||||
:disabled="!isRoomOwner"
|
||||
@click="
|
||||
(e) => {
|
||||
this.$socket.emit('chat_message', '/set_chars 2');
|
||||
e.preventDefault();
|
||||
}
|
||||
"
|
||||
/>
|
||||
<input
|
||||
type="button"
|
||||
:class="{btn:true, 'small-btn':true, active: characters_to_distribute === 3}"
|
||||
:value="3"
|
||||
:disabled="!isRoomOwner"
|
||||
@click="
|
||||
(e) => {
|
||||
this.$socket.emit('chat_message', '/set_chars 3');
|
||||
e.preventDefault();
|
||||
}
|
||||
"
|
||||
/>
|
||||
<input
|
||||
type="button"
|
||||
:class="{btn:true, 'small-btn':true, active: characters_to_distribute === 4}"
|
||||
:value="4"
|
||||
:disabled="!isRoomOwner"
|
||||
@click="
|
||||
(e) => {
|
||||
this.$socket.emit('chat_message', '/set_chars 4');
|
||||
e.preventDefault();
|
||||
}
|
||||
"
|
||||
/>
|
||||
<h3>{{ $t("bots") }}</h3>
|
||||
<input
|
||||
type="button"
|
||||
@ -308,12 +262,6 @@
|
||||
:midPosition="c.midPosition"
|
||||
:endPosition="c.endPosition"
|
||||
/>
|
||||
<AnimatedEffect
|
||||
v-for="c in fullScreenEffects"
|
||||
v-bind:key="c.key"
|
||||
:text="c.text"
|
||||
:startPosition="c.startPosition"
|
||||
/>
|
||||
<div v-if="started">
|
||||
<deck
|
||||
:endTurnAction="
|
||||
@ -339,6 +287,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<chat :username="username" />
|
||||
<div id="cursors" style="position:absolute; top:0; left:0; width:100%; height:100%; pointer-events:none;">
|
||||
<div v-for="x, i in mouse_positions" :key="x.name" :style="{position:'absolute', top: x.data.y + 'px', left: x.data.x + 'px', transition: 'all 0.1s linear'}">
|
||||
<div :style="`width: 0;height: 0;border-left: 10px solid transparent;border-right: 10px solid transparent;border-bottom: 20px solid #${x.data.color};transform: rotate(-30deg);`"/>
|
||||
<span>{{ x.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Chooser
|
||||
v-if="selectedInfo"
|
||||
:text="$t('details')"
|
||||
@ -388,18 +342,10 @@
|
||||
<transition name="bounce">
|
||||
<DeadRoleNotification
|
||||
v-if="deadRoleData"
|
||||
:key="deadRoleData.name"
|
||||
:playerCard="deadRoleData"
|
||||
:playerRole="deadRoleData.role"
|
||||
/>
|
||||
</transition>
|
||||
<transition name="bounce">
|
||||
<ExpansionPopup
|
||||
:show="showPopup"
|
||||
:expansion="selectedExpansionInfo"
|
||||
@close="closePopup"
|
||||
/>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -418,8 +364,6 @@ import DeadRoleNotification from "./DeadRoleNotification.vue";
|
||||
import AnimatedCard from "./AnimatedCard.vue";
|
||||
import { emojiMap } from "@/utils/emoji-map.js";
|
||||
import { expansionsMap } from "@/utils/expansions-map.js";
|
||||
import AnimatedEffect from './AnimatedEffect.vue';
|
||||
import ExpansionPopup from '@/components/ExpansionPopup.vue';
|
||||
|
||||
const cumulativeOffset = function (element) {
|
||||
var top = 0,
|
||||
@ -434,6 +378,7 @@ const cumulativeOffset = function (element) {
|
||||
left: left - Math.floor(Math.random() * 20) + 10,
|
||||
};
|
||||
};
|
||||
import { useMouse } from '@vueuse/core'
|
||||
|
||||
export default {
|
||||
name: "Lobby",
|
||||
@ -449,8 +394,7 @@ export default {
|
||||
Status,
|
||||
DeadRoleNotification,
|
||||
AnimatedCard,
|
||||
AnimatedEffect,
|
||||
ExpansionPopup,
|
||||
Card,
|
||||
},
|
||||
data: () => ({
|
||||
username: "",
|
||||
@ -477,18 +421,12 @@ export default {
|
||||
displayAdminStatus: false,
|
||||
is_replay: false,
|
||||
turn: -1,
|
||||
deadRoleData: false,
|
||||
deadRoleData: null,
|
||||
cardsToAnimate: [],
|
||||
characters_to_distribute: 2,
|
||||
fullScreenEffects: [],
|
||||
showPopup: false,
|
||||
selectedExpansionInfo: {},
|
||||
owner: undefined,
|
||||
mouse_positions: {},
|
||||
my_mouse_pos: {},
|
||||
}),
|
||||
sockets: {
|
||||
expansion_info(data) {
|
||||
this.selectedExpansionInfo = JSON.parse(data);
|
||||
},
|
||||
room(data) {
|
||||
this.lobbyName = data.name;
|
||||
if (!data.started) {
|
||||
@ -504,8 +442,6 @@ export default {
|
||||
this.togglable_expansions = data.available_expansions;
|
||||
this.expansions = data.expansions;
|
||||
this.is_replay = data.is_replay;
|
||||
this.owner = data.owner;
|
||||
this.characters_to_distribute = data.characters_to_distribute;
|
||||
this.players = data.players.map((x) => {
|
||||
return {
|
||||
name: x.name,
|
||||
@ -519,9 +455,22 @@ export default {
|
||||
notify_dead_role(data) {
|
||||
this.deadRoleData = data;
|
||||
setTimeout(() => {
|
||||
this.deadRoleData = false;
|
||||
this.deadRoleData = null;
|
||||
}, 4000);
|
||||
},
|
||||
mouse_positions_update(data) {
|
||||
let newData = data.filter((x) => x.name !== this.username).map((x) => {
|
||||
return {
|
||||
name: x.name,
|
||||
data: {
|
||||
x: x.data.x * window.innerWidth,
|
||||
y: x.data.y * window.innerHeight,
|
||||
color: x.data.color,
|
||||
}
|
||||
};
|
||||
});
|
||||
this.mouse_positions = newData;
|
||||
},
|
||||
debug(data) {
|
||||
this.debug_mode = data;
|
||||
},
|
||||
@ -585,94 +534,14 @@ export default {
|
||||
this.cardsToAnimate = this.cardsToAnimate.filter((x) => x.key !== key);
|
||||
}, 1800);
|
||||
},
|
||||
chat_message(msg) {
|
||||
if (typeof msg !== "string") {
|
||||
let key = Math.random();
|
||||
let username = msg.text.substring(1, msg.text.indexOf(":")-1);
|
||||
setTimeout(() => {
|
||||
this.fullScreenEffects.push({
|
||||
key: key,
|
||||
text: '💬',
|
||||
startPosition: cumulativeOffset(document.getElementById(username)),
|
||||
});
|
||||
}, 50);
|
||||
setTimeout(() => {
|
||||
this.fullScreenEffects = this.fullScreenEffects.filter(
|
||||
(x) => x.key !== key
|
||||
);
|
||||
}, 3000);
|
||||
return;
|
||||
}
|
||||
let params = msg.split('|')
|
||||
let type = params.shift().substring(1)
|
||||
let messageMap = {
|
||||
prison_turn: '⛓️;🔒;⏭️',
|
||||
explode: '💥;🧨',
|
||||
purchase_card: '🛒;💸',
|
||||
prison_free: '🆓;🔑',
|
||||
snake_bit: '🐍;🩸',
|
||||
beer_save: '🍺;😇',
|
||||
sheriff: '⭐',
|
||||
spilled_beer: '🍺;😭',
|
||||
use_special: '🔝;✨',
|
||||
died: '💀;👻;😭;☠️;🪦;F',
|
||||
died_role: '💀;👻;😭;☠️;🪦;F',
|
||||
}
|
||||
if (messageMap[type]) {
|
||||
let key = Math.random();
|
||||
let avail = messageMap[type].split(';');
|
||||
for (let i = 0; i < 5; i++) {
|
||||
setTimeout(() => {
|
||||
this.fullScreenEffects.push({
|
||||
key: key+i,
|
||||
text: avail[Math.floor(Math.random() * avail.length)],
|
||||
startPosition: cumulativeOffset(document.getElementById(params[0])),
|
||||
});
|
||||
}, 50 * i);
|
||||
setTimeout(() => {
|
||||
this.fullScreenEffects = this.fullScreenEffects.filter(
|
||||
(x) => x.key !== key+i
|
||||
);
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
},
|
||||
suggest_expansion(expansionName) {
|
||||
if (this.expansions.includes(expansionName)) return;
|
||||
let key = Math.random();
|
||||
let decel = document.getElementById(expansionName);
|
||||
if (!decel) return;
|
||||
let decelOffset = cumulativeOffset(decel);
|
||||
for (let i = 0; i < 6; i++) {
|
||||
setTimeout(() => {
|
||||
this.fullScreenEffects.push({
|
||||
key: key+i,
|
||||
text: i == 0 ? '🤠' : i == 5 ? '💭' : emojiMap[expansionName],
|
||||
startPosition: decelOffset,
|
||||
});
|
||||
}, 50 * i);
|
||||
setTimeout(() => {
|
||||
this.fullScreenEffects = this.fullScreenEffects.filter(
|
||||
(x) => x.key !== key+i
|
||||
);
|
||||
}, 3000);
|
||||
}
|
||||
},
|
||||
card_scrapped(data) {
|
||||
let decel = document.getElementById("actual-scrap");
|
||||
if (!decel) {
|
||||
console.log("card_scrapped no deck");
|
||||
return;
|
||||
}
|
||||
let phand = document.getElementById(`${data.player}-hand`);
|
||||
if (data.pile == "train_robbery") {
|
||||
decel = phand
|
||||
phand = document.getElementById("train-robbery-deck");
|
||||
} else if (data.pile == "gold_rush") {
|
||||
decel = phand
|
||||
phand = document.getElementById("gold-rush-deck");
|
||||
}
|
||||
let decelOffset = cumulativeOffset(decel);
|
||||
let phand = document.getElementById(`${data.player}-hand`);
|
||||
if (!phand) {
|
||||
console.log("card_scrapped no phand");
|
||||
return;
|
||||
@ -731,7 +600,11 @@ export default {
|
||||
return "";
|
||||
},
|
||||
isRoomOwner() {
|
||||
return this.owner === this.username;
|
||||
if (this.players.length > 0) {
|
||||
let pls = this.players.filter((x) => !x.is_bot);
|
||||
return pls.length > 0 && pls[0].name == this.username;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
startGameCard() {
|
||||
if (!this.started && this.players.length > 2 && this.isRoomOwner) {
|
||||
@ -769,14 +642,6 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
showExpansionInfo(id) {
|
||||
this.showPopup = true;
|
||||
this.$socket.emit("get_expansion_info", id);
|
||||
},
|
||||
closePopup() {
|
||||
this.showPopup = false;
|
||||
this.selectedExpansionCards = [];
|
||||
},
|
||||
getExpansionCard(id) {
|
||||
let ex = expansionsMap[id];
|
||||
ex.classes = {
|
||||
@ -802,9 +667,29 @@ export default {
|
||||
document.title = "PewPew!";
|
||||
},
|
||||
toggleExpansions(name) {
|
||||
if (!this.isRoomOwner) return this.$socket.emit("toggle_expansion", `suggest;${name}`);
|
||||
if (!this.isRoomOwner) return;
|
||||
this.$socket.emit("toggle_expansion", name);
|
||||
},
|
||||
// updateMousePosition() {
|
||||
// this.my_mouse_pos = {
|
||||
// x, y
|
||||
// }
|
||||
// this.$socket.emit("mouse_position", this.my_mouse_pos);
|
||||
// },
|
||||
startSendingMousePositions() {
|
||||
// this.$el.addEventListener('mousemove', this.updateMousePosition());
|
||||
const { x, y } = useMouse()
|
||||
this.sendInterval = setInterval(() => {
|
||||
if (x == 0 && y == 0) return;
|
||||
if (this.my_mouse_pos.x == x && this.my_mouse_pos.y == y) return;
|
||||
if (this.my_mouse_pos.x == 0 || this.my_mouse_pos.y == 0) return;
|
||||
|
||||
// normalize to page size
|
||||
this.my_mouse_pos = Object.assign({}, { x: x.value / window.innerWidth, y: y.value/ window.innerHeight });
|
||||
console.log(this.my_mouse_pos);
|
||||
this.$socket.emit("mouse_position", this.my_mouse_pos);
|
||||
}, 100);
|
||||
},
|
||||
toggleCompetitive() {
|
||||
if (!this.isRoomOwner) return;
|
||||
this.$socket.emit("toggle_comp");
|
||||
@ -828,7 +713,6 @@ export default {
|
||||
let icon = "";
|
||||
let nonBots = this.players.filter((x) => !x.is_bot);
|
||||
let isOwner = nonBots.length > 0 && nonBots[0].name == player.name;
|
||||
let isMe = this.username == player.name;
|
||||
if (!this.started) icon = "🤠";
|
||||
else
|
||||
icon =
|
||||
@ -842,12 +726,11 @@ export default {
|
||||
return {
|
||||
name: player.name,
|
||||
number:
|
||||
(isMe
|
||||
(this.username == player.name
|
||||
? this.$t("you")
|
||||
: isOwner
|
||||
? this.$t("owner")
|
||||
: "") + (player.dist ? `${player.dist}⛰` : ""),
|
||||
isMe: isMe,
|
||||
icon: icon,
|
||||
is_character: true,
|
||||
avatar: player.avatar,
|
||||
@ -932,6 +815,7 @@ export default {
|
||||
replay: this.$route.query.replay,
|
||||
ffw: this.$route.query.ffw,
|
||||
});
|
||||
this.startSendingMousePositions();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -998,13 +882,6 @@ export default {
|
||||
justify-content: space-evenly;
|
||||
margin-bottom: 12pt;
|
||||
}
|
||||
.small-btn {
|
||||
min-width: 28pt;
|
||||
}
|
||||
.small-btn.active {
|
||||
color: var(--bg-color);
|
||||
background: var(--font-color);
|
||||
}
|
||||
#admin-status {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
@ -1067,29 +944,4 @@ export default {
|
||||
transform: translateY(-5px) scale(1.05);
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 500pt) {
|
||||
.players-table {
|
||||
border-bottom: dashed #ccc2;
|
||||
}
|
||||
}
|
||||
.info-button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.info-button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
|
@ -11,8 +11,11 @@
|
||||
<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="position:relative;left:-90pt;top:65pt;justify-content: space-evenly;width: 25pt;">
|
||||
<h3 style="background:gold;border-radius:15pt;padding:2pt 2pt;color:black;text-align:center"> 💵️ {{ gold_nuggets }} </h3>
|
||||
<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">
|
||||
<span :key="gold_nuggets">{{gold_nuggets}}</span>
|
||||
</transition>
|
||||
<span>💵️</span>
|
||||
</div>
|
||||
<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"
|
||||
@ -273,7 +276,7 @@ export default {
|
||||
is_character: true,
|
||||
is_player: true
|
||||
}})
|
||||
if (this.card_against && this.card_against.can_target_self && (this.equipment.length > 0 || this.card_against.name === 'Tequila')) {
|
||||
if (this.card_against && this.card_against.can_target_self && this.equipment.length > 0) {
|
||||
vis.push({
|
||||
name: this.name,
|
||||
number: '0⛰',
|
||||
@ -500,7 +503,7 @@ export default {
|
||||
padding: 10pt 40pt 0pt 40pt;
|
||||
overflow:auto;
|
||||
border-radius: 4pt;
|
||||
min-height: 122pt;
|
||||
min-height: 40pt;
|
||||
}
|
||||
@media not all and (min-resolution:.001dpcm)
|
||||
{ @supports (-webkit-appearance:none) and (stroke-color:transparent) {
|
||||
|
@ -1,126 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div :class="{stationcard:true, 'cant-play':!trainPiece || trainPiece.is_locomotive}">
|
||||
<h4>{{ cardName }}</h4>
|
||||
<div :class="{ emoji: true, bottomed: card.avatar }">{{ emoji }}</div>
|
||||
<div class="alt_text">{{ card.alt_text }}</div>
|
||||
<div class="price">
|
||||
<card v-for="c, i in price" :key="i" :card="c"/>
|
||||
</div>
|
||||
</div>
|
||||
<card v-if="trainPiece" :card="trainPiece" :class="{'cant-play':trainPiece.is_locomotive}"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Card from '@/components/Card.vue'
|
||||
|
||||
export default {
|
||||
name: "StationCard",
|
||||
props: {
|
||||
card: Object,
|
||||
price: Array,
|
||||
trainPiece: Object,
|
||||
donotlocalize: Boolean,
|
||||
},
|
||||
components: {
|
||||
Card
|
||||
},
|
||||
computed: {
|
||||
cardName() {
|
||||
if (
|
||||
!this.donotlocalize &&
|
||||
this.$t(`cards.${this.card.name}.name`) !==
|
||||
`cards.${this.card.name}.name`
|
||||
) {
|
||||
return this.$t(`cards.${this.card.name}.name`);
|
||||
}
|
||||
if (this.card.name == "you") {
|
||||
return this.$t("you");
|
||||
}
|
||||
return this.card.name;
|
||||
},
|
||||
emoji() {
|
||||
return this.card.icon != "you" ? this.card.icon : this.$t("you");
|
||||
},
|
||||
suit() {
|
||||
if (this.card && !isNaN(this.card.suit)) {
|
||||
let x = ["♦️", "♣️", "♥️", "♠️", "🤑", "🚂"];
|
||||
return x[this.card.suit];
|
||||
} else if (this.card.suit) {
|
||||
return this.card.suit;
|
||||
}
|
||||
return "";
|
||||
},
|
||||
number() {
|
||||
if (isNaN(this.card.suit)) return this.card.number;
|
||||
if (this.card.number === 1) return "A";
|
||||
else if (this.card.number === 11) return "J";
|
||||
else if (this.card.number === 12) return "Q";
|
||||
else if (this.card.number === 13) return "K";
|
||||
else return this.card.number;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.stationcard {
|
||||
cursor: pointer;
|
||||
width: 60pt;
|
||||
min-width: 60pt;
|
||||
height: 60pt;
|
||||
margin: 6pt;
|
||||
border-radius: 16pt 16pt 2pt 2pt;
|
||||
position: relative;
|
||||
transition: all 0.5s ease-in-out;
|
||||
text-overflow: ellipsis;
|
||||
word-wrap: normal;
|
||||
color: white;
|
||||
background: repeating-linear-gradient(
|
||||
0deg,
|
||||
rgb(198 78 45),
|
||||
rgb(198 78 45) 5px,
|
||||
rgb(178 58 25) 5px,
|
||||
rgb(178 58 25) 10px
|
||||
);
|
||||
border: 2pt solid rgb(198 78 45);
|
||||
box-shadow: 0 0 0pt 2pt var(--font-color), 0 0 5pt 2pt #aaa;
|
||||
}
|
||||
.stationcard h4 {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
top: -15pt;
|
||||
font-size: 10pt;
|
||||
}
|
||||
.alt_text {
|
||||
right: 3pt;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
font-size: small;
|
||||
bottom: 20pt;
|
||||
left: 3pt;
|
||||
}
|
||||
.stationcard .price {
|
||||
justify-content: center;
|
||||
/* left: -12pt; */
|
||||
margin-top: -20pt;
|
||||
/* left: 0; */
|
||||
display: flex;
|
||||
width: 60pt;
|
||||
transform: scale(0.3);
|
||||
}
|
||||
.price .card {
|
||||
transform: rotate(14deg);
|
||||
}
|
||||
.train-piece {
|
||||
margin: 6pt;
|
||||
}
|
||||
.cant-play {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.stationcard .card {
|
||||
cursor: unset;
|
||||
}
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,6 @@
|
||||
"spectate_lobbies": "Spectate ongoing games:",
|
||||
"no_lobby_available": "No lobbies available",
|
||||
"create_lobby": "Open a lobby:",
|
||||
"characters_to_distribute": "Characters to distribute: ",
|
||||
"lobby_name": "Name:",
|
||||
"leave_room": "Leave lobby",
|
||||
"warning": "Warning!",
|
||||
@ -100,56 +99,47 @@
|
||||
"copy": "Copy invite",
|
||||
"no_players_in_range": "You can't see the other players, equip a weapon or a scope!",
|
||||
"cantplaycard": "You can't play this card like that!",
|
||||
"choose_baggage_car": "Discard this for a Missed! Panic!, Cat Balou, or an extra BANG!",
|
||||
"choose_mail_car": "Choose which card to give to another player",
|
||||
"choose_other_player": "Choose the player to give the card to",
|
||||
"choose_sleeper_car": "Choose a card to discard for Sleeper Car",
|
||||
"choose_buy_train": "Discard a card to rob the train, and get the carriage",
|
||||
"chat": {
|
||||
"spectators": " | A spectator is watching the game | {n} spectators are watching the game",
|
||||
"chat": "Chat",
|
||||
"joined": "👋 ;{0}; joined the lobby",
|
||||
"died": "☠️ ;{0}; died",
|
||||
"died_role": "☠️ ;{0}; was a ;{1};!",
|
||||
"won": "🏆 ;{0}; won! Their role was ;{1};",
|
||||
"joined": ";{0}; joined the lobby",
|
||||
"died": ";{0}; died",
|
||||
"died_role": ";{0}; was a ;{1};!",
|
||||
"won": ";{0}; won! Their role was ;{1};",
|
||||
"choose_character": ";{0}; has ;{1}; as character, his special ability is: ;{2};!",
|
||||
"starting": "The game is starting!",
|
||||
"sheriff": "⭐ ;{0}; is the sheriff!",
|
||||
"sheriff": ";{0}; is the sheriff!",
|
||||
"did_choose_character": ";{0}; did choose the character.",
|
||||
"turn": "⏩ It is the turn of ;{0};.",
|
||||
"turn": "It is the turn of ;{0};.",
|
||||
"draw_from_scrap": ";{0}; did draw the first card from the scrap pile.",
|
||||
"draw_from_player": ";{0}; did draw the first card from the hand of ;{1};.",
|
||||
"flipped": ";{0}; flipped a ;{1}; ;{2};.",
|
||||
"scrapped": ";{0}; discarded a ;{1}; ;{2};.",
|
||||
"explode": "💥 ;{0}; blew up the dynamite.",
|
||||
"explode": ";{0}; blew up the dynamite.",
|
||||
"beer_save": ";{0}; used a beer to save his life.",
|
||||
"get_nugget": ";{0}; got a gold nugget using a Beer.",
|
||||
"play_card": ";{0}; played ;{1};.",
|
||||
"play_card_green": ";{0}; put in game ;{1};.",
|
||||
"play_card_with": ";{0}; played ;{1};, discarding ;{2};.",
|
||||
"purchase_card": ";{0}; purchased ;{1};.",
|
||||
"play_card_against": ";{0}; played ;{1}; against ;{2};.",
|
||||
"play_card_against_with": ";{0}; played ;{1}; against ;{2};, discarding ;{3};.",
|
||||
"play_card_for": ";{0}; played ;{1}; for ;{2};.",
|
||||
"spilled_beer": ";{0}; spilled a ;{1};.",
|
||||
"diligenza": ";{0}; played ;{1}; and draws 2 cards.",
|
||||
"wellsfargo": ";{0}; played ;{1}; and draws 3 cards.",
|
||||
"saloon": "🍻 ;{0}; played ;{1}; and heals 1 HP to everyone alive.",
|
||||
"saloon": ";{0}; player ;{1}; and heals 1 HP to everyone alive.",
|
||||
"special_bart_cassidy": ";{0}; received a compensation because he was injured.",
|
||||
"special_el_gringo": ";{0}; stole a card from ;{1}; when he was was injured.",
|
||||
"special_calamity": ";{0}; played ;{1}; as Bang! against ;{2};.",
|
||||
"allroles3": "In the game there are: ;{1}; ;{0};, ;{3}; ;{2};, ;{5}; ;{4};.",
|
||||
"allroles4": "In the game there are: ;{1}; ;{0};, ;{3}; ;{2};, ;{5}; ;{4};, ;{7}; ;{6};.",
|
||||
"guess": "🤔 ;{0}; guesses ;{1};.",
|
||||
"guess": ";{0}; guesses ;{1};.",
|
||||
"guess_right": ";{0}; was right.",
|
||||
"guess_wrong": ";{0}; was wrong.",
|
||||
"fratelli_sangue": ";{0}; gave one of his lives to ;{1};.",
|
||||
"doctor_heal": ";{0}; was healed by the doctor.",
|
||||
"respond": "↩️ ;{0}; responded with ;{1};.",
|
||||
"change_username": "✏️ ;{0}; is now ;{1};.",
|
||||
"respond": ";{0}; responded with ;{1};.",
|
||||
"change_username": ";{0}; is now ;{1};.",
|
||||
"lobby_reset": "Going back to lobby in ;{0}; seconds...",
|
||||
"prison_free": "🆓 ;{0}; got out of prison",
|
||||
"prison_turn": "🔐 ;{0}; stayed in prison this turn",
|
||||
"prison_free": ";{0}; got out of prison",
|
||||
"prison_turn": ";{0}; stayed in prison this turn",
|
||||
"flip_event": "🎴 EVENT: ;{0}; 🎴",
|
||||
"choose_manette": ";{0}; committed to play only cards of suit ;{1}; in this turn.",
|
||||
"UnionPacific": ";{0}; played Union Pacific and draws 4 cards from the deck",
|
||||
@ -157,10 +147,8 @@
|
||||
"gold_rush_pay_discard": ";{0}; discarded ;{2}; from ;{1};.",
|
||||
"choose_emporio": ";{0}; has chosen ;{1}; from General Store.",
|
||||
"shotgun_scrap": "When the shotgun hit ;{0}; a card flew away from his hand (;{1};)",
|
||||
"taglia_reward": "💰 ;{1}; got a card from the bounty on ;{0};",
|
||||
"snake_bit": "🐍 ;{0}; was bitten by the Rattle Snake.",
|
||||
"in_private_car": "🚋💁🏻 ;{0}; is in a private car and couldn't get Bang!ed by ;{1};",
|
||||
"bought_train": "🚂 ;{0}; robbed the train at ;{1}; and got the ;{2};"
|
||||
"taglia_reward": ";{1}; got a card from the bounty on ;{0};",
|
||||
"snake_bit": ";{0}; was bitten by the Rattle Snake."
|
||||
},
|
||||
"foc": {
|
||||
"leggedelwest": "He must play this card on this turn if possible."
|
||||
@ -542,7 +530,7 @@
|
||||
},
|
||||
"Fratelli Di Sangue": {
|
||||
"name": "Blood Brothers",
|
||||
"desc": "At the begin of their turn, players can lose 1 hp (except the last one) to give it to another player"
|
||||
"desc": "At the begin of their turn, payers can lose 1 hp (except the last one) to give it to another player"
|
||||
},
|
||||
"I Dalton": {
|
||||
"name": "The Daltons",
|
||||
@ -712,7 +700,7 @@
|
||||
"desc": "During your turn you can use any card as BANG! (Click on the card once equipped)."
|
||||
},
|
||||
"SerpenteASonagli": {
|
||||
"name": "Rattle Snake",
|
||||
"name": "Serpente a Sonagli",
|
||||
"desc": "Play on any player. At the beginning of his turn. if that player draws on Spades, he loses I life point."
|
||||
},
|
||||
"Shotgun": {
|
||||
@ -828,7 +816,7 @@
|
||||
"desc": "Before drawing, players with more cards in their hand than Youl must give him a card of their choice."
|
||||
},
|
||||
"Camposanto": {
|
||||
"name": "Bone Orchard",
|
||||
"name": "Camposanto",
|
||||
"desc": "At the beginning of their turn, each eliminated player comes back to the game with 1 health point. Draw a role card at random from the eliminated players."
|
||||
},
|
||||
"Darling Valentine": {
|
||||
@ -844,7 +832,7 @@
|
||||
"desc": "When Helena enters the game, \"draw!\": if Hearts or Diamonds are drawn, shuffle the active role cards except for the Sheriff, and redistribute them at random."
|
||||
},
|
||||
"Lady Rosa del Texas": {
|
||||
"name": "Lady Rose of Texas",
|
||||
"name": "Lady Rosa del Texas",
|
||||
"desc": "During their turn, each player can switch places with the player on their right, who skips their next turn. (Click the card)"
|
||||
},
|
||||
"Miss Susanna": {
|
||||
@ -852,7 +840,7 @@
|
||||
"desc": "During their turn, each player must play at least 3 cards. If they don't, they lose 1 health point."
|
||||
},
|
||||
"Regolamento di Conti": {
|
||||
"name": "Showdown",
|
||||
"name": "Regolamento di Conti",
|
||||
"desc": "All cards can be played as if they were BANG!. BANG! cards can be played as if they were Missed! (Click the card)"
|
||||
},
|
||||
"Sacagaway": {
|
||||
@ -862,130 +850,6 @@
|
||||
"Wild West Show": {
|
||||
"name": "Wild West Show",
|
||||
"desc": "The goal for each player becomes: \"Be the last one standing!\""
|
||||
},
|
||||
"Boom Town": {
|
||||
"name": "Boom Town",
|
||||
"desc": "Discard a Bang! to rob the train"
|
||||
},
|
||||
"Caticor": {
|
||||
"name": "Caticor",
|
||||
"desc": "Discard a Cat Balou or Panico to rob the train"
|
||||
},
|
||||
"Creepy Creek": {
|
||||
"name": "Creepy Creek",
|
||||
"desc": "Discard a card of spades to rob the train"
|
||||
},
|
||||
"Crowns Hole": {
|
||||
"name": "Crown's Hole",
|
||||
"desc": "Discard a beer to rob the train"
|
||||
},
|
||||
"Deadwood": {
|
||||
"name": "Deadwood",
|
||||
"desc": "Discard an equipment card to rob the train"
|
||||
},
|
||||
"Dodgeville": {
|
||||
"name": "Dodgeville",
|
||||
"desc": "Discard a Missed! to rob the train"
|
||||
},
|
||||
"Fort Worth": {
|
||||
"name": "Fort Worth",
|
||||
"desc": "Discard a card with number 10, J, Q, K, A to rob the train"
|
||||
},
|
||||
"Frisco": {
|
||||
"name": "Frisco",
|
||||
"desc": "Discard a card of clubs to rob the train"
|
||||
},
|
||||
"Miners Oath": {
|
||||
"name": "Miner's Oath",
|
||||
"desc": "Discard a card of diamonds to rob the train"
|
||||
},
|
||||
"San Tafe": {
|
||||
"name": "San Tafe",
|
||||
"desc": "Discard a card of hearts to rob the train"
|
||||
},
|
||||
"Tombrock": {
|
||||
"name": "Tombrock",
|
||||
"desc": "Lose 1 life point to rob the train"
|
||||
},
|
||||
"Yooma": {
|
||||
"name": "Yooma",
|
||||
"desc": "Discard a card with number between 2 and 9 to rob the train"
|
||||
},
|
||||
"Virginia Town": {
|
||||
"name": "Virginia Town",
|
||||
"desc": "Discard two cards to rob the train"
|
||||
},
|
||||
"Ironhorse": {
|
||||
"name": "Ironhorse",
|
||||
"desc": "Each player, including the one who activated the effect, is targeted by a BANG!\nNo player is responsible for any loss of life points.\nIf all players are eliminated at the same time, the Outlaws win."
|
||||
},
|
||||
"Leland": {
|
||||
"name": "Leland",
|
||||
"desc": "LOCOMOTIVE: perform the effect of the Emporium, starting with the current player and proceeding clockwise."
|
||||
},
|
||||
"Baggage Car": {
|
||||
"name": "Baggage Car",
|
||||
"desc": "Discard this card to gain the effect of a Missed!, Panic!, Cat Balou, or an extra BANG! card."
|
||||
},
|
||||
"Caboose": {
|
||||
"name": "Caboose",
|
||||
"desc": "To discard one of your blue-bordered cards, include a car as if it were a Missed!"
|
||||
},
|
||||
"Cattle Truck": {
|
||||
"name": "Cattle Truck",
|
||||
"desc": "Discard this card to look at the top 3 cards of the discard pile and choose 1 to add to your hand."
|
||||
},
|
||||
"Circus Wagon": {
|
||||
"name": "Circus Wagon",
|
||||
"desc": "Discard this card. Each other player must discard a card that he has in play."
|
||||
},
|
||||
"Coal Hopper": {
|
||||
"name": "Coal Hopper",
|
||||
"desc": "Discard this card to draw a card and discard a car in play in front of any player of your choice."
|
||||
},
|
||||
"Dining Car": {
|
||||
"name": "Dining Car",
|
||||
"desc": "At the beginning of your turn, \"pick!\": if it's Hearts, regain 1 life point."
|
||||
},
|
||||
"Express Car": {
|
||||
"name": "Express Car",
|
||||
"desc": "Discard all your hand cards and take another turn."
|
||||
},
|
||||
"Ghost Car": {
|
||||
"name": "Ghost Car",
|
||||
"desc": "Play it on any player except the Sheriff. If you are eliminated, you remain in play, but cannot look at or lose any life points."
|
||||
},
|
||||
"Lounge Car": {
|
||||
"name": "Lounge Car",
|
||||
"desc": "Discard this card to draw 2 cards from the deck and put 1 of them in play in front of you and 1 in front of another player."
|
||||
},
|
||||
"Lumber Flatcar": {
|
||||
"name": "Lumber Flatcar",
|
||||
"desc": "Play this card on any player (including yourself). While this card is in play, that player sees all other players at a distance increased by 1."
|
||||
},
|
||||
"Mail Car": {
|
||||
"name": "Mail Car",
|
||||
"desc": "Discard this card to draw 3 cards and give 1 of them to another player of your choice."
|
||||
},
|
||||
"Observation Car": {
|
||||
"name": "Observation Car",
|
||||
"desc": "You see other players at a distance reduced by 1. Other players see you at a distance increased by 1."
|
||||
},
|
||||
"Passenger Car": {
|
||||
"name": "Passenger Car",
|
||||
"desc": "Discard this card to draw a card (from hand or in play) from another player."
|
||||
},
|
||||
"Prisoner Car": {
|
||||
"name": "Prisoner Car",
|
||||
"desc": "Duel and Indians! cards played by other players have no effect on you."
|
||||
},
|
||||
"Private Car": {
|
||||
"name": "Private Car",
|
||||
"desc": "If you have no cards in hand, you cannot be targeted by BANG! cards."
|
||||
},
|
||||
"Sleeper Car": {
|
||||
"name": "Sleeper Car",
|
||||
"desc": "Once per turn, you may discard another of your blue-bordered cards in play."
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
@ -1037,9 +901,7 @@
|
||||
"highnooncards": "High Noon - Event Cards",
|
||||
"foccards": "Fistful of Cards - Event Cards",
|
||||
"goldrushcards": "Gold Rush Cards",
|
||||
"valleyofshadowscards": "The Valley of Shadows Cards",
|
||||
"wildwestshowcards": "Wild West Show Cards",
|
||||
"trainrobberycards": "Train Robbery Cards"
|
||||
"valleyofshadowscards": "The Valley of Shadows Cards"
|
||||
},
|
||||
"theme": {
|
||||
"sepia": "Sepia",
|
||||
|
@ -1,918 +0,0 @@
|
||||
{
|
||||
"trademark": "¡Bang! es una marca registrada propiedad de DVGiochi",
|
||||
"tip_1": "¡Mejor con amigos!",
|
||||
"tip_2": "¡El icono 🤖️ significa que un jugador es un bot!",
|
||||
"tip_3": "¡Puedes hacer clic en las cartas de personajes y equipos de otros jugadores si deseas saber más!",
|
||||
"tip_4": "¡Incluye Dodge City, High Noon, Fistful Of Cards!",
|
||||
"tip_5": "¿Encontraste un error? ¡Envíanos un mensaje en Discord!",
|
||||
"tip_6": "¡Ahora con un servidor de Discord!",
|
||||
"tip_7": "¡Si quieres ayudarnos a traducir el juego a tu idioma, contáctanos en Discord!",
|
||||
"tip_8": "¡Si te desconectas durante una partida en curso, serás reemplazado por un bot (mientras estás ausente)!",
|
||||
"tip_9": "¡Si estás en el móvil, mantén pulsada una carta para leer la descripción!",
|
||||
"tip_10": "¡En caso de duda, dispara a todos los demás jugadores!",
|
||||
"online_players": "Jugadores en línea: ",
|
||||
"shuffle_players": "Mezclar jugadores",
|
||||
"choose_username": "Elige un nombre de usuario:",
|
||||
"report_bug": "Escribe en qué consiste el error",
|
||||
"report": "Reportar un error",
|
||||
"available_lobbies": "Salas disponibles:",
|
||||
"spectate_lobbies": "Ver partidas en curso:",
|
||||
"no_lobby_available": "No hay salas disponibles",
|
||||
"create_lobby": "Abrir una sala:",
|
||||
"characters_to_distribute": "Personajes a distribuir: ",
|
||||
"lobby_name": "Nombre:",
|
||||
"leave_room": "Salir de la sala",
|
||||
"warning": "¡Advertencia!",
|
||||
"connection_error": "No se puede conectar al servidor.",
|
||||
"end_turn": "¡Terminar turno!",
|
||||
"start_game": "¡Empezar!",
|
||||
"expansions": "Expansiones",
|
||||
"click_to_toggle": "Haz clic para alternar",
|
||||
"details": "Detalles",
|
||||
"ok": "OK",
|
||||
"you": "TÚ",
|
||||
"owner": "PROPIETARIO",
|
||||
"cancel": "CANCELAR",
|
||||
"send": "ENVIAR",
|
||||
"password": "Contraseña: ",
|
||||
"room_password_prompt": "Contraseña de la sala: ",
|
||||
"private_room": "Sala privada",
|
||||
"room": "Sala: ",
|
||||
"room_players": "Jugadores (tú eres {username})",
|
||||
"choose_character": "Elige tu personaje",
|
||||
"choose_card": "Elige una carta",
|
||||
"choose_card_from": " de ",
|
||||
"flip_card": "↙️ Voltear una carta",
|
||||
"draw_cards": "⏬ Roba tus cartas del mazo",
|
||||
"play_cards": "▶️ Juega tus cartas",
|
||||
"respond_card": "↩️ Responder a la carta",
|
||||
"wait": "⏸ Espera",
|
||||
"choose_cards": "🔽 Elige una carta",
|
||||
"take_dmg": "Recibir daño",
|
||||
"choose_response": "Elige tu respuesta ",
|
||||
"choose_response_to": "a ",
|
||||
"choose_response_needed": "NECESARIA ",
|
||||
"choose_manette": "Elige un palo, solo podrás jugar cartas con ese palo en este turno.",
|
||||
"hand": "MANO",
|
||||
"card_against": "¿Contra quién jugarás tu carta?",
|
||||
"choose_sid_scrap": "Descarta 2 cartas para no morir",
|
||||
"choose_card_to_get": "Elige una carta",
|
||||
"choose_guess": "Adivina el color del palo",
|
||||
"choose_ranch": "Elige las cartas para reemplazar",
|
||||
"choose_dalton": "Elige qué equipo descartar",
|
||||
"choose_fratelli_di_sangue": "Elige a quién quieres donar una de tus vidas",
|
||||
"choose_fantasma": "Elige a quién resucitar",
|
||||
"choose_sventagliata": "Elige otro objetivo para golpear con Fanning",
|
||||
"choose_tornado": "Elige una carta para descartar por el tornado",
|
||||
"choose_bandidos": "Elige entre descartar 2 cartas o perder una vida (1 carta si solo tienes 1)",
|
||||
"choose_poker": "Todos descartan 1 carta (si no hay As, el jugador que jugó poker elige 2 cartas)",
|
||||
"choose_from_poker;2": "Elige qué cartas obtener (máx. 2)",
|
||||
"choose_from_poker;1": "Elige qué carta obtener",
|
||||
"choose_cecchino": "Elige a quién disparar",
|
||||
"choose_rimbalzo_player": "Elige el objetivo del rebote",
|
||||
"choose_rimbalzo_card": "Elige la carta para descartar el rebote",
|
||||
"choose_nuova_identita": "Elige si quieres mantener tu personaje actual o si quieres cambiarlo y empezar con 2 PV",
|
||||
"choose_bicchierino": "Un jugador de tu elección recupera 1 PV",
|
||||
"choose_bottiglia": "¡Elige cómo jugar la Botella!",
|
||||
"choose_complice": "¡Elige cómo jugar el Cómplice!",
|
||||
"choose_ricercato": "Elige contra quién jugar Se Busca.",
|
||||
"choose_birra_function": "Elige entre obtener 1 pepita de oro descartando la cerveza o si quieres jugar la cerveza.",
|
||||
"choose_play_as_bang": "Elige qué carta jugar como Bang!",
|
||||
"choose_flint_special": "Elige qué carta intercambiar.",
|
||||
"emporio_others": "{0} está eligiendo qué carta obtener de la Tienda General",
|
||||
"you_died": "ESTÁS MUERTO",
|
||||
"spectate": "ESPECTAR",
|
||||
"you_win": "HAS GANADO",
|
||||
"you_lose": "HAS PERDIDO",
|
||||
"special_ability": "HABILIDAD ESPECIAL",
|
||||
"gold_rush_discard": "Descarta el equipo de la fiebre del oro de otro jugador (pagando el precio + 1)",
|
||||
"gold_rush_discard_2": "Descarta el equipo de la fiebre del oro de otro jugador (pagando el precio + 1)",
|
||||
"discard": "DESCARTAR",
|
||||
"to_regain_1_hp": "PARA RECUPERAR 1 PV",
|
||||
"play_your_turn": "JUEGA TU TURNO",
|
||||
"you_are": "Eres",
|
||||
"did_pick_as": "eligió esto como segunda carta",
|
||||
"blackjack_special": "Si la carta es de diamantes o corazones, roba otra carta.",
|
||||
"choose_scarp_card_to": "ELIGE QUÉ CARTA DESCARTAR PARA USAR",
|
||||
"pick_a_card": "VOLTEAR UNA CARTA",
|
||||
"to_defend_from": "PARA DEFENDERTE DE",
|
||||
"submit": "Enviar",
|
||||
"copy": "Copiar invitación",
|
||||
"no_players_in_range": "No puedes ver a los otros jugadores, equipa un arma o un visor!",
|
||||
"cantplaycard": "¡No puedes jugar esta carta así!",
|
||||
"chat": {
|
||||
"spectators": " | Un espectador está viendo la partida | {n} espectadores están viendo la partida",
|
||||
"chat": "Chat",
|
||||
"joined": "👋 ;{0}; se unió a la sala",
|
||||
"died": "☠️ ;{0}; murió",
|
||||
"died_role": "☠️ ;{0}; era un ;{1};!",
|
||||
"won": "🏆 ;{0}; ganó! Su rol era ;{1};",
|
||||
"choose_character": ";{0}; tiene ;{1}; como personaje, su habilidad especial es: ;{2};!",
|
||||
"starting": "¡El juego está comenzando!",
|
||||
"sheriff": "⭐ ;{0}; es el sheriff!",
|
||||
"did_choose_character": ";{0}; eligió el personaje.",
|
||||
"turn": "⏩ Es el turno de ;{0};.",
|
||||
"draw_from_scrap": ";{0}; robó la primera carta del montón de descartes.",
|
||||
"draw_from_player": ";{0}; robó la primera carta de la mano de ;{1};.",
|
||||
"flipped": ";{0}; volteó un ;{1}; ;{2};.",
|
||||
"scrapped": ";{0}; descartó un ;{1}; ;{2};.",
|
||||
"explode": "💥 ;{0}; hizo explotar la dinamita.",
|
||||
"beer_save": ";{0}; usó una cerveza para salvar su vida.",
|
||||
"get_nugget": ";{0}; obtuvo una pepita de oro usando una Cerveza.",
|
||||
"play_card": ";{0}; jugó ;{1};.",
|
||||
"play_card_green": ";{0}; puso en juego ;{1};.",
|
||||
"play_card_with": ";{0}; jugó ;{1};, descartando ;{2};.",
|
||||
"purchase_card": ";{0}; compró ;{1};.",
|
||||
"play_card_against": ";{0}; jugó ;{1}; contra ;{2};.",
|
||||
"play_card_against_with": ";{0}; jugó ;{1}; contra ;{2};, descartando ;{3};.",
|
||||
"play_card_for": ";{0}; jugó ;{1}; para ;{2};.",
|
||||
"spilled_beer": ";{0}; derramó una ;{1};.",
|
||||
"diligenza": ";{0}; jugó ;{1}; y roba 2 cartas.",
|
||||
"wellsfargo": ";{0}; jugó ;{1}; y roba 3 cartas.",
|
||||
"saloon": "🍻 ;{0}; jugó ;{1}; y cura 1 PV a todos los vivos.",
|
||||
"special_bart_cassidy": ";{0}; recibió una compensación porque fue herido.",
|
||||
"special_el_gringo": ";{0}; robó una carta de ;{1}; cuando fue herido.",
|
||||
"special_calamity": ";{0}; jugó ;{1}; como Bang! contra ;{2};.",
|
||||
"allroles3": "En el juego hay: ;{1}; ;{0};, ;{3}; ;{2};, ;{5}; ;{4};.",
|
||||
"allroles4": "En el juego hay: ;{1}; ;{0};, ;{3}; ;{2};, ;{5}; ;{4};, ;{7}; ;{6};.",
|
||||
"guess": "🤔 ;{0}; adivina ;{1};.",
|
||||
"guess_right": ";{0}; tenía razón.",
|
||||
"guess_wrong": ";{0}; estaba equivocado.",
|
||||
"fratelli_sangue": ";{0}; dio una de sus vidas a ;{1};.",
|
||||
"doctor_heal": ";{0}; fue curado por el doctor.",
|
||||
"respond": "↩️ ;{0}; respondió con ;{1};.",
|
||||
"change_username": "✏️ ;{0}; ahora es ;{1};.",
|
||||
"lobby_reset": "Volviendo a la sala en ;{0}; segundos...",
|
||||
"prison_free": "🆓 ;{0}; salió de la prisión",
|
||||
"prison_turn": "🔐 ;{0}; se quedó en prisión este turno",
|
||||
"flip_event": "🎴 EVENTO: ;{0}; 🎴",
|
||||
"choose_manette": ";{0}; se comprometió a jugar solo cartas del palo ;{1}; en este turno.",
|
||||
"UnionPacific": ";{0}; jugó Union Pacific y roba 4 cartas del mazo",
|
||||
"use_special": ";{0}; usó la habilidad especial de su personaje (;{1};)",
|
||||
"gold_rush_pay_discard": ";{0}; descartó ;{2}; de ;{1};.",
|
||||
"choose_emporio": ";{0}; eligió ;{1}; de la Tienda General.",
|
||||
"shotgun_scrap": "Cuando la escopeta golpeó a ;{0};, una carta voló de su mano (;{1};)",
|
||||
"taglia_reward": "💰 ;{1}; obtuvo una carta de la recompensa por ;{0};",
|
||||
"snake_bit": "🐍 ;{0}; fue mordido por la serpiente de cascabel."
|
||||
},
|
||||
"foc": {
|
||||
"leggedelwest": "Debe jugar esta carta en este turno si es posible."
|
||||
},
|
||||
"mods": "Modificadores",
|
||||
"bots": "Bots",
|
||||
"add_bot": "Añadir un bot",
|
||||
"remove_bot": "Eliminar un bot",
|
||||
"minimum_players": "El juego necesita al menos 3 jugadores para empezar",
|
||||
"mod_comp": "Modo competitivo (desactiva recibir daño automáticamente)",
|
||||
"disconnect_bot": "Reemplazar jugadores que se desconecten por bots",
|
||||
"your_turn": "¡Juega tu turno!",
|
||||
"your_response": "¡Responde!",
|
||||
"your_choose": "¡Elige una carta!",
|
||||
"cards": {
|
||||
"Barile": {
|
||||
"name": "Barril",
|
||||
"desc": "Cuando alguien juega un Bang contra ti. Puedes voltear la primera carta del mazo, si el palo es corazones, cuenta como una carta Fallaste"
|
||||
},
|
||||
"Dinamite": {
|
||||
"name": "Dinamita",
|
||||
"desc": "Al jugar la dinamita, colócala frente a ti, permanecerá inofensiva durante toda una ronda. Al comienzo del siguiente turno antes de robar y antes de cualquier volteo de carta (ej. Prisión), voltea una carta de la parte superior del mazo. Si una carta está entre 2 y 9 de picas (inclusive), la dinamita explota: pierdes 3 vidas y descartas la carta, de lo contrario, pasa la dinamita al siguiente jugador, quien robará a su vez después de haber terminado su turno"
|
||||
},
|
||||
"Mirino": {
|
||||
"name": "Mira",
|
||||
"desc": "Ves a los otros jugadores a una distancia de -1"
|
||||
},
|
||||
"Mustang": {
|
||||
"name": "Mustang",
|
||||
"desc": "Los otros jugadores te ven a una distancia de +1"
|
||||
},
|
||||
"Prigione": {
|
||||
"name": "Prisión",
|
||||
"desc": "Equipa esta carta a otro jugador, excepto el Sheriff. El jugador elegido al comienzo de su turno, debe voltear una carta antes de robar: si es corazones, descarta esta carta y juega el turno normalmente, de lo contrario, descarta esta carta y salta el turno"
|
||||
},
|
||||
"Remington": {
|
||||
"name": "Remington",
|
||||
"desc": "Puedes disparar a otro jugador a una distancia de 3 o menos"
|
||||
},
|
||||
"Rev Carabine": {
|
||||
"name": "Rev. Carabina",
|
||||
"desc": "Puedes disparar a otro jugador a una distancia de 4 o menos"
|
||||
},
|
||||
"Schofield": {
|
||||
"name": "Schofield",
|
||||
"desc": "Puedes disparar a otro jugador a una distancia de 2 o menos"
|
||||
},
|
||||
"Volcanic": {
|
||||
"name": "Volcánica",
|
||||
"desc": "Puedes disparar a otro jugador a una distancia de 1 o menos, sin embargo, ya no tienes el límite de 1 Bang"
|
||||
},
|
||||
"Winchester": {
|
||||
"name": "Winchester",
|
||||
"desc": "Puedes disparar a otro jugador a una distancia de 5 o menos"
|
||||
},
|
||||
"Bang!": {
|
||||
"name": "Bang!",
|
||||
"desc": "Dispara a un jugador a la vista. Si no tienes armas, tu vista es de 1"
|
||||
},
|
||||
"Birra": {
|
||||
"name": "Cerveza",
|
||||
"desc": "Juega esta carta para recuperar un punto de vida. No puedes curarte más allá del límite máximo de tu personaje. Si estás a punto de perder tu último punto de vida, también puedes jugar esta carta en el turno de tu oponente. La cerveza ya no tiene efecto si solo quedan dos jugadores"
|
||||
},
|
||||
"Cat Balou": {
|
||||
"name": "Cat Balou",
|
||||
"desc": "Elige y descarta una carta de otro jugador."
|
||||
},
|
||||
"Diligenza": {
|
||||
"name": "Diligencia",
|
||||
"desc": "Roba 2 cartas del mazo."
|
||||
},
|
||||
"Duello": {
|
||||
"name": "Duelo",
|
||||
"desc": "Juega esta carta contra cualquier jugador. Por turnos, comenzando con tu oponente, puedes descartar una carta Bang!, el primer jugador que no lo haga pierde 1 vida."
|
||||
},
|
||||
"Emporio": {
|
||||
"name": "Tienda General",
|
||||
"desc": "Pon sobre la mesa N cartas del mazo, donde N es el número de jugadores vivos, por turnos, comenzando contigo, elige una carta y agrégala a tu mano"
|
||||
},
|
||||
"Gatling": {
|
||||
"name": "Gatling",
|
||||
"desc": "Dispara a todos los otros jugadores"
|
||||
},
|
||||
"Indiani!": {
|
||||
"name": "¡Indios!",
|
||||
"desc": "Todos los demás jugadores deben descartar una carta Bang! o perder 1 punto de vida"
|
||||
},
|
||||
"Mancato!": {
|
||||
"name": "¡Fallaste!",
|
||||
"desc": "Usa esta carta para cancelar el efecto de un Bang"
|
||||
},
|
||||
"Panico!": {
|
||||
"name": "¡Pánico!",
|
||||
"desc": "Roba una carta a un jugador a una distancia de 1"
|
||||
},
|
||||
"Saloon": {
|
||||
"name": "Saloon",
|
||||
"desc": "Todos recuperan 1 punto de vida"
|
||||
},
|
||||
"WellsFargo": {
|
||||
"name": "Wells Fargo",
|
||||
"desc": "Roba 3 cartas del mazo"
|
||||
},
|
||||
"Binocolo": {
|
||||
"name": "Binoculares",
|
||||
"desc": "Ves a los otros jugadores a una distancia de -1"
|
||||
},
|
||||
"Riparo": {
|
||||
"name": "Escondite",
|
||||
"desc": "Los otros jugadores te ven a una distancia de +1"
|
||||
},
|
||||
"Pugno!": {
|
||||
"name": "¡Puñetazo!",
|
||||
"desc": "Dispara a un jugador a una distancia de 1"
|
||||
},
|
||||
"Rag Time": {
|
||||
"name": "Rag Time",
|
||||
"desc": "Roba una carta de otro jugador a cualquier distancia"
|
||||
},
|
||||
"Rissa": {
|
||||
"name": "Pelea",
|
||||
"desc": "Elige una carta para descartar de la mano/equipo de todos los demás jugadores"
|
||||
},
|
||||
"Schivata": {
|
||||
"name": "Esquiva",
|
||||
"desc": "Usa esta carta para cancelar el efecto de un Bang y luego roba una carta."
|
||||
},
|
||||
"Springfield": {
|
||||
"name": "Springfield",
|
||||
"desc": "Dispara a un jugador a cualquier distancia"
|
||||
},
|
||||
"Tequila": {
|
||||
"name": "Tequila",
|
||||
"desc": "Cura 1 PV a un jugador de tu elección (puede ser tú)"
|
||||
},
|
||||
"Whisky": {
|
||||
"name": "Whisky",
|
||||
"desc": "Cura 2 PV"
|
||||
},
|
||||
"Bibbia": {
|
||||
"name": "Biblia",
|
||||
"desc": "Usa esta carta para cancelar el efecto de un Bang y luego roba una carta."
|
||||
},
|
||||
"Cappello": {
|
||||
"name": "Sombrero de Diez Galones",
|
||||
"desc": "Usa esta carta para cancelar el efecto de un Bang"
|
||||
},
|
||||
"Placca Di Ferro": {
|
||||
"name": "Placa de Hierro",
|
||||
"desc": "Usa esta carta para cancelar el efecto de un Bang"
|
||||
},
|
||||
"Sombrero": {
|
||||
"name": "Sombrero",
|
||||
"desc": "Usa esta carta para cancelar el efecto de un Bang"
|
||||
},
|
||||
"Pugnale": {
|
||||
"name": "Cuchillo",
|
||||
"desc": "Dispara a un jugador a una distancia de 1"
|
||||
},
|
||||
"Derringer": {
|
||||
"name": "Derringer",
|
||||
"desc": "Dispara a un jugador a una distancia de 1 y luego roba una carta."
|
||||
},
|
||||
"Borraccia": {
|
||||
"name": "Cantimplora",
|
||||
"desc": "Recupera 1 PV"
|
||||
},
|
||||
"Can Can": {
|
||||
"name": "Can Can",
|
||||
"desc": "Elige y descarta una carta de otro jugador."
|
||||
},
|
||||
"Conestoga": {
|
||||
"name": "Conestoga",
|
||||
"desc": "Roba una carta de otro jugador a cualquier distancia"
|
||||
},
|
||||
"Fucile Da Caccia": {
|
||||
"name": "Rifle de Búfalo",
|
||||
"desc": "Dispara a un jugador a cualquier distancia"
|
||||
},
|
||||
"Pony Express": {
|
||||
"name": "Pony Express",
|
||||
"desc": "Roba 3 cartas del mazo"
|
||||
},
|
||||
"Pepperbox": {
|
||||
"name": "Pepperbox",
|
||||
"desc": "Dispara a un jugador a la vista. Si no tienes armas, tu vista es de 1"
|
||||
},
|
||||
"Howitzer": {
|
||||
"name": "Howitzer",
|
||||
"desc": "Dispara a todos los otros jugadores"
|
||||
},
|
||||
"Bart Cassidy": {
|
||||
"name": "Bart Cassidy",
|
||||
"desc": "Cada vez que es herido, roba una carta."
|
||||
},
|
||||
"Black Jack": {
|
||||
"name": "Black Jack",
|
||||
"desc": "Al comienzo de su turno, cuando tiene que robar, muestra a todos la segunda carta, si es corazones o diamantes, roba una tercera carta sin mostrarla."
|
||||
},
|
||||
"Calamity Janet": {
|
||||
"name": "Calamity Janet",
|
||||
"desc": "Puede usar las cartas Fallaste! como Bang! y viceversa."
|
||||
},
|
||||
"El Gringo": {
|
||||
"name": "El Gringo",
|
||||
"desc": "Cada vez que es herido, roba una carta de la mano del jugador atacante."
|
||||
},
|
||||
"Jesse Jones": {
|
||||
"name": "Jesse Jones",
|
||||
"desc": "Cuando tiene que robar sus cartas, puede robar la primera carta de la mano de otro jugador. (haz clic en las cartas del jugador enemigo si deseas usar la habilidad)"
|
||||
},
|
||||
"Jourdonnais": {
|
||||
"name": "Jourdonnais",
|
||||
"desc": "Juega como si tuviera un Barril siempre activo, si equipa otro Barril, puede voltear 2 cartas."
|
||||
},
|
||||
"Kit Carlson": {
|
||||
"name": "Kit Carlson",
|
||||
"desc": "Cuando tiene que robar, mira 3 cartas y elige 2, colocando la otra carta en la parte superior del mazo."
|
||||
},
|
||||
"Lucky Duke": {
|
||||
"name": "Lucky Duke",
|
||||
"desc": "Cada vez que tiene que voltear una carta, puede voltear 2 veces."
|
||||
},
|
||||
"Paul Regret": {
|
||||
"name": "Paul Regret",
|
||||
"desc": "Los otros jugadores lo ven a una distancia de +1."
|
||||
},
|
||||
"Pedro Ramirez": {
|
||||
"name": "Pedro Ramirez",
|
||||
"desc": "Cuando tiene que robar, puede tomar la primera carta del montón de descartes. (haz clic en las cartas descartadas para usar la habilidad)"
|
||||
},
|
||||
"Rose Doolan": {
|
||||
"name": "Rose Doolan",
|
||||
"desc": "Ve a los otros jugadores a una distancia de -1."
|
||||
},
|
||||
"Sid Ketchum": {
|
||||
"name": "Sid Ketchum",
|
||||
"desc": "Puede descartar 2 cartas para recuperar 1 PV."
|
||||
},
|
||||
"Slab The Killer": {
|
||||
"name": "Slab The Killer",
|
||||
"desc": "Para esquivar sus cartas Bang!, los otros jugadores necesitan 2 cartas Fallaste!"
|
||||
},
|
||||
"Suzy Lafayette": {
|
||||
"name": "Suzy Lafayette",
|
||||
"desc": "Siempre que tiene la mano vacía, roba una carta."
|
||||
},
|
||||
"Vulture Sam": {
|
||||
"name": "Vulture Sam",
|
||||
"desc": "Cuando un jugador muere, obtiene todas las cartas en la mano y los equipos del muerto."
|
||||
},
|
||||
"Willy The Kid": {
|
||||
"name": "Willy The Kid",
|
||||
"desc": "No tiene límites en la cantidad de Bang que puede usar."
|
||||
},
|
||||
"Pixie Pete": {
|
||||
"name": "Pixie Pete",
|
||||
"desc": "Roba 3 cartas en lugar de 2."
|
||||
},
|
||||
"Tequila Joe": {
|
||||
"name": "Tequila Joe",
|
||||
"desc": "Cuando juega una Cerveza, recupera 2 PV."
|
||||
},
|
||||
"Greg Digger": {
|
||||
"name": "Greg Digger",
|
||||
"desc": "Siempre que un jugador muere, recupera hasta 2 vidas."
|
||||
},
|
||||
"Herb Hunter": {
|
||||
"name": "Herb Hunter",
|
||||
"desc": "Siempre que un jugador muere, roba 2 cartas."
|
||||
},
|
||||
"Elena Fuente": {
|
||||
"name": "Elena Fuente",
|
||||
"desc": "Puede usar cualquier carta de su mano como Fallaste."
|
||||
},
|
||||
"Bill Noface": {
|
||||
"name": "Bill Noface",
|
||||
"desc": "Roba 1 carta + 1 carta por cada herida que tiene."
|
||||
},
|
||||
"Molly Stark": {
|
||||
"name": "Molly Stark",
|
||||
"desc": "Cuando usa una carta de su mano fuera de su turno, roba una carta."
|
||||
},
|
||||
"Apache Kid": {
|
||||
"name": "Apache Kid",
|
||||
"desc": "Las cartas de diamantes ♦️ jugadas contra él no tienen efecto (no funciona en duelos)."
|
||||
},
|
||||
"Sean Mallory": {
|
||||
"name": "Sean Mallory",
|
||||
"desc": "Puede mantener hasta 10 cartas en su mano al terminar el turno."
|
||||
},
|
||||
"Belle Star": {
|
||||
"name": "Belle Star",
|
||||
"desc": "Durante su turno, las cartas verdes y azules de los otros jugadores no funcionan."
|
||||
},
|
||||
"Vera Custer": {
|
||||
"name": "Vera Custer",
|
||||
"desc": "Antes de robar, puede elegir la habilidad especial de otro jugador vivo. Esta habilidad se usa hasta el próximo turno."
|
||||
},
|
||||
"Chuck Wengam": {
|
||||
"name": "Chuck Wengam",
|
||||
"desc": "En su turno, puede decidir perder 1 PV para robar 2 cartas del mazo."
|
||||
},
|
||||
"Pat Brennan": {
|
||||
"name": "Pat Brennan",
|
||||
"desc": "En lugar de robar, puede robar una carta del equipo de otro jugador. (haz clic en el jugador enemigo si deseas usar la habilidad)"
|
||||
},
|
||||
"José Delgado": {
|
||||
"name": "José Delgado",
|
||||
"desc": "En su turno, puede descartar una carta azul para robar 2 cartas, hasta dos veces por turno."
|
||||
},
|
||||
"Doc Holyday": {
|
||||
"name": "Doc Holyday",
|
||||
"desc": "Puede descartar 2 cartas para jugar un Bang."
|
||||
},
|
||||
"Fuorilegge": {
|
||||
"name": "Forajido"
|
||||
},
|
||||
"Rinnegato": {
|
||||
"name": "Renegado"
|
||||
},
|
||||
"Sceriffo": {
|
||||
"name": "Sheriff"
|
||||
},
|
||||
"Vice": {
|
||||
"name": "Ayudante"
|
||||
},
|
||||
"Miniera Abbandonata": {
|
||||
"name": "Mina Abandonada",
|
||||
"desc": "Los jugadores roban del montón de descartes en su fase 1 y descartan en la parte superior del mazo durante la fase 3 (si el montón de descartes se agota, deben robar y descartar en la parte superior del mazo)"
|
||||
},
|
||||
"Il Giudice": {
|
||||
"name": "El Juez",
|
||||
"desc": "No puedes equipar cartas a ti mismo ni a otros jugadores"
|
||||
},
|
||||
"Agguato": {
|
||||
"name": "Emboscada",
|
||||
"desc": "La distancia base entre dos jugadores es de 1"
|
||||
},
|
||||
"Rimbalzo": {
|
||||
"name": "Rebote",
|
||||
"desc": "El jugador puede jugar Bang contra las cartas equipadas por los otros jugadores, si no juegan Fallaste, se descartan (haz clic en la carta de evento)"
|
||||
},
|
||||
"Cecchino": {
|
||||
"name": "Francotirador",
|
||||
"desc": "Durante su turno, los jugadores pueden descartar 2 Bang! para disparar un Bang! que requiere 2 Fallaste (haz clic en la carta)"
|
||||
},
|
||||
"Lazo": {
|
||||
"name": "Lazo",
|
||||
"desc": "Las cartas en la ranura de equipo no funcionan"
|
||||
},
|
||||
"Ranch": {
|
||||
"name": "Rancho",
|
||||
"desc": "Después de robar, el jugador puede descartar tantas cartas como quiera de su mano y robar tantas del mazo"
|
||||
},
|
||||
"Dead Man": {
|
||||
"name": "Hombre Muerto",
|
||||
"desc": "El primer jugador que muera vuelve a la vida con 2 PV y 2 cartas"
|
||||
},
|
||||
"Liquore Forte": {
|
||||
"name": "Licor Fuerte",
|
||||
"desc": "Los jugadores pueden saltar el robo para recuperar 1 PV (haz clic en la carta de evento para usar)"
|
||||
},
|
||||
"Vendetta": {
|
||||
"name": "Venganza",
|
||||
"desc": "Al terminar el turno, el jugador voltea una carta del mazo, si es un ❤️ juega otro turno (pero no voltea otra carta)"
|
||||
},
|
||||
"Roulette Russa": {
|
||||
"name": "Ruleta Rusa",
|
||||
"desc": "Comenzando por el sheriff, cada jugador descarta 1 Fallaste, el primero que no lo haga pierde 2 PV"
|
||||
},
|
||||
"Legge Del West": {
|
||||
"name": "Ley del Oeste",
|
||||
"desc": "Cada jugador muestra la segunda carta que roba y debe usarla en esa ronda (si es posible)"
|
||||
},
|
||||
"Peyote": {
|
||||
"name": "Peyote",
|
||||
"desc": "En lugar de robar, el jugador intenta adivinar el color del palo, si acierta, agrega la carta a su mano y continúa intentando adivinar la siguiente carta"
|
||||
},
|
||||
"Fratelli Di Sangue": {
|
||||
"name": "Hermanos de Sangre",
|
||||
"desc": "Al comienzo de su turno, los jugadores pueden perder 1 PV (excepto el último) para dárselo a otro jugador"
|
||||
},
|
||||
"I Dalton": {
|
||||
"name": "Los Dalton",
|
||||
"desc": "Los jugadores que tengan cartas azules equipadas, descartan una de esas cartas a su elección"
|
||||
},
|
||||
"Sermone": {
|
||||
"name": "El Sermón",
|
||||
"desc": "Los jugadores no pueden jugar Bang! durante su turno"
|
||||
},
|
||||
"Città Fantasma": {
|
||||
"name": "Ciudad Fantasma",
|
||||
"desc": "Todos los jugadores muertos vuelven a la vida en su turno, no pueden morir y roban 3 cartas en lugar de 2. Cuando terminan su turno, mueren."
|
||||
},
|
||||
"Il Reverendo": {
|
||||
"name": "El Reverendo",
|
||||
"desc": "Las cervezas no se pueden jugar"
|
||||
},
|
||||
"Sbornia": {
|
||||
"name": "Resaca",
|
||||
"desc": "Los personajes pierden sus habilidades especiales"
|
||||
},
|
||||
"Il Dottore": {
|
||||
"name": "El Doctor",
|
||||
"desc": "El jugador con la menor cantidad de PV recupera 1 PV"
|
||||
},
|
||||
"Corsa All Oro": {
|
||||
"name": "Fiebre del Oro",
|
||||
"desc": "Los turnos se juegan en sentido antihorario"
|
||||
},
|
||||
"Maledizione": {
|
||||
"name": "Maldición",
|
||||
"desc": "Todas las cartas son de picas ♠️"
|
||||
},
|
||||
"Sparatoria": {
|
||||
"name": "Tiroteo",
|
||||
"desc": "El límite de Bang! del turno es de 2"
|
||||
},
|
||||
"Benedizione": {
|
||||
"name": "Bendición",
|
||||
"desc": "Todas las cartas son de corazones ❤️"
|
||||
},
|
||||
"Il Treno": {
|
||||
"name": "Llegada del Tren",
|
||||
"desc": "Los jugadores roban 1 carta extra"
|
||||
},
|
||||
"Sete": {
|
||||
"name": "Sed",
|
||||
"desc": "Los jugadores solo roban 1 carta al comienzo de su turno"
|
||||
},
|
||||
"Nuova Identita": {
|
||||
"name": "Nueva Identidad",
|
||||
"desc": "Al comienzo de su turno, cada jugador puede elegir cambiar su personaje con el otro mostrado al comienzo del juego. Si lo hace, comienza con 2 PV"
|
||||
},
|
||||
"Manette": {
|
||||
"name": "Esposas",
|
||||
"desc": "Después de robar en la fase 1, el jugador declara un palo. Solo podrá usar cartas de ese palo durante ese turno"
|
||||
},
|
||||
"Mezzogiorno di Fuoco": {
|
||||
"name": "Mediodía de Fuego",
|
||||
"desc": "Cada jugador pierde 1 PV al comenzar su turno"
|
||||
},
|
||||
"Per Un Pugno Di Carte": {
|
||||
"name": "Por un Puñado de Cartas",
|
||||
"desc": "Al comienzo de su turno, el jugador es objetivo de tantos Bang como cartas tenga en su mano"
|
||||
},
|
||||
"Pepita": {
|
||||
"name": "Pepita de Oro"
|
||||
},
|
||||
"Bicchierino": {
|
||||
"name": "Chupito",
|
||||
"desc": "Puedes elegir a un jugador que recupere 1 PV (incluso tú)"
|
||||
},
|
||||
"Bottiglia": {
|
||||
"name": "Botella",
|
||||
"desc": "Se puede jugar como Pánico!, Cerveza o Bang!"
|
||||
},
|
||||
"Complice": {
|
||||
"name": "Cómplice",
|
||||
"desc": "Se puede jugar como Tienda General, Duelo o Cat Balou."
|
||||
},
|
||||
"Corsa All Oro_gr": {
|
||||
"name": "Fiebre del Oro",
|
||||
"desc": "Terminas tu turno, recuperas todos tus PV y comienzas un nuevo turno."
|
||||
},
|
||||
"Rum": {
|
||||
"name": "Ron",
|
||||
"desc": "Voltea 4 cartas, por cada palo diferente, ganas 1 PV."
|
||||
},
|
||||
"Union Pacific": {
|
||||
"name": "Union Pacific",
|
||||
"desc": "Roba 4 cartas del mazo."
|
||||
},
|
||||
"Calumet": {
|
||||
"name": "Calumet",
|
||||
"desc": "Las cartas de diamantes jugadas por otros jugadores no tienen efecto sobre ti."
|
||||
},
|
||||
"Cinturone": {
|
||||
"name": "Cinturón",
|
||||
"desc": "Puedes mantener hasta 8 cartas cuando terminas tu turno."
|
||||
},
|
||||
"Ferro di Cavallo": {
|
||||
"name": "Herradura",
|
||||
"desc": "Cada vez que tienes que voltear una carta, ¡volteas dos veces!"
|
||||
},
|
||||
"Piccone": {
|
||||
"name": "Pico",
|
||||
"desc": "Obtienes 1 carta más cuando robas al comienzo del turno."
|
||||
},
|
||||
"Ricercato": {
|
||||
"name": "Se Busca",
|
||||
"desc": "Juega sobre otro jugador, quien mate al objetivo obtiene 2 cartas extra y 1 pepita de oro."
|
||||
},
|
||||
"Setaccio": {
|
||||
"name": "Cazador de Oro",
|
||||
"desc": "Paga 1 pepita de oro para robar 1 carta del mazo, hasta dos veces por turno. (Haz clic en la carta equipada para usar)"
|
||||
},
|
||||
"Stivali": {
|
||||
"name": "Botas",
|
||||
"desc": "Cada vez que pierdes 1 PV, robas 1 carta del mazo."
|
||||
},
|
||||
"Talismano": {
|
||||
"name": "Amuleto de la Suerte",
|
||||
"desc": "Cada vez que pierdes 1 PV, obtienes 1 pepita de oro."
|
||||
},
|
||||
"Zaino": {
|
||||
"name": "Mochila",
|
||||
"desc": "Paga 2 pepitas de oro para curar 1 PV. (Haz clic en la carta equipada para usar)"
|
||||
},
|
||||
"Don Bell": {
|
||||
"name": "Don Bell",
|
||||
"desc": "Cuando termina su turno, voltea una carta, si es Corazones ❤️ o Diamantes ♦️, juega nuevamente."
|
||||
},
|
||||
"Dutch Will": {
|
||||
"name": "Dutch Will",
|
||||
"desc": "Roba 2 cartas, descarta 1 y toma 1 pepita de oro."
|
||||
},
|
||||
"Jacky Murieta": {
|
||||
"name": "Jacky Murieta",
|
||||
"desc": "Durante su turno puede pagar 2 pepitas de oro para tener la capacidad de disparar otro Bang!"
|
||||
},
|
||||
"Josh McCloud": {
|
||||
"name": "Josh McCloud",
|
||||
"desc": "Puede pagar 2 pepitas de oro para obtener la primera carta del mazo de fiebre del oro."
|
||||
},
|
||||
"Madam Yto": {
|
||||
"name": "Madam Yto",
|
||||
"desc": "Roba 1 carta del mazo cada vez que se juega una cerveza."
|
||||
},
|
||||
"Pretty Luzena": {
|
||||
"name": "Pretty Luzena",
|
||||
"desc": "Una vez por turno, puede tener un descuento de 1 en la tienda de cartas de fiebre del oro."
|
||||
},
|
||||
"Raddie Snake": {
|
||||
"name": "Raddie Snake",
|
||||
"desc": "Puede descartar 1 pepita de oro para robar 1 carta del mazo durante su turno (máximo 2 veces por turno)."
|
||||
},
|
||||
"Simeon Picos": {
|
||||
"name": "Simeon Picos",
|
||||
"desc": "Obtiene 1 pepita de oro cada vez que pierde 1 PV."
|
||||
},
|
||||
"Fantasma": {
|
||||
"name": "Fantasma",
|
||||
"desc": "Juega sobre cualquier jugador eliminado: ese jugador vuelve al juego, pero no puede ganar ni perder puntos de vida."
|
||||
},
|
||||
"Lemat": {
|
||||
"name": "Lemat",
|
||||
"desc": "Durante tu turno puedes usar cualquier carta como Bang! (Haz clic en la carta una vez equipada)."
|
||||
},
|
||||
"SerpenteASonagli": {
|
||||
"name": "Serpiente de Cascabel",
|
||||
"desc": "Juega sobre cualquier jugador. Al comienzo de su turno, si ese jugador roba en Picas, pierde 1 punto de vida."
|
||||
},
|
||||
"Shotgun": {
|
||||
"name": "Escopeta",
|
||||
"desc": "Cada vez que hieres a un jugador, debe descartar una carta de su mano."
|
||||
},
|
||||
"Taglia": {
|
||||
"name": "Recompensa",
|
||||
"desc": "Juega sobre cualquier jugador. Si ese jugador es golpeado por Bang!, la persona que disparó obtiene una carta del mazo."
|
||||
},
|
||||
"Mira": {
|
||||
"name": "Apuntar",
|
||||
"desc": "Juega esta carta junto con una carta Bang!. Si el objetivo es golpeado, pierde 2 puntos de vida."
|
||||
},
|
||||
"RitornoDiFiamma": {
|
||||
"name": "Retroceso",
|
||||
"desc": "Cuenta como una carta Fallaste!. El jugador que disparó es el objetivo de un Bang!."
|
||||
},
|
||||
"Bandidos": {
|
||||
"name": "Bandidos",
|
||||
"desc": "Cada jugador elige entre descartar 2 cartas de su mano (o 1 si solo tiene 1) o perder 1 punto de vida."
|
||||
},
|
||||
"Fuga": {
|
||||
"name": "Fuga",
|
||||
"desc": "Puede jugarse fuera de turno. Evita el efecto de una carta marrón (no Bang!) de la que eres objetivo."
|
||||
},
|
||||
"Sventagliata": {
|
||||
"name": "Acribillar",
|
||||
"desc": "Cuenta como el único Bang! del turno. Un jugador de tu elección a una distancia de 1 del objetivo (si lo hay, excluyéndote a ti mismo) también es objetivo de un Bang."
|
||||
},
|
||||
"UltimoGiro": {
|
||||
"name": "Última Ronda",
|
||||
"desc": "Recupera 1 punto de vida"
|
||||
},
|
||||
"Poker": {
|
||||
"name": "Póker",
|
||||
"desc": "Todos los demás jugadores descartan una carta de su mano, al mismo tiempo. Si no hay Ases, roba hasta 2 de esas cartas."
|
||||
},
|
||||
"Salvo": {
|
||||
"name": "¡Salvado!",
|
||||
"desc": "Puede jugarse fuera de turno. Evita que otro jugador pierda 1 punto de vida. Si sobrevive, roba 2 cartas de su mano o del mazo (a tu elección)."
|
||||
},
|
||||
"Tomahawk": {
|
||||
"name": "Tomahawk",
|
||||
"desc": "Ataca a un jugador hasta una distancia de 2."
|
||||
},
|
||||
"Tornado": {
|
||||
"name": "Tornado",
|
||||
"desc": "Todos descartan una carta de su mano (si es posible), luego roban 2 cartas del mazo."
|
||||
},
|
||||
"Black Flower": {
|
||||
"name": "Flor Negra",
|
||||
"desc": "Una vez por turno, puedes usar una carta de Picas para disparar un Bang! extra"
|
||||
},
|
||||
"Colorado Bill": {
|
||||
"name": "Colorado Bill",
|
||||
"desc": "Cada vez que juegas una carta Bang!, si robas una Picas, el disparo no puede ser evitado."
|
||||
},
|
||||
"Der Spot Burst Ringer": {
|
||||
"name": "Der Spot Burst Ringer",
|
||||
"desc": "Una vez por turno, puedes usar una carta Bang! como una Gatling."
|
||||
},
|
||||
"Evelyn Shebang": {
|
||||
"name": "Evelyn Shebang",
|
||||
"desc": "Puedes elegir no robar cartas durante tu fase de robo. Por cada carta no robada, disparas un Bang! a un objetivo alcanzable, a un objetivo diferente."
|
||||
},
|
||||
"Henry Block": {
|
||||
"name": "Henry Block",
|
||||
"desc": "Cualquiera que robe o descarte una de tus cartas en juego o en mano es objetivo de un Bang!."
|
||||
},
|
||||
"Lemonade Jim": {
|
||||
"name": "Lemonade Jim",
|
||||
"desc": "Cada vez que otro jugador juega una Cerveza, puedes descartar una carta de tu mano para recuperar también 1 punto de vida."
|
||||
},
|
||||
"Mick Defender": {
|
||||
"name": "Mick Defender",
|
||||
"desc": "Si eres objetivo de una carta marrón (no Bang!), puedes usar una carta Fallaste! para evitar 1 efecto."
|
||||
},
|
||||
"Tuco Franziskaner": {
|
||||
"name": "Tuco Franziskaner",
|
||||
"desc": "Si no tienes cartas azules equipadas, robas 2 cartas adicionales."
|
||||
},
|
||||
"Big Spencer": {
|
||||
"name": "Big Spencer",
|
||||
"desc": "Comienza con 5 cartas. No puede jugar Fallaste!"
|
||||
},
|
||||
"Flint Westwood": {
|
||||
"name": "Flint Westwood",
|
||||
"desc": "Puede intercambiar una carta de su mano con 2 cartas aleatorias de la mano de otro jugador durante su turno."
|
||||
},
|
||||
"Gary Looter": {
|
||||
"name": "Gary Looter",
|
||||
"desc": "Roba todas las cartas sobrantes descartadas por otros jugadores al final de cada turno."
|
||||
},
|
||||
"Greygory Deckard": {
|
||||
"name": "Greygory Deckard",
|
||||
"desc": "Al comienzo de su turno, puede robar 2 personajes aleatorios y gana todas sus habilidades."
|
||||
},
|
||||
"John Pain": {
|
||||
"name": "John Pain",
|
||||
"desc": "Si tiene menos de 6 cartas en su mano, cuando un jugador \"¡roba!\", John agrega la carta robada a su mano."
|
||||
},
|
||||
"Lee Van Kliff": {
|
||||
"name": "Lee Van Kliff",
|
||||
"desc": "Durante su turno, puede descartar una carta Bang! para repetir el efecto de una carta marrón que acaba de jugar."
|
||||
},
|
||||
"Teren Kill": {
|
||||
"name": "Teren Kill",
|
||||
"desc": "Cada vez que va a ser eliminado, \"¡roba!\": si no es una carta de Picas, Teren se queda en 1 punto de vida y roba 1 carta."
|
||||
},
|
||||
"Youl Grinner": {
|
||||
"name": "Youl Grinner",
|
||||
"desc": "Antes de robar, los jugadores con más cartas en su mano que Youl deben darle una carta de su elección."
|
||||
},
|
||||
"Camposanto": {
|
||||
"name": "Cementerio",
|
||||
"desc": "Al comienzo de su turno, cada jugador eliminado vuelve al juego con 1 punto de vida. Roba una carta de rol al azar de los jugadores eliminados."
|
||||
},
|
||||
"Darling Valentine": {
|
||||
"name": "Darling Valentine",
|
||||
"desc": "Al comienzo de su turno, cada jugador descarta su mano y roba el mismo número de cartas del mazo."
|
||||
},
|
||||
"Dorothy Rage": {
|
||||
"name": "Dorothy Rage",
|
||||
"desc": "Durante su turno, cada jugador puede forzar a otro jugador a jugar una carta."
|
||||
},
|
||||
"Helena Zontero": {
|
||||
"name": "Helena Zontero",
|
||||
"desc": "Cuando Helena entra en el juego, \"¡roba!\": si se roba un Corazón o un Diamante, baraja las cartas de rol activas excepto el Sheriff y redistribúyelas al azar."
|
||||
},
|
||||
"Lady Rosa del Texas": {
|
||||
"name": "Lady Rose of Texas",
|
||||
"desc": "Durante su turno, cada jugador puede cambiar de lugar con el jugador a su derecha, quien se salta su próximo turno. (Haz clic en la carta)"
|
||||
},
|
||||
"Miss Susanna": {
|
||||
"name": "Miss Susanna",
|
||||
"desc": "Durante su turno, cada jugador debe jugar al menos 3 cartas. Si no lo hacen, pierden 1 punto de vida."
|
||||
},
|
||||
"Regolamento di Conti": {
|
||||
"name": "Rendición de Cuentas",
|
||||
"desc": "Todas las cartas pueden jugarse como si fueran Bang!. Las cartas Bang! pueden jugarse como si fueran Fallaste! (Haz clic en la carta)"
|
||||
},
|
||||
"Sacagaway": {
|
||||
"name": "Sacagaway",
|
||||
"desc": "Todos los jugadores juegan con sus cartas boca arriba (excepto su carta de rol!)."
|
||||
},
|
||||
"Wild West Show": {
|
||||
"name": "Wild West Show",
|
||||
"desc": "El objetivo de cada jugador se convierte en: \"¡Sé el último en pie!\""
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
"character": "Personajes",
|
||||
"characters_special": "Cada personaje tiene habilidades especiales y una cantidad de vidas que los hacen únicos. \nLas vidas son el número de puntos de vida que puedes perder antes de morir e indican también el número máximo de cartas que puedes mantener en tu mano.",
|
||||
"deathnobeer": "Cuando pierdes tu último punto de vida y no tienes una cerveza 🍺️ en tu mano, mueres. \nTus cartas se descartan y tu rol se revela a todos.",
|
||||
"discard": "Descartar",
|
||||
"distance": "Distancia",
|
||||
"distancecalc": "La distancia se calcula automáticamente por el juego y corresponde a la distancia mínima entre los jugadores a la izquierda y a la derecha.",
|
||||
"drawinstructions": "Para robar cartas, debes hacer clic en el mazo cuando veas esta animación.",
|
||||
"drawthecards": "Roba las cartas",
|
||||
"endgame": "Fin del juego",
|
||||
"endgameconditions": "El juego termina cuando se cumple una de las siguientes condiciones:",
|
||||
"endgamesheriffwin": "Todos los forajidos 🐺️ y renegados 🦅️ están muertos. \nEn este caso, el sheriff ⭐️ y los ayudantes 🎖️ ganan.",
|
||||
"endgameshriffdeath": "El sheriff ⭐️ muere. \nSi el renegado 🦅️ es el último jugador en pie, gana, de lo contrario, los forajidos ganan.",
|
||||
"endingturn": "Cuando hayas terminado de jugar tus cartas, es decir, cuando no quieras o no puedas jugar más cartas, debes descartar las cartas que excedan tu número actual de vidas.\n\nLuego pasas el turno al siguiente jugador haciendo clic en terminar turno.",
|
||||
"equipment": "EQUIPO",
|
||||
"justoneweapon": "Solo puedes tener 1 arma equipada.",
|
||||
"maxtwocardsequip": "No puedes tener 2 cartas con el mismo nombre equipadas.",
|
||||
"outlawreward": "Cualquiera que mate a un forajido 🐺️ roba 3 cartas del mazo (otros forajidos también 🐺️).",
|
||||
"playerdeath": "La muerte de un jugador",
|
||||
"playingcards": "Jugar las cartas",
|
||||
"playingdmg": "Puedes jugar tus cartas para ti mismo o para dañar a otros jugadores intentando eliminarlos.",
|
||||
"playingduringturn": "Solo puedes jugar las cartas en tu turno. Para jugar cartas, haz clic en las cartas de tu mano.\nCon la excepción de cartas usadas como respuesta, como Fallaste 😅️.",
|
||||
"playingifyouwant": "No estás obligado a jugar cartas.",
|
||||
"playlimit": "Solo hay 3 limitaciones:",
|
||||
"playonlyonebang": "Solo puedes jugar 1 Bang! \npor turno (se refiere solo a cartas llamadas Bang!)",
|
||||
"rewardspen": "Penalidades y recompensas",
|
||||
"roles": "Roles",
|
||||
"sheriffkillsvice": "Si el sheriff ⭐️ mata a un ayudante, pierde todas las cartas en su mano y en juego frente a él.",
|
||||
"thecards": "Cartas",
|
||||
"title": "Cómo jugar",
|
||||
"turndiscard": "Descarta las cartas sobrantes",
|
||||
"turndraw": "Roba 2 cartas",
|
||||
"turnplay": "Juega cualquier cantidad de cartas",
|
||||
"turns": "Turnos",
|
||||
"turnstart": "Siempre comienza con el Sheriff ⭐️, y el juego continúa en el sentido de las agujas del reloj, los turnos se dividen en 3 fases.",
|
||||
"weapon": "ARMA",
|
||||
"renegade": "Renegado",
|
||||
"vice": "Ayudante",
|
||||
"outlaw": "Forajido",
|
||||
"sheriff": "Sheriff",
|
||||
"allcharacters": "Todos los personajes",
|
||||
"gotoallcharacters": "Ir a todos los personajes",
|
||||
"gotocards": "Ir a las cartas",
|
||||
"gotohighnoon": "Ir al Mediodía",
|
||||
"gotofoc": "Ir a Un Puñado de Cartas",
|
||||
"gotogoldrush": "Ir a Fiebre del Oro",
|
||||
"highnooncards": "Mediodía - Cartas de Evento",
|
||||
"foccards": "Un Puñado de Cartas - Cartas de Evento",
|
||||
"goldrushcards": "Cartas de Fiebre del Oro",
|
||||
"valleyofshadowscards": "Cartas del Valle de las Sombras"
|
||||
},
|
||||
"theme": {
|
||||
"sepia": "Sepia",
|
||||
"light": "Claro",
|
||||
"dark": "Oscuro",
|
||||
"grayscale": "Escala de Grises",
|
||||
"black": "Negro"
|
||||
}
|
||||
}
|
@ -1,918 +0,0 @@
|
||||
{
|
||||
"trademark": "Bang! est une marque déposée détenue par DVGiochi",
|
||||
"tip_1": "C'est mieux avec des amis !",
|
||||
"tip_2": "L'icône 🤖️ signifie qu'un joueur est un bot !",
|
||||
"tip_3": "Vous pouvez cliquer sur les cartes des personnages et des équipements des autres joueurs si vous souhaitez en savoir plus !",
|
||||
"tip_4": "Dodge City, High Noon, Fistful Of Cards inclus !",
|
||||
"tip_5": "Trouvé un bug ? Envoyez-nous un message sur Discord !",
|
||||
"tip_6": "Maintenant avec un serveur Discord !",
|
||||
"tip_7": "Si vous voulez nous aider à traduire le jeu dans votre langue, contactez-nous sur Discord !",
|
||||
"tip_8": "Si vous vous déconnectez pendant une partie en cours, vous serez remplacé par un bot (pendant votre absence) !",
|
||||
"tip_9": "Si vous êtes sur mobile, maintenez une carte pour lire la description !",
|
||||
"tip_10": "En cas de doute, tirez sur tous les autres joueurs !",
|
||||
"online_players": "Joueurs en ligne : ",
|
||||
"shuffle_players": "Mélanger les joueurs",
|
||||
"choose_username": "Choisissez un nom d'utilisateur :",
|
||||
"report_bug": "Décrivez le bug",
|
||||
"report": "Signaler un bug",
|
||||
"available_lobbies": "Salles disponibles :",
|
||||
"spectate_lobbies": "Observer les parties en cours :",
|
||||
"no_lobby_available": "Aucune salle disponible",
|
||||
"create_lobby": "Ouvrir une salle :",
|
||||
"characters_to_distribute": "Personnages à distribuer : ",
|
||||
"lobby_name": "Nom :",
|
||||
"leave_room": "Quitter la salle",
|
||||
"warning": "Attention !",
|
||||
"connection_error": "Impossible de se connecter au serveur.",
|
||||
"end_turn": "Terminer le tour !",
|
||||
"start_game": "Commencer !",
|
||||
"expansions": "Extensions",
|
||||
"click_to_toggle": "Cliquez pour basculer",
|
||||
"details": "Détails",
|
||||
"ok": "OK",
|
||||
"you": "VOUS",
|
||||
"owner": "PROPRIÉTAIRE",
|
||||
"cancel": "ANNULER",
|
||||
"send": "ENVOYER",
|
||||
"password": "Mot de passe : ",
|
||||
"room_password_prompt": "Mot de passe de la salle : ",
|
||||
"private_room": "Salle privée",
|
||||
"room": "Salle : ",
|
||||
"room_players": "Joueurs (vous êtes {username})",
|
||||
"choose_character": "Choisissez votre personnage",
|
||||
"choose_card": "Choisissez une carte",
|
||||
"choose_card_from": " de ",
|
||||
"flip_card": "↙️ Retourner une carte",
|
||||
"draw_cards": "⏬ Piochez vos cartes du paquet",
|
||||
"play_cards": "▶️ Jouez vos cartes",
|
||||
"respond_card": "↩️ Répondez à la carte",
|
||||
"wait": "⏸ Attendre",
|
||||
"choose_cards": "🔽 Choisissez une carte",
|
||||
"take_dmg": "Subir des dégâts",
|
||||
"choose_response": "Choisissez votre réponse ",
|
||||
"choose_response_to": "à ",
|
||||
"choose_response_needed": "NÉCESSAIRE ",
|
||||
"choose_manette": "Choisissez une couleur, vous ne pourrez jouer que des cartes de cette couleur ce tour.",
|
||||
"hand": "MAIN",
|
||||
"card_against": "Contre qui jouez-vous votre carte ?",
|
||||
"choose_sid_scrap": "Défaussez 2 cartes pour ne pas mourir",
|
||||
"choose_card_to_get": "Choisissez une carte",
|
||||
"choose_guess": "Devinez la couleur de la carte",
|
||||
"choose_ranch": "Choisissez les cartes à remplacer",
|
||||
"choose_dalton": "Choisissez quel équipement défausser",
|
||||
"choose_fratelli_di_sangue": "Choisissez à qui donner une de vos vies",
|
||||
"choose_fantasma": "Choisissez qui ramener à la vie",
|
||||
"choose_sventagliata": "Choisissez une autre cible pour le tir",
|
||||
"choose_tornado": "Choisissez une carte à défausser pour le tornade",
|
||||
"choose_bandidos": "Choisissez entre défausser 2 cartes ou perdre une vie (1 carte si vous n'avez qu'une)",
|
||||
"choose_poker": "Tout le monde défausse 1 carte (s'il n'y a pas d'As, le joueur ayant joué le poker choisit 2 cartes)",
|
||||
"choose_from_poker;2": "Choisissez quelles cartes récupérer (max 2)",
|
||||
"choose_from_poker;1": "Choisissez quelle carte récupérer",
|
||||
"choose_cecchino": "Choisissez qui tirer",
|
||||
"choose_rimbalzo_player": "Choisissez la cible du rebond",
|
||||
"choose_rimbalzo_card": "Choisissez la carte à défausser pour le rebond",
|
||||
"choose_nuova_identita": "Choisissez si vous voulez garder votre personnage actuel ou en changer et repartir de 2 PV",
|
||||
"choose_bicchierino": "Un joueur de votre choix regagne 1 PV",
|
||||
"choose_bottiglia": "Choisissez comment jouer la Bouteille !",
|
||||
"choose_complice": "Choisissez comment jouer Complice !",
|
||||
"choose_ricercato": "Choisissez contre qui jouer Recherché.",
|
||||
"choose_birra_function": "Choisissez entre obtenir 1 pépite d'or en défaussant la bière ou jouer la bière.",
|
||||
"choose_play_as_bang": "Choisissez quelle carte jouer comme Bang !",
|
||||
"choose_flint_special": "Choisissez quelle carte échanger.",
|
||||
"emporio_others": "{0} choisit quelle carte récupérer du Magasin général",
|
||||
"you_died": "VOUS ÊTES MORT",
|
||||
"spectate": "SPECTATEUR",
|
||||
"you_win": "VOUS AVEZ GAGNÉ",
|
||||
"you_lose": "VOUS AVEZ PERDU",
|
||||
"special_ability": "CAPACITÉ SPÉCIALE",
|
||||
"gold_rush_discard": "Défaussez l'équipement de ruée vers l'or d'un autre joueur (en payant le prix + 1)",
|
||||
"gold_rush_discard_2": "Défaussez l'équipement de ruée vers l'or d'un autre joueur (en payant le prix + 1)",
|
||||
"discard": "DÉFAUSSER",
|
||||
"to_regain_1_hp": "POUR REGAINER 1 PV",
|
||||
"play_your_turn": "JOUEZ VOTRE TOUR",
|
||||
"you_are": "Vous êtes",
|
||||
"did_pick_as": "a choisi cette carte comme deuxième",
|
||||
"blackjack_special": "Si la carte est un carreau ou un cœur, il pioche une autre carte.",
|
||||
"choose_scarp_card_to": "CHOISISSEZ QUELLE CARTE DÉFAUSSER POUR UTILISER",
|
||||
"pick_a_card": "RETIRER UNE CARTE",
|
||||
"to_defend_from": "POUR VOUS DÉFENDRE DE",
|
||||
"submit": "Soumettre",
|
||||
"copy": "Copier l'invitation",
|
||||
"no_players_in_range": "Vous ne voyez pas les autres joueurs, équipez une arme ou une lunette !",
|
||||
"cantplaycard": "Vous ne pouvez pas jouer cette carte de cette façon !",
|
||||
"chat": {
|
||||
"spectators": " | Un spectateur regarde la partie | {n} spectateurs regardent la partie",
|
||||
"chat": "Chat",
|
||||
"joined": "👋 ;{0}; a rejoint la salle",
|
||||
"died": "☠️ ;{0}; est mort",
|
||||
"died_role": "☠️ ;{0}; était un ;{1}; !",
|
||||
"won": "🏆 ;{0}; a gagné ! Leur rôle était ;{1};",
|
||||
"choose_character": ";{0}; a ;{1}; comme personnage, sa capacité spéciale est : ;{2}; !",
|
||||
"starting": "La partie commence !",
|
||||
"sheriff": "⭐ ;{0}; est le shérif !",
|
||||
"did_choose_character": ";{0}; a choisi le personnage.",
|
||||
"turn": "⏩ C'est le tour de ;{0};.",
|
||||
"draw_from_scrap": ";{0}; a pioché la première carte de la pile de défausse.",
|
||||
"draw_from_player": ";{0}; a pioché la première carte de la main de ;{1};.",
|
||||
"flipped": ";{0}; a retourné un ;{1}; ;{2};.",
|
||||
"scrapped": ";{0}; a défaussé un ;{1}; ;{2};.",
|
||||
"explode": "💥 ;{0}; a fait exploser la dynamite.",
|
||||
"beer_save": ";{0}; a utilisé une bière pour sauver sa vie.",
|
||||
"get_nugget": ";{0}; a obtenu une pépite d'or en utilisant une bière.",
|
||||
"play_card": ";{0}; a joué ;{1};.",
|
||||
"play_card_green": ";{0}; a mis en jeu ;{1};.",
|
||||
"play_card_with": ";{0}; a joué ;{1};, en défaussant ;{2};.",
|
||||
"purchase_card": ";{0}; a acheté ;{1};.",
|
||||
"play_card_against": ";{0}; a joué ;{1}; contre ;{2};.",
|
||||
"play_card_against_with": ";{0}; a joué ;{1}; contre ;{2};, en défaussant ;{3};.",
|
||||
"play_card_for": ";{0}; a joué ;{1}; pour ;{2};.",
|
||||
"spilled_beer": ";{0}; a renversé une ;{1};.",
|
||||
"diligenza": ";{0}; a joué ;{1}; et pioche 2 cartes.",
|
||||
"wellsfargo": ";{0}; a joué ;{1}; et pioche 3 cartes.",
|
||||
"saloon": "🍻 ;{0}; a joué ;{1}; et soigne 1 PV à tous les vivants.",
|
||||
"special_bart_cassidy": ";{0}; a reçu une compensation car il a été blessé.",
|
||||
"special_el_gringo": ";{0}; a volé une carte à ;{1}; lorsqu'il a été blessé.",
|
||||
"special_calamity": ";{0}; a joué ;{1}; comme Bang ! contre ;{2};.",
|
||||
"allroles3": "Dans le jeu il y a : ;{1}; ;{0};, ;{3}; ;{2};, ;{5}; ;{4};.",
|
||||
"allroles4": "Dans le jeu il y a : ;{1}; ;{0};, ;{3}; ;{2};, ;{5}; ;{4};, ;{7}; ;{6};.",
|
||||
"guess": "🤔 ;{0}; devine ;{1};.",
|
||||
"guess_right": ";{0}; avait raison.",
|
||||
"guess_wrong": ";{0}; avait tort.",
|
||||
"fratelli_sangue": ";{0}; a donné une de ses vies à ;{1};.",
|
||||
"doctor_heal": ";{0}; a été soigné par le docteur.",
|
||||
"respond": "↩️ ;{0}; a répondu avec ;{1};.",
|
||||
"change_username": "✏️ ;{0}; est maintenant ;{1};.",
|
||||
"lobby_reset": "Retour à la salle dans ;{0}; secondes...",
|
||||
"prison_free": "🆓 ;{0}; est sorti de prison",
|
||||
"prison_turn": "🔐 ;{0}; est resté en prison ce tour",
|
||||
"flip_event": "🎴 ÉVÉNEMENT : ;{0}; 🎴",
|
||||
"choose_manette": ";{0}; s'est engagé à ne jouer que des cartes de couleur ;{1}; ce tour.",
|
||||
"UnionPacific": ";{0}; a joué Union Pacific et pioche 4 cartes du paquet",
|
||||
"use_special": ";{0}; a utilisé la capacité spéciale de son personnage (;{1};)",
|
||||
"gold_rush_pay_discard": ";{0}; a défaussé ;{2}; de ;{1};.",
|
||||
"choose_emporio": ";{0}; a choisi ;{1}; du Magasin général.",
|
||||
"shotgun_scrap": "Lorsque le fusil a touché ;{0}; une carte a volé de sa main (;{1};)",
|
||||
"taglia_reward": "💰 ;{1}; a obtenu une carte de la prime sur ;{0};",
|
||||
"snake_bit": "🐍 ;{0}; a été mordu par le serpent à sonnettes."
|
||||
},
|
||||
"foc": {
|
||||
"leggedelwest": "Il doit jouer cette carte ce tour si possible."
|
||||
},
|
||||
"mods": "Modificateurs",
|
||||
"bots": "Bots",
|
||||
"add_bot": "Ajouter un bot",
|
||||
"remove_bot": "Supprimer un bot",
|
||||
"minimum_players": "Le jeu nécessite au moins 3 joueurs pour commencer",
|
||||
"mod_comp": "Mode compétitif (désactive la prise de dégâts automatique)",
|
||||
"disconnect_bot": "Remplacer les joueurs qui se déconnectent par des bots",
|
||||
"your_turn": "Jouez votre tour !",
|
||||
"your_response": "Répondez !",
|
||||
"your_choose": "Choisissez une carte !",
|
||||
"cards": {
|
||||
"Barile": {
|
||||
"name": "Baril",
|
||||
"desc": "Quand quelqu'un joue un Bang contre vous. Vous pouvez retourner la première carte du paquet, si la couleur est Cœur alors elle compte comme une carte Raté"
|
||||
},
|
||||
"Dinamite": {
|
||||
"name": "Dynamite",
|
||||
"desc": "Lorsque vous jouez la Dynamite, placez-la devant vous, elle restera inoffensive pendant un tour complet. Au début du prochain tour avant de piocher et avant tout retournement de carte (par exemple Prison), retournez une carte du dessus du paquet. Si une carte est entre 2 et 9 de pique (inclus), la dynamite explose : vous perdez 3 vies et défaussez la carte, sinon passez la dynamite au joueur suivant, qui piochera à son tour après avoir terminé son tour"
|
||||
},
|
||||
"Mirino": {
|
||||
"name": "Lunette",
|
||||
"desc": "Vous voyez les autres joueurs à une distance de -1"
|
||||
},
|
||||
"Mustang": {
|
||||
"name": "Mustang",
|
||||
"desc": "Les autres joueurs vous voient à une distance de +1"
|
||||
},
|
||||
"Prigione": {
|
||||
"name": "Prison",
|
||||
"desc": "Équipez cette carte à un autre joueur, sauf le Shérif. Le joueur choisi au début de son tour, doit retourner une carte avant de piocher : si c'est Cœur, défaussez cette carte et jouez le tour normalement, sinon défaussez cette carte et passez le tour"
|
||||
},
|
||||
"Remington": {
|
||||
"name": "Remington",
|
||||
"desc": "Vous pouvez tirer sur un autre joueur à une distance de 3 ou moins"
|
||||
},
|
||||
"Rev Carabine": {
|
||||
"name": "Rev. Carabine",
|
||||
"desc": "Vous pouvez tirer sur un autre joueur à une distance de 4 ou moins"
|
||||
},
|
||||
"Schofield": {
|
||||
"name": "Schofield",
|
||||
"desc": "Vous pouvez tirer sur un autre joueur à une distance de 2 ou moins"
|
||||
},
|
||||
"Volcanic": {
|
||||
"name": "Volcanic",
|
||||
"desc": "Vous pouvez tirer sur un autre joueur à une distance de 1 ou moins, cependant vous n'avez plus la limite d'un Bang"
|
||||
},
|
||||
"Winchester": {
|
||||
"name": "Winchester",
|
||||
"desc": "Vous pouvez tirer sur un autre joueur à une distance de 5 ou moins"
|
||||
},
|
||||
"Bang!": {
|
||||
"name": "Bang!",
|
||||
"desc": "Tirez sur un joueur en vue. Si vous n'avez pas d'armes, votre vue est de 1"
|
||||
},
|
||||
"Birra": {
|
||||
"name": "Bière",
|
||||
"desc": "Jouez cette carte pour regagner un point de vie. Vous ne pouvez pas soigner plus que la limite maximale de votre personnage. Si vous êtes sur le point de perdre votre dernier point de vie, vous pouvez également jouer cette carte pendant le tour de votre adversaire. La bière ne fait plus effet s'il ne reste que deux joueurs"
|
||||
},
|
||||
"Cat Balou": {
|
||||
"name": "Cat Balou",
|
||||
"desc": "Choisissez et défaussez une carte d'un autre joueur."
|
||||
},
|
||||
"Diligenza": {
|
||||
"name": "Diligence",
|
||||
"desc": "Piochez 2 cartes du paquet."
|
||||
},
|
||||
"Duello": {
|
||||
"name": "Duel",
|
||||
"desc": "Jouez cette carte contre n'importe quel joueur. À tour de rôle, en commençant par votre adversaire, vous pouvez défausser une carte Bang!, le premier joueur qui ne le fait pas perd 1 vie."
|
||||
},
|
||||
"Emporio": {
|
||||
"name": "Magasin Général",
|
||||
"desc": "Mettez sur la table N cartes du paquet, où N est le nombre de joueurs vivants, à tour de rôle, en commençant par vous, choisissez une carte et ajoutez-la à votre main"
|
||||
},
|
||||
"Gatling": {
|
||||
"name": "Gatling",
|
||||
"desc": "Tirez sur tous les autres joueurs"
|
||||
},
|
||||
"Indiani!": {
|
||||
"name": "Indiens !",
|
||||
"desc": "Tous les autres joueurs doivent défausser une carte Bang! ou perdre 1 point de vie"
|
||||
},
|
||||
"Mancato!": {
|
||||
"name": "Raté !",
|
||||
"desc": "Utilisez cette carte pour annuler l'effet d'un Bang"
|
||||
},
|
||||
"Panico!": {
|
||||
"name": "Panique !",
|
||||
"desc": "Volez une carte à un joueur à une distance de 1"
|
||||
},
|
||||
"Saloon": {
|
||||
"name": "Saloon",
|
||||
"desc": "Tout le monde regagne 1 point de vie"
|
||||
},
|
||||
"WellsFargo": {
|
||||
"name": "Wells Fargo",
|
||||
"desc": "Piochez 3 cartes du paquet"
|
||||
},
|
||||
"Binocolo": {
|
||||
"name": "Jumelles",
|
||||
"desc": "Vous voyez les autres joueurs à une distance de -1"
|
||||
},
|
||||
"Riparo": {
|
||||
"name": "Cachette",
|
||||
"desc": "Les autres joueurs vous voient à une distance de +1"
|
||||
},
|
||||
"Pugno!": {
|
||||
"name": "Coup de Poing !",
|
||||
"desc": "Tirez sur un joueur à une distance de 1"
|
||||
},
|
||||
"Rag Time": {
|
||||
"name": "Rag Time",
|
||||
"desc": "Volez une carte à un autre joueur à n'importe quelle distance"
|
||||
},
|
||||
"Rissa": {
|
||||
"name": "Bagarre",
|
||||
"desc": "Choisissez une carte à défausser de la main/équipement de tous les autres joueurs"
|
||||
},
|
||||
"Schivata": {
|
||||
"name": "Esquive",
|
||||
"desc": "Utilisez cette carte pour annuler l'effet d'un Bang et ensuite piochez une carte."
|
||||
},
|
||||
"Springfield": {
|
||||
"name": "Springfield",
|
||||
"desc": "Tirez sur un joueur à n'importe quelle distance"
|
||||
},
|
||||
"Tequila": {
|
||||
"name": "Tequila",
|
||||
"desc": "Soignez 1 PV à un joueur de votre choix (cela peut être vous)"
|
||||
},
|
||||
"Whisky": {
|
||||
"name": "Whisky",
|
||||
"desc": "Soignez 2 PV"
|
||||
},
|
||||
"Bibbia": {
|
||||
"name": "Bible",
|
||||
"desc": "Utilisez cette carte pour annuler l'effet d'un Bang et ensuite piochez une carte."
|
||||
},
|
||||
"Cappello": {
|
||||
"name": "Chapeau de Dix Gallons",
|
||||
"desc": "Utilisez cette carte pour annuler l'effet d'un Bang"
|
||||
},
|
||||
"Placca Di Ferro": {
|
||||
"name": "Plaque de Fer",
|
||||
"desc": "Utilisez cette carte pour annuler l'effet d'un Bang"
|
||||
},
|
||||
"Sombrero": {
|
||||
"name": "Sombrero",
|
||||
"desc": "Utilisez cette carte pour annuler l'effet d'un Bang"
|
||||
},
|
||||
"Pugnale": {
|
||||
"name": "Couteau",
|
||||
"desc": "Tirez sur un joueur à une distance de 1"
|
||||
},
|
||||
"Derringer": {
|
||||
"name": "Derringer",
|
||||
"desc": "Tirez sur un joueur à une distance de 1 et ensuite piochez une carte."
|
||||
},
|
||||
"Borraccia": {
|
||||
"name": "Gourde",
|
||||
"desc": "Regagnez 1 PV"
|
||||
},
|
||||
"Can Can": {
|
||||
"name": "Can Can",
|
||||
"desc": "Choisissez et défaussez une carte d'un autre joueur."
|
||||
},
|
||||
"Conestoga": {
|
||||
"name": "Conestoga",
|
||||
"desc": "Volez une carte à un autre joueur à n'importe quelle distance"
|
||||
},
|
||||
"Fucile Da Caccia": {
|
||||
"name": "Fusil de Buffle",
|
||||
"desc": "Tirez sur un joueur à n'importe quelle distance"
|
||||
},
|
||||
"Pony Express": {
|
||||
"name": "Pony Express",
|
||||
"desc": "Piochez 3 cartes du paquet"
|
||||
},
|
||||
"Pepperbox": {
|
||||
"name": "Pepperbox",
|
||||
"desc": "Tirez sur un joueur en vue. Si vous n'avez pas d'armes, votre vue est de 1"
|
||||
},
|
||||
"Howitzer": {
|
||||
"name": "Howitzer",
|
||||
"desc": "Tirez sur tous les autres joueurs"
|
||||
},
|
||||
"Bart Cassidy": {
|
||||
"name": "Bart Cassidy",
|
||||
"desc": "Chaque fois qu'il est blessé, il pioche une carte."
|
||||
},
|
||||
"Black Jack": {
|
||||
"name": "Black Jack",
|
||||
"desc": "Au début de son tour, lorsqu'il doit piocher, il montre à tout le monde la deuxième carte, si c'est un Cœur ou un Carreau, il pioche une troisième carte sans la montrer."
|
||||
},
|
||||
"Calamity Janet": {
|
||||
"name": "Calamity Janet",
|
||||
"desc": "Elle peut utiliser les cartes Raté ! comme Bang ! et vice versa."
|
||||
},
|
||||
"El Gringo": {
|
||||
"name": "El Gringo",
|
||||
"desc": "Chaque fois qu'il est blessé, il vole une carte de la main du joueur attaquant."
|
||||
},
|
||||
"Jesse Jones": {
|
||||
"name": "Jesse Jones",
|
||||
"desc": "Lorsqu'il doit piocher ses cartes, il peut piocher la première carte de la main d'un autre joueur. (cliquez sur les cartes des joueurs ennemis si vous voulez utiliser la capacité)"
|
||||
},
|
||||
"Jourdonnais": {
|
||||
"name": "Jourdonnais",
|
||||
"desc": "Il joue comme s'il avait un Baril toujours actif, s'il équipe un autre Baril, il peut retourner 2 cartes."
|
||||
},
|
||||
"Kit Carlson": {
|
||||
"name": "Kit Carlson",
|
||||
"desc": "Lorsqu'il doit piocher, il regarde 3 cartes et en choisit 2, mettant l'autre carte sur le dessus du paquet."
|
||||
},
|
||||
"Lucky Duke": {
|
||||
"name": "Lucky Duke",
|
||||
"desc": "Chaque fois qu'il doit retourner une carte, il peut retourner 2 fois."
|
||||
},
|
||||
"Paul Regret": {
|
||||
"name": "Paul Regret",
|
||||
"desc": "Les autres joueurs le voient à une distance de +1."
|
||||
},
|
||||
"Pedro Ramirez": {
|
||||
"name": "Pedro Ramirez",
|
||||
"desc": "Lorsqu'il doit piocher, il peut prendre la première carte de la pile de défausse. (cliquez sur les cartes défaussées pour utiliser la capacité)"
|
||||
},
|
||||
"Rose Doolan": {
|
||||
"name": "Rose Doolan",
|
||||
"desc": "Elle voit les autres joueurs à une distance de -1."
|
||||
},
|
||||
"Sid Ketchum": {
|
||||
"name": "Sid Ketchum",
|
||||
"desc": "Il peut défausser 2 cartes pour regagner 1 PV."
|
||||
},
|
||||
"Slab The Killer": {
|
||||
"name": "Slab The Killer",
|
||||
"desc": "Pour esquiver ses cartes Bang !, les autres joueurs ont besoin de 2 cartes Raté !"
|
||||
},
|
||||
"Suzy Lafayette": {
|
||||
"name": "Suzy Lafayette",
|
||||
"desc": "Chaque fois qu'elle a une main vide, elle pioche une carte."
|
||||
},
|
||||
"Vulture Sam": {
|
||||
"name": "Vulture Sam",
|
||||
"desc": "Lorsqu'un joueur meurt, il obtient toutes les cartes dans la main et les équipements du mort."
|
||||
},
|
||||
"Willy The Kid": {
|
||||
"name": "Willy The Kid",
|
||||
"desc": "Il n'a pas de limite au nombre de Bang qu'il peut utiliser."
|
||||
},
|
||||
"Pixie Pete": {
|
||||
"name": "Pixie Pete",
|
||||
"desc": "Il pioche 3 cartes au lieu de 2."
|
||||
},
|
||||
"Tequila Joe": {
|
||||
"name": "Tequila Joe",
|
||||
"desc": "Lorsqu'il joue une Bière, il regagne 2 PV."
|
||||
},
|
||||
"Greg Digger": {
|
||||
"name": "Greg Digger",
|
||||
"desc": "Chaque fois qu'un joueur meurt, il regagne jusqu'à 2 vies."
|
||||
},
|
||||
"Herb Hunter": {
|
||||
"name": "Herb Hunter",
|
||||
"desc": "Chaque fois qu'un joueur meurt, il pioche 2 cartes."
|
||||
},
|
||||
"Elena Fuente": {
|
||||
"name": "Elena Fuente",
|
||||
"desc": "Elle peut utiliser n'importe quelle carte de sa main comme Raté."
|
||||
},
|
||||
"Bill Noface": {
|
||||
"name": "Bill Noface",
|
||||
"desc": "Pioche 1 carte + 1 carte pour chaque blessure qu'il a."
|
||||
},
|
||||
"Molly Stark": {
|
||||
"name": "Molly Stark",
|
||||
"desc": "Lorsqu'elle utilise une carte de sa main en dehors de son tour, elle pioche une carte."
|
||||
},
|
||||
"Apache Kid": {
|
||||
"name": "Apache Kid",
|
||||
"desc": "Les cartes de carreaux ♦️ jouées contre lui n'ont aucun effet (ne fonctionne pas en duel)."
|
||||
},
|
||||
"Sean Mallory": {
|
||||
"name": "Sean Mallory",
|
||||
"desc": "Il peut garder jusqu'à 10 cartes dans sa main lorsqu'il termine le tour."
|
||||
},
|
||||
"Belle Star": {
|
||||
"name": "Belle Star",
|
||||
"desc": "Pendant son tour, les cartes vertes et bleues des autres joueurs ne fonctionnent pas."
|
||||
},
|
||||
"Vera Custer": {
|
||||
"name": "Vera Custer",
|
||||
"desc": "Avant de piocher, elle peut choisir la capacité spéciale d'un autre joueur vivant. Cette capacité est utilisée jusqu'au prochain tour."
|
||||
},
|
||||
"Chuck Wengam": {
|
||||
"name": "Chuck Wengam",
|
||||
"desc": "Lors de son tour, il peut décider de perdre 1 PV pour piocher 2 cartes du paquet."
|
||||
},
|
||||
"Pat Brennan": {
|
||||
"name": "Pat Brennan",
|
||||
"desc": "Au lieu de piocher, il peut voler une carte de l'équipement d'un autre joueur. (cliquez sur le joueur ennemi si vous voulez utiliser la capacité)"
|
||||
},
|
||||
"José Delgado": {
|
||||
"name": "José Delgado",
|
||||
"desc": "Lors de son tour, il peut défausser une carte bleue pour piocher 2 cartes, jusqu'à deux fois par tour."
|
||||
},
|
||||
"Doc Holyday": {
|
||||
"name": "Doc Holyday",
|
||||
"desc": "Il peut défausser 2 cartes pour jouer un Bang."
|
||||
},
|
||||
"Fuorilegge": {
|
||||
"name": "Hors-la-loi"
|
||||
},
|
||||
"Rinnegato": {
|
||||
"name": "Renégat"
|
||||
},
|
||||
"Sceriffo": {
|
||||
"name": "Shérif"
|
||||
},
|
||||
"Vice": {
|
||||
"name": "Adjoint"
|
||||
},
|
||||
"Miniera Abbandonata": {
|
||||
"name": "Mine Abandonnée",
|
||||
"desc": "Les joueurs piochent dans la pile de défausse pendant leur phase 1 et défaussent sur le dessus du paquet pendant la phase 3 (si la pile de défausse est épuisée, ils doivent piocher et défausser sur le dessus du paquet)"
|
||||
},
|
||||
"Il Giudice": {
|
||||
"name": "Le Juge",
|
||||
"desc": "Vous ne pouvez pas équiper des cartes sur vous-même ou sur d'autres joueurs"
|
||||
},
|
||||
"Agguato": {
|
||||
"name": "Embuscade",
|
||||
"desc": "La distance de base entre deux joueurs est de 1"
|
||||
},
|
||||
"Rimbalzo": {
|
||||
"name": "Rebond",
|
||||
"desc": "Le joueur peut jouer Bang contre les cartes équipées par les autres joueurs, s'ils ne jouent pas Raté, elles sont défaussées (cliquez sur la carte d'événement)"
|
||||
},
|
||||
"Cecchino": {
|
||||
"name": "Sniper",
|
||||
"desc": "Pendant leur tour, les joueurs peuvent défausser 2 Bang! pour tirer un Bang! qui nécessite 2 Raté (cliquez sur la carte)"
|
||||
},
|
||||
"Lazo": {
|
||||
"name": "Lasso",
|
||||
"desc": "Les cartes dans la fente d'équipement ne fonctionnent pas"
|
||||
},
|
||||
"Ranch": {
|
||||
"name": "Ranch",
|
||||
"desc": "Après avoir pioché, le joueur peut défausser autant de cartes qu'il veut de sa main et en piocher autant du paquet"
|
||||
},
|
||||
"Dead Man": {
|
||||
"name": "Mort",
|
||||
"desc": "Le premier joueur qui est mort revient à la vie avec 2 PV et 2 cartes"
|
||||
},
|
||||
"Liquore Forte": {
|
||||
"name": "Liqueur Forte",
|
||||
"desc": "Les joueurs peuvent sauter la pioche pour regagner 1 PV (cliquez sur la carte d'événement pour utiliser)"
|
||||
},
|
||||
"Vendetta": {
|
||||
"name": "Vengeance",
|
||||
"desc": "Lorsqu'il termine son tour, le joueur retourne une carte du paquet, si c'est un ❤️, il joue un autre tour (mais il ne retourne pas une autre carte)"
|
||||
},
|
||||
"Roulette Russa": {
|
||||
"name": "Roulette Russe",
|
||||
"desc": "En commençant par le shérif, chaque joueur défausse un Raté, le premier qui ne le fait pas perd 2 PV"
|
||||
},
|
||||
"Legge Del West": {
|
||||
"name": "La Loi de l'Ouest",
|
||||
"desc": "Chaque joueur montre la deuxième carte qu'il pioche et doit l'utiliser dans ce tour (si c'est possible)"
|
||||
},
|
||||
"Peyote": {
|
||||
"name": "Peyote",
|
||||
"desc": "Au lieu de piocher, le joueur essaie de deviner la couleur de la carte, s'il a raison, il ajoute la carte à sa main et continue d'essayer de deviner la carte suivante"
|
||||
},
|
||||
"Fratelli Di Sangue": {
|
||||
"name": "Frères de Sang",
|
||||
"desc": "Au début de leur tour, les joueurs peuvent perdre 1 PV (sauf le dernier) pour le donner à un autre joueur"
|
||||
},
|
||||
"I Dalton": {
|
||||
"name": "Les Dalton",
|
||||
"desc": "Les joueurs ayant des cartes bleues équipées, en défaussent une de leur choix"
|
||||
},
|
||||
"Sermone": {
|
||||
"name": "Le Sermon",
|
||||
"desc": "Les joueurs ne peuvent pas jouer Bang! pendant leur tour"
|
||||
},
|
||||
"Città Fantasma": {
|
||||
"name": "Ville Fantôme",
|
||||
"desc": "Tous les joueurs morts reviennent à la vie à leur tour, ils ne peuvent pas mourir et piochent 3 cartes au lieu de 2. Lorsqu'ils terminent leur tour, ils meurent."
|
||||
},
|
||||
"Il Reverendo": {
|
||||
"name": "Le Révérend",
|
||||
"desc": "Les bières ne peuvent pas être jouées"
|
||||
},
|
||||
"Sbornia": {
|
||||
"name": "Gueule de Bois",
|
||||
"desc": "Les personnages perdent leurs capacités spéciales"
|
||||
},
|
||||
"Il Dottore": {
|
||||
"name": "Le Docteur",
|
||||
"desc": "Le joueur avec le moins de PV récupère 1 PV"
|
||||
},
|
||||
"Corsa All Oro": {
|
||||
"name": "Ruée vers l'Or",
|
||||
"desc": "Les tours sont joués dans le sens inverse des aiguilles d'une montre"
|
||||
},
|
||||
"Maledizione": {
|
||||
"name": "Malédiction",
|
||||
"desc": "Toutes les cartes sont des ♠️"
|
||||
},
|
||||
"Sparatoria": {
|
||||
"name": "Fusillade",
|
||||
"desc": "La limite de Bang! du tour est de 2"
|
||||
},
|
||||
"Benedizione": {
|
||||
"name": "Bénédiction",
|
||||
"desc": "Toutes les cartes sont des ❤️"
|
||||
},
|
||||
"Il Treno": {
|
||||
"name": "Arrivée du Train",
|
||||
"desc": "Les joueurs piochent 1 carte supplémentaire"
|
||||
},
|
||||
"Sete": {
|
||||
"name": "Soif",
|
||||
"desc": "Les joueurs ne piochent qu'une seule carte au début de leur tour"
|
||||
},
|
||||
"Nuova Identita": {
|
||||
"name": "Nouvelle Identité",
|
||||
"desc": "Au début de leur tour, chaque joueur peut choisir de changer de personnage avec celui montré au début du jeu. S'il le fait, il repart avec 2 PV"
|
||||
},
|
||||
"Manette": {
|
||||
"name": "Menottes",
|
||||
"desc": "Après avoir pioché en phase 1, le joueur déclare une couleur. Il ne pourra utiliser que des cartes de cette couleur pour ce tour"
|
||||
},
|
||||
"Mezzogiorno di Fuoco": {
|
||||
"name": "Midi de Feu",
|
||||
"desc": "Chaque joueur perd 1 PV lorsqu'il commence son tour"
|
||||
},
|
||||
"Per Un Pugno Di Carte": {
|
||||
"name": "Pour une Poignée de Cartes",
|
||||
"desc": "Au début de son tour, le joueur est la cible de Bang aussi nombreux que le nombre de cartes qu'il a en main"
|
||||
},
|
||||
"Pepita": {
|
||||
"name": "Pépite d'Or"
|
||||
},
|
||||
"Bicchierino": {
|
||||
"name": "Verre",
|
||||
"desc": "Vous pouvez choisir un joueur qui regagne 1 PV (même vous)"
|
||||
},
|
||||
"Bottiglia": {
|
||||
"name": "Bouteille",
|
||||
"desc": "Peut être jouée comme Panique !, Bière ou Bang !"
|
||||
},
|
||||
"Complice": {
|
||||
"name": "Complice",
|
||||
"desc": "Peut être joué comme Magasin Général, Duel ou Cat Balou."
|
||||
},
|
||||
"Corsa All Oro_gr": {
|
||||
"name": "Ruée vers l'Or",
|
||||
"desc": "Vous terminez votre tour, regagnez tous vos PV et commencez un nouveau tour."
|
||||
},
|
||||
"Rum": {
|
||||
"name": "Rhum",
|
||||
"desc": "Retournez 4 cartes, pour chaque couleur différente, vous gagnez 1 PV."
|
||||
},
|
||||
"Union Pacific": {
|
||||
"name": "Union Pacific",
|
||||
"desc": "Piochez 4 cartes du paquet."
|
||||
},
|
||||
"Calumet": {
|
||||
"name": "Calumet",
|
||||
"desc": "Les cartes de carreaux jouées par les autres joueurs n'ont aucun effet sur vous."
|
||||
},
|
||||
"Cinturone": {
|
||||
"name": "Ceinture",
|
||||
"desc": "Vous pouvez garder jusqu'à 8 cartes lorsque vous terminez votre tour."
|
||||
},
|
||||
"Ferro di Cavallo": {
|
||||
"name": "Fer à Cheval",
|
||||
"desc": "Chaque fois que vous devez retourner une carte, vous retournez deux fois !"
|
||||
},
|
||||
"Piccone": {
|
||||
"name": "Pioche",
|
||||
"desc": "Vous obtenez 1 carte supplémentaire lorsque vous piochez au début du tour."
|
||||
},
|
||||
"Ricercato": {
|
||||
"name": "Recherché",
|
||||
"desc": "Jouez-le sur un autre joueur, qui tue la cible obtient 2 cartes supplémentaires et 1 pépite d'or."
|
||||
},
|
||||
"Setaccio": {
|
||||
"name": "Pan d'Or",
|
||||
"desc": "Payez 1 pépite d'or pour piocher 1 carte du paquet, jusqu'à deux fois par tour. (Cliquez sur la carte équipée pour utiliser)"
|
||||
},
|
||||
"Stivali": {
|
||||
"name": "Bottes",
|
||||
"desc": "Chaque fois que vous perdez 1 PV, vous piochez 1 carte du paquet."
|
||||
},
|
||||
"Talismano": {
|
||||
"name": "Porte-Bonheur",
|
||||
"desc": "Chaque fois que vous perdez 1 PV, vous obtenez 1 pépite d'or."
|
||||
},
|
||||
"Zaino": {
|
||||
"name": "Sac à Dos",
|
||||
"desc": "Payez 2 pépites d'or pour soigner 1 PV. (Cliquez sur la carte équipée pour utiliser)"
|
||||
},
|
||||
"Don Bell": {
|
||||
"name": "Don Bell",
|
||||
"desc": "Lorsqu'il termine son tour, il retourne une carte, si elle retourne Cœur ❤️ ou Carreau ♦️, il joue à nouveau."
|
||||
},
|
||||
"Dutch Will": {
|
||||
"name": "Dutch Will",
|
||||
"desc": "Il pioche 2 cartes, en défausse 1 et prend 1 pépite d'or."
|
||||
},
|
||||
"Jacky Murieta": {
|
||||
"name": "Jacky Murieta",
|
||||
"desc": "Pendant son tour, il peut payer 2 pépites d'or pour avoir la capacité de tirer un autre Bang !"
|
||||
},
|
||||
"Josh McCloud": {
|
||||
"name": "Josh McCloud",
|
||||
"desc": "Il peut payer 2 pépites d'or pour obtenir la première carte du paquet de ruée vers l'or."
|
||||
},
|
||||
"Madam Yto": {
|
||||
"name": "Madam Yto",
|
||||
"desc": "Elle pioche 1 carte du paquet chaque fois qu'une bière est jouée."
|
||||
},
|
||||
"Pretty Luzena": {
|
||||
"name": "Pretty Luzena",
|
||||
"desc": "Une fois par tour, elle peut bénéficier d'une réduction de 1 sur la boutique des cartes ruée vers l'or."
|
||||
},
|
||||
"Raddie Snake": {
|
||||
"name": "Raddie Snake",
|
||||
"desc": "Il peut jeter 1 pépite d'or pour piocher 1 carte du paquet pendant son tour (2 fois max par tour)."
|
||||
},
|
||||
"Simeon Picos": {
|
||||
"name": "Simeon Picos",
|
||||
"desc": "Il obtient 1 pépite d'or chaque fois qu'il perd 1 PV."
|
||||
},
|
||||
"Fantasma": {
|
||||
"name": "Fantôme",
|
||||
"desc": "Jouez sur un joueur éliminé : Ce joueur revient dans le jeu, mais ne peut ni gagner ni perdre des points de vie."
|
||||
},
|
||||
"Lemat": {
|
||||
"name": "Lemat",
|
||||
"desc": "Pendant votre tour, vous pouvez utiliser n'importe quelle carte comme Bang ! (Cliquez sur la carte une fois équipée)."
|
||||
},
|
||||
"SerpenteASonagli": {
|
||||
"name": "Serpent à Sonnettes",
|
||||
"desc": "Jouez sur n'importe quel joueur. Au début de son tour. si ce joueur pioche sur Piques, il perd 1 point de vie."
|
||||
},
|
||||
"Shotgun": {
|
||||
"name": "Fusil",
|
||||
"desc": "Chaque fois que vous blessez un joueur, il doit défausser une carte de sa main."
|
||||
},
|
||||
"Taglia": {
|
||||
"name": "Prime",
|
||||
"desc": "Jouez sur n'importe qui. Si ce joueur est touché par Bang !, la personne qui a tiré obtient une carte du paquet."
|
||||
},
|
||||
"Mira": {
|
||||
"name": "Viser",
|
||||
"desc": "Jouez cette carte avec une carte Bang!. Si la cible est touchée, elle perd 2 points de vie."
|
||||
},
|
||||
"RitornoDiFiamma": {
|
||||
"name": "Retour de Flamme",
|
||||
"desc": "Compte comme une carte Raté!. Le joueur qui a tiré est la cible d'un Bang!."
|
||||
},
|
||||
"Bandidos": {
|
||||
"name": "Bandidos",
|
||||
"desc": "Chaque joueur choisit de défausser 2 cartes de sa main (ou 1 s'il n'en a qu'une) ou de perdre 1 point de vie."
|
||||
},
|
||||
"Fuga": {
|
||||
"name": "Fuite",
|
||||
"desc": "Peut être jouée hors tour. Évite l'effet d'une carte brune (pas Bang!) dont vous êtes la cible."
|
||||
},
|
||||
"Sventagliata": {
|
||||
"name": "Ventilateur",
|
||||
"desc": "Compte comme le seul Bang! du tour. Un joueur de votre choix à une distance de 1 de la cible (s'il y en a un, à l'exclusion de vous-même) est également une cible d'un Bang."
|
||||
},
|
||||
"UltimoGiro": {
|
||||
"name": "Dernière Tournée",
|
||||
"desc": "Récupère 1 point de vie"
|
||||
},
|
||||
"Poker": {
|
||||
"name": "Poker",
|
||||
"desc": "Tous les autres joueurs défaussent une carte de leur main, en même temps. S'il n'y a pas d'As, piochez jusqu'à 2 de ces cartes."
|
||||
},
|
||||
"Salvo": {
|
||||
"name": "Sauvé !",
|
||||
"desc": "Peut être jouée hors tour. Empêche un autre joueur de perdre 1 point de vie. S'il survit, il pioche 2 cartes de sa main ou du paquet (votre choix)."
|
||||
},
|
||||
"Tomahawk": {
|
||||
"name": "Tomahawk",
|
||||
"desc": "Attaque un joueur jusqu'à une distance de 2."
|
||||
},
|
||||
"Tornado": {
|
||||
"name": "Tornade",
|
||||
"desc": "Tout le monde défausse une carte de leur main (si possible), puis pioche 2 cartes du paquet."
|
||||
},
|
||||
"Black Flower": {
|
||||
"name": "Fleur Noire",
|
||||
"desc": "Une fois par tour, vous pouvez utiliser une carte de Pique pour tirer un Bang ! supplémentaire"
|
||||
},
|
||||
"Colorado Bill": {
|
||||
"name": "Colorado Bill",
|
||||
"desc": "Chaque fois que vous jouez une carte Bang!, si vous piochez un Pique, le tir ne peut pas être évité."
|
||||
},
|
||||
"Der Spot Burst Ringer": {
|
||||
"name": "Der Spot Burst Ringer",
|
||||
"desc": "Une fois par tour, vous pouvez utiliser une carte Bang! comme une Gatling."
|
||||
},
|
||||
"Evelyn Shebang": {
|
||||
"name": "Evelyn Shebang",
|
||||
"desc": "Vous pouvez choisir de ne pas piocher de cartes pendant votre phase de pioche. Pour chaque carte non piochée, vous tirez un Bang! sur une cible atteignable, sur une cible différente."
|
||||
},
|
||||
"Henry Block": {
|
||||
"name": "Henry Block",
|
||||
"desc": "Quiconque pioche ou défausse une de vos cartes en jeu ou en main est la cible d'un Bang!."
|
||||
},
|
||||
"Lemonade Jim": {
|
||||
"name": "Lemonade Jim",
|
||||
"desc": "Chaque fois qu'un autre joueur joue une Bière, vous pouvez défausser une carte de votre main pour regagner également 1 point de vie."
|
||||
},
|
||||
"Mick Defender": {
|
||||
"name": "Mick Defender",
|
||||
"desc": "Si vous êtes la cible d'une carte brune (pas Bang!), vous pouvez utiliser une carte Raté! pour éviter un effet."
|
||||
},
|
||||
"Tuco Franziskaner": {
|
||||
"name": "Tuco Franziskaner",
|
||||
"desc": "Si vous n'avez pas de cartes bleues équipées, vous piochez 2 cartes supplémentaires."
|
||||
},
|
||||
"Big Spencer": {
|
||||
"name": "Big Spencer",
|
||||
"desc": "Commence avec 5 cartes. Ne peut pas jouer Raté!"
|
||||
},
|
||||
"Flint Westwood": {
|
||||
"name": "Flint Westwood",
|
||||
"desc": "Peut échanger une carte de sa main avec 2 cartes aléatoires de la main d'un autre joueur pendant son tour."
|
||||
},
|
||||
"Gary Looter": {
|
||||
"name": "Gary Looter",
|
||||
"desc": "Pioche toutes les cartes excédentaires défaussées par les autres joueurs à la fin de chaque tour."
|
||||
},
|
||||
"Greygory Deckard": {
|
||||
"name": "Greygory Deckard",
|
||||
"desc": "Au début de son tour, peut piocher 2 personnages aléatoires et gagne toutes leurs capacités."
|
||||
},
|
||||
"John Pain": {
|
||||
"name": "John Pain",
|
||||
"desc": "S'il a moins de 6 cartes en main, lorsqu'un joueur « pioche! », John ajoute la carte piochée à sa main."
|
||||
},
|
||||
"Lee Van Kliff": {
|
||||
"name": "Lee Van Kliff",
|
||||
"desc": "Pendant son tour, peut défausser une carte Bang! pour répéter l'effet d'une carte à bordure brune qu'il vient de jouer."
|
||||
},
|
||||
"Teren Kill": {
|
||||
"name": "Teren Kill",
|
||||
"desc": "Chaque fois qu'il serait éliminé, « piochez! » : si ce n'est pas une carte de Pique, Teren reste à 1 point de vie et pioche 1 carte."
|
||||
},
|
||||
"Youl Grinner": {
|
||||
"name": "Youl Grinner",
|
||||
"desc": "Avant de piocher, les joueurs ayant plus de cartes en main que Youl doivent lui donner une carte de leur choix."
|
||||
},
|
||||
"Camposanto": {
|
||||
"name": "Cimetière",
|
||||
"desc": "Au début de leur tour, chaque joueur éliminé revient dans le jeu avec 1 point de vie. Piochez une carte de rôle au hasard parmi les joueurs éliminés."
|
||||
},
|
||||
"Darling Valentine": {
|
||||
"name": "Darling Valentine",
|
||||
"desc": "Au début de leur tour, chaque joueur défausse sa main et pioche le même nombre de cartes du paquet."
|
||||
},
|
||||
"Dorothy Rage": {
|
||||
"name": "Dorothy Rage",
|
||||
"desc": "Pendant leur tour, chaque joueur peut forcer un autre joueur à jouer une carte."
|
||||
},
|
||||
"Helena Zontero": {
|
||||
"name": "Helena Zontero",
|
||||
"desc": "Quand Helena entre dans le jeu, « pioche! » : si un Cœur ou un Carreau est pioché, mélangez les cartes de rôle actives sauf le Shérif, et redistribuez-les au hasard."
|
||||
},
|
||||
"Lady Rosa del Texas": {
|
||||
"name": "Lady Rose of Texas",
|
||||
"desc": "Pendant leur tour, chaque joueur peut échanger sa place avec le joueur à sa droite, qui passe son prochain tour. (Cliquez sur la carte)"
|
||||
},
|
||||
"Miss Susanna": {
|
||||
"name": "Miss Susanna",
|
||||
"desc": "Pendant leur tour, chaque joueur doit jouer au moins 3 cartes. S'ils ne le font pas, ils perdent 1 point de vie."
|
||||
},
|
||||
"Regolamento di Conti": {
|
||||
"name": "Règlement de Comptes",
|
||||
"desc": "Toutes les cartes peuvent être jouées comme si elles étaient Bang!. Les cartes Bang! peuvent être jouées comme si elles étaient Raté! (Cliquez sur la carte)"
|
||||
},
|
||||
"Sacagaway": {
|
||||
"name": "Sacagaway",
|
||||
"desc": "Tous les joueurs jouent avec leurs cartes face visible (sauf leur carte de rôle!)."
|
||||
},
|
||||
"Wild West Show": {
|
||||
"name": "Wild West Show",
|
||||
"desc": "Le but de chaque joueur devient : « Soyez le dernier debout ! »"
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
"character": "Personnages",
|
||||
"characters_special": "Chaque personnage a des capacités spéciales et un nombre de vies qui les rendent uniques. \nLes vies sont le nombre de points de vie que vous pouvez perdre avant de mourir et indiquent également le nombre maximum de cartes que vous pouvez garder en main.",
|
||||
"deathnobeer": "Lorsque vous perdez votre dernier point de vie et que vous n'avez pas de bière 🍺️ en main, vous mourrez. \nVos cartes sont défaussées et votre rôle est révélé à tout le monde.",
|
||||
"discard": "Défausser",
|
||||
"distance": "Distance",
|
||||
"distancecalc": "La distance est automatiquement calculée par le jeu et correspond à la distance minimale entre les joueurs à gauche et à droite.",
|
||||
"drawinstructions": "Pour piocher des cartes, vous devez cliquer sur le paquet lorsque vous voyez cette animation.",
|
||||
"drawthecards": "Piochez les cartes",
|
||||
"endgame": "Fin du jeu",
|
||||
"endgameconditions": "Le jeu se termine lorsque l'une des conditions suivantes est remplie :",
|
||||
"endgamesheriffwin": "Tous les hors-la-loi 🐺️ et les renégats 🦅️ sont morts. \nDans ce cas, le shérif ⭐️ et les adjoints 🎖️ gagnent.",
|
||||
"endgameshriffdeath": "Le shérif ⭐️ meurt. \nSi le renégat 🦅️ est le dernier joueur en vie, il gagne, sinon les hors-la-loi gagnent.",
|
||||
"endingturn": "Lorsque vous avez fini de jouer vos cartes, c'est-à-dire lorsque vous ne voulez plus ou ne pouvez plus jouer de cartes, vous devez défausser les cartes qui dépassent votre nombre actuel de vies.\n\nEnsuite, vous passez le tour au joueur suivant en cliquant sur terminer le tour.",
|
||||
"equipment": "ÉQUIPEMENT",
|
||||
"justoneweapon": "Vous ne pouvez avoir qu'une seule arme équipée.",
|
||||
"maxtwocardsequip": "Vous ne pouvez pas avoir 2 cartes avec le même nom équipées.",
|
||||
"outlawreward": "Quiconque tue un hors-la-loi 🐺️ pioche 3 cartes du paquet (les autres hors-la-loi aussi 🐺️).",
|
||||
"playerdeath": "La mort d'un joueur",
|
||||
"playingcards": "Jouer les cartes",
|
||||
"playingdmg": "Vous pouvez jouer vos cartes pour vous-même ou pour nuire à d'autres joueurs en essayant de les éliminer.",
|
||||
"playingduringturn": "Vous ne pouvez jouer les cartes que pendant votre tour. Pour jouer des cartes, cliquez sur les cartes de votre main.\nÀ l'exception des cartes utilisées en réponse, comme Raté 😅️.",
|
||||
"playingifyouwant": "Vous n'êtes pas obligé de jouer des cartes.",
|
||||
"playlimit": "Il n'y a que 3 limitations :",
|
||||
"playonlyonebang": "Vous ne pouvez jouer qu'un seul Bang! \npar tour (se réfère uniquement aux cartes nommées Bang!)",
|
||||
"rewardspen": "Pénalités et récompenses",
|
||||
"roles": "Rôles",
|
||||
"sheriffkillsvice": "Si le shérif ⭐️ tue un adjoint, il perd toutes les cartes de sa main et en jeu devant lui.",
|
||||
"thecards": "Cartes",
|
||||
"title": "Comment jouer",
|
||||
"turndiscard": "Défaussez toutes les cartes excédentaires",
|
||||
"turndraw": "Piochez 2 cartes",
|
||||
"turnplay": "Jouez autant de cartes que vous le souhaitez",
|
||||
"turns": "Tours",
|
||||
"turnstart": "Cela commence toujours par le Shérif ⭐️, et le jeu continue dans le sens des aiguilles d'une montre, les tours sont divisés en 3 phases.",
|
||||
"weapon": "ARME",
|
||||
"renegade": "Renégat",
|
||||
"vice": "Adjoint",
|
||||
"outlaw": "Hors-la-loi",
|
||||
"sheriff": "Shérif",
|
||||
"allcharacters": "Tous les personnages",
|
||||
"gotoallcharacters": "Aller à tous les personnages",
|
||||
"gotocards": "Aller aux cartes",
|
||||
"gotohighnoon": "Aller à Midi",
|
||||
"gotofoc": "Aller à Une Poignée de Cartes",
|
||||
"gotogoldrush": "Aller à Ruée vers l'Or",
|
||||
"highnooncards": "Midi - Cartes Événements",
|
||||
"foccards": "Une Poignée de Cartes - Cartes Événements",
|
||||
"goldrushcards": "Cartes Ruée vers l'Or",
|
||||
"valleyofshadowscards": "Cartes Vallée des Ombres"
|
||||
},
|
||||
"theme": {
|
||||
"sepia": "Sépia",
|
||||
"light": "Clair",
|
||||
"dark": "Sombre",
|
||||
"grayscale": "Gris",
|
||||
"black": "Noir"
|
||||
}
|
||||
}
|
@ -1,9 +1,6 @@
|
||||
import it from './it.json'
|
||||
import en from './en.json'
|
||||
import cs from './cs.json'
|
||||
import fr from './fr.json'
|
||||
import es from './es.json'
|
||||
import ru from './ru.json'
|
||||
|
||||
export const defaultLocale = 'it'
|
||||
|
||||
@ -12,8 +9,5 @@ export const fallbackLocale = 'en'
|
||||
export const languages = {
|
||||
it: it,
|
||||
en: en,
|
||||
cs: cs,
|
||||
fr: fr,
|
||||
es: es,
|
||||
ru: ru,
|
||||
cs: cs
|
||||
}
|
@ -19,7 +19,6 @@
|
||||
"spectate_lobbies": "Osserva le partite in corso:",
|
||||
"no_lobby_available": "Nessuna stanza disponibile",
|
||||
"create_lobby": "Crea una stanza:",
|
||||
"characters_to_distribute": "Personaggi da distribuire: ",
|
||||
"lobby_name": "Nome:",
|
||||
"leave_room": "Esci dalla stanza",
|
||||
"warning": "Attenzione!",
|
||||
@ -103,48 +102,44 @@
|
||||
"chat": {
|
||||
"spectators": " | Uno spettatore sta guardando la partita | {n} spettatori stanno guardando la partita",
|
||||
"chat": "Chat",
|
||||
"joined": "👋 ;{0}; è entrato nella stanza",
|
||||
"died": "☠️ ;{0}; è morto",
|
||||
"died_role": "☠️ ;{0}; era ;{1};!",
|
||||
"won": "🏆 ;{0}; ha vinto! Il suo ruolo era ;{1};",
|
||||
"joined": ";{0}; è entrato nella stanza",
|
||||
"died": ";{0}; è morto",
|
||||
"died_role": ";{0}; era ;{1};!",
|
||||
"won": ";{0}; ha vinto! Il suo ruolo era ;{1};",
|
||||
"choose_character": ";{0}; ha come personaggio ;{1};, la sua abilità speciale è: ;{2};!",
|
||||
"starting": "La partita sta iniziando!",
|
||||
"sheriff": "⭐ ;{0}; è lo sceriffo!",
|
||||
"sheriff": ";{0}; è lo sceriffo!",
|
||||
"did_choose_character": ";{0}; ha scelto il personaggio.",
|
||||
"turn": "⏩ È il turno di ;{0};.",
|
||||
"turn": "È il turno di ;{0};.",
|
||||
"draw_from_scrap": ";{0}; ha pescato la prima carta dalla pila delle carte scartate.",
|
||||
"draw_from_player": ";{0}; ha pescato la prima carta dalla mano di ;{1};.",
|
||||
"flipped": ";{0}; ha estratto ;{1}; ;{2};.",
|
||||
"scrapped": ";{0}; ha scartato ;{1}; ;{2};.",
|
||||
"explode": "💥 ;{0}; ha fatto esplodere la dinamite.",
|
||||
"explode": ";{0}; ha fatto esplodere la dinamite.",
|
||||
"beer_save": ";{0}; ha usato una birra per recuperare una vita.",
|
||||
"get_nugget": ";{0}; ha ottenuto una pepita d'oro usando una Birra.",
|
||||
"play_card": ";{0}; ha giocato ;{1};.",
|
||||
"play_card_green": ";{0}; ha messo in gioco ;{1};.",
|
||||
"play_card_with": ";{0}; ha giocato ;{1};, scartando ;{2};.",
|
||||
"purchase_card": ";{0}; ha comprato ;{1};.",
|
||||
"play_card_against": ";{0}; ha giocato ;{1}; contro ;{2};.",
|
||||
"play_card_against_with": ";{0}; ha giocato ;{1}; contro ;{2};, scartando ;{3};.",
|
||||
"play_card_for": ";{0}; ha giocato ;{1}; per ;{2};.",
|
||||
"spilled_beer": ";{0}; ha rovesciato una ;{1};.",
|
||||
"diligenza": ";{0}; ha giocato ;{1}; e ha pescato 2 carte.",
|
||||
"wellsfargo": ";{0}; ha giocato ;{1}; e ha pescato 3 carte.",
|
||||
"saloon": "🍻 ;{0}; ha giocato ;{1}; e ha curato 1 punto vita a tutti.",
|
||||
"saloon": ";{0}; ha giocato ;{1}; e ha curato 1 punto vita a tutti.",
|
||||
"special_bart_cassidy": ";{0}; ha ricevuto un risarcimento perchè è stato ferito.",
|
||||
"special_el_gringo": ";{0}; rubato una carta a ;{1}; mentre veniva colpito.",
|
||||
"special_calamity": ";{0}; ha giocato ;{1}; come un Bang! contro ;{2};.",
|
||||
"allroles3": "Nella partita ci sono: ;{1}; ;{0};, ;{3}; ;{2}; e ;{5}; ;{4};.",
|
||||
"allroles4": "Nella partita ci sono: ;{1}; ;{0};, ;{3}; ;{2};, ;{5}; ;{4}; e ;{7}; ;{6};.",
|
||||
"guess": "🤔 ;{0}; pensa sia ;{1};.",
|
||||
"guess": ";{0}; pensa sia ;{1};.",
|
||||
"guess_right": ";{0}; ha indovinato.",
|
||||
"guess_wrong": ";{0}; ha sbagliato.",
|
||||
"fratelli_sangue": ";{0}; ha donato una delle sue vite a ;{1};.",
|
||||
"doctor_heal": ";{0}; è stato curato dal dottore.",
|
||||
"respond": "↩️ ;{0}; ha risposto con ;{1};.",
|
||||
"change_username": "✏️ ;{0}; ha cambiato nome in ;{1};.",
|
||||
"respond": ";{0}; ha risposto con ;{1};.",
|
||||
"change_username": ";{0}; ha cambiato nome in ;{1};.",
|
||||
"lobby_reset": "Si ritorna alla stanza in ;{0}; secondi...",
|
||||
"prison_free": "🆓 ;{0}; è uscito di prigione",
|
||||
"prison_turn": "🔐 ;{0}; rimane in prigione questo turno",
|
||||
"prison_free": ";{0}; è uscito di prigione",
|
||||
"prison_turn": ";{0}; rimane in prigione questo turno",
|
||||
"flip_event": "🎴 EVENTO: ;{0}; 🎴",
|
||||
"choose_manette": ";{0}; si è impegnato ad usare solo carte di seme ;{1}; in questo turno.",
|
||||
"UnionPacific": ";{0}; ha giocato Union Pacific e ha pescato 4 carte.",
|
||||
@ -152,9 +147,8 @@
|
||||
"gold_rush_pay_discard": ";{0}; ha fatto scartare ;{2}; a ;{1};.",
|
||||
"choose_emporio": ";{0}; ha scelto ;{1}; da Emporio.",
|
||||
"shotgun_scrap": "Quando lo shotgun ha colpito ;{0}; gli ha tolto una carta (;{1};)",
|
||||
"taglia_reward": "💰 ;{1}; ha ottenuto ricompensa dalla taglia su ;{0};",
|
||||
"snake_bit": "🐍 ;{0}; è stato morso dal Serpente a Sonagli.",
|
||||
"in_private_car": "🚋💁🏻 ;{0}; è in una carrozza privata e non è stato attaccato da ;{1};"
|
||||
"taglia_reward": ";{1}; ha ottenuto ricompensa dalla taglia su ;{0};",
|
||||
"snake_bit": ";{0}; è stato morso dal Serpente a Sonagli."
|
||||
},
|
||||
"foc": {
|
||||
"leggedelwest": "Ed è obbligato a usarla nel suo turno, se possibile"
|
||||
@ -856,130 +850,6 @@
|
||||
"Wild West Show": {
|
||||
"name": "Wild West Show",
|
||||
"desc": "L'obiettivo di ogni giocatore diventa: \"Rimani l'ultimo in gioco!\""
|
||||
},
|
||||
"Boom Town": {
|
||||
"name": "Boom Town",
|
||||
"desc": "Scarta una Bang! per derubare il treno"
|
||||
},
|
||||
"Caticor": {
|
||||
"name": "Caticor",
|
||||
"desc": "Scarta una Cat Balou o un Panico per derubare il treno"
|
||||
},
|
||||
"Creepy Creek": {
|
||||
"name": "Creepy Creek",
|
||||
"desc": "Scarta una carta di picche per derubare il treno"
|
||||
},
|
||||
"Crowns Hole": {
|
||||
"name": "Crown's Hole",
|
||||
"desc": "Scarta una birra per derubare il treno"
|
||||
},
|
||||
"Deadwood": {
|
||||
"name": "Deadwood",
|
||||
"desc": "Scarta una carta equipaggiamento per derubare il treno"
|
||||
},
|
||||
"Dodgeville": {
|
||||
"name": "Dodgeville",
|
||||
"desc": "Scarta un Mancato! per derubare il treno"
|
||||
},
|
||||
"Fort Worth": {
|
||||
"name": "Fort Worth",
|
||||
"desc": "Scarta una carta con il numero 10, J, Q, K, A per derubare il treno"
|
||||
},
|
||||
"Frisco": {
|
||||
"name": "Frisco",
|
||||
"desc": "Scarta una carta di fiori per derubare il treno"
|
||||
},
|
||||
"Miners Oath": {
|
||||
"name": "Miner's Oath",
|
||||
"desc": "Scarta una carta di quadri per derubare il treno"
|
||||
},
|
||||
"San Tafe": {
|
||||
"name": "San Tafe",
|
||||
"desc": "Scarta una carta di cuori per derubare il treno"
|
||||
},
|
||||
"Tombrock": {
|
||||
"name": "Tombrock",
|
||||
"desc": "Per derubare il treno, perdi 1 punto vita"
|
||||
},
|
||||
"Yooma": {
|
||||
"name": "Yooma",
|
||||
"desc": "Scarta una carta con un numero compreso tra 2 e 9 per derubare il treno"
|
||||
},
|
||||
"Virginia Town": {
|
||||
"name": "Virginia Town",
|
||||
"desc": "Scarta due carte per derubare il treno"
|
||||
},
|
||||
"Ironhorse": {
|
||||
"name": "Ironhorse",
|
||||
"desc": "LOCOMOTIVA: Ogni giocatore, incluso colui che ha attivato l'effetto, è bersaglio di un BANG!\nNessun giocatore è responsabile dell'eventuale perdita di punti vita.\nSe tutti i giocatori vengono eliminati allo stesso tempo, i Fuorilegge vincono."
|
||||
},
|
||||
"Leland": {
|
||||
"name": "Leland",
|
||||
"desc": "LOCOMOTIVA: svolgi l'effetto dell'Emporio, cominciando dal giocatore di turno e procedendo in senso orario."
|
||||
},
|
||||
"Baggage Car": {
|
||||
"name": "Baggage Car",
|
||||
"desc": "Scartalo: ottieni l'effetto di un Mancato!, Panico!, Cat Balou o di un BANG! extra.\nDiscard this for a Missed!Panic!, Cat Balou, or an extra BANG!"
|
||||
},
|
||||
"Caboose": {
|
||||
"name": "Caboose",
|
||||
"desc": "Pro scartare un aura tua carta bordo bin incuso un vagone come se fosse un Mancato!"
|
||||
},
|
||||
"Cattle Truck": {
|
||||
"name": "Cattle Truck",
|
||||
"desc": "Scartalo: guarda le 3 carte in cima agli scarti e pescane I"
|
||||
},
|
||||
"Circus Wagon": {
|
||||
"name": "Circus Wagon",
|
||||
"desc": "Scartalo: ogni altro giocatore deve scartare una carta che ha in gioco."
|
||||
},
|
||||
"Coal Hopper": {
|
||||
"name": "Coal Hopper",
|
||||
"desc": "Scartalo: pesca una carta e scarta un vagone in gioco davanti a un giocatore a ma scelta."
|
||||
},
|
||||
"Dining Car": {
|
||||
"name": "Dining Car",
|
||||
"desc": "A inizio turno, \"estrai!\": se è Cuori, recuperi I punto vita."
|
||||
},
|
||||
"Express Car": {
|
||||
"name": "Express Car",
|
||||
"desc": "Scarta tutte le carte in mano, poi gioca un altro turno"
|
||||
},
|
||||
"Ghost Car": {
|
||||
"name": "Ghost Car",
|
||||
"desc": "Giocalo su chiunque tranne lo Sceritfo. Se vieni eliminato, invece resti in gioco, ma non puol guada nare ne perdere punk vita."
|
||||
},
|
||||
"Lounge Car": {
|
||||
"name": "Lounge Car",
|
||||
"desc": "Scartalo: pesca 2 vagoni dal mazzo, mettine I in gioco di fronte a te e 1 di fronte a un altro giocatore."
|
||||
},
|
||||
"Lumber Flatcar": {
|
||||
"name": "Lumber Flatcar",
|
||||
"desc": "Giocalo su un qualsiasi giocatore (compreso te). Finché questa carta è in gioco, quel giocatore vede gli altri giocatori a distanza aumentata di 1."
|
||||
},
|
||||
"Mail Car": {
|
||||
"name": "Mail Car",
|
||||
"desc": "Scartalo: pesca 3 carte e dai 1 di esse a un altro giocatore a tua scelta."
|
||||
},
|
||||
"Observation Car": {
|
||||
"name": "Observation Car",
|
||||
"desc": "Tu vedi gli altri a distanza -1. Gli altri a vedono a distanza +1."
|
||||
},
|
||||
"Passenger Car": {
|
||||
"name": "Passenger Car",
|
||||
"desc": "Scartalo: pesca una carta (in mano o in gioco) da un altro giocatore"
|
||||
},
|
||||
"Prisoner Car": {
|
||||
"name": "Prisoner Car",
|
||||
"desc": "Le carte Duello e Indiani! giocate dagli altri giocatori non hanno effetto su di te."
|
||||
},
|
||||
"Private Car": {
|
||||
"name": "Private Car",
|
||||
"desc": "se non hai carte in mano. non puoi essere bersaelio di carte BANG"
|
||||
},
|
||||
"Sleeper Car": {
|
||||
"name": "Sleeper Car",
|
||||
"desc": "Una volta per turno, puoi scartare un'altra tua carta a bordo blu incluso."
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
|
@ -1,918 +0,0 @@
|
||||
{
|
||||
"trademark": "Bang! является торговой маркой, принадлежащей DVGiochi",
|
||||
"tip_1": "Лучше с друзьями!",
|
||||
"tip_2": "Иконка 🤖️ означает, что игрок - бот!",
|
||||
"tip_3": "Вы можете нажать на карты персонажей и оборудования других игроков, если хотите узнать больше!",
|
||||
"tip_4": "Включает Dodge City, High Noon, Fistful Of Cards!",
|
||||
"tip_5": "Нашли ошибку? Напишите нам в Discord!",
|
||||
"tip_6": "Теперь у нас есть сервер Discord!",
|
||||
"tip_7": "Если вы хотите помочь нам перевести игру на ваш язык, свяжитесь с нами в Discord!",
|
||||
"tip_8": "Если вы отключитесь во время игры, вас заменит бот (пока вы отсутствуете)!",
|
||||
"tip_9": "Если вы на мобильном устройстве, удерживайте карту, чтобы прочитать описание!",
|
||||
"tip_10": "Если сомневаетесь, стреляйте во всех других игроков!",
|
||||
"online_players": "Онлайн-игроки: ",
|
||||
"shuffle_players": "Перемешать игроков",
|
||||
"choose_username": "Выберите имя пользователя:",
|
||||
"report_bug": "Опишите ошибку",
|
||||
"report": "Сообщить об ошибке",
|
||||
"available_lobbies": "Доступные лобби:",
|
||||
"spectate_lobbies": "Наблюдать за играми:",
|
||||
"no_lobby_available": "Нет доступных лобби",
|
||||
"create_lobby": "Создать лобби:",
|
||||
"characters_to_distribute": "Персонажи для распределения: ",
|
||||
"lobby_name": "Название:",
|
||||
"leave_room": "Покинуть лобби",
|
||||
"warning": "Внимание!",
|
||||
"connection_error": "Не удается подключиться к серверу.",
|
||||
"end_turn": "Конец хода!",
|
||||
"start_game": "Начать!",
|
||||
"expansions": "Дополнения",
|
||||
"click_to_toggle": "Нажмите, чтобы переключить",
|
||||
"details": "Детали",
|
||||
"ok": "OK",
|
||||
"you": "ВЫ",
|
||||
"owner": "ВЛАДЕЛЕЦ",
|
||||
"cancel": "ОТМЕНА",
|
||||
"send": "ОТПРАВИТЬ",
|
||||
"password": "Пароль: ",
|
||||
"room_password_prompt": "Пароль для лобби: ",
|
||||
"private_room": "Частное лобби",
|
||||
"room": "Лобби: ",
|
||||
"room_players": "Игроки (вы - {username})",
|
||||
"choose_character": "Выберите своего персонажа",
|
||||
"choose_card": "Выберите карту",
|
||||
"choose_card_from": " из ",
|
||||
"flip_card": "↙️ Перевернуть карту",
|
||||
"draw_cards": "⏬ Возьмите свои карты из колоды",
|
||||
"play_cards": "▶️ Сыграйте свои карты",
|
||||
"respond_card": "↩️ Ответить на карту",
|
||||
"wait": "⏸ Подождите",
|
||||
"choose_cards": "🔽 Выберите карту",
|
||||
"take_dmg": "Получить урон",
|
||||
"choose_response": "Выберите ваш ответ ",
|
||||
"choose_response_to": "на ",
|
||||
"choose_response_needed": "ТРЕБУЕТСЯ ",
|
||||
"choose_manette": "Выберите масть, вы сможете играть только карты с этой мастью в этом ходу.",
|
||||
"hand": "РУКА",
|
||||
"card_against": "Против кого вы сыграете карту?",
|
||||
"choose_sid_scrap": "Сбросьте 2 карты, чтобы не умереть",
|
||||
"choose_card_to_get": "Выберите карту",
|
||||
"choose_guess": "Угадайте цвет масти",
|
||||
"choose_ranch": "Выберите карты для замены",
|
||||
"choose_dalton": "Выберите, какое оборудование сбросить",
|
||||
"choose_fratelli_di_sangue": "Выберите, кому вы хотите пожертвовать одну из своих жизней",
|
||||
"choose_fantasma": "Выберите, кого воскресить",
|
||||
"choose_sventagliata": "Выберите другую цель для попадания с Fanning",
|
||||
"choose_tornado": "Выберите карту для сброса в торнадо",
|
||||
"choose_bandidos": "Выберите между сбросом 2 карт или потерей жизни (1 карта, если у вас только 1)",
|
||||
"choose_poker": "Все сбрасывают 1 карту (если нет туза, игрок, который сыграл покер, выбирает 2 карты)",
|
||||
"choose_from_poker;2": "Выберите карты для получения (макс. 2)",
|
||||
"choose_from_poker;1": "Выберите карту для получения",
|
||||
"choose_cecchino": "Выберите, в кого стрелять",
|
||||
"choose_rimbalzo_player": "Выберите цель для рикошета",
|
||||
"choose_rimbalzo_card": "Выберите карту для сброса рикошета",
|
||||
"choose_nuova_identita": "Выберите, хотите ли вы сохранить текущего персонажа или изменить его и начать с 2 жизнями",
|
||||
"choose_bicchierino": "Игрок по вашему выбору восстанавливает 1 жизнь",
|
||||
"choose_bottiglia": "Выберите, как играть Бутылку!",
|
||||
"choose_complice": "Выберите, как играть Подельника!",
|
||||
"choose_ricercato": "Выберите, против кого играть Разыскивается.",
|
||||
"choose_birra_function": "Выберите между получением 1 золотого самородка, сбросив пиво, или игрой пива.",
|
||||
"choose_play_as_bang": "Выберите, какую карту сыграть как Bang!",
|
||||
"choose_flint_special": "Выберите, какую карту обменять.",
|
||||
"emporio_others": "{0} выбирает, какую карту получить из Общего магазина",
|
||||
"you_died": "ВЫ УМЕРЛИ",
|
||||
"spectate": "НАБЛЮДАТЬ",
|
||||
"you_win": "ВЫ ВЫИГРАЛИ",
|
||||
"you_lose": "ВЫ ПРОИГРАЛИ",
|
||||
"special_ability": "ОСОБАЯ СПОСОБНОСТЬ",
|
||||
"gold_rush_discard": "Сбросьте оборудование золотой лихорадки другого игрока (уплачивая цену + 1)",
|
||||
"gold_rush_discard_2": "Сбросьте оборудование золотой лихорадки другого игрока (уплачивая цену + 1)",
|
||||
"discard": "СБРОСИТЬ",
|
||||
"to_regain_1_hp": "ВОССТАНОВИТЬ 1 ЖИЗНЬ",
|
||||
"play_your_turn": "СЫГРАЙТЕ СВОЙ ХОД",
|
||||
"you_are": "Вы",
|
||||
"did_pick_as": "выбрал это как вторую карту",
|
||||
"blackjack_special": "Если карта - бубны или черви, он берет еще одну карту.",
|
||||
"choose_scarp_card_to": "ВЫБЕРИТЕ КАРТУ ДЛЯ СБРОСА, ЧТОБЫ ИСПОЛЬЗОВАТЬ",
|
||||
"pick_a_card": "ПЕРЕВЕРНИТЕ КАРТУ",
|
||||
"to_defend_from": "ЗАЩИЩАЙТЕСЬ ОТ",
|
||||
"submit": "Отправить",
|
||||
"copy": "Скопировать приглашение",
|
||||
"no_players_in_range": "Вы не видите других игроков, экипируйте оружие или прицел!",
|
||||
"cantplaycard": "Вы не можете играть эту карту таким образом!",
|
||||
"chat": {
|
||||
"spectators": " | Один зритель смотрит игру | {n} зрителей смотрят игру",
|
||||
"chat": "Чат",
|
||||
"joined": "👋 ;{0}; присоединился к лобби",
|
||||
"died": "☠️ ;{0}; умер",
|
||||
"died_role": "☠️ ;{0}; был ;{1};!",
|
||||
"won": "🏆 ;{0}; выиграл! Их роль была ;{1};",
|
||||
"choose_character": ";{0}; имеет ;{1}; как персонажа, его особая способность: ;{2};!",
|
||||
"starting": "Игра начинается!",
|
||||
"sheriff": "⭐ ;{0}; шериф!",
|
||||
"did_choose_character": ";{0}; выбрал персонажа.",
|
||||
"turn": "⏩ Сейчас ход ;{0};.",
|
||||
"draw_from_scrap": ";{0}; взял первую карту из кучи сброса.",
|
||||
"draw_from_player": ";{0}; взял первую карту из руки ;{1};.",
|
||||
"flipped": ";{0}; перевернул ;{1}; ;{2};.",
|
||||
"scrapped": ";{0}; сбросил ;{1}; ;{2};.",
|
||||
"explode": "💥 ;{0}; взорвал динамит.",
|
||||
"beer_save": ";{0}; использовал пиво, чтобы спасти свою жизнь.",
|
||||
"get_nugget": ";{0}; получил золотой самородок, используя Пиво.",
|
||||
"play_card": ";{0}; сыграл ;{1};.",
|
||||
"play_card_green": ";{0}; ввел в игру ;{1};.",
|
||||
"play_card_with": ";{0}; сыграл ;{1};, сбросив ;{2};.",
|
||||
"purchase_card": ";{0}; купил ;{1};.",
|
||||
"play_card_against": ";{0}; сыграл ;{1}; против ;{2};.",
|
||||
"play_card_against_with": ";{0}; сыграл ;{1}; против ;{2};, сбросив ;{3};.",
|
||||
"play_card_for": ";{0}; сыграл ;{1}; для ;{2};.",
|
||||
"spilled_beer": ";{0}; пролил ;{1};.",
|
||||
"diligenza": ";{0}; сыграл ;{1}; и взял 2 карты.",
|
||||
"wellsfargo": ";{0}; сыграл ;{1}; и взял 3 карты.",
|
||||
"saloon": "🍻 ;{0}; сыграл ;{1}; и исцелил 1 HP всем живым.",
|
||||
"special_bart_cassidy": ";{0}; получил компенсацию, потому что был ранен.",
|
||||
"special_el_gringo": ";{0}; украл карту у ;{1};, когда был ранен.",
|
||||
"special_calamity": ";{0}; сыграл ;{1}; как Bang! против ;{2};.",
|
||||
"allroles3": "В игре есть: ;{1}; ;{0};, ;{3}; ;{2};, ;{5}; ;{4};.",
|
||||
"allroles4": "В игре есть: ;{1}; ;{0};, ;{3}; ;{2};, ;{5}; ;{4};, ;{7}; ;{6};.",
|
||||
"guess": "🤔 ;{0}; угадывает ;{1};.",
|
||||
"guess_right": ";{0}; был прав.",
|
||||
"guess_wrong": ";{0}; ошибся.",
|
||||
"fratelli_sangue": ";{0}; дал одну из своих жизней ;{1};.",
|
||||
"doctor_heal": ";{0}; был исцелен доктором.",
|
||||
"respond": "↩️ ;{0}; ответил ;{1};.",
|
||||
"change_username": "✏️ ;{0}; теперь ;{1};.",
|
||||
"lobby_reset": "Возвращение в лобби через ;{0}; секунд...",
|
||||
"prison_free": "🆓 ;{0}; вышел из тюрьмы",
|
||||
"prison_turn": "🔐 ;{0}; остался в тюрьме в этот ход",
|
||||
"flip_event": "🎴 СОБЫТИЕ: ;{0}; 🎴",
|
||||
"choose_manette": ";{0}; обязался играть только карты масти ;{1}; в этом ходу.",
|
||||
"UnionPacific": ";{0}; сыграл Union Pacific и взял 4 карты из колоды",
|
||||
"use_special": ";{0}; использовал особую способность своего персонажа (;{1};)",
|
||||
"gold_rush_pay_discard": ";{0}; сбросил ;{2}; у ;{1};.",
|
||||
"choose_emporio": ";{0}; выбрал ;{1}; из Общего магазина.",
|
||||
"shotgun_scrap": "Когда дробовик попал в ;{0};, карта улетела из его руки (;{1};)",
|
||||
"taglia_reward": "💰 ;{1}; получил карту за награду за ;{0};",
|
||||
"snake_bit": "🐍 ;{0}; был укушен гремучей змеей."
|
||||
},
|
||||
"foc": {
|
||||
"leggedelwest": "Он должен сыграть эту карту в этот ход, если возможно."
|
||||
},
|
||||
"mods": "Модификаторы",
|
||||
"bots": "Боты",
|
||||
"add_bot": "Добавить бота",
|
||||
"remove_bot": "Удалить бота",
|
||||
"minimum_players": "Для начала игры нужно как минимум 3 игрока",
|
||||
"mod_comp": "Соревновательный режим (отключает автоматическое получение урона)",
|
||||
"disconnect_bot": "Заменить отключившихся игроков ботами",
|
||||
"your_turn": "Сыграйте свой ход!",
|
||||
"your_response": "Ответьте!",
|
||||
"your_choose": "Выберите карту!",
|
||||
"cards": {
|
||||
"Barile": {
|
||||
"name": "Бочка",
|
||||
"desc": "Когда кто-то играет Bang против вас. Вы можете перевернуть первую карту из колоды, если масть - червы, то это считается картой Промах"
|
||||
},
|
||||
"Dinamite": {
|
||||
"name": "Динамит",
|
||||
"desc": "Когда играете Динамит, положите его перед собой, он будет безвреден в течение всего раунда. В начале следующего хода перед взятием карт и перед любым переворотом карты (например, Тюрьма), переверните карту с верха колоды. Если карта между 2 и 9 пиками (включительно), динамит взрывается: вы теряете 3 жизни и сбрасываете карту, иначе передайте динамит следующему игроку, который возьмет карту после окончания вашего хода"
|
||||
},
|
||||
"Mirino": {
|
||||
"name": "Прицел",
|
||||
"desc": "Вы видите других игроков на расстоянии -1"
|
||||
},
|
||||
"Mustang": {
|
||||
"name": "Мустанг",
|
||||
"desc": "Другие игроки видят вас на расстоянии +1"
|
||||
},
|
||||
"Prigione": {
|
||||
"name": "Тюрьма",
|
||||
"desc": "Экипируйте эту карту другому игроку, кроме шерифа. Выбранный игрок в начале своего хода должен перевернуть карту перед взятием: если это червы, сбросьте эту карту и играйте ход нормально, иначе сбросьте эту карту и пропустите ход"
|
||||
},
|
||||
"Remington": {
|
||||
"name": "Ремингтон",
|
||||
"desc": "Вы можете стрелять в другого игрока на расстоянии 3 или меньше"
|
||||
},
|
||||
"Rev Carabine": {
|
||||
"name": "Карабин Рев.",
|
||||
"desc": "Вы можете стрелять в другого игрока на расстоянии 4 или меньше"
|
||||
},
|
||||
"Schofield": {
|
||||
"name": "Шофилд",
|
||||
"desc": "Вы можете стрелять в другого игрока на расстоянии 2 или меньше"
|
||||
},
|
||||
"Volcanic": {
|
||||
"name": "Вулканик",
|
||||
"desc": "Вы можете стрелять в другого игрока на расстоянии 1 или меньше, однако у вас больше нет ограничения в 1 Bang"
|
||||
},
|
||||
"Winchester": {
|
||||
"name": "Винчестер",
|
||||
"desc": "Вы можете стрелять в другого игрока на расстоянии 5 или меньше"
|
||||
},
|
||||
"Bang!": {
|
||||
"name": "Bang!",
|
||||
"desc": "Стреляйте в игрока на виду. Если у вас нет оружия, ваша дальность - 1"
|
||||
},
|
||||
"Birra": {
|
||||
"name": "Пиво",
|
||||
"desc": "Сыграйте эту карту, чтобы восстановить одно очко жизни. Вы не можете исцелиться более чем на максимальный предел вашего персонажа. Если вы собираетесь потерять свою последнюю жизнь, вы также можете сыграть эту карту в ход вашего противника. Пиво больше не действует, если осталось только два игрока"
|
||||
},
|
||||
"Cat Balou": {
|
||||
"name": "Кэт Баллоу",
|
||||
"desc": "Выберите и сбросьте карту любого другого игрока."
|
||||
},
|
||||
"Diligenza": {
|
||||
"name": "Дилижанс",
|
||||
"desc": "Возьмите 2 карты из колоды."
|
||||
},
|
||||
"Duello": {
|
||||
"name": "Дуэль",
|
||||
"desc": "Сыграйте эту карту против любого игрока. По очереди, начиная с вашего противника, вы можете сбросить карту Bang!, первый игрок, который этого не сделает, теряет 1 жизнь."
|
||||
},
|
||||
"Emporio": {
|
||||
"name": "Общий магазин",
|
||||
"desc": "Положите на стол N карт из колоды, где N - количество живых игроков, по очереди, начиная с вас, выберите карту и добавьте ее в свою руку"
|
||||
},
|
||||
"Gatling": {
|
||||
"name": "Гатлинг",
|
||||
"desc": "Стреляйте во всех остальных игроков"
|
||||
},
|
||||
"Indiani!": {
|
||||
"name": "Индейцы!",
|
||||
"desc": "Все остальные игроки должны сбросить карту Bang! или потерять 1 очко здоровья"
|
||||
},
|
||||
"Mancato!": {
|
||||
"name": "Промах!",
|
||||
"desc": "Используйте эту карту, чтобы отменить эффект Bang"
|
||||
},
|
||||
"Panico!": {
|
||||
"name": "Паника!",
|
||||
"desc": "Украдите карту у игрока на расстоянии 1"
|
||||
},
|
||||
"Saloon": {
|
||||
"name": "Салун",
|
||||
"desc": "Все восстанавливают 1 очко здоровья"
|
||||
},
|
||||
"WellsFargo": {
|
||||
"name": "Веллс Фарго",
|
||||
"desc": "Возьмите 3 карты из колоды"
|
||||
},
|
||||
"Binocolo": {
|
||||
"name": "Бинокль",
|
||||
"desc": "Вы видите других игроков на расстоянии -1"
|
||||
},
|
||||
"Riparo": {
|
||||
"name": "Укрытие",
|
||||
"desc": "Другие игроки видят вас на расстоянии +1"
|
||||
},
|
||||
"Pugno!": {
|
||||
"name": "Удар!",
|
||||
"desc": "Стреляйте в игрока на расстоянии 1"
|
||||
},
|
||||
"Rag Time": {
|
||||
"name": "Регтайм",
|
||||
"desc": "Украдите карту у другого игрока на любом расстоянии"
|
||||
},
|
||||
"Rissa": {
|
||||
"name": "Драка",
|
||||
"desc": "Выберите карту для сброса из руки/оборудования всех остальных игроков"
|
||||
},
|
||||
"Schivata": {
|
||||
"name": "Уклонение",
|
||||
"desc": "Используйте эту карту, чтобы отменить эффект Bang и затем взять карту."
|
||||
},
|
||||
"Springfield": {
|
||||
"name": "Спрингфилд",
|
||||
"desc": "Стреляйте в игрока на любом расстоянии"
|
||||
},
|
||||
"Tequila": {
|
||||
"name": "Текила",
|
||||
"desc": "Исцелите 1 HP игроку по вашему выбору (можете быть вы)"
|
||||
},
|
||||
"Whisky": {
|
||||
"name": "Виски",
|
||||
"desc": "Исцелите 2 HP"
|
||||
},
|
||||
"Bibbia": {
|
||||
"name": "Библия",
|
||||
"desc": "Используйте эту карту, чтобы отменить эффект Bang и затем взять карту."
|
||||
},
|
||||
"Cappello": {
|
||||
"name": "Шляпа Десяти Галлонов",
|
||||
"desc": "Используйте эту карту, чтобы отменить эффект Bang"
|
||||
},
|
||||
"Placca Di Ferro": {
|
||||
"name": "Железная Пластина",
|
||||
"desc": "Используйте эту карту, чтобы отменить эффект Bang"
|
||||
},
|
||||
"Sombrero": {
|
||||
"name": "Сомбреро",
|
||||
"desc": "Используйте эту карту, чтобы отменить эффект Bang"
|
||||
},
|
||||
"Pugnale": {
|
||||
"name": "Нож",
|
||||
"desc": "Стреляйте в игрока на расстоянии 1"
|
||||
},
|
||||
"Derringer": {
|
||||
"name": "Дерринджер",
|
||||
"desc": "Стреляйте в игрока на расстоянии 1 и затем возьмите карту."
|
||||
},
|
||||
"Borraccia": {
|
||||
"name": "Фляга",
|
||||
"desc": "Восстановите 1 HP"
|
||||
},
|
||||
"Can Can": {
|
||||
"name": "Канкан",
|
||||
"desc": "Выберите и сбросьте карту любого другого игрока."
|
||||
},
|
||||
"Conestoga": {
|
||||
"name": "Конесто",
|
||||
"desc": "Украдите карту у другого игрока на любом расстоянии"
|
||||
},
|
||||
"Fucile Da Caccia": {
|
||||
"name": "Охотничий Ружьё",
|
||||
"desc": "Стреляйте в игрока на любом расстоянии"
|
||||
},
|
||||
"Pony Express": {
|
||||
"name": "Пони Экспресс",
|
||||
"desc": "Возьмите 3 карты из колоды"
|
||||
},
|
||||
"Pepperbox": {
|
||||
"name": "Пеппербокс",
|
||||
"desc": "Стреляйте в игрока на виду. Если у вас нет оружия, ваша дальность - 1"
|
||||
},
|
||||
"Howitzer": {
|
||||
"name": "Гаубица",
|
||||
"desc": "Стреляйте во всех остальных игроков"
|
||||
},
|
||||
"Bart Cassidy": {
|
||||
"name": "Барт Кэссиди",
|
||||
"desc": "Каждый раз, когда он ранен, он берет карту."
|
||||
},
|
||||
"Black Jack": {
|
||||
"name": "Блэк Джек",
|
||||
"desc": "В начале своего хода, когда он должен взять карту, он показывает всем вторую карту, если это червы или бубны, он берет третью карту, не показывая ее."
|
||||
},
|
||||
"Calamity Janet": {
|
||||
"name": "Каламити Джанет",
|
||||
"desc": "Она может использовать карты Промах! как Bang! и наоборот."
|
||||
},
|
||||
"El Gringo": {
|
||||
"name": "Эль Гринго",
|
||||
"desc": "Каждый раз, когда он ранен, он берет карту из руки атакующего игрока."
|
||||
},
|
||||
"Jesse Jones": {
|
||||
"name": "Джесси Джонс",
|
||||
"desc": "Когда он должен взять свои карты, он может взять первую карту из руки другого игрока. (нажмите на карты вражеского игрока, если хотите использовать эту способность)"
|
||||
},
|
||||
"Jourdonnais": {
|
||||
"name": "Журдонэ",
|
||||
"desc": "Он играет, как если бы у него всегда была активная Бочка, если он экипирует другую Бочку, он может перевернуть 2 карты."
|
||||
},
|
||||
"Kit Carlson": {
|
||||
"name": "Кит Карлсон",
|
||||
"desc": "Когда он должен взять карту, он смотрит 3 карты и выбирает 2, положив другую карту на верх колоды."
|
||||
},
|
||||
"Lucky Duke": {
|
||||
"name": "Счастливчик Дюк",
|
||||
"desc": "Каждый раз, когда он должен перевернуть карту, он может перевернуть 2 раза."
|
||||
},
|
||||
"Paul Regret": {
|
||||
"name": "Пол Регрет",
|
||||
"desc": "Другие игроки видят его на расстоянии +1."
|
||||
},
|
||||
"Pedro Ramirez": {
|
||||
"name": "Педро Рамирес",
|
||||
"desc": "Когда он должен взять карту, он может взять первую карту из кучи сброса. (нажмите на карты в куче сброса, чтобы использовать эту способность)"
|
||||
},
|
||||
"Rose Doolan": {
|
||||
"name": "Роуз Дулан",
|
||||
"desc": "Она видит других игроков на расстоянии -1."
|
||||
},
|
||||
"Sid Ketchum": {
|
||||
"name": "Сид Кетчум",
|
||||
"desc": "Он может сбросить 2 карты, чтобы восстановить 1 HP."
|
||||
},
|
||||
"Slab The Killer": {
|
||||
"name": "Слэб Убийца",
|
||||
"desc": "Чтобы уклониться от его Bang! карт, другим игрокам нужны 2 Промах!"
|
||||
},
|
||||
"Suzy Lafayette": {
|
||||
"name": "Сьюзи Лафайет",
|
||||
"desc": "Каждый раз, когда у нее пустая рука, она берет карту."
|
||||
},
|
||||
"Vulture Sam": {
|
||||
"name": "Волчер Сэм",
|
||||
"desc": "Когда игрок умирает, он получает все карты из руки и экипировку умершего."
|
||||
},
|
||||
"Willy The Kid": {
|
||||
"name": "Вилли Кид",
|
||||
"desc": "У него нет ограничений на количество Bang, которые он может использовать."
|
||||
},
|
||||
"Pixie Pete": {
|
||||
"name": "Пикси Пит",
|
||||
"desc": "Он берет 3 карты вместо 2."
|
||||
},
|
||||
"Tequila Joe": {
|
||||
"name": "Текила Джо",
|
||||
"desc": "Когда он играет Пиво, он восстанавливает 2 HP."
|
||||
},
|
||||
"Greg Digger": {
|
||||
"name": "Грег Диггер",
|
||||
"desc": "Каждый раз, когда игрок умирает, он восстанавливает до 2 жизней."
|
||||
},
|
||||
"Herb Hunter": {
|
||||
"name": "Херб Хантер",
|
||||
"desc": "Каждый раз, когда игрок умирает, он берет 2 карты."
|
||||
},
|
||||
"Elena Fuente": {
|
||||
"name": "Елена Фуэнте",
|
||||
"desc": "Она может использовать любую карту из своей руки как Промах."
|
||||
},
|
||||
"Bill Noface": {
|
||||
"name": "Билл Безликий",
|
||||
"desc": "Он берет 1 карту + 1 карту за каждую рану, которую он имеет."
|
||||
},
|
||||
"Molly Stark": {
|
||||
"name": "Молли Старк",
|
||||
"desc": "Когда она использует карту из своей руки вне своего хода, она берет карту."
|
||||
},
|
||||
"Apache Kid": {
|
||||
"name": "Апачи Кид",
|
||||
"desc": "Карты бубен ♦️, сыгранные против него, не имеют эффекта (не работает в дуэлях)."
|
||||
},
|
||||
"Sean Mallory": {
|
||||
"name": "Шон Мэллори",
|
||||
"desc": "Он может держать до 10 карт в руке, заканчивая ход."
|
||||
},
|
||||
"Belle Star": {
|
||||
"name": "Белль Стар",
|
||||
"desc": "Во время ее хода зеленые и синие карты других игроков не работают."
|
||||
},
|
||||
"Vera Custer": {
|
||||
"name": "Вера Кастер",
|
||||
"desc": "Перед взятием карт она может выбрать особую способность другого живого игрока. Эта способность используется до следующего хода."
|
||||
},
|
||||
"Chuck Wengam": {
|
||||
"name": "Чак Венгам",
|
||||
"desc": "Во время своего хода он может решить потерять 1 HP, чтобы взять 2 карты из колоды."
|
||||
},
|
||||
"Pat Brennan": {
|
||||
"name": "Пэт Бреннан",
|
||||
"desc": "Вместо того чтобы брать карты, он может украсть карту из экипировки другого игрока. (нажмите на вражеского игрока, если хотите использовать эту способность)"
|
||||
},
|
||||
"José Delgado": {
|
||||
"name": "Хосе Дельгадо",
|
||||
"desc": "Во время своего хода он может сбросить синюю карту, чтобы взять 2 карты, до двух раз за ход."
|
||||
},
|
||||
"Doc Holyday": {
|
||||
"name": "Док Холидей",
|
||||
"desc": "Он может сбросить 2 карты, чтобы сыграть Bang."
|
||||
},
|
||||
"Fuorilegge": {
|
||||
"name": "Бандит"
|
||||
},
|
||||
"Rinnegato": {
|
||||
"name": "Ренегат"
|
||||
},
|
||||
"Sceriffo": {
|
||||
"name": "Шериф"
|
||||
},
|
||||
"Vice": {
|
||||
"name": "Помощник"
|
||||
},
|
||||
"Miniera Abbandonata": {
|
||||
"name": "Заброшенная Шахта",
|
||||
"desc": "Игроки берут карты из кучи сброса в фазе 1 и сбрасывают на верх колоды в фазе 3 (если куча сброса заканчивается, они должны брать и сбрасывать на верх колоды)"
|
||||
},
|
||||
"Il Giudice": {
|
||||
"name": "Судья",
|
||||
"desc": "Вы не можете экипировать карты на себя или других игроков"
|
||||
},
|
||||
"Agguato": {
|
||||
"name": "Засада",
|
||||
"desc": "Базовое расстояние между двумя игроками - 1"
|
||||
},
|
||||
"Rimbalzo": {
|
||||
"name": "Рикошет",
|
||||
"desc": "Игрок может играть Bang против карт, экипированных другими игроками, если они не играют Промах, они сбрасываются (нажмите на карту события)"
|
||||
},
|
||||
"Cecchino": {
|
||||
"name": "Снайпер",
|
||||
"desc": "Во время своего хода игроки могут сбросить 2 Bang!, чтобы стрелять Bang!, который требует 2 Промах (нажмите на карту)"
|
||||
},
|
||||
"Lazo": {
|
||||
"name": "Лассо",
|
||||
"desc": "Карты в слоте экипировки не работают"
|
||||
},
|
||||
"Ranch": {
|
||||
"name": "Ранчо",
|
||||
"desc": "После взятия карт игрок может сбросить любое количество карт из руки и взять столько же из колоды"
|
||||
},
|
||||
"Dead Man": {
|
||||
"name": "Мертвец",
|
||||
"desc": "Первый игрок, который умрет, вернется к жизни с 2 HP и 2 картами"
|
||||
},
|
||||
"Liquore Forte": {
|
||||
"name": "Крепкий Ликёр",
|
||||
"desc": "Игроки могут пропустить взятие карт, чтобы восстановить 1 HP (нажмите на карту события, чтобы использовать)"
|
||||
},
|
||||
"Vendetta": {
|
||||
"name": "Месть",
|
||||
"desc": "Заканчивая ход, игрок переворачивает карту из колоды, если это ❤️, он играет еще один ход (но не переворачивает другую карту)"
|
||||
},
|
||||
"Roulette Russa": {
|
||||
"name": "Русская Рулетка",
|
||||
"desc": "Начиная с шерифа, каждый игрок сбрасывает 1 Промах, первый, кто этого не сделает, теряет 2 HP"
|
||||
},
|
||||
"Legge Del West": {
|
||||
"name": "Закон Запада",
|
||||
"desc": "Каждый игрок показывает вторую карту, которую он берет, и должен использовать ее в этом раунде (если это возможно)"
|
||||
},
|
||||
"Peyote": {
|
||||
"name": "Пейот",
|
||||
"desc": "Вместо взятия карт игрок пытается угадать цвет масти, если он прав, добавляет карту в руку и продолжает пытаться угадать следующую карту"
|
||||
},
|
||||
"Fratelli Di Sangue": {
|
||||
"name": "Кровные Братья",
|
||||
"desc": "В начале своего хода игроки могут потерять 1 HP (кроме последнего), чтобы отдать его другому игроку"
|
||||
},
|
||||
"I Dalton": {
|
||||
"name": "Дальтоны",
|
||||
"desc": "Игроки, у которых экипированы синие карты, сбрасывают одну из этих карт по своему выбору"
|
||||
},
|
||||
"Sermone": {
|
||||
"name": "Проповедь",
|
||||
"desc": "Игроки не могут играть Bang! во время своего хода"
|
||||
},
|
||||
"Città Fantasma": {
|
||||
"name": "Город Призрак",
|
||||
"desc": "Все умершие игроки возвращаются к жизни в свой ход, они не могут умереть и берут 3 карты вместо 2. Когда они заканчивают ход, они умирают."
|
||||
},
|
||||
"Il Reverendo": {
|
||||
"name": "Преподобный",
|
||||
"desc": "Пиво не может быть сыграно"
|
||||
},
|
||||
"Sbornia": {
|
||||
"name": "Похмелье",
|
||||
"desc": "Персонажи теряют свои особые способности"
|
||||
},
|
||||
"Il Dottore": {
|
||||
"name": "Доктор",
|
||||
"desc": "Игрок с наименьшим количеством HP получает 1 HP"
|
||||
},
|
||||
"Corsa All Oro": {
|
||||
"name": "Золотая Лихорадка",
|
||||
"desc": "Ходы играются против часовой стрелки"
|
||||
},
|
||||
"Maledizione": {
|
||||
"name": "Проклятие",
|
||||
"desc": "Все карты - пики ♠️"
|
||||
},
|
||||
"Sparatoria": {
|
||||
"name": "Перестрелка",
|
||||
"desc": "Лимит Bang! за ход - 2"
|
||||
},
|
||||
"Benedizione": {
|
||||
"name": "Благословение",
|
||||
"desc": "Все карты - червы ❤️"
|
||||
},
|
||||
"Il Treno": {
|
||||
"name": "Прибытие Поезда",
|
||||
"desc": "Игроки берут 1 дополнительную карту"
|
||||
},
|
||||
"Sete": {
|
||||
"name": "Жажда",
|
||||
"desc": "Игроки берут только 1 карту в начале своего хода"
|
||||
},
|
||||
"Nuova Identita": {
|
||||
"name": "Новая Личность",
|
||||
"desc": "В начале своего хода каждый игрок может выбрать сменить персонажа на другого, показанного в начале игры. Если он это делает, он начинает с 2 HP"
|
||||
},
|
||||
"Manette": {
|
||||
"name": "Наручники",
|
||||
"desc": "После взятия карт в фазе 1 игрок объявляет масть. Он сможет использовать только карты этой масти в этом ходу"
|
||||
},
|
||||
"Mezzogiorno di Fuoco": {
|
||||
"name": "Полдень",
|
||||
"desc": "Каждый игрок теряет 1 HP, когда начинается его ход"
|
||||
},
|
||||
"Per Un Pugno Di Carte": {
|
||||
"name": "За Горсть Карт",
|
||||
"desc": "В начале своего хода игрок становится целью стольких Bang, сколько карт у него в руке"
|
||||
},
|
||||
"Pepita": {
|
||||
"name": "Золотой Самородок"
|
||||
},
|
||||
"Bicchierino": {
|
||||
"name": "Стаканчик",
|
||||
"desc": "Вы можете выбрать игрока, который восстанавливает 1 HP (даже себя)"
|
||||
},
|
||||
"Bottiglia": {
|
||||
"name": "Бутылка",
|
||||
"desc": "Можно сыграть как Паника!, Пиво или Bang!"
|
||||
},
|
||||
"Complice": {
|
||||
"name": "Подельник",
|
||||
"desc": "Можно сыграть как Общий магазин, Дуэль или Кэт Баллоу."
|
||||
},
|
||||
"Corsa All Oro_gr": {
|
||||
"name": "Золотая Лихорадка",
|
||||
"desc": "Вы заканчиваете ход, восстанавливаете все HP и начинаете новый ход."
|
||||
},
|
||||
"Rum": {
|
||||
"name": "Ром",
|
||||
"desc": "Переверните 4 карты, за каждую масть вы получаете 1 HP."
|
||||
},
|
||||
"Union Pacific": {
|
||||
"name": "Union Pacific",
|
||||
"desc": "Возьмите 4 карты из колоды."
|
||||
},
|
||||
"Calumet": {
|
||||
"name": "Калюмет",
|
||||
"desc": "Карты бубен, сыгранные другими игроками, не имеют на вас эффекта."
|
||||
},
|
||||
"Cinturone": {
|
||||
"name": "Ремень",
|
||||
"desc": "Вы можете держать до 8 карт, когда заканчиваете ход."
|
||||
},
|
||||
"Ferro di Cavallo": {
|
||||
"name": "Подкова",
|
||||
"desc": "Каждый раз, когда вы должны перевернуть карту, переворачивайте дважды!"
|
||||
},
|
||||
"Piccone": {
|
||||
"name": "Кирка",
|
||||
"desc": "Вы получаете 1 карту больше, когда берете в начале хода."
|
||||
},
|
||||
"Ricercato": {
|
||||
"name": "Разыскивается",
|
||||
"desc": "Сыграйте на другого игрока, кто убьет цель, получит 2 дополнительные карты и 1 золотой самородок."
|
||||
},
|
||||
"Setaccio": {
|
||||
"name": "Золотодобытчик",
|
||||
"desc": "Заплатите 1 золотой самородок, чтобы взять 1 карту из колоды, до двух раз за ход. (Нажмите на экипированную карту, чтобы использовать)"
|
||||
},
|
||||
"Stivali": {
|
||||
"name": "Сапоги",
|
||||
"desc": "Каждый раз, когда вы теряете 1 HP, вы берете 1 карту из колоды."
|
||||
},
|
||||
"Talismano": {
|
||||
"name": "Амулет Удачи",
|
||||
"desc": "Каждый раз, когда вы теряете 1 HP, вы получаете 1 золотой самородок."
|
||||
},
|
||||
"Zaino": {
|
||||
"name": "Рюкзак",
|
||||
"desc": "Заплатите 2 золотых самородка, чтобы исцелить 1 HP. (Нажмите на экипированную карту, чтобы использовать)"
|
||||
},
|
||||
"Don Bell": {
|
||||
"name": "Дон Белл",
|
||||
"desc": "Когда он заканчивает ход, он переворачивает карту, если это Червы ❤️ или Бубны ♦️, он играет снова."
|
||||
},
|
||||
"Dutch Will": {
|
||||
"name": "Датч Вилл",
|
||||
"desc": "Он берет 2 карты, сбрасывает 1 и берет 1 золотой самородок."
|
||||
},
|
||||
"Jacky Murieta": {
|
||||
"name": "Джекки Мурьета",
|
||||
"desc": "Во время своего хода он может заплатить 2 золотых самородка, чтобы иметь возможность стрелять еще раз!"
|
||||
},
|
||||
"Josh McCloud": {
|
||||
"name": "Джош МакКлауд",
|
||||
"desc": "Он может заплатить 2 золотых самородка, чтобы получить первую карту из колоды золотой лихорадки."
|
||||
},
|
||||
"Madam Yto": {
|
||||
"name": "Мадам Ито",
|
||||
"desc": "Она берет 1 карту из колоды каждый раз, когда играется Пиво."
|
||||
},
|
||||
"Pretty Luzena": {
|
||||
"name": "Красотка Лузена",
|
||||
"desc": "Один раз за ход она может получить скидку 1 на магазине карт золотой лихорадки."
|
||||
},
|
||||
"Raddie Snake": {
|
||||
"name": "Рэдди Снейк",
|
||||
"desc": "Он может выбросить 1 золотой самородок, чтобы взять 1 карту из колоды во время своего хода (максимум 2 раза за ход)."
|
||||
},
|
||||
"Simeon Picos": {
|
||||
"name": "Симеон Пикос",
|
||||
"desc": "Он получает 1 золотой самородок каждый раз, когда теряет 1 HP."
|
||||
},
|
||||
"Fantasma": {
|
||||
"name": "Призрак",
|
||||
"desc": "Сыграйте на любом выбывшем игроке: этот игрок возвращается в игру, но не может получить или потерять очки жизни."
|
||||
},
|
||||
"Lemat": {
|
||||
"name": "Лемат",
|
||||
"desc": "Во время своего хода вы можете использовать любую карту как Bang! (Нажмите на карту после экипировки)."
|
||||
},
|
||||
"SerpenteASonagli": {
|
||||
"name": "Гремучая Змея",
|
||||
"desc": "Сыграйте на любом игроке. В начале своего хода, если этот игрок берет в Пики, он теряет 1 HP."
|
||||
},
|
||||
"Shotgun": {
|
||||
"name": "Дробовик",
|
||||
"desc": "Каждый раз, когда вы раните игрока, он должен сбросить карту из руки."
|
||||
},
|
||||
"Taglia": {
|
||||
"name": "Награда",
|
||||
"desc": "Сыграйте на любом игроке. Если этот игрок попадает под Bang!, тот, кто стрелял, получает карту из колоды."
|
||||
},
|
||||
"Mira": {
|
||||
"name": "Прицел",
|
||||
"desc": "Сыграйте эту карту вместе с Bang!. Если цель поражена, она теряет 2 HP."
|
||||
},
|
||||
"RitornoDiFiamma": {
|
||||
"name": "Отдача",
|
||||
"desc": "Считается как Промах!. Игрок, который стрелял, становится целью Bang!."
|
||||
},
|
||||
"Bandidos": {
|
||||
"name": "Бандитос",
|
||||
"desc": "Каждый игрок выбирает между сбросом 2 карт из руки (или 1, если у него только 1) или потерей 1 HP."
|
||||
},
|
||||
"Fuga": {
|
||||
"name": "Побег",
|
||||
"desc": "Может быть сыграно вне хода. Избегает эффекта коричневой карты (не Bang!), направленной на вас."
|
||||
},
|
||||
"Sventagliata": {
|
||||
"name": "Стрельба В Ряд",
|
||||
"desc": "Считается единственным Bang! за ход. Игрок по вашему выбору на расстоянии 1 от цели (если есть, кроме вас) также становится целью Bang."
|
||||
},
|
||||
"UltimoGiro": {
|
||||
"name": "Последний Вздох",
|
||||
"desc": "Восстанавливает 1 HP"
|
||||
},
|
||||
"Poker": {
|
||||
"name": "Покер",
|
||||
"desc": "Все остальные игроки сбрасывают карту из руки одновременно. Если нет тузов, возьмите до 2 из этих карт."
|
||||
},
|
||||
"Salvo": {
|
||||
"name": "Спасение!",
|
||||
"desc": "Может быть сыграно вне хода. Предотвращает потерю 1 HP другим игроком. Если он выживает, возьмите 2 карты из его руки или из колоды (по вашему выбору)."
|
||||
},
|
||||
"Tomahawk": {
|
||||
"name": "Томагавк",
|
||||
"desc": "Атакует игрока на расстоянии до 2."
|
||||
},
|
||||
"Tornado": {
|
||||
"name": "Торнадо",
|
||||
"desc": "Все сбрасывают карту из руки (если возможно), затем берут 2 карты из колоды."
|
||||
},
|
||||
"Black Flower": {
|
||||
"name": "Черный Цветок",
|
||||
"desc": "Один раз за ход вы можете использовать карту Пик, чтобы стрелять еще раз Bang!"
|
||||
},
|
||||
"Colorado Bill": {
|
||||
"name": "Колорадо Билл",
|
||||
"desc": "Каждый раз, когда вы играете карту Bang!, если вы берете Пики, выстрел не может быть уклонен."
|
||||
},
|
||||
"Der Spot Burst Ringer": {
|
||||
"name": "Дер Спот Бурст Рингер",
|
||||
"desc": "Один раз за ход вы можете использовать карту Bang! как Гатлинг."
|
||||
},
|
||||
"Evelyn Shebang": {
|
||||
"name": "Эвелин Шебанг",
|
||||
"desc": "Вы можете выбрать не брать карты во время фазы взятия. За каждую не взятую карту вы стреляете Bang! в достижимую цель, в разных целях."
|
||||
},
|
||||
"Henry Block": {
|
||||
"name": "Генри Блок",
|
||||
"desc": "Любой, кто берет или сбрасывает одну из ваших карт в игре или в руке, становится целью Bang!."
|
||||
},
|
||||
"Lemonade Jim": {
|
||||
"name": "Лимонад Джим",
|
||||
"desc": "Каждый раз, когда другой игрок играет Пиво, вы можете сбросить карту из руки, чтобы также восстановить 1 HP."
|
||||
},
|
||||
"Mick Defender": {
|
||||
"name": "Мик Защитник",
|
||||
"desc": "Если вы становитесь целью коричневой карты (не Bang!), вы можете использовать карту Промах!, чтобы избежать 1 эффекта."
|
||||
},
|
||||
"Tuco Franziskaner": {
|
||||
"name": "Туко Францисканер",
|
||||
"desc": "Если у вас нет экипированных синих карт, вы берете 2 дополнительные карты."
|
||||
},
|
||||
"Big Spencer": {
|
||||
"name": "Большой Спенсер",
|
||||
"desc": "Начинает с 5 картами. Не может играть Промах!"
|
||||
},
|
||||
"Flint Westwood": {
|
||||
"name": "Флинт Вествуд",
|
||||
"desc": "Он может обменять карту из своей руки на 2 случайные карты из руки другого игрока во время своего хода."
|
||||
},
|
||||
"Gary Looter": {
|
||||
"name": "Гэри Лутер",
|
||||
"desc": "Он берет все избыточные карты, сброшенные другими игроками в конце каждого хода."
|
||||
},
|
||||
"Greygory Deckard": {
|
||||
"name": "Грейгори Декард",
|
||||
"desc": "В начале своего хода он может взять 2 случайных персонажа и получает все их способности."
|
||||
},
|
||||
"John Pain": {
|
||||
"name": "Джон Пейн",
|
||||
"desc": "Если у него меньше 6 карт в руке, когда игрок \"берет!\", Джон добавляет взятую карту в свою руку."
|
||||
},
|
||||
"Lee Van Kliff": {
|
||||
"name": "Ли Ван Клифф",
|
||||
"desc": "Во время своего хода он может сбросить карту Bang!, чтобы повторить эффект коричневой карты, которую он только что сыграл."
|
||||
},
|
||||
"Teren Kill": {
|
||||
"name": "Терен Килл",
|
||||
"desc": "Каждый раз, когда он должен быть устранен, \"берет!\": если это не Пики, Терен остается с 1 HP и берет 1 карту."
|
||||
},
|
||||
"Youl Grinner": {
|
||||
"name": "Юл Гриннер",
|
||||
"desc": "Перед взятием карт игроки с большим количеством карт в руке, чем у Юла, должны дать ему карту по своему выбору."
|
||||
},
|
||||
"Camposanto": {
|
||||
"name": "Кладбище",
|
||||
"desc": "В начале своего хода каждый устраненный игрок возвращается в игру с 1 HP. Возьмите карту роли случайным образом из устраненных игроков."
|
||||
},
|
||||
"Darling Valentine": {
|
||||
"name": "Дарлинг Валентайн",
|
||||
"desc": "В начале своего хода каждый игрок сбрасывает свою руку и берет столько же карт из колоды."
|
||||
},
|
||||
"Dorothy Rage": {
|
||||
"name": "Дороти Рейдж",
|
||||
"desc": "Во время своего хода каждый игрок может заставить другого игрока сыграть карту."
|
||||
},
|
||||
"Helena Zontero": {
|
||||
"name": "Хелена Зонтеро",
|
||||
"desc": "Когда Хелена вступает в игру, \"берет!\": если берутся Червы или Бубны, перетасуйте активные карты ролей, кроме шерифа, и перераспределите их случайным образом."
|
||||
},
|
||||
"Lady Rosa del Texas": {
|
||||
"name": "Леди Роза из Техаса",
|
||||
"desc": "Во время своего хода каждый игрок может поменяться местами с игроком справа, который пропускает свой следующий ход. (Нажмите на карту)"
|
||||
},
|
||||
"Miss Susanna": {
|
||||
"name": "Мисс Сюзанна",
|
||||
"desc": "Во время своего хода каждый игрок должен сыграть как минимум 3 карты. Если они этого не сделают, они теряют 1 HP."
|
||||
},
|
||||
"Regolamento di Conti": {
|
||||
"name": "Сворачивание Счетов",
|
||||
"desc": "Все карты могут быть сыграны, как если бы они были Bang!. Карты Bang! могут быть сыграны, как если бы они были Промах! (Нажмите на карту)"
|
||||
},
|
||||
"Sacagaway": {
|
||||
"name": "Сакаджавея",
|
||||
"desc": "Все игроки играют с картами лицом вверх (кроме карты роли!)."
|
||||
},
|
||||
"Wild West Show": {
|
||||
"name": "Шоу Дикого Запада",
|
||||
"desc": "Цель каждого игрока становится: \"Будь последним стоящим!\""
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
"character": "Персонажи",
|
||||
"characters_special": "У каждого персонажа есть особые способности и количество жизней, которые делают их уникальными. \nЖизни - это количество очков жизни, которые вы можете потерять до смерти, а также указывают на максимальное количество карт, которые вы можете держать в руке.",
|
||||
"deathnobeer": "Когда вы теряете последнее очко жизни и у вас нет пива 🍺️ в руке, вы умираете. \nВаши карты сбрасываются, и ваша роль раскрывается всем.",
|
||||
"discard": "Сбросить",
|
||||
"distance": "Расстояние",
|
||||
"distancecalc": "Расстояние автоматически рассчитывается игрой и соответствует минимальному расстоянию между игроками слева и справа.",
|
||||
"drawinstructions": "Чтобы взять карты, вам нужно нажать на колоду, когда вы видите эту анимацию.",
|
||||
"drawthecards": "Возьмите карты",
|
||||
"endgame": "Конец игры",
|
||||
"endgameconditions": "Игра заканчивается, когда выполняется одно из следующих условий:",
|
||||
"endgamesheriffwin": "Все бандиты 🐺️ и ренегаты 🦅️ мертвы. \nВ этом случае шериф ⭐️ и помощники 🎖️ выигрывают.",
|
||||
"endgameshriffdeath": "Шериф ⭐️ умирает. \nЕсли ренегат 🦅️ - последний оставшийся в живых игрок, он выигрывает, иначе выигрывают бандиты.",
|
||||
"endingturn": "Когда вы закончили играть свои карты, то есть, когда вы не хотите или не можете играть больше карт, вы должны сбросить карты, превышающие ваше текущее количество жизней.\n\nЗатем вы передаете ход следующему игроку, нажав на конец хода.",
|
||||
"equipment": "ОБОРУДОВАНИЕ",
|
||||
"justoneweapon": "Вы можете иметь только одно оружие экипировано.",
|
||||
"maxtwocardsequip": "Вы не можете иметь 2 карты с одинаковым названием экипированы.",
|
||||
"outlawreward": "Кто убьет бандита 🐺️ берет 3 карты из колоды (другие бандиты тоже 🐺️).",
|
||||
"playerdeath": "Смерть игрока",
|
||||
"playingcards": "Играйте карты",
|
||||
"playingdmg": "Вы можете играть свои карты для себя или для нанесения вреда другим игрокам, пытаясь их устранить.",
|
||||
"playingduringturn": "Вы можете играть карты только в свой ход. Чтобы играть карты, нажмите на карты из вашей руки.\nЗа исключением карт, используемых как ответ, таких как Промах 😅️.",
|
||||
"playingifyouwant": "Вы не обязаны играть карты.",
|
||||
"playlimit": "Существуют только 3 ограничения:",
|
||||
"playonlyonebang": "Вы можете играть только 1 Bang! \nза ход (относится только к картам, названным Bang!)",
|
||||
"rewardspen": "Наказания и награды",
|
||||
"roles": "Роли",
|
||||
"sheriffkillsvice": "Если шериф ⭐️ убивает помощника, он теряет все карты в руке и в игре перед ним.",
|
||||
"thecards": "Карты",
|
||||
"title": "Как играть",
|
||||
"turndiscard": "Сбросьте лишние карты",
|
||||
"turndraw": "Возьмите 2 карты",
|
||||
"turnplay": "Играйте любое количество карт",
|
||||
"turns": "Ходы",
|
||||
"turnstart": "Всегда начинается с шерифа ⭐️, и игра продолжается по часовой стрелке, ходы делятся на 3 фазы.",
|
||||
"weapon": "ОРУЖИЕ",
|
||||
"renegade": "Ренегат",
|
||||
"vice": "Помощник",
|
||||
"outlaw": "Бандит",
|
||||
"sheriff": "Шериф",
|
||||
"allcharacters": "Все персонажи",
|
||||
"gotoallcharacters": "Перейти ко всем персонажам",
|
||||
"gotocards": "Перейти к картам",
|
||||
"gotohighnoon": "Перейти к Полдню",
|
||||
"gotofoc": "Перейти к Горсти Карт",
|
||||
"gotogoldrush": "Перейти к Золотой Лихорадке",
|
||||
"highnooncards": "Полдень - Карты Событий",
|
||||
"foccards": "Горсть Карт - Карты Событий",
|
||||
"goldrushcards": "Карты Золотой Лихорадки",
|
||||
"valleyofshadowscards": "Карты Долины Теней"
|
||||
},
|
||||
"theme": {
|
||||
"sepia": "Сепия",
|
||||
"light": "Светлый",
|
||||
"dark": "Темный",
|
||||
"grayscale": "Черно-белый",
|
||||
"black": "Черный"
|
||||
}
|
||||
}
|
@ -5,5 +5,4 @@ export const emojiMap = {
|
||||
'fistful_of_cards': '🎴',
|
||||
'the_valley_of_shadows': '👻',
|
||||
'wild_west_show': '🎪',
|
||||
'train_robbery': '🚂',
|
||||
}
|
@ -28,19 +28,13 @@ export const expansionsMap = {
|
||||
icon: '👻',
|
||||
back: true,
|
||||
expansion: 'the-valley-of-shadows',
|
||||
status: 'beta',
|
||||
},
|
||||
'wild_west_show': {
|
||||
name: 'Wild West Show',
|
||||
icon: '🎪',
|
||||
back: true,
|
||||
expansion: 'wild-west-show',
|
||||
status: 'beta',
|
||||
},
|
||||
'train_robbery': {
|
||||
name: 'The Great Train Robbery',
|
||||
icon: '🚂',
|
||||
back: true,
|
||||
expansion: 'train-roobbery',
|
||||
status: 'wip',
|
||||
status: 'alpha',
|
||||
}
|
||||
}
|
3352
frontend/yarn.lock
3352
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user