Basiccard (#33)
* update nullification * Slash * kill player * correct players to alive_players * add log for changehp and dying * usecard log & indicator * setemotion, logevent * fix distanceTo * shutdown server when console start * game over * complete slash * change format of flist.txt to avoid '\r\n' * fix \r\n * peach, zhiheng * ask for peach
This commit is contained in:
parent
22235ee6ec
commit
0029949a40
|
@ -143,6 +143,7 @@ fk.client_callback["Setup"] = function(jsonData)
|
||||||
end
|
end
|
||||||
|
|
||||||
fk.client_callback["EnterRoom"] = function(jsonData)
|
fk.client_callback["EnterRoom"] = function(jsonData)
|
||||||
|
Self = ClientPlayer:new(fk.Self)
|
||||||
ClientInstance.players = {Self}
|
ClientInstance.players = {Self}
|
||||||
ClientInstance.alive_players = {Self}
|
ClientInstance.alive_players = {Self}
|
||||||
ClientInstance.discard_pile = {}
|
ClientInstance.discard_pile = {}
|
||||||
|
@ -188,6 +189,12 @@ fk.client_callback["ArrangeSeats"] = function(jsonData)
|
||||||
p.seat = i
|
p.seat = i
|
||||||
table.insert(players, p)
|
table.insert(players, p)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
for i = 1, #players - 1 do
|
||||||
|
players[i].next = players[i + 1]
|
||||||
|
end
|
||||||
|
players[#players].next = players[1]
|
||||||
|
|
||||||
ClientInstance.players = players
|
ClientInstance.players = players
|
||||||
|
|
||||||
ClientInstance:notifyUI("ArrangeSeats", jsonData)
|
ClientInstance:notifyUI("ArrangeSeats", jsonData)
|
||||||
|
@ -355,6 +362,27 @@ fk.client_callback["GameLog"] = function(jsonData)
|
||||||
ClientInstance:appendLog(data)
|
ClientInstance:appendLog(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
fk.client_callback["LogEvent"] = function(jsonData)
|
||||||
|
local data = json.decode(jsonData)
|
||||||
|
if data.type == "Death" then
|
||||||
|
table.removeOne(
|
||||||
|
ClientInstance.alive_players,
|
||||||
|
ClientInstance:getPlayerById(data.to)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
ClientInstance:notifyUI("LogEvent", jsonData)
|
||||||
|
end
|
||||||
|
|
||||||
|
fk.client_callback["AddCardUseHistory"] = function(jsonData)
|
||||||
|
local data = json.decode(jsonData)
|
||||||
|
Self:addCardUseHistory(data[1], data[2])
|
||||||
|
end
|
||||||
|
|
||||||
|
fk.client_callback["ResetCardUseHistory"] = function(jsonData)
|
||||||
|
if jsonData == "" then jsonData = nil end
|
||||||
|
Self:resetCardUseHistory(jsonData)
|
||||||
|
end
|
||||||
|
|
||||||
-- Create ClientInstance (used by Lua)
|
-- Create ClientInstance (used by Lua)
|
||||||
ClientInstance = Client:new()
|
ClientInstance = Client:new()
|
||||||
dofile "lua/client/client_util.lua"
|
dofile "lua/client/client_util.lua"
|
||||||
|
|
|
@ -77,6 +77,12 @@ function GetCards(pack_name)
|
||||||
return json.encode(ret)
|
return json.encode(ret)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function DistanceTo(from, to)
|
||||||
|
local a = ClientInstance:getPlayerById(from)
|
||||||
|
local b = ClientInstance:getPlayerById(to)
|
||||||
|
return a:distanceTo(b)
|
||||||
|
end
|
||||||
|
|
||||||
---@param card string | integer
|
---@param card string | integer
|
||||||
---@param player integer
|
---@param player integer
|
||||||
function CanUseCard(card, player)
|
function CanUseCard(card, player)
|
||||||
|
@ -96,6 +102,9 @@ end
|
||||||
---@param selected integer[] @ ids of selected targets
|
---@param selected integer[] @ ids of selected targets
|
||||||
---@param selected_cards integer[] @ ids of selected cards
|
---@param selected_cards integer[] @ ids of selected cards
|
||||||
function CanUseCardToTarget(card, to_select, selected)
|
function CanUseCardToTarget(card, to_select, selected)
|
||||||
|
if ClientInstance:getPlayerById(to_select).dead then
|
||||||
|
return "false"
|
||||||
|
end
|
||||||
local c ---@type Card
|
local c ---@type Card
|
||||||
local selected_cards
|
local selected_cards
|
||||||
if type(card) == "number" then
|
if type(card) == "number" then
|
||||||
|
@ -264,6 +273,23 @@ Fk:loadTranslationTable{
|
||||||
["Sort Cards"] = "牌序",
|
["Sort Cards"] = "牌序",
|
||||||
["Chat"] = "聊天",
|
["Chat"] = "聊天",
|
||||||
["Log"] = "战报",
|
["Log"] = "战报",
|
||||||
|
|
||||||
|
["$GameOver"] = "游戏结束",
|
||||||
|
["$Winner"] = "%1 获胜",
|
||||||
|
["Back To Lobby"] = "返回大厅",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Game concepts
|
||||||
|
Fk:loadTranslationTable{
|
||||||
|
["lord"] = "主公",
|
||||||
|
["loyalist"] = "忠臣",
|
||||||
|
["rebel"] = "反贼",
|
||||||
|
["renegade"] = "内奸",
|
||||||
|
["lord+loyalist"] = "主忠",
|
||||||
|
|
||||||
|
["normal_damage"] = "无属性",
|
||||||
|
["fire_damage"] = "火属性",
|
||||||
|
["thunder_damage"] = "雷属性",
|
||||||
}
|
}
|
||||||
|
|
||||||
-- related to sendLog
|
-- related to sendLog
|
||||||
|
@ -296,6 +322,9 @@ Fk:loadTranslationTable{
|
||||||
-- useCard
|
-- useCard
|
||||||
["#UseCard"] = "%from 使用了牌 %card",
|
["#UseCard"] = "%from 使用了牌 %card",
|
||||||
["#UseCardToTargets"] = "%from 使用了牌 %card,目标是 %to",
|
["#UseCardToTargets"] = "%from 使用了牌 %card,目标是 %to",
|
||||||
|
["#CardUseCollaborator"] = "%from 在此次 %card 中的子目标是 %to",
|
||||||
|
["#UseCardToCard"] = "%from 使用了牌 %card,目标是 %arg",
|
||||||
|
["#ResponsePlayCard"] = "%from 打出了牌 %card",
|
||||||
|
|
||||||
-- judge
|
-- judge
|
||||||
["#InitialJudge"] = "%from 的判定牌为 %card",
|
["#InitialJudge"] = "%from 的判定牌为 %card",
|
||||||
|
@ -306,4 +335,16 @@ Fk:loadTranslationTable{
|
||||||
["#TurnOver"] = "%from 将武将牌翻面,现在是 %arg",
|
["#TurnOver"] = "%from 将武将牌翻面,现在是 %arg",
|
||||||
["face_up"] = "正面朝上",
|
["face_up"] = "正面朝上",
|
||||||
["face_down"] = "背面朝上",
|
["face_down"] = "背面朝上",
|
||||||
|
|
||||||
|
-- damage, heal and lose HP
|
||||||
|
["#Damage"] = "%to 对 %from 造成了 %arg 点 %arg2 伤害",
|
||||||
|
["#DamageWithNoFrom"] = "%from 受到了 %arg 点 %arg2 伤害",
|
||||||
|
["#LoseHP"] = "%from 失去了 %arg 点体力",
|
||||||
|
["#HealHP"] = "%from 回复了 %arg 点体力",
|
||||||
|
["#ShowHPAndMaxHP"] = "%from 现在的体力值为 %arg,体力上限为 %arg2",
|
||||||
|
|
||||||
|
-- dying and death
|
||||||
|
["#EnterDying"] = "%from 进入了濒死阶段",
|
||||||
|
["#KillPlayer"] = "%from [%arg] 阵亡,凶手是 %to",
|
||||||
|
["#KillPlayerWithNoKiller"] = "%from [%arg] 阵亡,无伤害来源",
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
---@field general string
|
---@field general string
|
||||||
---@field handcard_num integer
|
---@field handcard_num integer
|
||||||
---@field seat integer
|
---@field seat integer
|
||||||
|
---@field next Player
|
||||||
---@field phase Phase
|
---@field phase Phase
|
||||||
---@field faceup boolean
|
---@field faceup boolean
|
||||||
---@field chained boolean
|
---@field chained boolean
|
||||||
|
@ -50,6 +51,7 @@ function Player:initialize()
|
||||||
self.role = ""
|
self.role = ""
|
||||||
self.general = ""
|
self.general = ""
|
||||||
self.seat = 0
|
self.seat = 0
|
||||||
|
self.next = nil
|
||||||
self.phase = Player.PhaseNone
|
self.phase = Player.PhaseNone
|
||||||
self.faceup = true
|
self.faceup = true
|
||||||
self.chained = false
|
self.chained = false
|
||||||
|
@ -240,7 +242,15 @@ end
|
||||||
|
|
||||||
---@param other Player
|
---@param other Player
|
||||||
function Player:distanceTo(other)
|
function Player:distanceTo(other)
|
||||||
local right = math.abs(self.seat - other.seat)
|
assert(other:isInstanceOf(Player))
|
||||||
|
local right = 0
|
||||||
|
local temp = self
|
||||||
|
while temp ~= other do
|
||||||
|
if not temp.dead then
|
||||||
|
right = right + 1
|
||||||
|
end
|
||||||
|
temp = temp.next
|
||||||
|
end
|
||||||
local left = #Fk:currentRoom().alive_players - right
|
local left = #Fk:currentRoom().alive_players - right
|
||||||
local ret = math.min(left, right)
|
local ret = math.min(left, right)
|
||||||
-- TODO: corrent distance here using skills
|
-- TODO: corrent distance here using skills
|
||||||
|
@ -260,11 +270,18 @@ function Player:addCardUseHistory(cardName, num)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Player:resetCardUseHistory(cardName)
|
function Player:resetCardUseHistory(cardName)
|
||||||
|
if not cardName then
|
||||||
|
self.cardUsedHistory = {}
|
||||||
|
end
|
||||||
if self.cardUsedHistory[cardName] then
|
if self.cardUsedHistory[cardName] then
|
||||||
self.cardUsedHistory[cardName] = 0
|
self.cardUsedHistory[cardName] = 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Player:usedTimes(cardName)
|
||||||
|
return self.cardUsedHistory[cardName] or 0
|
||||||
|
end
|
||||||
|
|
||||||
function Player:isKongcheng()
|
function Player:isKongcheng()
|
||||||
return #self:getCardIds(Player.Hand) == 0
|
return #self:getCardIds(Player.Hand) == 0
|
||||||
end
|
end
|
||||||
|
@ -277,6 +294,10 @@ function Player:isAllNude()
|
||||||
return #self:getCardIds() == 0
|
return #self:getCardIds() == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Player:isWounded()
|
||||||
|
return self.hp < self.maxHp
|
||||||
|
end
|
||||||
|
|
||||||
---@param skill string | Skill
|
---@param skill string | Skill
|
||||||
---@return Skill
|
---@return Skill
|
||||||
local function getActualSkill(skill)
|
local function getActualSkill(skill)
|
||||||
|
|
|
@ -71,4 +71,12 @@ fk.CardEffecting = 56
|
||||||
fk.CardEffectFinished = 57
|
fk.CardEffectFinished = 57
|
||||||
fk.CardEffectCancelledOut = 58
|
fk.CardEffectCancelledOut = 58
|
||||||
|
|
||||||
fk.NumOfEvents = 59
|
fk.AskForPeaches = 59
|
||||||
|
fk.AskForPeachesDone = 60
|
||||||
|
fk.Death = 61
|
||||||
|
fk.BuryVictim = 62
|
||||||
|
fk.BeforeGameOverJudge = 63
|
||||||
|
fk.GameOverJudge = 64
|
||||||
|
fk.GameFinished = 65
|
||||||
|
|
||||||
|
fk.NumOfEvents = 66
|
||||||
|
|
|
@ -74,7 +74,7 @@ function GameLogic:chooseGenerals()
|
||||||
room:broadcastProperty(lord, "general")
|
room:broadcastProperty(lord, "general")
|
||||||
end
|
end
|
||||||
|
|
||||||
local nonlord = room:getOtherPlayers(lord)
|
local nonlord = room:getOtherPlayers(lord, true)
|
||||||
local generals = Fk:getGeneralsRandomly(#nonlord * 3, Fk.generals, {lord_general})
|
local generals = Fk:getGeneralsRandomly(#nonlord * 3, Fk.generals, {lord_general})
|
||||||
table.shuffle(generals)
|
table.shuffle(generals)
|
||||||
for _, p in ipairs(nonlord) do
|
for _, p in ipairs(nonlord) do
|
||||||
|
@ -150,7 +150,7 @@ function GameLogic:action()
|
||||||
self:trigger(fk.GameStart)
|
self:trigger(fk.GameStart)
|
||||||
local room = self.room
|
local room = self.room
|
||||||
|
|
||||||
for _, p in ipairs(room.players) do
|
for _, p in ipairs(room.alive_players) do
|
||||||
self:trigger(fk.DrawInitialCards, p, { num = 4 })
|
self:trigger(fk.DrawInitialCards, p, { num = 4 })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,14 @@ function Room:initialize(_room)
|
||||||
|
|
||||||
self.room.startGame = function(_self)
|
self.room.startGame = function(_self)
|
||||||
Room.initialize(self, _room) -- clear old data
|
Room.initialize(self, _room) -- clear old data
|
||||||
self:run()
|
local co_func = function()
|
||||||
|
self:run()
|
||||||
|
end
|
||||||
|
local co = coroutine.create(co_func)
|
||||||
|
while not self.game_finished do
|
||||||
|
coroutine.resume(co)
|
||||||
|
end
|
||||||
|
fk.qInfo("Game Finished.")
|
||||||
end
|
end
|
||||||
|
|
||||||
self.players = {}
|
self.players = {}
|
||||||
|
@ -126,19 +133,18 @@ function Room:deadPlayerFilter(playerIds)
|
||||||
return newPlayerIds
|
return newPlayerIds
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param sortBySeat boolean
|
|
||||||
---@return ServerPlayer[]
|
---@return ServerPlayer[]
|
||||||
function Room:getAlivePlayers(sortBySeat)
|
function Room:getAlivePlayers()
|
||||||
sortBySeat = sortBySeat or true
|
local current = self.current
|
||||||
|
local temp = current.next
|
||||||
local alivePlayers = {}
|
local ret = {current}
|
||||||
for _, player in ipairs(self.players) do
|
while temp ~= current do
|
||||||
if player:isAlive() then
|
if not temp.dead then
|
||||||
table.insert(alivePlayers, player)
|
table.insert(ret, temp)
|
||||||
end
|
end
|
||||||
|
temp = temp.next
|
||||||
end
|
end
|
||||||
|
return ret
|
||||||
return alivePlayers
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param player ServerPlayer
|
---@param player ServerPlayer
|
||||||
|
@ -169,8 +175,13 @@ end
|
||||||
|
|
||||||
---@param expect ServerPlayer
|
---@param expect ServerPlayer
|
||||||
---@return ServerPlayer[]
|
---@return ServerPlayer[]
|
||||||
function Room:getOtherPlayers(expect)
|
function Room:getOtherPlayers(expect, include_dead)
|
||||||
local ret = {table.unpack(self.players)}
|
local ret
|
||||||
|
if include_dead then
|
||||||
|
ret = {table.unpack(self.players)}
|
||||||
|
else
|
||||||
|
ret = {table.unpack(self.alive_players)}
|
||||||
|
end
|
||||||
table.removeOne(ret, expect)
|
table.removeOne(ret, expect)
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
@ -391,6 +402,25 @@ function Room:sendLog(log)
|
||||||
self:doBroadcastNotify("GameLog", json.encode(log))
|
self:doBroadcastNotify("GameLog", json.encode(log))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Room:doAnimate(type, data, players)
|
||||||
|
players = players or self.players
|
||||||
|
data.type = type
|
||||||
|
self:doBroadcastNotify("Animate", json.encode(data), players)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Room:setEmotion(player, name)
|
||||||
|
self:doAnimate("Emotion", {
|
||||||
|
player = player.id,
|
||||||
|
emotion = name
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function Room:sendLogEvent(type, data, players)
|
||||||
|
players = players or self.players
|
||||||
|
data.type = type
|
||||||
|
self:doBroadcastNotify("LogEvent", json.encode(data), players)
|
||||||
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- interactive functions
|
-- interactive functions
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
@ -465,14 +495,7 @@ function Room:askForDiscard(player, minNum, maxNum, includeEquip, skillName)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:moveCards({
|
self:throwCard(toDiscard, skillName, player, player)
|
||||||
ids = toDiscard,
|
|
||||||
from = player.id,
|
|
||||||
toArea = Card.DiscardPile,
|
|
||||||
moveReason = fk.ReasonDiscard,
|
|
||||||
proposer = player.id,
|
|
||||||
skillName = skillName
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param player ServerPlayer
|
---@param player ServerPlayer
|
||||||
|
@ -644,7 +667,7 @@ function Room:askForNullification(players, card_name, prompt, cancelable, extra_
|
||||||
extra_data = extra_data or {}
|
extra_data = extra_data or {}
|
||||||
prompt = prompt or "#AskForUseCard"
|
prompt = prompt or "#AskForUseCard"
|
||||||
|
|
||||||
self:notifyMoveFocus(self.players, card_name)
|
self:notifyMoveFocus(self.alive_players, card_name)
|
||||||
self:doBroadcastNotify("WaitForNullification", "")
|
self:doBroadcastNotify("WaitForNullification", "")
|
||||||
|
|
||||||
local data = {card_name, prompt, cancelable, extra_data}
|
local data = {card_name, prompt, cancelable, extra_data}
|
||||||
|
@ -776,13 +799,57 @@ end
|
||||||
---@param cardUseEvent CardUseStruct
|
---@param cardUseEvent CardUseStruct
|
||||||
---@return boolean
|
---@return boolean
|
||||||
function Room:useCard(cardUseEvent)
|
function Room:useCard(cardUseEvent)
|
||||||
|
local from = cardUseEvent.customFrom or cardUseEvent.from
|
||||||
self:moveCards({
|
self:moveCards({
|
||||||
ids = { cardUseEvent.cardId },
|
ids = { cardUseEvent.cardId },
|
||||||
from = cardUseEvent.customFrom or cardUseEvent.from,
|
from = from,
|
||||||
toArea = Card.Processing,
|
toArea = Card.Processing,
|
||||||
moveReason = fk.ReasonUse,
|
moveReason = fk.ReasonUse,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
self:setEmotion(self:getPlayerById(from), Fk:getCardById(cardUseEvent.cardId).name)
|
||||||
|
self:doAnimate("Indicate", {
|
||||||
|
from = from,
|
||||||
|
to = cardUseEvent.tos or {},
|
||||||
|
})
|
||||||
|
if cardUseEvent.tos then
|
||||||
|
local to = {}
|
||||||
|
for _, t in ipairs(cardUseEvent.tos) do
|
||||||
|
table.insert(to, t[1])
|
||||||
|
end
|
||||||
|
self:sendLog{
|
||||||
|
type = "#UseCardToTargets",
|
||||||
|
from = from,
|
||||||
|
to = to,
|
||||||
|
card = {cardUseEvent.cardId},
|
||||||
|
}
|
||||||
|
for _, t in ipairs(cardUseEvent.tos) do
|
||||||
|
if t[2] then
|
||||||
|
local temp = {table.unpack(t)}
|
||||||
|
table.remove(temp, 1)
|
||||||
|
self:sendLog{
|
||||||
|
type = "#CardUseCollaborator",
|
||||||
|
from = t[1],
|
||||||
|
to = temp,
|
||||||
|
card = {cardUseEvent.cardId},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif cardUseEvent.toCardId then
|
||||||
|
self:sendLog{
|
||||||
|
type = "#UseCardToCard",
|
||||||
|
from = from,
|
||||||
|
card = {cardUseEvent.cardId},
|
||||||
|
arg = Fk:getCardById(cardUseEvent.toCardId).name,
|
||||||
|
}
|
||||||
|
else
|
||||||
|
self:sendLog{
|
||||||
|
type = "#UseCard",
|
||||||
|
from = from,
|
||||||
|
card = {cardUseEvent.cardId},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
if Fk:getCardById(cardUseEvent.cardId).skill then
|
if Fk:getCardById(cardUseEvent.cardId).skill then
|
||||||
Fk:getCardById(cardUseEvent.cardId).skill:onUse(self, cardUseEvent)
|
Fk:getCardById(cardUseEvent.cardId).skill:onUse(self, cardUseEvent)
|
||||||
end
|
end
|
||||||
|
@ -992,7 +1059,7 @@ function Room:doCardEffect(cardEffectEvent)
|
||||||
end
|
end
|
||||||
elseif Fk:getCardById(cardEffectEvent.cardId).type == Card.TypeTrick then
|
elseif Fk:getCardById(cardEffectEvent.cardId).type == Card.TypeTrick then
|
||||||
local players = {}
|
local players = {}
|
||||||
for _, p in ipairs(self.players) do
|
for _, p in ipairs(self.alive_players) do
|
||||||
local cards = p.player_cards[Player.Hand]
|
local cards = p.player_cards[Player.Hand]
|
||||||
for _, cid in ipairs(cards) do
|
for _, cid in ipairs(cards) do
|
||||||
if Fk:getCardById(cid).name == "nullification" then
|
if Fk:getCardById(cid).name == "nullification" then
|
||||||
|
@ -1071,7 +1138,7 @@ function Room:moveCards(...)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
self:notifyMoveCards(self.players, cardsMoveStructs)
|
self:notifyMoveCards(nil, cardsMoveStructs)
|
||||||
|
|
||||||
for _, data in ipairs(cardsMoveStructs) do
|
for _, data in ipairs(cardsMoveStructs) do
|
||||||
if #data.moveInfo > 0 then
|
if #data.moveInfo > 0 then
|
||||||
|
@ -1227,6 +1294,54 @@ function Room:changeHp(player, num, reason, skillName, damageStruct)
|
||||||
|
|
||||||
assert(not (data.reason == "recover" and data.num < 0))
|
assert(not (data.reason == "recover" and data.num < 0))
|
||||||
player.hp = math.min(player.hp + data.num, player.maxHp)
|
player.hp = math.min(player.hp + data.num, player.maxHp)
|
||||||
|
self:broadcastProperty(player, "hp")
|
||||||
|
|
||||||
|
if reason == "damage" then
|
||||||
|
local damage_nature_table = {
|
||||||
|
[fk.NormalDamage] = "normal_damage",
|
||||||
|
[fk.FireDamage] = "fire_damage",
|
||||||
|
[fk.ThunderDamage] = "thunder_damage",
|
||||||
|
}
|
||||||
|
if damageStruct.from then
|
||||||
|
self:sendLog{
|
||||||
|
type = "#Damage",
|
||||||
|
to = {damageStruct.from},
|
||||||
|
from = player.id,
|
||||||
|
arg = 0 - num,
|
||||||
|
arg2 = damage_nature_table[damageStruct.damageType],
|
||||||
|
}
|
||||||
|
else
|
||||||
|
self:sendLog{
|
||||||
|
type = "#DamageWithNoFrom",
|
||||||
|
from = player.id,
|
||||||
|
arg = 0 - num,
|
||||||
|
arg2 = damage_nature_table[damageStruct.damageType],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
self:sendLogEvent("Damage", {
|
||||||
|
to = player.id,
|
||||||
|
damageType = damage_nature_table[damageStruct.damageType],
|
||||||
|
})
|
||||||
|
elseif reason == "loseHp" then
|
||||||
|
self:sendLog{
|
||||||
|
type = "#LoseHP",
|
||||||
|
from = player.id,
|
||||||
|
arg = 0 - num,
|
||||||
|
}
|
||||||
|
elseif reason == "recover" then
|
||||||
|
self:sendLog{
|
||||||
|
type = "#HealHP",
|
||||||
|
from = player.id,
|
||||||
|
arg = num,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
self:sendLog{
|
||||||
|
type = "#ShowHPAndMaxHP",
|
||||||
|
from = player.id,
|
||||||
|
arg = player.hp,
|
||||||
|
arg2 = player.maxHp,
|
||||||
|
}
|
||||||
|
|
||||||
self.logic:trigger(fk.HpChanged, player, data)
|
self.logic:trigger(fk.HpChanged, player, data)
|
||||||
|
|
||||||
|
@ -1281,6 +1396,7 @@ function Room:changeMaxHp(player, num)
|
||||||
end
|
end
|
||||||
|
|
||||||
player.maxHp = math.max(player.maxHp + num, 0)
|
player.maxHp = math.max(player.maxHp + num, 0)
|
||||||
|
self:broadcastProperty(player, "maxHp")
|
||||||
local diff = player.hp - player.maxHp
|
local diff = player.hp - player.maxHp
|
||||||
if diff > 0 then
|
if diff > 0 then
|
||||||
if not self:changeHp(player, -diff) then
|
if not self:changeHp(player, -diff) then
|
||||||
|
@ -1328,7 +1444,7 @@ function Room:damage(damageStruct)
|
||||||
|
|
||||||
if not self:changeHp(victim, -damageStruct.damage, "damage", damageStruct.skillName, damageStruct) then
|
if not self:changeHp(victim, -damageStruct.damage, "damage", damageStruct.skillName, damageStruct) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
stages = {
|
stages = {
|
||||||
[fk.Damage] = damageStruct.from,
|
[fk.Damage] = damageStruct.from,
|
||||||
|
@ -1368,35 +1484,58 @@ end
|
||||||
function Room:enterDying(dyingStruct)
|
function Room:enterDying(dyingStruct)
|
||||||
local dyingPlayer = self:getPlayerById(dyingStruct.who)
|
local dyingPlayer = self:getPlayerById(dyingStruct.who)
|
||||||
dyingPlayer.dying = true
|
dyingPlayer.dying = true
|
||||||
|
self:broadcastProperty(dyingPlayer, "dying")
|
||||||
|
self:sendLog{
|
||||||
|
type = "#EnterDying",
|
||||||
|
from = dyingPlayer.id,
|
||||||
|
}
|
||||||
self.logic:trigger(fk.EnterDying, dyingPlayer, dyingStruct)
|
self.logic:trigger(fk.EnterDying, dyingPlayer, dyingStruct)
|
||||||
|
|
||||||
if dyingPlayer.hp < 1 then
|
if dyingPlayer.hp < 1 then
|
||||||
local alivePlayers = self:getAlivePlayers()
|
self.logic:trigger(fk.Dying, dyingPlayer, dyingStruct)
|
||||||
for _, player in ipairs(alivePlayers) do
|
self.logic:trigger(fk.AskForPeaches, dyingPlayer, dyingStruct)
|
||||||
self.logic:trigger(fk.Dying, player, dyingStruct)
|
self.logic:trigger(fk.AskForPeachesDone, dyingPlayer, dyingStruct)
|
||||||
|
|
||||||
if player.hp > 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if dyingPlayer.hp < 1 then
|
|
||||||
---@type DeathStruct
|
|
||||||
local deathData = {
|
|
||||||
who = dyingPlayer.id,
|
|
||||||
damage = dyingStruct.damage,
|
|
||||||
}
|
|
||||||
self:killPlayer(deathData)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not dyingPlayer.dead then
|
||||||
|
dyingPlayer.dying = false
|
||||||
|
self:broadcastProperty(dyingPlayer, "dying")
|
||||||
|
end
|
||||||
self.logic:trigger(fk.AfterDying, dyingPlayer, dyingStruct)
|
self.logic:trigger(fk.AfterDying, dyingPlayer, dyingStruct)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param deathStruct DeathStruct
|
---@param deathStruct DeathStruct
|
||||||
function Room:killPlayer(deathStruct)
|
function Room:killPlayer(deathStruct)
|
||||||
print(self:getPlayerById(deathStruct.who).general .. " is dead")
|
local victim = self:getPlayerById(deathStruct.who)
|
||||||
self:gameOver()
|
victim.dead = true
|
||||||
|
table.removeOne(self.alive_players, victim)
|
||||||
|
|
||||||
|
local logic = self.logic
|
||||||
|
logic:trigger(fk.BeforeGameOverJudge, victim, deathStruct)
|
||||||
|
|
||||||
|
local killer = deathStruct.damage and deathStruct.damage.from or nil
|
||||||
|
if killer then
|
||||||
|
self:sendLog{
|
||||||
|
type = "#KillPlayer",
|
||||||
|
to = {killer},
|
||||||
|
from = victim.id,
|
||||||
|
arg = victim.role,
|
||||||
|
}
|
||||||
|
else
|
||||||
|
self:sendLog{
|
||||||
|
type = "#KillPlayerWithNoKiller",
|
||||||
|
from = victim.id,
|
||||||
|
arg = victim.role,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
self:sendLogEvent("Death", {to = victim.id})
|
||||||
|
|
||||||
|
self:broadcastProperty(victim, "role")
|
||||||
|
self:broadcastProperty(victim, "dead")
|
||||||
|
|
||||||
|
logic:trigger(fk.GameOverJudge, victim, deathStruct)
|
||||||
|
logic:trigger(fk.Death, victim, deathStruct)
|
||||||
|
logic:trigger(fk.BuryVictim, victim, deathStruct)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- lose/acquire skill actions
|
-- lose/acquire skill actions
|
||||||
|
@ -1502,6 +1641,26 @@ function Room:judge(data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param card_ids integer[]
|
||||||
|
---@param skillName string
|
||||||
|
---@param who ServerPlayer
|
||||||
|
---@param thrower ServerPlayer
|
||||||
|
function Room:throwCard(card_ids, skillName, who, thrower)
|
||||||
|
if type(card_ids) == "number" then
|
||||||
|
card_ids = {card_ids}
|
||||||
|
end
|
||||||
|
skillName = skillName or ""
|
||||||
|
thrower = thrower or who
|
||||||
|
self:moveCards({
|
||||||
|
ids = card_ids,
|
||||||
|
from = who.id,
|
||||||
|
toArea = Card.DiscardPile,
|
||||||
|
moveReason = fk.ReasonDiscard,
|
||||||
|
proposer = thrower.id,
|
||||||
|
skillName = skillName
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
-- other helpers
|
-- other helpers
|
||||||
|
|
||||||
function Room:adjustSeats()
|
function Room:adjustSeats()
|
||||||
|
@ -1545,10 +1704,16 @@ function Room:shuffleDrawPile()
|
||||||
table.shuffle(self.draw_pile)
|
table.shuffle(self.draw_pile)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Room:gameOver()
|
function Room:gameOver(winner)
|
||||||
self.game_finished = true
|
self.game_finished = true
|
||||||
-- dosomething
|
|
||||||
|
for _, p in ipairs(self.players) do
|
||||||
|
self:broadcastProperty(p, "role")
|
||||||
|
end
|
||||||
|
self:doBroadcastNotify("GameOver", winner)
|
||||||
|
|
||||||
self.room:gameOver()
|
self.room:gameOver()
|
||||||
|
coroutine.yield()
|
||||||
end
|
end
|
||||||
|
|
||||||
function CreateRoom(_room)
|
function CreateRoom(_room)
|
||||||
|
|
|
@ -19,8 +19,6 @@ function ServerPlayer:initialize(_self)
|
||||||
self.state = _self:getStateString()
|
self.state = _self:getStateString()
|
||||||
self.room = nil
|
self.room = nil
|
||||||
|
|
||||||
self.next = nil
|
|
||||||
|
|
||||||
-- Below are for doBroadcastRequest
|
-- Below are for doBroadcastRequest
|
||||||
self.request_data = ""
|
self.request_data = ""
|
||||||
self.client_reply = ""
|
self.client_reply = ""
|
||||||
|
@ -208,4 +206,44 @@ function ServerPlayer:play(phase_table)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function ServerPlayer:drawCards(num, skillName, fromPlace)
|
||||||
|
return self.room:drawCards(self, num, skillName, fromPlace)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ServerPlayer:bury()
|
||||||
|
-- self:clearFlags()
|
||||||
|
-- self:clearHistory()
|
||||||
|
self:throwAllCards()
|
||||||
|
-- self:throwAllMarks()
|
||||||
|
-- self:clearPiles()
|
||||||
|
|
||||||
|
-- self.room:clearPlayerCardLimitation(self, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ServerPlayer:throwAllCards(flag)
|
||||||
|
local room = self.room
|
||||||
|
flag = flag or "hej"
|
||||||
|
if string.find(flag, "h") then
|
||||||
|
room:throwCard(self.player_cards[Player.Hand], "", self)
|
||||||
|
end
|
||||||
|
|
||||||
|
if string.find(flag, "e") then
|
||||||
|
room:throwCard(self.player_cards[Player.Equip], "", self)
|
||||||
|
end
|
||||||
|
|
||||||
|
if string.find(flag, "j") then
|
||||||
|
room:throwCard(self.player_cards[Player.Judge], "", self)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ServerPlayer:addCardUseHistory(cardName, num)
|
||||||
|
Player.addCardUseHistory(self, cardName, num)
|
||||||
|
self:doNotify("AddCardUseHistory", json.encode{cardName, num})
|
||||||
|
end
|
||||||
|
|
||||||
|
function ServerPlayer:resetCardUseHistory(cardName)
|
||||||
|
Player.resetCardUseHistory(self, cardName)
|
||||||
|
self:doNotify("ResetCardUseHistory", cardName or "")
|
||||||
|
end
|
||||||
|
|
||||||
return ServerPlayer
|
return ServerPlayer
|
||||||
|
|
|
@ -1,8 +1,48 @@
|
||||||
|
---@param victim ServerPlayer
|
||||||
|
local function getWinner(victim)
|
||||||
|
local room = victim.room
|
||||||
|
local winner = ""
|
||||||
|
local alive = room.alive_players
|
||||||
|
|
||||||
|
if victim.role == "lord" then
|
||||||
|
if #alive == 1 and alive[1].role == "renegade" then
|
||||||
|
winner = "renegede"
|
||||||
|
else
|
||||||
|
winner = "rebel"
|
||||||
|
end
|
||||||
|
elseif victim.role ~= "loyalist" then
|
||||||
|
local lord_win = true
|
||||||
|
for _, p in ipairs(alive) do
|
||||||
|
if p.role == "rebel" or p.role == "renegade" then
|
||||||
|
lord_win = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if lord_win then
|
||||||
|
winner = "lord+loyalist"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return winner
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param killer ServerPlayer
|
||||||
|
local function rewardAndPunish(killer, victim)
|
||||||
|
if killer.dead then return end
|
||||||
|
if victim.role == "rebel" then
|
||||||
|
killer:drawCards(3, "kill")
|
||||||
|
elseif victim.role == "loyalist" and killer.role == "lord" then
|
||||||
|
killer:throwAllCards("he")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
GameRule = fk.CreateTriggerSkill{
|
GameRule = fk.CreateTriggerSkill{
|
||||||
name = "game_rule",
|
name = "game_rule",
|
||||||
events = {
|
events = {
|
||||||
fk.GameStart, fk.DrawInitialCards, fk.TurnStart,
|
fk.GameStart, fk.DrawInitialCards, fk.TurnStart,
|
||||||
fk.EventPhaseProceeding, fk.EventPhaseEnd, fk.EventPhaseChanging,
|
fk.EventPhaseProceeding, fk.EventPhaseEnd, fk.EventPhaseChanging,
|
||||||
|
fk.AskForPeaches, fk.AskForPeachesDone,
|
||||||
|
fk.GameOverJudge, fk.BuryVictim,
|
||||||
},
|
},
|
||||||
priority = 0,
|
priority = 0,
|
||||||
|
|
||||||
|
@ -40,7 +80,7 @@ GameRule = fk.CreateTriggerSkill{
|
||||||
table.insert(move_to_notify.moveInfo,
|
table.insert(move_to_notify.moveInfo,
|
||||||
{ cardId = id, fromArea = Card.DrawPile })
|
{ cardId = id, fromArea = Card.DrawPile })
|
||||||
end
|
end
|
||||||
room:notifyMoveCards(room.players, {move_to_notify})
|
room:notifyMoveCards(nil, {move_to_notify})
|
||||||
|
|
||||||
for _, id in ipairs(cardIds) do
|
for _, id in ipairs(cardIds) do
|
||||||
room:setCardArea(id, Card.PlayerHand, player.id)
|
room:setCardArea(id, Card.PlayerHand, player.id)
|
||||||
|
@ -129,12 +169,52 @@ GameRule = fk.CreateTriggerSkill{
|
||||||
end,
|
end,
|
||||||
[fk.EventPhaseEnd] = function()
|
[fk.EventPhaseEnd] = function()
|
||||||
if player.phase == Player.Play then
|
if player.phase == Player.Play then
|
||||||
-- TODO: clear history
|
player:resetCardUseHistory()
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
[fk.EventPhaseChanging] = function()
|
[fk.EventPhaseChanging] = function()
|
||||||
-- TODO: copy but dont copy all
|
-- TODO: copy but dont copy all
|
||||||
end,
|
end,
|
||||||
|
[fk.AskForPeaches] = function()
|
||||||
|
local savers = room:getAlivePlayers()
|
||||||
|
for _, p in ipairs(savers) do
|
||||||
|
if player.hp > 0 or player.dead then break end
|
||||||
|
while player.hp < 1 do
|
||||||
|
local peach_use = room:askForUseCard(p, "peach")
|
||||||
|
if not peach_use then break end
|
||||||
|
peach_use.tos = { {player.id} }
|
||||||
|
room:useCard(peach_use)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
[fk.AskForPeachesDone] = function()
|
||||||
|
if player.hp < 1 then
|
||||||
|
---@type DeathStruct
|
||||||
|
local deathData = {
|
||||||
|
who = player.id,
|
||||||
|
damage = data.damage,
|
||||||
|
}
|
||||||
|
room:killPlayer(deathData)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
[fk.GameOverJudge] = function()
|
||||||
|
local winner = getWinner(player)
|
||||||
|
if winner ~= "" then
|
||||||
|
room:gameOver(winner)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
[fk.BuryVictim] = function()
|
||||||
|
player:bury()
|
||||||
|
if room.tag["SkipNormalDeathProcess"] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local damage = data.damage
|
||||||
|
if damage and damage.from then
|
||||||
|
local killer = room:getPlayerById(damage.from)
|
||||||
|
rewardAndPunish(killer, player);
|
||||||
|
end
|
||||||
|
end,
|
||||||
default = function()
|
default = function()
|
||||||
print("game_rule: Event=" .. event)
|
print("game_rule: Event=" .. event)
|
||||||
room:askForSkillInvoke(player, "rule")
|
room:askForSkillInvoke(player, "rule")
|
||||||
|
|
|
@ -101,7 +101,9 @@ local zhiheng = fk.CreateActiveSkill{
|
||||||
return #selected == 0 and #selected_cards > 0
|
return #selected == 0 and #selected_cards > 0
|
||||||
end,
|
end,
|
||||||
on_effect = function(self, room, effect)
|
on_effect = function(self, room, effect)
|
||||||
room:drawCards(room:getPlayerById(effect.from), #effect.cards, "zhiheng")
|
local from = room:getPlayerById(effect.from)
|
||||||
|
room:throwCard(effect.cards, self.name, from)
|
||||||
|
room:drawCards(from, #effect.cards, self.name)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
local sunquan = General:new(extension, "sunquan", "wu", 4)
|
local sunquan = General:new(extension, "sunquan", "wu", 4)
|
||||||
|
|
|
@ -7,26 +7,31 @@ Fk:loadTranslationTable{
|
||||||
|
|
||||||
local slashSkill = fk.CreateActiveSkill{
|
local slashSkill = fk.CreateActiveSkill{
|
||||||
name = "slash_skill",
|
name = "slash_skill",
|
||||||
|
can_use = function(self, player)
|
||||||
|
-- TODO: tmd skill
|
||||||
|
return player:usedTimes("slash") < 1
|
||||||
|
end,
|
||||||
target_filter = function(self, to_select, selected)
|
target_filter = function(self, to_select, selected)
|
||||||
if #selected == 0 then
|
if #selected == 0 then
|
||||||
local player = Fk:currentRoom():getPlayerById(to_select)
|
local player = Fk:currentRoom():getPlayerById(to_select)
|
||||||
return Self ~= player
|
return Self ~= player and Self:inMyAttackRange(player)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
feasible = function(self, selected)
|
feasible = function(self, selected)
|
||||||
|
-- TODO: tmd
|
||||||
return #selected == 1
|
return #selected == 1
|
||||||
end,
|
end,
|
||||||
on_effect = function(self, room, effect)
|
on_effect = function(self, room, effect)
|
||||||
local to = effect.to
|
local to = effect.to
|
||||||
local from = effect.from
|
local from = effect.from
|
||||||
local cid = room:askForCardChosen(
|
|
||||||
room:getPlayerById(from),
|
room:damage({
|
||||||
room:getPlayerById(to),
|
from = from,
|
||||||
"hej",
|
to = to,
|
||||||
"snatch"
|
damage = 1,
|
||||||
)
|
damageType = fk.NormalDamage,
|
||||||
|
skillName = self.name
|
||||||
room:obtainCard(from, cid)
|
})
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
local slash = fk.CreateBasicCard{
|
local slash = fk.CreateBasicCard{
|
||||||
|
@ -115,10 +120,28 @@ extension:addCards({
|
||||||
jink:clone(Card.Diamond, 11),
|
jink:clone(Card.Diamond, 11),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
local peachSkill = fk.CreateActiveSkill{
|
||||||
|
name = "peach_skill",
|
||||||
|
can_use = function(self, player)
|
||||||
|
return player:isWounded()
|
||||||
|
end,
|
||||||
|
on_effect = function(self, room, effect)
|
||||||
|
local to = effect.to
|
||||||
|
local from = effect.from
|
||||||
|
|
||||||
|
room:recover{
|
||||||
|
who = to,
|
||||||
|
num = 1,
|
||||||
|
recoverBy = from,
|
||||||
|
skillName = self.name
|
||||||
|
}
|
||||||
|
end
|
||||||
|
}
|
||||||
local peach = fk.CreateBasicCard{
|
local peach = fk.CreateBasicCard{
|
||||||
name = "peach",
|
name = "peach",
|
||||||
suit = Card.Heart,
|
suit = Card.Heart,
|
||||||
number = 3,
|
number = 3,
|
||||||
|
skill = peachSkill,
|
||||||
}
|
}
|
||||||
Fk:loadTranslationTable{
|
Fk:loadTranslationTable{
|
||||||
["peach"] = "桃",
|
["peach"] = "桃",
|
||||||
|
@ -261,6 +284,9 @@ extension:addCards({
|
||||||
|
|
||||||
local nullificationSkill = fk.CreateActiveSkill{
|
local nullificationSkill = fk.CreateActiveSkill{
|
||||||
name = "nullification_skill",
|
name = "nullification_skill",
|
||||||
|
can_use = function()
|
||||||
|
return false
|
||||||
|
end,
|
||||||
on_effect = function(self, room, effect)
|
on_effect = function(self, room, effect)
|
||||||
if effect.responseToEvent then
|
if effect.responseToEvent then
|
||||||
effect.responseToEvent.isCancellOut = true
|
effect.responseToEvent.isCancellOut = true
|
||||||
|
@ -374,6 +400,7 @@ local crossbow = fk.CreateWeapon{
|
||||||
name = "crossbow",
|
name = "crossbow",
|
||||||
suit = Card.Club,
|
suit = Card.Club,
|
||||||
number = 1,
|
number = 1,
|
||||||
|
attack_range = 1,
|
||||||
}
|
}
|
||||||
Fk:loadTranslationTable{
|
Fk:loadTranslationTable{
|
||||||
["crossbow"] = "诸葛连弩",
|
["crossbow"] = "诸葛连弩",
|
||||||
|
@ -388,6 +415,7 @@ local qingGang = fk.CreateWeapon{
|
||||||
name = "qinggang_sword",
|
name = "qinggang_sword",
|
||||||
suit = Card.Spade,
|
suit = Card.Spade,
|
||||||
number = 6,
|
number = 6,
|
||||||
|
attack_range = 2,
|
||||||
}
|
}
|
||||||
Fk:loadTranslationTable{
|
Fk:loadTranslationTable{
|
||||||
["qinggang_sword"] = "青釭剑",
|
["qinggang_sword"] = "青釭剑",
|
||||||
|
@ -401,6 +429,7 @@ local iceSword = fk.CreateWeapon{
|
||||||
name = "ice_sword",
|
name = "ice_sword",
|
||||||
suit = Card.Spade,
|
suit = Card.Spade,
|
||||||
number = 2,
|
number = 2,
|
||||||
|
attack_range = 2,
|
||||||
}
|
}
|
||||||
Fk:loadTranslationTable{
|
Fk:loadTranslationTable{
|
||||||
["ice_sword"] = "寒冰剑",
|
["ice_sword"] = "寒冰剑",
|
||||||
|
@ -414,6 +443,7 @@ local doubleSwords = fk.CreateWeapon{
|
||||||
name = "double_swords",
|
name = "double_swords",
|
||||||
suit = Card.Spade,
|
suit = Card.Spade,
|
||||||
number = 2,
|
number = 2,
|
||||||
|
attack_range = 2,
|
||||||
}
|
}
|
||||||
Fk:loadTranslationTable{
|
Fk:loadTranslationTable{
|
||||||
["double_swords"] = "雌雄双股剑",
|
["double_swords"] = "雌雄双股剑",
|
||||||
|
@ -427,6 +457,7 @@ local blade = fk.CreateWeapon{
|
||||||
name = "blade",
|
name = "blade",
|
||||||
suit = Card.Spade,
|
suit = Card.Spade,
|
||||||
number = 5,
|
number = 5,
|
||||||
|
attack_range = 3,
|
||||||
}
|
}
|
||||||
Fk:loadTranslationTable{
|
Fk:loadTranslationTable{
|
||||||
["blade"] = "青龙偃月刀",
|
["blade"] = "青龙偃月刀",
|
||||||
|
@ -440,6 +471,7 @@ local spear = fk.CreateWeapon{
|
||||||
name = "spear",
|
name = "spear",
|
||||||
suit = Card.Spade,
|
suit = Card.Spade,
|
||||||
number = 12,
|
number = 12,
|
||||||
|
attack_range = 3,
|
||||||
}
|
}
|
||||||
Fk:loadTranslationTable{
|
Fk:loadTranslationTable{
|
||||||
["spear"] = "丈八蛇矛",
|
["spear"] = "丈八蛇矛",
|
||||||
|
@ -453,6 +485,7 @@ local axe = fk.CreateWeapon{
|
||||||
name = "axe",
|
name = "axe",
|
||||||
suit = Card.Diamond,
|
suit = Card.Diamond,
|
||||||
number = 5,
|
number = 5,
|
||||||
|
attack_range = 3,
|
||||||
}
|
}
|
||||||
Fk:loadTranslationTable{
|
Fk:loadTranslationTable{
|
||||||
["axe"] = "贯石斧",
|
["axe"] = "贯石斧",
|
||||||
|
@ -466,6 +499,7 @@ local halberd = fk.CreateWeapon{
|
||||||
name = "halberd",
|
name = "halberd",
|
||||||
suit = Card.Diamond,
|
suit = Card.Diamond,
|
||||||
number = 12,
|
number = 12,
|
||||||
|
attack_range = 4,
|
||||||
}
|
}
|
||||||
Fk:loadTranslationTable{
|
Fk:loadTranslationTable{
|
||||||
["halberd"] = "方天画戟",
|
["halberd"] = "方天画戟",
|
||||||
|
@ -479,6 +513,7 @@ local kylinBow = fk.CreateWeapon{
|
||||||
name = "kylin_bow",
|
name = "kylin_bow",
|
||||||
suit = Card.Heart,
|
suit = Card.Heart,
|
||||||
number = 5,
|
number = 5,
|
||||||
|
attack_range = 5,
|
||||||
}
|
}
|
||||||
Fk:loadTranslationTable{
|
Fk:loadTranslationTable{
|
||||||
["kylin_bow"] = "麒麟弓",
|
["kylin_bow"] = "麒麟弓",
|
||||||
|
|
|
@ -4,6 +4,8 @@ import QtQuick.Layouts
|
||||||
import "Common"
|
import "Common"
|
||||||
import "RoomElement"
|
import "RoomElement"
|
||||||
import "RoomLogic.js" as Logic
|
import "RoomLogic.js" as Logic
|
||||||
|
import "skin-bank.js" as SkinBank
|
||||||
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: roomScene
|
id: roomScene
|
||||||
|
@ -159,7 +161,7 @@ Item {
|
||||||
maxHp: model.maxHp
|
maxHp: model.maxHp
|
||||||
hp: model.hp
|
hp: model.hp
|
||||||
seatNumber: model.seatNumber
|
seatNumber: model.seatNumber
|
||||||
isDead: model.isDead
|
dead: model.dead
|
||||||
dying: model.dying
|
dying: model.dying
|
||||||
faceup: model.faceup
|
faceup: model.faceup
|
||||||
chained: model.chained
|
chained: model.chained
|
||||||
|
@ -224,7 +226,7 @@ Item {
|
||||||
self.maxHp: dashboardModel.maxHp
|
self.maxHp: dashboardModel.maxHp
|
||||||
self.hp: dashboardModel.hp
|
self.hp: dashboardModel.hp
|
||||||
self.seatNumber: dashboardModel.seatNumber
|
self.seatNumber: dashboardModel.seatNumber
|
||||||
self.isDead: dashboardModel.isDead
|
self.dead: dashboardModel.dead
|
||||||
self.dying: dashboardModel.dying
|
self.dying: dashboardModel.dying
|
||||||
self.faceup: dashboardModel.faceup
|
self.faceup: dashboardModel.faceup
|
||||||
self.chained: dashboardModel.chained
|
self.chained: dashboardModel.chained
|
||||||
|
@ -459,6 +461,15 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shortcut {
|
||||||
|
sequence: "D"
|
||||||
|
property bool show_distance: false
|
||||||
|
onActivated: {
|
||||||
|
show_distance = !show_distance;
|
||||||
|
showDistance(show_distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "Esc"
|
sequence: "Esc"
|
||||||
onActivated: {
|
onActivated: {
|
||||||
|
@ -491,6 +502,18 @@ Item {
|
||||||
log.append(msg);
|
log.append(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showDistance(show) {
|
||||||
|
for (let i = 0; i < photoModel.count; i++) {
|
||||||
|
let item = photos.itemAt(i);
|
||||||
|
if (show) {
|
||||||
|
let dis = Backend.callLuaFunction("DistanceTo",[Self.id, item.playerid]);
|
||||||
|
item.distance = parseInt(dis);
|
||||||
|
} else {
|
||||||
|
item.distance = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
toast.show(Backend.translate("$EnterRoom"));
|
toast.show(Backend.translate("$EnterRoom"));
|
||||||
|
|
||||||
|
@ -504,7 +527,7 @@ Item {
|
||||||
maxHp: 0,
|
maxHp: 0,
|
||||||
hp: 0,
|
hp: 0,
|
||||||
seatNumber: 1,
|
seatNumber: 1,
|
||||||
isDead: false,
|
dead: false,
|
||||||
dying: false,
|
dying: false,
|
||||||
faceup: true,
|
faceup: true,
|
||||||
chained: false,
|
chained: false,
|
||||||
|
@ -527,7 +550,7 @@ Item {
|
||||||
maxHp: 0,
|
maxHp: 0,
|
||||||
hp: 0,
|
hp: 0,
|
||||||
seatNumber: i + 1,
|
seatNumber: i + 1,
|
||||||
isDead: false,
|
dead: false,
|
||||||
dying: false,
|
dying: false,
|
||||||
faceup: true,
|
faceup: true,
|
||||||
chained: false,
|
chained: false,
|
||||||
|
|
|
@ -255,4 +255,8 @@ RowLayout {
|
||||||
for (let i = 0; i < skillButtons.count; i++)
|
for (let i = 0; i < skillButtons.count; i++)
|
||||||
skillButtons.itemAt(i).enabled = false;
|
skillButtons.itemAt(i).enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function tremble() {
|
||||||
|
selfPhoto.tremble();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import QtQuick
|
||||||
|
import ".."
|
||||||
|
|
||||||
|
GraphicsBox {
|
||||||
|
property string winner: ""
|
||||||
|
|
||||||
|
id: root
|
||||||
|
title.text: Backend.translate("$GameOver")
|
||||||
|
width: Math.max(140, body.width + 20)
|
||||||
|
height: body.height + title.height + 20
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: body
|
||||||
|
x: 10
|
||||||
|
y: title.height + 5
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: Backend.translate("$Winner").arg(Backend.translate(winner))
|
||||||
|
color: "#E4D5A0"
|
||||||
|
}
|
||||||
|
|
||||||
|
MetroButton {
|
||||||
|
text: Backend.translate("Back To Lobby")
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
ClientInstance.notifyServer("QuitRoom", "[]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,12 +19,13 @@ Item {
|
||||||
property int maxHp: 0
|
property int maxHp: 0
|
||||||
property int hp: 0
|
property int hp: 0
|
||||||
property int seatNumber: 1
|
property int seatNumber: 1
|
||||||
property bool isDead: false
|
property bool dead: false
|
||||||
property bool dying: false
|
property bool dying: false
|
||||||
property bool faceup: true
|
property bool faceup: true
|
||||||
property bool chained: false
|
property bool chained: false
|
||||||
property bool drank: false
|
property bool drank: false
|
||||||
property bool isOwner: false
|
property bool isOwner: false
|
||||||
|
property int distance: 0
|
||||||
property string status: "normal"
|
property string status: "normal"
|
||||||
|
|
||||||
property alias handcardArea: handcardAreaItem
|
property alias handcardArea: handcardAreaItem
|
||||||
|
@ -164,7 +165,7 @@ Item {
|
||||||
anchors.fill: photoMask
|
anchors.fill: photoMask
|
||||||
source: generalImage
|
source: generalImage
|
||||||
saturation: 0
|
saturation: 0
|
||||||
visible: root.isDead
|
visible: root.dead
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
|
@ -212,8 +213,8 @@ Item {
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
// id: saveme
|
// id: saveme
|
||||||
visible: root.isDead || root.dying
|
visible: root.dead || root.dying
|
||||||
source: SkinBank.DEATH_DIR + (root.isDead ? root.role : "saveme")
|
source: SkinBank.DEATH_DIR + (root.dead ? root.role : "saveme")
|
||||||
anchors.centerIn: photoMask
|
anchors.centerIn: photoMask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,6 +411,17 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: "white"
|
||||||
|
height: 20
|
||||||
|
width: 20
|
||||||
|
visible: distance != 0
|
||||||
|
Text {
|
||||||
|
text: distance
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onGeneralChanged: {
|
onGeneralChanged: {
|
||||||
if (!roomScene.isStarted) return;
|
if (!roomScene.isStarted) return;
|
||||||
generalName.text = Backend.translate(general);
|
generalName.text = Backend.translate(general);
|
||||||
|
|
|
@ -170,6 +170,14 @@ function moveCards(moves) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setEmotion(id, emotion) {
|
function setEmotion(id, emotion) {
|
||||||
|
let path = (SkinBank.PIXANIM_DIR + emotion).replace("file://", "");
|
||||||
|
if (!Backend.exists(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Backend.isDir(path)) {
|
||||||
|
// TODO: set picture emotion
|
||||||
|
return;
|
||||||
|
}
|
||||||
let component = Qt.createComponent("RoomElement/PixmapAnimation.qml");
|
let component = Qt.createComponent("RoomElement/PixmapAnimation.qml");
|
||||||
if (component.status !== Component.Ready)
|
if (component.status !== Component.Ready)
|
||||||
return;
|
return;
|
||||||
|
@ -183,7 +191,8 @@ function setEmotion(id, emotion) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let animation = component.createObject(photo, {source: emotion, anchors: {centerIn: photo}});
|
let animation = component.createObject(photo, {source: emotion});
|
||||||
|
animation.anchors.centerIn = photo;
|
||||||
animation.finished.connect(() => animation.destroy());
|
animation.finished.connect(() => animation.destroy());
|
||||||
animation.start();
|
animation.start();
|
||||||
}
|
}
|
||||||
|
@ -644,3 +653,47 @@ callbacks["AskForResponseCard"] = function(jsonData) {
|
||||||
callbacks["WaitForNullification"] = function() {
|
callbacks["WaitForNullification"] = function() {
|
||||||
roomScene.state = "notactive";
|
roomScene.state = "notactive";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callbacks["Animate"] = function(jsonData) {
|
||||||
|
// jsonData: [Object object]
|
||||||
|
let data = JSON.parse(jsonData);
|
||||||
|
switch (data.type) {
|
||||||
|
case "Indicate":
|
||||||
|
data.to.forEach(item => {
|
||||||
|
doIndicate(data.from, [item[0]]);
|
||||||
|
if (item[1]) {
|
||||||
|
doIndicate(item[0], item.slice(1));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case "Emotion":
|
||||||
|
setEmotion(data.player, data.emotion);
|
||||||
|
break;
|
||||||
|
case "LightBox":
|
||||||
|
break;
|
||||||
|
case "SuperLightBox":
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callbacks["LogEvent"] = function(jsonData) {
|
||||||
|
// jsonData: [Object object]
|
||||||
|
let data = JSON.parse(jsonData);
|
||||||
|
switch (data.type) {
|
||||||
|
case "Damage":
|
||||||
|
let item = getPhotoOrDashboard(data.to);
|
||||||
|
setEmotion(data.to, "damage");
|
||||||
|
item.tremble();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callbacks["GameOver"] = function(jsonData) {
|
||||||
|
roomScene.state = "notactive";
|
||||||
|
roomScene.popupBox.source = "RoomElement/GameOverBox.qml";
|
||||||
|
let box = roomScene.popupBox.item;
|
||||||
|
box.winner = jsonData;
|
||||||
|
}
|
||||||
|
|
|
@ -159,8 +159,9 @@ static void writeFileMD5(QFile &dest, const QString &fname) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data = f.readAll();
|
auto data = f.readAll();
|
||||||
|
data.replace(QByteArray("\r\n"), QByteArray("\n"));
|
||||||
auto hash = QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex();
|
auto hash = QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex();
|
||||||
dest.write(fname.toUtf8() + '=' + hash + '\n');
|
dest.write(fname.toUtf8() + '=' + hash + ';');
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeDirMD5(QFile &dest, const QString &dir, const QString &filter) {
|
static void writeDirMD5(QFile &dest, const QString &dir, const QString &filter) {
|
||||||
|
@ -186,6 +187,7 @@ QString calcFileMD5() {
|
||||||
qFatal("Cannot open flist.txt. Quitting.");
|
qFatal("Cannot open flist.txt. Quitting.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeDirMD5(flist, "packages", "*.lua");
|
||||||
writeDirMD5(flist, "lua", "*.lua");
|
writeDirMD5(flist, "lua", "*.lua");
|
||||||
writeDirMD5(flist, "qml", "*.qml");
|
writeDirMD5(flist, "qml", "*.qml");
|
||||||
writeDirMD5(flist, "qml", "*.js");
|
writeDirMD5(flist, "qml", "*.js");
|
||||||
|
|
|
@ -98,7 +98,9 @@ QString ServerPlayer::waitForReply(int timeout)
|
||||||
{
|
{
|
||||||
QString ret;
|
QString ret;
|
||||||
if (getState() != Player::Online) {
|
if (getState() != Player::Online) {
|
||||||
|
#ifndef QT_DEBUG
|
||||||
QThread::sleep(1);
|
QThread::sleep(1);
|
||||||
|
#endif
|
||||||
ret = "__cancel";
|
ret = "__cancel";
|
||||||
} else {
|
} else {
|
||||||
ret = router->waitForReply(timeout);
|
ret = router->waitForReply(timeout);
|
||||||
|
|
Loading…
Reference in New Issue