Enhancement (#108)

优化拖曳
牌局查看技能
狮子不给死人加血
GameEvent相关函数
觉醒技默认cost和锁定技一样
This commit is contained in:
notify 2023-04-09 11:44:19 +08:00 committed by GitHub
parent a51806f902
commit b0c2855389
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 180 additions and 7 deletions

View File

@ -133,6 +133,16 @@ function GetAllPiles(id)
return json.encode(ClientInstance:getPlayerById(id).special_cards or {}) return json.encode(ClientInstance:getPlayerById(id).special_cards or {})
end end
function GetPlayerSkills(id)
local p = ClientInstance:getPlayerById(id)
return json.encode(table.map(p.player_skills, function(s)
return s.visible and {
name = s.name,
description = Fk:getDescription(s.name),
} or nil
end))
end
---@param card string | integer ---@param card string | integer
---@param player integer ---@param player integer
function CanUseCard(card, player) function CanUseCard(card, player)

View File

@ -117,6 +117,10 @@ function Card:initialize(name, suit, number, color)
setmetatable(self, mt) setmetatable(self, mt)
end end
function Card:__tostring()
return string.format("%s[%s %d]", self.name, self:getSuitString(), self.number)
end
--- 克隆特定卡牌并赋予花色与点数。 --- 克隆特定卡牌并赋予花色与点数。
--- ---
--- 会将skill/special_skills/equip_skill继承到克隆牌中。 --- 会将skill/special_skills/equip_skill继承到克隆牌中。

View File

@ -93,6 +93,10 @@ function Player:initialize()
self.fixedDistance = {} self.fixedDistance = {}
end end
function Player:__tostring()
return string.format("%s #%d", self.id < 0 and "Bot" or "Player", math.abs(self.id))
end
--- 设置角色、体力、技能。 --- 设置角色、体力、技能。
---@param general General @ 角色类型 ---@param general General @ 角色类型
---@param setHp boolean @ 是否设置体力 ---@param setHp boolean @ 是否设置体力

View File

@ -70,7 +70,7 @@ end
---@return boolean @ returns true if trigger is broken ---@return boolean @ returns true if trigger is broken
function TriggerSkill:cost(event, target, player, data) function TriggerSkill:cost(event, target, player, data)
local ret = false local ret = false
if self.frequency == Skill.Compulsory then if self.frequency == Skill.Compulsory or self.frequency == Skill.Wake then
return true return true
end end

View File

@ -131,6 +131,23 @@ function table.simpleClone(self)
return ret return ret
end end
-- similar to table.clone but convert all class/instances to string
function table.cloneWithoutClass(self)
local ret = {}
for k, v in pairs(self) do
if type(v) == "table" then
if v.class or v.super then
ret[k] = tostring(v)
else
ret[k] = table.cloneWithoutClass(v)
end
else
ret[k] = v
end
end
return ret
end
-- if table does not contain the element, we insert it -- if table does not contain the element, we insert it
function table:insertIfNeed(element) function table:insertIfNeed(element)
if not table.contains(self, element) then if not table.contains(self, element) then

View File

@ -37,3 +37,25 @@ dofile "lua/server/events/pindian.lua"
-- TODO: fix this -- TODO: fix this
GameEvent.BreakEvent = 999 GameEvent.BreakEvent = 999
local eventTranslations = {
[GameEvent.ChangeHp] = "GameEvent.ChangeHp",
[GameEvent.Damage] = "GameEvent.Damage",
[GameEvent.LoseHp] = "GameEvent.LoseHp",
[GameEvent.Recover] = "GameEvent.Recover",
[GameEvent.ChangeMaxHp] = "GameEvent.ChangeMaxHp",
[GameEvent.Dying] = "GameEvent.Dying",
[GameEvent.Death] = "GameEvent.Death",
[GameEvent.MoveCards] = "GameEvent.MoveCards",
[GameEvent.UseCard] = "GameEvent.UseCard",
[GameEvent.RespondCard] = "GameEvent.RespondCard",
[GameEvent.SkillEffect] = "GameEvent.SkillEffect",
[GameEvent.Judge] = "GameEvent.Judge",
[GameEvent.DrawInitial] = "GameEvent.DrawInitial",
[GameEvent.Round] = "GameEvent.Round",
[GameEvent.Turn] = "GameEvent.Turn",
[GameEvent.Pindian] = "GameEvent.Pindian",
}
function GameEvent.static:translate(id)
return eventTranslations[id]
end

View File

@ -2,6 +2,7 @@
---@field public room Room ---@field public room Room
---@field public event integer ---@field public event integer
---@field public data any ---@field public data any
---@field public parent GameEvent
---@field public main_func fun(self: GameEvent) ---@field public main_func fun(self: GameEvent)
---@field public clear_func fun(self: GameEvent) ---@field public clear_func fun(self: GameEvent)
---@field public extra_clear_funcs any[] ---@field public extra_clear_funcs any[]
@ -27,6 +28,15 @@ function GameEvent:initialize(event, ...)
self.interrupted = false self.interrupted = false
end end
function GameEvent:findParent(eventType)
local e = self.parent
repeat
if e.event == eventType then return e end
e = e.parent
until not e
return nil
end
function GameEvent:clear() function GameEvent:clear()
for _, f in ipairs(self.extra_clear_funcs) do for _, f in ipairs(self.extra_clear_funcs) do
if type(f) == "function" then f(self) end if type(f) == "function" then f(self) end
@ -39,6 +49,7 @@ function GameEvent:exec()
local logic = room.logic local logic = room.logic
local ret = false -- false or nil means this event is running normally local ret = false -- false or nil means this event is running normally
local extra_ret local extra_ret
self.parent = logic:getCurrentEvent()
logic.game_event_stack:push(self) logic.game_event_stack:push(self)
local co = coroutine.create(self.main_func) local co = coroutine.create(self.main_func)

View File

@ -276,10 +276,45 @@ function GameLogic:trigger(event, target, data)
return broken return broken
end end
---@return GameEvent
function GameLogic:getCurrentEvent() function GameLogic:getCurrentEvent()
return self.game_event_stack.t[self.game_event_stack.p] return self.game_event_stack.t[self.game_event_stack.p]
end end
function GameLogic:dumpEventStack(detailed)
local top = self:getCurrentEvent()
local i = self.game_event_stack.p
local inspect = p
if not top then return end
print("===== Start of event stack dump =====")
if not detailed then print("") end
repeat
local printable_data
if type(top.data) ~= "table" then
printable_data = top.data
else
printable_data = table.cloneWithoutClass(top.data)
end
if not detailed then
print("Stack level #" .. i .. ": " .. GameEvent:translate(top.event))
else
print("\nStack level #" .. i .. ":")
inspect{
eventId = GameEvent:translate(top.event),
data = printable_data or "nil",
}
end
top = top.parent
i = i - 1
until not top
print("\n===== End of event stack dump =====")
end
function GameLogic:breakEvent(ret) function GameLogic:breakEvent(ret)
coroutine.yield("__breakEvent", ret) coroutine.yield("__breakEvent", ret)
end end

View File

@ -419,7 +419,7 @@ local silverLion = fk.CreateArmor{
equip_skill = silverLionSkill, equip_skill = silverLionSkill,
on_uninstall = function(self, room, player) on_uninstall = function(self, room, player)
Armor.onUninstall(self, room, player) Armor.onUninstall(self, room, player)
if player:isWounded() and self.equip_skill:isEffectable(player) then if player:isAlive() and player:isWounded() and self.equip_skill:isEffectable(player) then
room:broadcastPlaySound("./packages/maneuvering/audio/card/silver_lion") room:broadcastPlaySound("./packages/maneuvering/audio/card/silver_lion")
room:setEmotion(player, "./packages/maneuvering/image/anim/silver_lion") room:setEmotion(player, "./packages/maneuvering/image/anim/silver_lion")
room:recover{ room:recover{

View File

@ -167,6 +167,7 @@ Item {
DragHandler { DragHandler {
enabled: draggable enabled: draggable
grabPermissions: PointHandler.TakeOverForbidden
xAxis.enabled: true xAxis.enabled: true
yAxis.enabled: true yAxis.enabled: true

View File

@ -0,0 +1,53 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Flickable {
id: root
anchors.fill: parent
property var extra_data: ({})
signal finish()
contentHeight: details.height
ScrollBar.vertical: ScrollBar {}
ColumnLayout {
id: details
width: parent.width - 16
// TODO: player details
Text {
id: screenName
Layout.fillWidth: true
font.pixelSize: 18
}
TextEdit {
id: skillDesc
Layout.fillWidth: true
font.pixelSize: 18
readOnly: true
selectByKeyboard: true
selectByMouse: false
wrapMode: TextEdit.WordWrap
textFormat: TextEdit.RichText
}
}
onExtra_dataChanged: {
if (!extra_data.photo) return;
screenName.text = "";
skillDesc.text = "";
let id = extra_data.photo.playerid;
if (id == 0) return;
let data = JSON.parse(Backend.callLuaFunction("GetPlayerSkills", [id]));
data.forEach(t => {
skillDesc.append("<b>" + Backend.translate(t.name) + "</b>: " + t.description)
});
}
}

View File

@ -28,6 +28,7 @@ Item {
} }
DragHandler { DragHandler {
grabPermissions: PointHandler.TakeOverForbidden
xAxis.enabled: true xAxis.enabled: true
yAxis.enabled: true yAxis.enabled: true
} }

View File

@ -9,7 +9,7 @@ Item {
width: 175 width: 175
height: 233 height: 233
scale: 0.75 scale: 0.75
property int playerid property int playerid: 0
property string general: "" property string general: ""
property string screenName: "" property string screenName: ""
property string role: "unknown" property string role: "unknown"
@ -319,11 +319,22 @@ Item {
} }
TapHandler { TapHandler {
onTapped: { acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.NoButton
if (parent.state != "candidate" || !parent.selectable) { gesturePolicy: TapHandler.WithinBounds
return;
onTapped: (p, btn) => {
if (btn === Qt.LeftButton || btn === Qt.NoButton) {
if (parent.state != "candidate" || !parent.selectable) {
return;
}
parent.selected = !parent.selected;
} else if (btn === Qt.RightButton) {
parent.showDetail();
} }
parent.selected = !parent.selected; }
onLongPressed: {
parent.showDetail();
} }
} }
@ -538,4 +549,8 @@ Item {
function updateLimitSkill(skill, time) { function updateLimitSkill(skill, time) {
limitSkills.update(skill, time); limitSkills.update(skill, time);
} }
function showDetail() {
roomScene.startCheat("RoomElement/Cheat/PlayerDetail.qml", { photo: this });
}
} }