first stable version

This commit is contained in:
Jerry Wu 2018-06-01 18:17:10 +08:00
parent 152a71ff05
commit 4e8525f4cf
5 changed files with 737 additions and 595 deletions

289
card.py
View File

@ -3,6 +3,7 @@ import game
from room import Room from room import Room
from json import dumps from json import dumps
cards = dict() cards = dict()
card_name = ["1.攻擊","2.防禦","3.治癒","4.補給","5.強奪","6.奇襲","7.交易","8.洞悉","9.妙策","10.掃射","11.加護","12.劇毒","13.詛咒","14.反制","15.狂亂","16.逆轉"] card_name = ["1.攻擊","2.防禦","3.治癒","4.補給","5.強奪","6.奇襲","7.交易","8.洞悉","9.妙策","10.掃射","11.加護","12.劇毒","13.詛咒","14.反制","15.狂亂","16.逆轉"]
unattackable = ['2','8','14','17','18'] unattackable = ['2','8','14','17','18']
@ -10,9 +11,14 @@ unrobable = ['8','17','18']
for i in range(len(card_name)): for i in range(len(card_name)):
cards[str(i+1)] = card_name[i] # initialize cards cards[str(i+1)] = card_name[i] # initialize cards
# create default deck # create default deck
# 攻擊*15 防禦*15 治癒*15 補給*10 強奪*10 奇襲*10 交易*10 洞悉*5 妙策*5 掃射*5 加護*5 劇毒*2 詛咒*2 反制*2 狂亂*2 逆轉*2 """
#default_deck = ['1', '2', '3'] * 5 + ['4', '5', '6', '7'] * 3 + ['8', '9', '10', '11'] * 2 + ['12', '13', '14', '15', '16'] 攻擊*7 防禦*7 治癒*7
default_deck = ['3', '4', '2', '1']*15 補給*4 強奪*4 奇襲*4 交易*4
洞悉*2 妙策*2 掃射*2 加護*2
劇毒*1 詛咒*1 反制*1 狂亂*1 逆轉*1
"""
default_deck = ['1', '2', '3'] * 7 + ['4', '5', '6', '7'] * 4 + ['8', '9', '10', '11'] * 2 + ['12', '13', '14', '15', '16']
random.shuffle(default_deck) # wash random.shuffle(default_deck) # wash
# card functions # card functions
@ -26,11 +32,10 @@ def attack(wscur, wsene):
r = [] r = []
cur.damage = 2 # 給反制判斷的 cur.damage = 2 # 給反制判斷的
r.append(( (wscur, ), dumps({"msg": "attack", "data": [cur.name, ene.name]}))) r.append(( (wscur, wsene), dumps({"msg": "attack", "data": [cur.name, ene.name]})))
if ene.defence(): if ene.defence():
r.append(( (wsene, ), r.append(( (wsene, ),
dumps({"msg": "attack", "data": [cur.name, ene.name], dumps({"action": "toDefend", "value": {"damage": cur.damage, "type": "attack"}})
"action": "toDefend", "value": {"damage": cur.damage}})
)) ))
cur.status = Room.NOTHING cur.status = Room.NOTHING
ene.status = Room.DEFENCE ene.status = Room.DEFENCE
@ -38,7 +43,10 @@ def attack(wscur, wsene):
r.append(( (wsene, wscur), r.append(( (wsene, wscur),
dumps({"msg": "damaged", "data": [ene.name, cur.damage]}) dumps({"msg": "damaged", "data": [ene.name, cur.damage]})
)) ))
cur.status = Room.NOTHING
ene.life -= cur.damage ene.life -= cur.damage
r.extend(Room.start_turn(wsene, wscur))
cur.attacking = False cur.attacking = False
cur.damage = 0 # reset cur.damage = 0 # reset
""" """
@ -62,10 +70,10 @@ def defend(wscur,wsene): # cur是用卡方
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = [] r = []
if ene.attacking or ene.surprise: if ene.attacking or ene.surprise:
r.append(( (wsene,wscur), "{} 防禦成功".format(cur.name))) r.append(( (wsene,wscur), dumps({"msg": "defended", "data": [cur.name]})))
else: else:
r.append(( (wsene,wscur), "{} 沒什麼可以防禦的,回復一點生命".format(cur.name))) r.append(( (wsene,wscur), dumps({"msg": "defend", "data": [cur.name]})))
cur.life += 1 cur.life += 1
return r return r
@ -89,209 +97,206 @@ def supply(wscur,wsene):
def rob(wscur,wsene): def rob(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = []
cur.robbing = True r.append(( (wscur, ), dumps({"msg": "rob", "data": [cur.name, ene.name],
print("{} 正在對 {} 行搶".format(cur.name,ene.name)) "action": "toRob", "value": {"enemy_card": ene.hand}})))
if ene.keep():
game.display(ene) # 顯示手牌 cur.status = Room.ROBBING
while True: r.append(( (wsene, ), dumps({"msg": "rob", "data": [cur.name, ene.name]})))
choice = input("請問要防禦嗎? 不使用請輸入0 ") return r
if choice in ene.hand:
if choice in unrobable:
skills[choice](cur,ene)
ene.remove_card(choice)
break
elif choice == "0":
break
else:
if len(ene.hand) == 0:
print("可惜,{} 有夠窮,沒東西能搶".format(ene.name))
else:
game.display(ene)
while True:
swag = input("{} 要搶哪張?".format(cur.name))
if swag in ene.hand:
ene.robbed(swag)
cur.add_card(swag)
break
cur.robbing = False
def surprise(wscur,wsene): def surprise(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
cur.surprise = True cur.surprise = True
cur.damage = 1 # 給反制判斷
print("{} 發動奇襲".format(cur.name)) r = []
cur.damage = 1
r.append(( (wscur, wsene), dumps({"msg": "surprise", "data": [cur.name]})))
if ene.defence(): if ene.defence():
game.display(ene) # 顯示手牌 r.append(( (wsene, ),
while True: dumps({"action": "toDefend", "value": {"damage": cur.damage, "type": "surprise"}})
choice = input("請問要防禦嗎? 不使用請輸入0 ") ))
if choice in ene.hand: cur.status = Room.NOTHING
if choice in unattackable: ene.status = Room.DEFENCE
skills[choice](cur,ene)
ene.remove_card(choice)
break
elif choice == "0":
print("{} 受到{}點傷害,而且掉了一張手牌".format(ene.name,cur.damage))
ene.life -= cur.damage
drop = random.choice(ene.hand)
ene.remove_card(drop)
break
else: else:
print("{} 受到{}點傷害,而且掉了一張手牌".format(ene.name,cur.damage)) r.append(( (wsene, wscur),
dumps({"msg": "surprised", "data": [ene.name, cur.damage]})
))
cur.status = Room.NOTHING
ene.life -= cur.damage ene.life -= cur.damage
drop = random.choice(ene.hand) drop = random.choice(ene.hand)
ene.remove_card(drop) ene.remove_card(drop)
cur.surprise = False cur.surprise = False
cur.damage = 0 # reset cur.damage = 0 # reset
r.extend(Room.start_turn(wsene, wscur))
return r
def trade(wscur,wsene): def trade(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = []
print("{} 想與 {} 進行交易".format(cur.name,ene.name)) if ene.hand:
cur.remove_card("7") # you can't trade the using card "trade" r.append(( (wsene, wscur),
game.display(cur) # 顯示手牌 dumps({"msg": "trade", "data": [cur.name, ene.name]})
while True: ))
choice = input("選擇一張手牌以交換 ")
if choice in cur.hand:
cur_item = choice
print("{} 選擇了 {}".format(cur.name,cards[choice]))
break
game.display(ene) # 顯示手牌
while True:
choice = input("選擇一張手牌以交換 ")
if choice in ene.hand:
ene_item = choice
print(ene.name,"choose",cards[choice])
break
# current player part
cur.hand.remove(cur_item)
cur.display.remove(cards[cur_item])
cur.hand.append(ene_item)
cur.display.append(cards[ene_item])
# enemy part
ene.hand.remove(ene_item)
ene.display.remove(cards[ene_item])
ene.hand.append(cur_item)
ene.display.append(cards[cur_item])
cur.add_card("7") # add back the card. game system will remove this card right away r.append(( (wscur,),
dumps({"action": "toTrade", "value": {"hand": cur.hand}}) # 更新已被移除的trade
))
cur.status = Room.TRADE
else:
r.append(( (wscur,wsene),
dumps({"msg": "tradeNoCard", "data": [cur.name]})
))
r.extend(Room.start_turn(wsene, wscur))
return r
def aware(wscur,wsene): def aware(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = []
if cur.attacking: if ene.attacking:
print("{} 洞悉了 {} 的攻擊,並抽取了一張手牌".format(ene.name,cur.name)) r.append(( (wsene,wscur), dumps({"msg": "awared", "data": [cur.name, ene.name, "攻擊"]})))
game.draw(ene)
elif cur.robbing: elif ene.robbing != "0":
print("{} 洞悉了 {} 的強奪,並抽取了一張手牌".format(ene.name,cur.name)) r.append(((wscur, wsene), dumps({"msg": "awared", "data": [cur.name, ene.name, "搶奪"]})))
game.draw(ene)
elif cur.surprise: elif ene.surprise:
print("{} 洞悉了 {} 的奇襲,並抽取了一張手牌".format(ene.name,cur.name)) r.append(( (wsene,wscur), dumps({"msg": "awared", "data": [cur.name, ene.name, "奇襲"]})))
game.draw(ene)
else: else:
r.append(((wscur, wsene), dumps({"msg": "aware", "data": [cur.name]})))
for _ in range(3): for _ in range(3):
print("{} 增加三張手牌".format(cur.name))
game.draw(cur) game.draw(cur)
return r
def plan(wscur,wsene): def plan(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = []
r.append(( (wsene, wscur),
dumps({"msg": "plan", "data": [cur.name]})
))
print("{} 有個妙策".format(cur.name))
options = random.sample(cur.deck,3) options = random.sample(cur.deck,3)
o_name = [] # names of cards in options r.append(( (wscur, ),
for id in options: dumps({"action": "toAdd", "value": {"cards": options}})
o_name.append(cards[id]) ))
print(o_name) cur.planning = options
while True: cur.status = Room.PLAN
"""while True:
choice = input("選擇一張卡加入手牌 ") choice = input("選擇一張卡加入手牌 ")
if choice in options: if choice in options:
cur.add_card(choice) cur.add_card(choice)
break break"""
return r
def sweep(wscur,wsene): def sweep(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
cur.attacking = True cur.attacking = True
r = []
cur.damage = random.randint(0,5) cur.damage = random.randint(0,5)
print("{}{} 進行掃射,威力是 {}".format(cur.name,ene.name,cur.damage)) r.append(( (wscur, wsene), dumps({"msg": "sweep", "data": [cur.name, ene.name, cur.damage]})))
if ene.defence(): if ene.defence():
game.display(ene) # 顯示手牌 r.append(( (wsene, ),
while True: dumps({"action": "toDefend", "value": {"damage": cur.damage, "type": "sweep"}})
choice = input("請問要防禦嗎? 不使用請輸入0 ") ))
if choice in ene.hand: cur.status = Room.NOTHING
if choice in unattackable: ene.status = Room.DEFENCE
skills[choice](cur,ene)
ene.remove_card(choice)
break
elif choice == "0":
print("{} 受到{}點傷害".format(ene.name,cur.damage))
ene.life -= cur.damage
break
else: else:
print("{} 受到{}點傷害".format(ene.name,cur.damage)) r.append(( (wsene, wscur),
dumps({"msg": "damaged", "data": [ene.name, cur.damage]})
))
cur.status = Room.NOTHING
ene.life -= cur.damage ene.life -= cur.damage
cur.attacking = False r.extend(Room.start_turn(wsene, wscur))
cur.damage = 0 # reset cur.attacking = False
cur.damage = 0 # reset
return r
def bless(wscur,wsene): def bless(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = []
print("{} 獲得加護,身上的毒素一掃而空,並回復三點生命,還抽取了兩張手牌".format(cur.name)) r.append(( (wsene,wscur), dumps({"msg": "bless", "data": [cur.name]})))
cur.poison = 0 # 解毒 cur.poison = 0 # 解毒
cur.life += 3 cur.life += 3
for _ in range(2): for _ in range(2):
game.draw(cur) game.draw(cur)
return r
def poison(wscur,wsene): def poison(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = []
if ene.poison != 0: r.append(( (wsene,wscur), dumps({"msg": "poison", "data": [cur.name, ene.name]})))
s = ""
else:
s = ""
print("{} 在食物下毒,{} {}中毒了".format(cur.name,ene.name, s))
ene.poison += 1 ene.poison += 1
return r
def curse(wscur,wsene): def curse(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = []
print("{} 詛咒了 {},使其損失四點生命,並掉了一張手牌".format(cur.name,ene.name))
ene.life -= 4 ene.life -= 4
drop = random.choice(ene.hand)
ene.remove_card(drop) msg = "curseNoCard"
if ene.hand:
drop = random.choice(ene.hand)
ene.remove_card(drop)
msg = "curse"
r.append(( (wsene,wscur), dumps({"msg": msg, "data": [cur.name, ene.name]})))
return r
def counter(wscur,wsene): def counter(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = []
if cur.attacking: if ene.attacking:
print("{} 反制了 {} 的攻擊,反彈了{}點傷害".format(ene.name,cur.name,cur.damage)) r.append(( (wsene,wscur), dumps({"msg": "countered", "data": [cur.name, ene.name, ene.damage]})))
cur.life -= cur.damage ene.life -= ene.damage
elif cur.surprise: elif ene.surprise:
print("{} 反制了 {} 的奇襲,反彈了{}點傷害,並使其掉了一張手牌".format(ene.name,cur.name,cur.damage)) r.append(( (wsene,wscur), dumps({"msg": "counteredSur", "data": [cur.name, ene.name, ene.damage]})))
cur -= cur.damage ene.life -= ene.damage
drop = random.choice(cur.hand) drop = random.choice(ene.hand)
cur.remove_card(drop) ene.remove_card(drop)
else: else:
print("{} 反制了敵手,使 {} 生命值減半了!".format(cur.name,ene.name)) r.append(( (wsene,wscur), dumps({"msg": "counter", "data": [cur.name, ene.name]})))
ene.life = ene.life//2 ene.life = ene.life//2
return r
def chaos(wscur,wsene): def chaos(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = []
print("{} 進入狂亂模式,回復三點生命,並對 {} 造成三點傷害".format(cur.name,ene.name)) r.append(( (wsene,wscur), dumps({"msg": "reverse", "data": [cur.name, ene.name]})))
cur.life += 3 cur.life += 3
ene.life -= 3 ene.life -= 3
return r
def reverse(wscur,wsene): def reverse(wscur,wsene):
cur, ene = wscur.player, wsene.player cur, ene = wscur.player, wsene.player
r = []
r.append(( (wsene,wscur), dumps({"msg": "reverse", "data": [cur.name]})))
print("{} 一口氣逆轉了情勢".format(cur.name))
cur.life,ene.life = ene.life,cur.life cur.life,ene.life = ene.life,cur.life
return r
skills = dict() skills = dict()
skill_name = [attack,defend,heal,supply,rob,surprise,trade,aware,plan,sweep,bless,poison,curse,counter,chaos,reverse] skill_name = [attack,defend,heal,supply,rob,surprise,trade,aware,plan,sweep,bless,poison,curse,counter,chaos,reverse]
for i in range(len(skill_name)): for i in range(len(skill_name)):
skills[str(i+1)] = skill_name[i] skills[str(i+1)] = skill_name[i]

53
game.py
View File

@ -8,13 +8,15 @@ class Player:
self.name = name self.name = name
self.deck = deck[:] # to pass by value instead of by reference self.deck = deck[:] # to pass by value instead of by reference
self.hand = [] self.hand = []
self.display = [] # names of cards in hand self.status = -1
self.life = 20 self.life = 15
self.poison = 0 self.poison = 0
self.damage = 0 # 因為反制要拿來判斷掃射 self.damage = 0 # 因為反制要拿來判斷掃射
self.playing = False self.playing = False
self.attacking = False self.attacking = False
self.robbing = False self.robbing = "0"
self.planning = [] # data temp for plan
self.trading = "0" # data temp for trade
self.surprise = False # 又是因為反制要判斷奇襲 self.surprise = False # 又是因為反制要判斷奇襲
self.turn = 0 self.turn = 0
@ -27,18 +29,17 @@ class Player:
def add_card(self,id): def add_card(self,id):
self.hand.append(id) self.hand.append(id)
self.display.append(card.cards[id])
self.deck.remove(id) self.deck.remove(id)
def remove_card(self,id): def remove_card(self,id):
self.hand.remove(id) self.hand.remove(id)
self.display.remove(card.cards[id])
self.deck.append(id) self.deck.append(id)
def robbed(self,id): # be robbed def robbed(self,id): # be robbed
self.hand.remove(id) try:
self.display.remove(card.cards[id]) self.hand.remove(id)
except:
print("rob except:", id, self.hand)
def defence(self): # to decide if player is able to defend or not def defence(self): # to decide if player is able to defend or not
for c in self.hand: for c in self.hand:
if c in card.unattackable: if c in card.unattackable:
@ -65,7 +66,7 @@ def display(player):
def draw(player): # 抽卡 def draw(player): # 抽卡
if len(player.deck) == 0: if len(player.deck) == 0:
player.life = -99999999 # 牌抽乾了就讓他死 player.life = -99999999 # 牌抽乾了就讓他死
return dumps({"msg": "noCard", "data": [player.name]}) return False
new = random.choice(player.deck) new = random.choice(player.deck)
player.add_card(new) player.add_card(new)
@ -73,37 +74,3 @@ def draw(player): # 抽卡
# turn control # turn control
# cur:current player # cur:current player
# ene:enemy # ene:enemy
async def turn(wsp1,wsp2):
p1, p2 = wsp1.player, wsp2.player
wscur, wsene = (wsp1, wsp2) if p1.playing == True else (wsp2, wsp1)
cur, ene = wscur.player, wsene.player
cur.turn += 1
await wscur.send("{} 的第{}回合".format(cur.name,cur.turn))
if cur.poison_check():
await wscur.send("{} 受到了劇毒的侵蝕".format(cur.name))
await wscur.send("{} 損失{}點生命".format(cur.name,cur.poison))
if cur.life <= 0:
return
await sendTo(health(p1,p2), wsp1, wsp2)
await sendTo(draw(cur), wsp1, wsp2) # 抽卡
await sendTo(display(cur), wscur) # 顯示手牌
while True:
await sendTo("請問要使用手牌嗎? 若不使用請輸入0", wscur)
print("Wait receive")
choice = await wscur.recv()
print("Received")
if choice in cur.hand:
card.skills[choice](wscur, wsene)
cur.remove_card(choice)
break
elif choice == "0":
break
elif choice == "-1":
cur.surrender()
await sendTo("{}投降".format(cur.name), wsp1, wsp2)
break
del choice # prevent reading old data
p1.playing,p2.playing = p2.playing,p1.playing # switch!

131
pyws.py
View File

@ -3,10 +3,11 @@ import game
from room import Room, sendTo from room import Room, sendTo
import asyncio import asyncio
import datetime
import random import random
import websockets import websockets
from json import dumps, loads from json import dumps, loads
import ssl
connected = {-1: []} connected = {-1: []}
character = dict() character = dict()
@ -18,6 +19,7 @@ for i in range(len(name)):
sad = None sad = None
fut = None fut = None
wait_fut = [0, 0]
async def wait(websocket, *cors, timeout=45, futs=None): async def wait(websocket, *cors, timeout=45, futs=None):
if futs != None: if futs != None:
fut_cor = futs fut_cor = futs
@ -25,37 +27,31 @@ async def wait(websocket, *cors, timeout=45, futs=None):
fut_cor = [cor() for cor in cors] fut_cor = [cor() for cor in cors]
done, pending = await asyncio.wait(fut_cor, done, pending = await asyncio.wait(fut_cor,
return_when=asyncio.FIRST_EXCEPTION, timeout=timeout) return_when=asyncio.FIRST_EXCEPTION, timeout=timeout)
#print(done, pending)
#print("Futures:", done, pending)
if pending: if pending:
#print("coroutine doesn't finish its work") for task in pending:
pass task.cancel()
if len(done): if len(done):
return list(done)[0].result() if list(done)[0].exception() == None:
else: return list(done)[0].result()
#print("SADDDDD") else:
return return "exception"
def random_room(): def random_room(room_list):
global connected, rooms
try: while len(room_list)>=1:
print(rooms) enter = random.choice(room_list)
except: print("rooms", enter, room_list)
rooms = list(connected)
rooms.remove(-1)
print(rooms)
while len(rooms)>=1:
enter = random.choice(rooms)
print("rooms", enter, rooms)
rooms.remove(enter)
if len(connected[enter]) < 2: if len(connected[enter]) < 2:
return enter return enter
while 1: while 1:
enter = random.randint(1, 99999) enter = random.randint(1, 99999)
if enter not in connected: if enter not in connected:
rooms.append(enter)
return enter return enter
async def enter_room(websocket): async def enter_room(websocket):
global connected ,sad, fut global connected ,sad, fut
@ -66,7 +62,7 @@ async def enter_room(websocket):
message = await wait(websocket, websocket.recv) message = await wait(websocket, websocket.recv)
if message == "n": if message == "n":
room_id = random_room() room_id = random_room(room_list)
else: else:
room_id = int(message) room_id = int(message)
@ -91,15 +87,16 @@ async def enter_room(websocket):
for ws in connected[room_id]: for ws in connected[room_id]:
ws.status = Room.PLAYING ws.status = Room.PLAYING
wsene = connected[room_id].players[0] if connected[room_id].players[1] is websocket else connected[room_id].players[1] wsene = connected[room_id].players[0] if connected[room_id].players[1] is ws else connected[room_id].players[1]
await ws.send(dumps({"room": room_id, "cur": websocket.player.name, "ene": wsene.player.name})) await ws.send(dumps({"room": room_id, "cur": ws.player.name, "ene": wsene.player.name}))
await ws.send(dumps({"msg": "firstAttack", "data": [players[0].player.name], "hand": ws.player.hand})) await ws.send(dumps({"msg": "firstAttack", "data": [players[0].player.name], "hand": ws.player.hand}))
fut.cancel() fut.cancel()
for ws_list, message in Room.start_turn(*players): for ws_list, message in Room.start_turn(*players):
await sendTo(message, *ws_list) await sendTo(message, *ws_list)
async def handler(websocket, path): async def handler(websocket, path):
global connected,sad, fut global connected,sad, fut, wait_fut, rooms
print("initialize")
# Register. # Register.
connected[-1].append(websocket) connected[-1].append(websocket)
websocket.status = Room.CONNECTED websocket.status = Room.CONNECTED
@ -113,7 +110,8 @@ async def handler(websocket, path):
websocket.player = game.Player(name[int(choice)-1], card.default_deck) websocket.player = game.Player(name[int(choice)-1], card.default_deck)
websocket.status = Room.MATCHING websocket.status = Room.MATCHING
except: except Exception as e:
print(e)
return # close the connection return # close the connection
@ -130,41 +128,92 @@ async def handler(websocket, path):
print("SAD", "FIRST" if websocket == sad else "SECOND") print("SAD", "FIRST" if websocket == sad else "SECOND")
fut = asyncio.ensure_future(websocket.recv()) fut = asyncio.ensure_future(websocket.recv())
try: try:
message = await wait(websocket, timeout=100000, futs=[fut]) message = await wait(websocket, timeout=100, futs=[fut])
print(message)
print(fut)
if message == "e": if message == "e":
connected[websocket.room].player_delete(websocket) connected[websocket.room].player_delete(websocket)
await websocket.send("You have left Room "+str(connected[websocket.room])) await websocket.send("You have left Room "+str(connected[websocket.room]))
del websocket.room del connected[websocket.room]
del websocket.room
connected[-1].append(websocket) connected[-1].append(websocket)
websocket.status = Room.MATCHING websocket.status = Room.MATCHING
elif message == "exception":
break
except asyncio.CancelledError: except asyncio.CancelledError:
pass pass
print("SADDDDDD", "FIRST" if websocket == sad else "SECOND") print("SADDDDDD", "FIRST" if websocket == sad else "SECOND")
elif websocket.status == Room.PLAYING: elif websocket.status == Room.PLAYING:
print("wait for message", "FIRST" if websocket == sad else "SECOND")
message = await wait(websocket, websocket.recv, timeout=100000) try:
print("received message", "FIRST" if websocket == sad else "SECOND") enemy = 0 if websocket == connected[websocket.room].players[1] else 1
wait_fut[(enemy+1)%2] = asyncio.ensure_future(websocket.recv())
print("wait for", "FIRST" if websocket == sad else "SECOND")
message = await wait(websocket, timeout=30, futs=[wait_fut[(enemy+1)%2]])
print("received message", message)
print("FIRST" if websocket == sad else "SECOND", ":", message)
if message == "exception":
break
message_to_send = connected[websocket.room].process(websocket, message)
for ws_list, message in message_to_send:
await sendTo(message, *ws_list)
if message_to_send != []:
try:
if loads(message_to_send[-1][1])['msg'] == 'win': # 取最後一筆訊息的msg
connected[websocket.room].player_delete(websocket)
break
except KeyError:
pass
wait_fut[enemy].cancel() # 取消另一方的await
message_to_send = connected[websocket.room].process(websocket, message)
for ws_list, message in message_to_send: except asyncio.CancelledError:
await sendTo(message, *ws_list) print("FIRST" if websocket == sad else "SECOND", "was Canceled\n\n")
elif websocket.status == Room.DISCONNECT:
break
finally: finally:
# Unregister. # Unregister.
try: try:
connected[websocket.room].player_delete(websocket)
if websocket not in connected[websocket.room]:
connected[websocket.room].players[0].status = Room.DISCONNECT
wait_fut[0].cancel()
wait_fut[1].cancel()
else:
if connected[websocket.room].player_delete(websocket):
await connected[websocket.room].players[0].send(dumps({"msg": "eneDisconn", "data": [connected[websocket.room].players[0].player.name]}))
connected[websocket.room].players[0].status = Room.DISCONNECT
wait_fut[0].cancel()
wait_fut[1].cancel()
# it will leave the loop and disconnect
if len(connected[websocket.room]) == 0: # clear the dictionary
print("delete")
del connected[websocket.room]
except: except:
connected[-1].remove(websocket) connected[-1].remove(websocket)
print(connected) print(connected)
"""cert = ssl.SSLContext() cert = ssl.SSLContext()
cert.load_cert_chain("/etc/letsencrypt/live/stoneapp.tech/fullchain.pem","/etc/letsencrypt/live/stoneapp.tech/privkey.pem") cert.load_cert_chain("/etc/letsencrypt/live/stoneapp.tech/fullchain.pem","/etc/letsencrypt/live/stoneapp.tech/privkey.pem")
start_server = websockets.serve(handler, '10.128.0.2', 8787,ssl=cert)""" start_server = websockets.serve(handler, '10.128.0.2', 8787,ssl=cert)
start_server = websockets.serve(handler, '127.0.0.1', 9000) #start_server = websockets.serve(handler, '127.0.0.1', 9000)
asyncio.get_event_loop().run_until_complete(start_server) asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever() asyncio.get_event_loop().run_forever()

471
room.py
View File

@ -1,178 +1,293 @@
import game, card import game, card
import random import random
from json import dumps, loads from json import dumps, loads
class Room:
class Room: CONNECTED = 0
CONNECTED = 0 MATCHING = 1
MATCHING = 1 PLAYING = 2
PLAYING = 2 WAITING = -1
WAITING = -1 DISCONNECT = -2
# Player Status Definition # Player Status Definition
NOTHING = -1 NOTHING = -1
IN_TURN = 0 IN_TURN = 0
ROBBED = 1 ROBBED = 1
DEFENCE = 2 DEFENCE = 2
ROBBING = 3 ROBBING = 3
TRADE = 4 TRADE = 4
PLAN = 5 TRADE_ENE = 5
def __init__(self, room): PLAN = 6
self.room = room def __init__(self, room):
self.players = [] self.room = room
self.players = []
def __len__(self):
return len(self.players) def __len__(self):
return len(self.players)
def __repr__(self):
return "ROOM {}, {} player(s)".format(str(self.room), len(self)) def __repr__(self):
return "ROOM {}, {} player(s)".format(str(self.room), len(self))
def __iter__(self):
return iter(self.players) def __iter__(self):
return iter(self.players)
def player_add(self, player):
if len(self) >= 2: def player_add(self, player):
return if len(self) >= 2:
self.players.append(player) return
self.players.append(player)
def player_delete(self, player):
try: def player_delete(self, player):
self.players.remove(player) try:
except: self.players.remove(player)
pass if len(self) == 1:
return True
else:
return False
"""async def start(self): except:
p1, p2 = self.players[0].player, self.players[1].player pass
first = random.choice([p1, p2])
print(first, p1, p2)
first.playing = True # so the first one will be random
await sendTo(first.name + "先攻", *self.players) """async def start(self):
print(first.name,"先攻") p1, p2 = self.players[0].player, self.players[1].player
print() # change line first = random.choice([p1, p2])
for _ in range(3): # 初始手牌*3 print(first, p1, p2)
game.draw(p1) first.playing = True # so the first one will be random
game.draw(p2) await sendTo(first.name + "先攻", *self.players)
print(first.name,"先攻")
while p1.life > 0 and p2.life > 0: print() # change line
print("game.turn start") for _ in range(3): # 初始手牌*3
await game.turn(self.players[0], self.players[1]) game.draw(p1)
print("game.turn end") game.draw(p2)
if p1.life <= 0:
print("{} 獲勝".format(p2.name)) while p1.life > 0 and p2.life > 0:
elif p2.life <= 0: print("game.turn start")
print("{} 獲勝".format(p1.name))""" await game.turn(self.players[0], self.players[1])
def start(self): # initialize the game print("game.turn end")
p1, p2 = self.players[0].player, self.players[1].player if p1.life <= 0:
ws_list = self.players[:] print("{} 獲勝".format(p2.name))
elif p2.life <= 0:
firstws = ws_list.pop(random.randint(0, 1)) print("{} 獲勝".format(p1.name))"""
#print(first, p1, p2) def start(self): # initialize the game
firstws.player.playing = True # so the first one will be random p1, p2 = self.players[0].player, self.players[1].player
#await sendTo(first.player.name + "先攻", *self.players) ws_list = self.players[:]
print(firstws.player.name,"先攻") firstws = ws_list.pop(random.randint(0, 1))
print() # change line #print(first, p1, p2)
for _ in range(3): # 初始手牌*3 firstws.player.playing = True # so the first one will be random
game.draw(p1) #await sendTo(first.player.name + "先攻", *self.players)
game.draw(p2)
return firstws, ws_list[0] # it will be second player print(firstws.player.name,"先攻")
@staticmethod print() # change line
def start_turn(wscur, wsene): for _ in range(3): # 初始手牌*3
cur, ene = wscur.player, wsene.player game.draw(p1)
game.draw(p2)
message_to_send = [] return firstws, ws_list[0] # it will be second player
@staticmethod
cur.playing, ene.playing = ene.playing, cur.playing def start_turn(wscur, wsene):
cur, ene = wscur.player, wsene.player
cur.turn += 1
message_to_send = []
message_to_send.append(( (wscur,), game.draw(cur)))
message_to_send.append(( (wscur,),
dumps({"player": { cur.playing, ene.playing = ene.playing, cur.playing
"turn": cur.turn, "hand": cur.hand, "deck_left": len(cur.deck),
"life": cur.life cur.turn += 1
} draw_res = game.draw(cur)
} if not draw_res:
) message_to_send.append(( (wscur, wsene), dumps({"msg": "noCard", "data": [cur.name]})))
)) else:
message_to_send.append(( (wscur,), draw_res))
message_to_send.append(( (wsene,),
dumps({"enemy": { if cur.poison_check():
"turn": cur.turn, "deck_left": len(cur.deck), message_to_send.append(( (wscur,wsene), dumps({"msg": "poisonDamaged", "data": [cur.name,cur.poison]})))
"life": cur.life # cur為當前回合之玩家故此處仍為cur
} message_to_send.append(( (wscur,),
} dumps({"player": {
) "turn": cur.turn, "hand": cur.hand, "deck_left": len(cur.deck),
)) "life": cur.life, "poison": cur.poison,
},
message_to_send.append(( (wsene,), dumps({"msg": "drawEne", "data": [cur.name]}))) "enemy": {
"life": ene.life, "deck_left": len(ene.deck),
cur.status = Room.IN_TURN "hand": len(ene.hand), "poison": ene.poison,
if cur.poison_check(): },
message_to_send.append(( (wscur,wsene), "{} 受到了劇毒的侵蝕, 損失{}點生命".format(cur.name,cur.poison))) "now": "player",
if cur.life <= 0: }
pass )
#await sendTo(health(p1,p2), wsp1, wsp2) ))
#await sendTo(draw(cur), wsp1, wsp2) # 抽卡
#message_to_send.append(( (wscur,), game.display(cur))) # 顯示手牌 message_to_send.append(( (wsene,),
#message_to_send.append(( (wscur,), "請問要使用手牌嗎? 若不使用請輸入0")) dumps({"player": {
return message_to_send "turn": ene.turn, "hand": ene.hand, "deck_left": len(ene.deck),
"life": ene.life, "poison": ene.poison,
def process(self, wscur, message): # cur is the person who send message to server },
"enemy": {
start_next_turn_cards = ['2', '3', '4', '8', '11', '12', '13', '14', '15', '16'] "turn": cur.turn, "deck_left": len(cur.deck),
cur = wscur.player "life": cur.life, "hand": len(cur.hand), "poison": cur.poison,
wsene = self.players[1] if wscur is self.players[0] else self.players[0] # cur為當前回合之玩家故此處仍為cur
ene = wsene.player },
message_to_send = [] "now": "enemy"
choice = message }
if cur.status == self.IN_TURN: )
))
if choice in cur.hand: message_to_send.append(( (wsene,), dumps({"msg": "drawEne", "data": [cur.name]})))
message_to_send.extend(card.skills[choice](wscur, wsene)) cur.status = Room.IN_TURN
if choice in start_next_turn_cards:
cur.status = self.NOTHING if cur.life <= 0:
message_to_send.extend(Room.start_turn(wsene, wscur)) message_to_send.append(( (wscur,), dumps({"msg": "win", "data": ["enemy"]})))
message_to_send.append(( (wsene,), dumps({"msg": "win", "data": ["player"]})))
cur.remove_card(choice)
elif choice == "0": elif ene.life <= 0:
cur.status = self.NOTHING message_to_send.append(( (wscur,), dumps({"msg": "win", "data": ["player"]})))
message_to_send.extend(Room.start_turn(wsene, wscur)) message_to_send.append(( (wsene,), dumps({"msg": "win", "data": ["enemy"]})))
"""elif choice == "-1":
cur.surrender()
{}投降".format(cur.name)"""
elif cur.status == self.ROBBING: #await sendTo(health(p1,p2), wsp1, wsp2)
pass #await sendTo(draw(cur), wsp1, wsp2) # 抽卡
#message_to_send.append(( (wscur,), game.display(cur))) # 顯示手牌
elif cur.status == self.ROBBED: #message_to_send.append(( (wscur,), "請問要使用手牌嗎? 若不使用請輸入0"))
pass return message_to_send
elif cur.status == self.DEFENCE: # cur是被攻擊方
if choice in cur.hand: def process(self, wscur, message): # cur is the person who send message to server
if choice in card.unattackable:
message_to_send.extend(card.skills[choice](wscur,wsene)) start_next_turn_cards = ['2', '3', '4', '8', '11', '12', '13', '14', '15', '16']
cur.remove_card(choice) cur = wscur.player
elif choice == "0": wsene = self.players[1] if wscur is self.players[0] else self.players[0]
message_to_send.append(( (wsene, wscur), "{} 受到{}點傷害".format(cur.name,ene.damage))) ene = wsene.player
ene.life -= cur.damage message_to_send = []
else: choice = message
message_to_send.append(( (wscur,wsene), "{} 受到{}點傷害".format(cur.name,ene.damage)))
cur.life -= cur.damage if cur.status == self.IN_TURN:
ene.attacking = False
ene.damage = 0 # reset if choice in cur.hand:
message_to_send.append(((wsene, wscur), dumps({"msg": "use", "data": [cur.name, choice]})))
message_to_send.extend(Room.start_turn(wscur, wsene)) cur.remove_card(choice)
elif cur.status == self.TRADE: message_to_send.extend(card.skills[choice](wscur, wsene))
pass
if choice in start_next_turn_cards:
elif cur.status == self.PLAN: cur.status = self.NOTHING
pass message_to_send.extend(Room.start_turn(wsene, wscur))
return message_to_send else: # 直接結束
async def sendTo(message, *ws_list): cur.status = self.NOTHING
for ws in ws_list: message_to_send.extend(Room.start_turn(wsene, wscur))
await ws.send(message)
"""elif choice == "-1":
cur.surrender()
{}投降".format(cur.name)"""
elif cur.status == self.ROBBING:
swag = choice
ene.status = self.NOTHING
if swag in ene.hand:
cur.robbing = swag
if ene.keep():
cur.status = Room.NOTHING
ene.status = Room.ROBBED
message_to_send.append(((wsene, ), dumps({"action": "toBeRobbed"})))
else:
ene.robbed(swag)
cur.add_card(swag)
message_to_send.append(( (wscur,wsene), dumps({"msg": "robbed", "data": [cur.name, cur.robbing]})))
cur.robbing = "0"
cur.status = Room.NOTHING
message_to_send.extend(Room.start_turn(wsene, wscur))
else: # 直接結束
message_to_send.append(((wsene, wscur), dumps({"msg": "cantRob", "data": [cur.name]})))
message_to_send.extend(Room.start_turn(wsene, wscur))
elif cur.status == self.ROBBED:
if choice in cur.hand and choice in card.unrobable:
message_to_send.extend(card.skills[choice](wscur,wsene))
cur.remove_card(choice)
else:
message_to_send.append(( (wscur,wsene), dumps({"msg": "robbed", "data": [ene.name, ene.robbing]})))
cur.robbed(ene.robbing)
ene.add_card(ene.robbing)
ene.robbing = "0"
message_to_send.extend(Room.start_turn(wscur, wsene))
elif cur.status == self.DEFENCE: # cur是被攻擊方
if choice in cur.hand:
if choice in card.unattackable:
message_to_send.extend(card.skills[choice](wscur,wsene))
cur.remove_card(choice)
else:
if ene.surprise:
msg = "surNoCard"
if ene.hand:
drop = random.choice(ene.hand)
ene.remove_card(drop)
msg = "surprised"
message_to_send.append(( (wsene, wscur), dumps({"msg": msg, "data": [cur.name, ene.damage]})))
else:
message_to_send.append(( (wsene, wscur), dumps({"msg": "damaged", "data": [cur.name, ene.damage]})))
cur.life -= ene.damage
else:
if ene.surprise:
drop = random.choice(ene.hand)
ene.remove_card(drop)
message_to_send.append(( (wsene, wscur), dumps({"msg": "surprised", "data": [cur.name, ene.damage]})))
else:
message_to_send.append(( (wsene, wscur), dumps({"msg": "damaged", "data": [cur.name, ene.damage]})))
cur.life -= ene.damage
ene.attacking = False
ene.surprise = False # 兩個都取消
ene.damage = 0 # reset
message_to_send.extend(Room.start_turn(wscur, wsene))
elif cur.status == self.TRADE:
if choice in cur.hand:
message_to_send.append(( (wsene, wscur), dumps({"msg": "tradeChoose", "data": [cur.name, choice]})))
message_to_send.append(( (wsene,), dumps({"action": "toTrade"})))
cur.trading = choice
cur.status = self.NOTHING
ene.status = self.TRADE_ENE
else: # 直接結束
message_to_send.extend(Room.start_turn(wsene, wscur))
elif cur.status == self.TRADE_ENE:
if cur.hand:
if choice not in cur.hand:
choice = random.sample(cur.hand, 1)[0] # decide a card randomly
ene.hand.remove(ene.trading)
ene.hand.append(choice)
cur.hand.remove(choice)
cur.hand.append(ene.trading)
else:
message_to_send.append(( (wsene,wscur), dumps( {"msg": "tradeNoCard", "data": [cur.name]})))
ene.trading = "0"
message_to_send.extend(Room.start_turn(wscur, wsene))
elif cur.status == self.PLAN:
if choice in cur.planning:
cur.add_card(choice)
cur.stauts = Room.NOTHING
cur.planning = []
message_to_send.extend(Room.start_turn(wsene, wscur))
print("status of ",cur.name, ":", cur.status)
print("status of ",ene.name, ":", ene.status)
return message_to_send
async def sendTo(message, *ws_list):
for ws in ws_list:
await ws.send(message)

