修倾国再点一下技能按钮会直接视为被取消
修服务端Log没有日期
修房间右上角没有轮数、对局时长、牌堆剩余牌数
修Linux上Log没有彩色字体
修短标记也会占用整整一行显示
修只有一张子卡的虚拟牌是无花色
修无花色牌不在牌面显示颜色
This commit is contained in:
notify 2023-04-20 00:19:48 +08:00 committed by GitHub
parent 85923c8a71
commit 1b8447acbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 236 additions and 59 deletions

View File

@ -568,7 +568,6 @@ fk.client_callback["Chat"] = function(jsonData)
end end
local p = ClientInstance:getPlayerById(data.sender) local p = ClientInstance:getPlayerById(data.sender)
-- TODO: observer chatting
if not p then if not p then
for _, pl in ipairs(ClientInstance.observers) do for _, pl in ipairs(ClientInstance.observers) do
if pl.id == data.sender then if pl.id == data.sender then

View File

@ -84,7 +84,7 @@ function GetCardData(id)
extension = card.package.extensionName, extension = card.package.extensionName,
number = card.number, number = card.number,
suit = card:getSuitString(), suit = card:getSuitString(),
color = card.color, color = card:getColorString(),
subtype = cardSubtypeStrings[card.sub_type] subtype = cardSubtypeStrings[card.sub_type]
} }
if card.skillName ~= "" then if card.skillName ~= "" then
@ -437,11 +437,7 @@ end
function GetInteractionOfSkill(skill_name) function GetInteractionOfSkill(skill_name)
local skill = Fk.skills[skill_name] local skill = Fk.skills[skill_name]
if skill and skill.interaction then if skill and skill.interaction then
if type(skill.interaction) == "function" then return json.encode(skill:interaction())
return json.encode(skill:interaction())
else
return json.encode(skill.interaction)
end
end end
return "null" return "null"
end end

View File

@ -111,6 +111,7 @@ FreeKill使用的是libgit2的C API与此同时使用Git完成拓展包的下
-- Room -- Room
["$EnterRoom"] = "成功加入房间。", ["$EnterRoom"] = "成功加入房间。",
["#currentRoundNum"] = "第 %1 轮",
["$Choice"] = "%1请选择", ["$Choice"] = "%1请选择",
["$ChooseGeneral"] = "请选择 %1 名武将", ["$ChooseGeneral"] = "请选择 %1 名武将",
["Same General Convert"] = "替换武将", ["Same General Convert"] = "替换武将",

View File

@ -158,9 +158,15 @@ local function updateColorAndNumber(card)
local color = Card.NoColor local color = Card.NoColor
local number = 0 local number = 0
local different_color = false local different_color = false
for _, id in ipairs(card.subcards) do for i, id in ipairs(card.subcards) do
local c = Fk:getCardById(id) local c = Fk:getCardById(id)
number = math.min(number + c.number, 13) number = math.min(number + c.number, 13)
if i == 1 then
card.suit = c.suit
else
card.suit = Card.NoSuit
end
if color ~= c.color then if color ~= c.color then
if not different_color then if not different_color then
if c.color ~= Card.NoColor then if c.color ~= Card.NoColor then
@ -278,7 +284,7 @@ end
--- 获取卡牌的文字信息并准备作为log发送。 --- 获取卡牌的文字信息并准备作为log发送。
function Card:toLogString() function Card:toLogString()
local ret = string.format('<font color="#0598BC"><b>%s</b></font>', Fk:translate(self.name) .. "[") local ret = string.format('<font color="#0598BC"><b>%s</b></font>', Fk:translate(self.name) .. "[")
if self:isVirtual() then if self:isVirtual() and #self.subcards ~= 1 then
ret = ret .. Fk:translate(self:getColorString()) ret = ret .. Fk:translate(self:getColorString())
else else
ret = ret .. Fk:translate("log_" .. self:getSuitString()) ret = ret .. Fk:translate("log_" .. self:getSuitString())

View File

@ -172,7 +172,18 @@ function fk.CreateActiveSkill(spec)
if spec.about_to_effect then skill.aboutToEffect = spec.about_to_effect end if spec.about_to_effect then skill.aboutToEffect = spec.about_to_effect end
if spec.on_effect then skill.onEffect = spec.on_effect end if spec.on_effect then skill.onEffect = spec.on_effect end
if spec.on_nullified then skill.onNullified = spec.on_nullified end if spec.on_nullified then skill.onNullified = spec.on_nullified end
skill.interaction = spec.interaction
if spec.interaction then
skill.interaction = setmetatable({}, {
__call = function(self)
if type(spec.interaction) == "function" then
return spec.interaction(self)
else
return spec.interaction
end
end,
})
end
return skill return skill
end end
@ -206,7 +217,18 @@ function fk.CreateViewAsSkill(spec)
skill.enabledAtResponse = spec.enabled_at_response skill.enabledAtResponse = spec.enabled_at_response
end end
skill.interaction = spec.interaction if spec.interaction then
skill.interaction = setmetatable({}, {
__call = function()
if type(spec.interaction) == "function" then
return spec.interaction(skill)
else
return spec.interaction
end
end,
})
end
return skill return skill
end end

View File

@ -96,6 +96,10 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
table.insert(toAreaIds, toAreaIds == Card.DrawPile and 1 or #toAreaIds + 1, info.cardId) table.insert(toAreaIds, toAreaIds == Card.DrawPile and 1 or #toAreaIds + 1, info.cardId)
end end
self:setCardArea(info.cardId, data.toArea, data.to) self:setCardArea(info.cardId, data.toArea, data.to)
if data.toArea == Card.DrawPile or realFromArea == Card.DrawPile then
self:doBroadcastNotify("UpdateDrawPile", #self.draw_pile)
end
Fk:filterCard(info.cardId, self:getPlayerById(data.to)) Fk:filterCard(info.cardId, self:getPlayerById(data.to))
local currentCard = Fk:getCardById(info.cardId) local currentCard = Fk:getCardById(info.cardId)

View File

@ -316,6 +316,8 @@ function Room:getNCards(num, from)
num = num - 1 num = num - 1
end end
self:doBroadcastNotify("UpdateDrawPile", #self.draw_pile)
return cardIds return cardIds
end end
@ -553,10 +555,13 @@ function Room:requestLoop(rest_time)
for _, p in ipairs(self.players) do for _, p in ipairs(self.players) do
self:notifyProperty(player, p, "general") self:notifyProperty(player, p, "general")
self:notifyProperty(player, p, "deputyGeneral")
p:marshal(player) p:marshal(player)
end end
-- TODO: tell drawPile player:doNotify("UpdateDrawPile", #self.draw_pile)
player:doNotify("UpdateRoundNum", self:getTag("RoundCount"))
table.insert(self.observers, {observee.id, player}) table.insert(self.observers, {observee.id, player})
end end

View File

@ -235,9 +235,7 @@ function ServerPlayer:reconnect()
}) })
self:doNotify("EnterLobby", "") self:doNotify("EnterLobby", "")
self:doNotify("EnterRoom", json.encode{ self:doNotify("EnterRoom", json.encode{
#room.players, room.timeout, #room.players, room.timeout, room.settings,
-- FIXME: use real room settings here
{ enableFreeAssign = false }
}) })
room:notifyProperty(self, self, "role") room:notifyProperty(self, self, "role")
@ -258,10 +256,12 @@ function ServerPlayer:reconnect()
for _, p in ipairs(room.players) do for _, p in ipairs(room.players) do
room:notifyProperty(self, p, "general") room:notifyProperty(self, p, "general")
room:notifyProperty(self, p, "deputyGeneral")
p:marshal(self) p:marshal(self)
end end
-- TODO: tell drawPile self:doNotify("UpdateDrawPile", #room.draw_pile)
self:doNotify("UpdateRoundNum", room:getTag("RoundCount"))
room:broadcastProperty(self, "state") room:broadcastProperty(self, "state")
end end

View File

@ -99,6 +99,7 @@ GameRule = fk.CreateTriggerSkill{
end end
room:setTag("RoundCount", room:getTag("RoundCount") + 1) room:setTag("RoundCount", room:getTag("RoundCount") + 1)
room:doBroadcastNotify("UpdateRoundNum", room:getTag("RoundCount"))
for _, p in ipairs(room.players) do for _, p in ipairs(room.players) do
p:setCardUseHistory("", 0, Player.HistoryRound) p:setCardUseHistory("", 0, Player.HistoryRound)

View File

@ -71,13 +71,14 @@ local test_active = fk.CreateActiveSkill{
end, end,
card_num = 2, card_num = 2,
target_filter = function() return true end, target_filter = function() return true end,
interaction = UI.ComboBox { interaction = function()return UI.ComboBox {
choices = Fk.package_names, choices = Fk.package_names,
-- default = "guanyu", -- default = "guanyu",
}, }end,
on_use = function(self, room, effect) on_use = function(self, room, effect)
--room:doSuperLightBox("packages/test/qml/Test.qml") --room:doSuperLightBox("packages/test/qml/Test.qml")
local from = room:getPlayerById(effect.from) local from = room:getPlayerById(effect.from)
print(self.interaction.data)
-- local result = room:askForCustomDialog(from, "simayi", "packages/test/qml/TestDialog.qml", "Hello, world. FROM LUA") -- local result = room:askForCustomDialog(from, "simayi", "packages/test/qml/TestDialog.qml", "Hello, world. FROM LUA")
-- print(result) -- print(result)

View File

@ -30,10 +30,12 @@ Item {
property alias tableCards: tablePile.cards property alias tableCards: tablePile.cards
property alias dashboard: dashboard property alias dashboard: dashboard
property alias skillInteraction: skillInteraction property alias skillInteraction: skillInteraction
property alias miscStatus: miscStatus
property var selected_targets: [] property var selected_targets: []
property string responding_card property string responding_card
property bool respond_play: false property bool respond_play: false
property bool autoPending: false
property var extra_data: ({}) property var extra_data: ({})
Image { Image {
@ -64,6 +66,7 @@ Item {
// tmp // tmp
Button { Button {
id: quitButton
text: "quit" text: "quit"
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
@ -137,6 +140,7 @@ Item {
skillInteraction.source = ""; skillInteraction.source = "";
dashboard.enableCards(responding_card); dashboard.enableCards(responding_card);
dashboard.enableSkills(responding_card); dashboard.enableSkills(responding_card);
autoPending = false;
progress.visible = true; progress.visible = true;
okCancel.visible = true; okCancel.visible = true;
} }
@ -627,6 +631,14 @@ Item {
} }
} }
MiscStatus {
id: miscStatus
anchors.right: quitButton.left
anchors.top: parent.top
anchors.rightMargin: 16
anchors.topMargin: 8
}
Danmaku { Danmaku {
id: danmaku id: danmaku
width: parent.width width: parent.width

View File

@ -88,7 +88,7 @@ Item {
Image { Image {
id: suitItem id: suitItem
visible: known visible: known
source: suit != "" ? SkinBank.CARD_SUIT_DIR + suit : "" source: (suit !== "" && suit !== "nosuit") ? SkinBank.CARD_SUIT_DIR + suit : ""
x: 3 x: 3
y: 19 y: 19
width: 21 width: 21
@ -108,8 +108,8 @@ Item {
Image { Image {
id: colorItem id: colorItem
visible: known && suit == "" visible: known && (suit === "" || suit === "nosuit")
source: (visible && color != "") ? SkinBank.CARD_SUIT_DIR + "/" + color : "" source: (visible && color !== "") ? SkinBank.CARD_SUIT_DIR + "/" + color : ""
x: 1 x: 1
} }

View File

@ -0,0 +1,69 @@
import QtQuick
import "../skin-bank.js" as SkinBank
Item {
id: root
property int pileNum: 0
property int roundNum: 0
property int playedTime: 0
visible: roundNum || pileNum
function getTimeString(time) {
let s = time % 60;
let m = (time - s) / 60;
let h = (time - s - m * 60) / 3600;
return h ? `${h}:${m}:${s}` : `${m}:${s}`;
}
Text {
id: roundTxt
anchors.right: parent.right
text: Backend.translate("#currentRoundNum").arg(roundNum)
color: "#F0E5DA"
font.pixelSize: 18
font.family: fontLibian.name
style: Text.Outline
styleColor: "#3D2D1C"
}
Text {
id: timeTxt
anchors.right: roundTxt.left
anchors.rightMargin: 12
color: "#F0E5DA"
font.pixelSize: 18
font.family: fontLibian.name
style: Text.Outline
styleColor: "#3D2D1C"
}
Timer {
interval: 1000
running: roomScene.isStarted
repeat: true
onTriggered: {
playedTime++;
timeTxt.text = getTimeString(playedTime);
}
}
Image {
id: deckImg
anchors.top: timeTxt.bottom
anchors.topMargin: 8
anchors.right: parent.right
anchors.rightMargin: 12
source: SkinBank.CARD_DIR + "card-back"
width: 32
height: 42
}
Text {
anchors.centerIn: deckImg
font.family: fontLibian.name
font.pixelSize: 32
color: "white"
style: Text.Outline
text: pileNum.toString()
}
}

View File

@ -6,7 +6,6 @@ import QtQuick.Layouts
Item { Item {
id: root id: root
width: 138 width: 138
height: markTxtList.height
ListModel { ListModel {
id: markList id: markList
@ -23,41 +22,44 @@ Item {
border.width: 1 border.width: 1
} }
Repeater {
id: markRepeater
model: markList
Item {
width: childrenRect.width
height: 22
Text {
text: Backend.translate(mark_name) + ' ' + Backend.translate(mark_extra)
font.family: fontLibian.name
font.pixelSize: 22
font.letterSpacing: -0.6
color: "white"
style: Text.Outline
textFormat: Text.RichText
}
TapHandler {
enabled: root.parent.state != "candidate" || !root.parent.selectable
onTapped: {
let data = JSON.parse(Backend.callLuaFunction("GetPile", [root.parent.playerid, mark_name]));
data = data.filter((e) => e !== -1);
if (data.length === 0)
return;
// Just for using room's right drawer
roomScene.startCheat("RoomElement/ViewPile.qml", {
name: mark_name,
ids: data
});
}
}
}
}
ColumnLayout { ColumnLayout {
id: markTxtList id: markTxtList
x: 2 x: 2
spacing: 0 spacing: 0
Repeater {
model: markList
Item {
width: childrenRect.width
height: 22
Text {
text: Backend.translate(mark_name) + ' ' + Backend.translate(mark_extra)
font.family: fontLibian.name
font.pixelSize: 22
color: "white"
style: Text.Outline
textFormat: Text.RichText
}
TapHandler {
enabled: root.parent.state != "candidate" || !root.parent.selectable
onTapped: {
let data = JSON.parse(Backend.callLuaFunction("GetPile", [root.parent.playerid, mark_name]));
data = data.filter((e) => e !== -1);
if (data.length === 0)
return;
// Just for using room's right drawer
roomScene.startCheat("RoomElement/ViewPile.qml", {
name: mark_name,
ids: data
});
}
}
}
}
} }
function setMark(mark, data) { function setMark(mark, data) {
@ -72,6 +74,8 @@ Item {
modelItem.mark_extra = data; modelItem.mark_extra = data;
else else
markList.append({ mark_name: mark, mark_extra: data }); markList.append({ mark_name: mark, mark_extra: data });
arrangeMarks();
} }
function removeMark(mark) { function removeMark(mark) {
@ -79,8 +83,48 @@ Item {
for (i = 0; i < markList.count; i++) { for (i = 0; i < markList.count; i++) {
if (markList.get(i).mark_name === mark) { if (markList.get(i).mark_name === mark) {
markList.remove(i, 1); markList.remove(i, 1);
arrangeMarks();
return; return;
} }
} }
} }
function arrangeMarks() {
let x = 0;
let y = 0;
let i;
let marks = [];
let long_marks = [];
for (i = 0; i < markRepeater.count; i++) {
let item = markRepeater.itemAt(i);
let w = item.width;
if (w < width / 2) marks.push(item);
else long_marks.push(item);
}
marks.concat(long_marks).forEach(item => {
let w = item.width;
if (x === 0) {
item.x = x; item.y = y;
if (w < width / 2) {
x += width / 2;
} else {
x = 0; y += 22;
}
} else {
if (w < width / 2) {
item.x = x; item.y = y;
x = 0; y += 22;
} else {
item.x = 0; item.y = y + 22;
x = 0; y += 44;
}
}
height = x ? y + 22 : y;
});
if (i === 0) height = 0;
}
} }

View File

@ -89,10 +89,16 @@ function doCancelButton() {
dashboard.enableSkills(); dashboard.enableSkills();
return; return;
} else if (roomScene.state == "responding") { } else if (roomScene.state == "responding") {
let p = dashboard.pending_skill;
dashboard.stopPending(); dashboard.stopPending();
dashboard.deactivateSkillButton(); dashboard.deactivateSkillButton();
dashboard.unSelectAll(); dashboard.unSelectAll();
replyToServer("__cancel"); if (roomScene.autoPending || !p) {
replyToServer("__cancel");
} else {
dashboard.enableCards(roomScene.responding_card);
dashboard.enableSkills(roomScene.responding_card);
}
return; return;
} }
@ -788,6 +794,7 @@ callbacks["AskForUseActiveSkill"] = function(jsonData) {
roomScene.respond_play = false; roomScene.respond_play = false;
roomScene.state = "responding"; roomScene.state = "responding";
roomScene.autoPending = true;
dashboard.startPending(skill_name); dashboard.startPending(skill_name);
cancelButton.enabled = cancelable; cancelButton.enabled = cancelable;
} }
@ -1013,3 +1020,13 @@ callbacks["UpdateLimitSkill"] = (j) => {
photo.updateLimitSkill(skill, time); photo.updateLimitSkill(skill, time);
} }
} }
callbacks["UpdateDrawPile"] = (j) => {
let data = parseInt(j);
roomScene.miscStatus.pileNum = data;
}
callbacks["UpdateRoundNum"] = (j) => {
let data = parseInt(j);
roomScene.miscStatus.roundNum = data;
}

View File

@ -106,20 +106,20 @@ void fkMsgHandler(QtMsgType type, const QMessageLogContext &context,
switch (type) { switch (type) {
case QtDebugMsg: case QtDebugMsg:
fprintf(stderr, "[%s/D] %s\n", threadName.constData(), fprintf(stderr, "%s[D] %s\n", threadName.constData(),
localMsg.constData()); localMsg.constData());
break; break;
case QtInfoMsg: case QtInfoMsg:
fprintf(stderr, "[%s/%s] %s\n", threadName.constData(), fprintf(stderr, "%s[%s] %s\n", threadName.constData(),
Color("I", Green).toUtf8().constData(), localMsg.constData()); Color("I", Green).toUtf8().constData(), localMsg.constData());
break; break;
case QtWarningMsg: case QtWarningMsg:
fprintf(stderr, "[%s/%s] %s\n", threadName.constData(), fprintf(stderr, "%s[%s] %s\n", threadName.constData(),
Color("W", Yellow, Bold).toUtf8().constData(), Color("W", Yellow, Bold).toUtf8().constData(),
localMsg.constData()); localMsg.constData());
break; break;
case QtCriticalMsg: case QtCriticalMsg:
fprintf(stderr, "[%s/%s] %s\n", threadName.constData(), fprintf(stderr, "%s[%s] %s\n", threadName.constData(),
Color("C", Red, Bold).toUtf8().constData(), localMsg.constData()); Color("C", Red, Bold).toUtf8().constData(), localMsg.constData());
#ifndef FK_SERVER_ONLY #ifndef FK_SERVER_ONLY
if (Backend != nullptr) { if (Backend != nullptr) {
@ -130,7 +130,7 @@ void fkMsgHandler(QtMsgType type, const QMessageLogContext &context,
#endif #endif
break; break;
case QtFatalMsg: case QtFatalMsg:
fprintf(stderr, "[%s/%s] %s\n", threadName.constData(), fprintf(stderr, "%s[%s] %s\n", threadName.constData(),
Color("E", Red, Bold).toUtf8().constData(), localMsg.constData()); Color("E", Red, Bold).toUtf8().constData(), localMsg.constData());
break; break;
} }