388
spec.json
View File

@ -1,192 +1,198 @@
choose character: "5" choose character: "5"
enter_room: room number / "n" // "n" to create a random room and enter it enter_room: room number / "n" // "n" to create a random room and enter it
out: room number / {"room": 18693, "cur": "圭月", "ene": "小兔"} out: room number / {"room": 7122, "cur": "圭月", "ene": "小兔"}
// shows room number, or send a object shows your player and enemy's // shows room number, or send a object shows your player and enemy's
: :
{"msg": "firstAttack", "data": [firstPlayer.name], "hand": player.hand} {"msg": "firstAttack", "data": [firstPlayer.name], "hand": player.hand}
: :
{ {
"player": { "player": {
"turn": 3, "hand": ['1','2','3','1','1','1'], "deck_left": 35, "turn": 3, "hand": ['1','2','3','1','1','1'], "deck_left": 35,
"life": 20 "life": 20, "poison": 0,
}, },
"enemy": {"turn": 3, "life": 20, "deck_left": 35 "enemy": {"turn": 3, "life": 20, "deck_left": 35, "hand": 30, "poison": 1,
} }
} }
{
"attack": "{} 攻擊 {}", {
"damaged": "{} 受到{}點傷害", "attack": "{} 攻擊 {}",
//"toDefend": "請問要防禦嗎?不出牌請輸入0", "damaged": "{} 受到{}點傷害",
"defended": "{} 防禦成功", //"toDefend": "請問要防禦嗎?不出牌請輸入0",
"defend": "{} 沒什麼可以防禦的,回復一點生命", "defended": "{} 防禦成功",
"heal": "{} 回復兩點生命", "defend": "{} 沒什麼可以防禦的,回復一點生命",
"supply": "{} 增加兩張手牌", "heal": "{} 回復兩點生命",
"rob": "{} 正在對 {} 行搶", "supply": "{} 增加兩張手牌",
"cantRob": "可惜,{} 有夠窮,沒東西能搶", "rob": "{} 正在對 {} 行搶",
"robbed": "{} 搶到了 {}" "cantRob": "{}沒有搶到任何東西",
"surprise": "{} 發動奇襲", "robbed": "{} 搶到了 {}",
"surprised": "{} 受到{}點傷害,而且掉了一張手牌", "surprise": "{} 發動奇襲",
"trade": "{} 想與 {} 進行交易", "surprised": "{} 受到{}點傷害,而且掉了一張手牌",
"tradeChoose": "{} 選擇了 {}", "trade": "{} 想與 {} 進行交易",
//"toRob": "{} 要搶哪張?", "tradeChoose": "{} 選擇了 {}",
//"toBeRobbed": "請問要防禦嗎?" //"toRob": "{} 要搶哪張?",
//"toTrade": "選擇一張手牌以交換", //"toBeRobbed": "請問要防禦嗎?"
"awared": "{} 洞悉了 {} 的{},並抽取了一張手牌", //"toTrade": "選擇一張手牌以交換",
/* "awared": "{} 洞悉了 {} 的{},並抽取了一張手牌",
"": "{} 洞悉了 {} 的強奪,並抽取了一張手牌", /*
"": "{} 洞悉了 {} 的奇襲,並抽取了一張手牌", "": "{} 洞悉了 {} 的強奪,並抽取了一張手牌",
*/ "": "{} 洞悉了 {} 的奇襲,並抽取了一張手牌",
"aware": "{} 增加三張手牌", */
"plan": "{} 有個妙策", "aware": "{} 增加三張手牌",
//"toAdd": "選擇一張卡加入手牌", "plan": "{} 有個妙策",
"sweep": "{} 對 {} 進行掃射,威力是 {}", //"toAdd": "選擇一張卡加入手牌",
"bless": "{} 獲得加護,身上的毒素一掃而空,並回復三點生命,還抽取了兩張手牌", "sweep": "{} 對 {} 進行掃射,威力是 {}",
"poison": "{} 在食物下毒,{}中毒了", "bless": "{} 獲得加護,身上的毒素一掃而空,並回復三點生命,還抽取了兩張手牌",
"curse": "{} 詛咒了 {},使其損失四點生命,並掉了一張手牌", "poison": "{} 在食物下毒,{}中毒了",
"countered": "{} 反制了 {} 的攻擊,反彈了{}點傷害", "curse": "{} 詛咒了 {},使其損失四點生命,並掉了一張手牌",
"counteredSur": "{} 反制了 {} 的攻擊,反彈了{}點傷害,並使其掉了一張手牌", "countered": "{} 反制了 {} 的攻擊,反彈了{}點傷害",
"counter": "{} 反制了敵手,使 {} 生命值減半了!", "counteredSur": "{} 反制了 {} 的攻擊,反彈了{}點傷害,並使其掉了一張手牌",
"chaos": "{} 進入狂亂模式,回復三點生命,並對 {} 造成三點傷害", "counter": "{} 反制了敵手,使 {} 生命值減半了!",
"reverse": "{} 一口氣逆轉了情勢", "chaos": "{} 進入狂亂模式,回復三點生命,並對 {} 造成三點傷害",
//"": "{} 的生命: {}", "reverse": "{} 一口氣逆轉了情勢",
//"": "這是 {} 的手牌", //"": "{} 的生命: {}",
"noCard": "你抽到了死神", //"": "這是 {} 的手牌",
"left": "牌組剩餘: {} 張", "noCard": "你抽到了死神",
//"": "{} 抽到了 {}", "left": "牌組剩餘: {} 張",
//"inTurn": "請問要使用手牌嗎? 若不使用請輸入0", //"": "{} 抽到了 {}",
"turnNumber": "{} 的第{}回合", //"inTurn": "請問要使用手牌嗎? 若不使用請輸入0",
"poisonDamaged": "{} 受到了劇毒的侵蝕,損失{}點生命", "turnNumber": "{} 的第{}回合",
"surrender": "{}投降", "poisonDamaged": "{} 受到了劇毒的侵蝕,損失{}點生命",
"firstAttack": "{}先攻", "surrender": "{}投降",
"win": "{}獲勝", "firstAttack": "{}先攻",
"draw": "{}抽到了{}", "win": "{}獲勝",
"drawEne": "{}抽了一張卡片" "draw": "{}抽到了{}",
"drawEne": "{}抽了一張卡片",
} "use": "{}使用了{}",
"eneDisconn": "因敵方斷線,所以{}獲勝",
}
1. attack
in: "1"
out:
cur: {"msg": "attack", "data": [cur.name, ene.name]} 1. attack
ene: {"msg": "attack", "data": [cur.name, ene.name], in: "1"
"action": "toDefend", "value": {"damage": cur.damage}} / () out:
in: "2" / "8" / "14" / "0" cur: {"msg": "attack", "data": [cur.name, ene.name]}
out: ene: cur, {"action": "toDefend", "value": {"damage": cur.damage, "type": "attack"}} /
cur: {"msg": "defended", "data": [ene.name]} / cur()
{"msg": "countered", "data": [ene.name]} / in: "2" / "8" / "14" / "0"
{"msg": "awared", "data": [ene.name, "攻擊"]} / out:
{"msg": "damaged", "data": [ene.name, cur.damage]} cur: {"msg": "defended", "data": [ene.name]} /
ene: {"msg": "countered", "data": [ene.name]} /
2. defend //使 {"msg": "awared", "data": [cur.name, ene.name, "攻擊"]} /
in: "2" {"msg": "damaged", "data": [ene.name, cur.damage]}
out: ene:
cur: {"msg": "defend", "data": [cur.name]} 2. defend //使
ene: in: "2"
3. heal out:
in: "3" cur: {"msg": "defend", "data": [cur.name]}
out: ene:
cur: {"msg": "heal", "data": [cur.name]} 3. heal
ene: in: "3"
4. supply out:
in: "4" cur: {"msg": "heal", "data": [cur.name]}
out: ene:
cur: {"msg": "supply", "data": [cur.name]} 4. supply
ene: in: "4"
5. rob out:
in: "5" cur: {"msg": "supply", "data": [cur.name]}
out: ene:
cur: {"msg": "rob", "data": [cur.name, ene.name], 5. rob
"action": "toRob", "value": {"emeny_card:", ene.hand}} / in: "5"
{"msg": "cantRob", "data": [ene.name]} out:
in: card number cur: {"msg": "rob", "data": [cur.name, ene.name],
out: "action": "toRob", "value": {"enemy_card": ene.hand}} /
ene: {"action": "toBeRobbed"} / () {{"msg": "cantRob", "data": [cur.name]}]}
in: "8" / "0" in: card number
out: out:
cur: {"msg": "defended", "data": [ene.name]} / ene: {"action": "toBeRobbed"} / ()
{"msg": "robbed", "data": [ene.name, card]} in: "8" / "0"
ene: out:
ene: / {"msg": "cantRob", "data": [ene.name]} cur: {"msg": "awared", "data": [cur.name, ene.name, "搶奪"]} /
6. surprise {"msg": "robbed", "data": [ene.name, card]}
in: "6" ene:
out: ene: / {{"msg": "cantRob", "data": [cur.name]}]}
cur: 6. surprise
ene: {"action": "toDefend", "value": {"damage": cur.damage}} / () in: "6"
in: "2" / "8" / "14" / "0" out:
out: cur: {"msg": "surprise", "data": [cur.name]}
cur: {"msg": "defended", "data": [ene.name]} / ene: cur, {"action": "toDefend", "value": {"damage": cur.damage, "type": "suprise"}} /
{"msg": "counteredSur", "data": [ene.name]} / cur()
{"msg": "awared", "data": [ene.name, "奇襲"]} / in: "2" / "8" / "14" / "0"
{"msg": "surprised", "data": [ene.name, cur.damage]} out:
ene: cur: {"msg": "defended", "data": [ene.name]} /
7. trade {"msg": "counteredSur", "data": [ene.name]} /
in: "7" {"msg": "awared", "data": [cur.name, ene.name, "奇襲"]} /
out: {"msg": "surprised", "data": [ene.name, cur.damage]}
cur: {"msg": "trade", "data": [cur.name, ene.name], "action": "toTrade"} ene:
in: card number 7. trade
out: in: "7"
cur: {"msg": "tradeChoose", "data": [cur.name, card number]} out:
ene: {"action": "toTrade"} cur: {"msg": "trade", "data": [cur.name, ene.name]},
ene: {"msg": "trade", "data": [cur.name, ene.name]} {"action": "toTrade", "value": ["hand": cur.hand]}
8. aware //使 in: card number
in: "8" out:
out: cur: {"msg": "tradeChoose", "data": [cur.name, card number]}
cur: {"msg": "aware", "data": [cur.name]} ene: cur, {"action": "toTrade"}
ene: ene: {"msg": "trade", "data": [cur.name, ene.name]}
9. plan 8. aware //使
in: "9" in: "8"
out: out:
cur: {"msg": "plan", "data": [cur.name], cur: {"msg": "aware", "data": [cur.name]}
"action": "toAdd", "value": {"cards": list}} ene:
in: card number 9. plan
ene: {"msg": "plan", "data": [cur.name]} in: "9"
10. bless out:
in: "10" cur: {"msg": "plan", "data": [cur.name]},
out: {"action": "toAdd", "value": {"cards": list}}
cur: {"msg": "bless", "data": [cur.name]} in: card number
ene: ene: {"msg": "plan", "data": [cur.name]}
11. sweep 10. bless
in: "11" in: "10"
out: out:
cur: cur: {"msg": "bless", "data": [cur.name]}
ene: {"action": "toDefend", "value": {"damage": cur.damage}} / () ene:
in: "2" / "8" / "14" / "0" 11. sweep
out: in: "11"
cur: {"msg": "defended", "data": [ene.name]} / out:
{"msg": "countered", "data": [ene.name]} / cur: {"msg": "sweep", "data": [cur.name, ene.name, cur.damage]}
{"msg": "awared", "data": [ene.name, "掃射"]} / ene: cur, {"action": "toDefend", "value": {"damage": cur.damage, "type": "sweep"}} /
{"msg": "damaged", "data": [ene.name, cur.damage]} ()
ene: in: "2" / "8" / "14" / "0"
12. poison out:
in: "12" cur: {"msg": "defended", "data": [ene.name]} /
out: {"msg": "countered", "data": [ene.name]} /
cur: {"msg": "poison", "data": [cur.name, ene.name]} {"msg": "awared", "data": [cur.name, ene.name, "掃射"]} /
ene: {"msg": "damaged", "data": [ene.name, cur.damage]}
13. curse ene:
in: "13" 12. poison
out: in: "12"
cur: {"msg": "curse", "data": [cur.name, ene.name]} out:
ene: cur: {"msg": "poison", "data": [cur.name, ene.name]}
14. counter //使 ene:
in: "14" 13. curse
out: in: "13"
cur: {"msg": "counter", "data": [cur.name, ene.name]} out:
ene: cur: {"msg": "curse", "data": [cur.name, ene.name]}
15. chaos ene:
in: "15" 14. counter //使
out: in: "14"
cur: {"msg": "chaos", "data": [cur.name, ene.name]} out:
ene: cur: {"msg": "counter", "data": [cur.name, ene.name]}
16. reverse ene:
in: "16" 15. chaos
out: in: "15"
cur: {"msg": "reverse", "data": [cur.name]} out:
cur: {"msg": "chaos", "data": [cur.name, ene.name]}
ene:
16. reverse
in: "16"
out:
cur: {"msg": "reverse", "data": [cur.name]}
ene: ene: