多选、勾选框和bugfix (#284)
- 修复了prompt看不见extra_data的bug - 添加askForChooseBoth用以选择多牌多角色的情况 - 拆分Util以方便开发插件识别 - 大招不再显示武将卡面信息 - 添加勾选框askForCheck,用以提供多选项多选 --------- Co-authored-by: notify <notify-ctrl@qq.com>
This commit is contained in:
parent
379ea06970
commit
513fcf36d7
|
@ -0,0 +1,87 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property bool enabled: true
|
||||||
|
property bool triggered: false
|
||||||
|
property alias text: title.text
|
||||||
|
property alias textColor: title.color
|
||||||
|
property alias textFont: title.font
|
||||||
|
property alias backgroundColor: bg.color
|
||||||
|
property alias border: bg.border
|
||||||
|
property alias iconSource: icon.source
|
||||||
|
property int padding: 5
|
||||||
|
|
||||||
|
signal clicked
|
||||||
|
|
||||||
|
id: button
|
||||||
|
width: icon.width + title.implicitWidth + padding * 2
|
||||||
|
height: Math.max(icon.height, title.implicitHeight) + padding * 2
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: bg
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "black"
|
||||||
|
border.width: 2
|
||||||
|
border.color: "white"
|
||||||
|
opacity: 0.8
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "hovered_checked"; when: hover.hovered && triggered
|
||||||
|
PropertyChanges { target: bg; color: "gold" }
|
||||||
|
PropertyChanges { target: title; color: "black" }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hovered"; when: hover.hovered
|
||||||
|
PropertyChanges { target: bg; color: "white" }
|
||||||
|
PropertyChanges { target: title; color: "black" }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "checked"; when: triggered
|
||||||
|
PropertyChanges { target: border; color: "gold" }
|
||||||
|
PropertyChanges { target: title; color: "gold" }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "disabled"; when: !enabled
|
||||||
|
PropertyChanges { target: button; opacity: 0.2 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
id: mouse
|
||||||
|
onTapped: if (parent.enabled) {
|
||||||
|
triggered = !triggered;
|
||||||
|
parent.clicked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: hover
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
x: padding
|
||||||
|
y: padding
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: icon
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: title
|
||||||
|
font.pixelSize: 18
|
||||||
|
// font.family: "WenQuanYi Micro Hei"
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: ""
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1008,6 +1008,48 @@ callbacks["AskForChoice"] = (jsonData) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callbacks["AskForCheck"] = (jsonData) => {
|
||||||
|
// jsonData: [ string[] choices, string skill ]
|
||||||
|
// TODO: multiple choices, e.g. benxi_ol
|
||||||
|
const data = JSON.parse(jsonData);
|
||||||
|
const choices = data[0];
|
||||||
|
const all_choices = data[1];
|
||||||
|
const min_num = data[2][0];
|
||||||
|
const max_num = data[2][1];
|
||||||
|
const cancelable = data[3];
|
||||||
|
const skill_name = data[4];
|
||||||
|
const prompt = data[5];
|
||||||
|
const detailed = data[6];
|
||||||
|
if (prompt === "") {
|
||||||
|
roomScene.promptText = Backend.translate("#AskForCheck")
|
||||||
|
.arg(Backend.translate(skill_name));
|
||||||
|
} else {
|
||||||
|
roomScene.setPrompt(processPrompt(prompt), true);
|
||||||
|
}
|
||||||
|
roomScene.state = "replying";
|
||||||
|
let qmlSrc;
|
||||||
|
if (!detailed) {
|
||||||
|
qmlSrc = "../RoomElement/CheckBox.qml";
|
||||||
|
} else {
|
||||||
|
qmlSrc = "../RoomElement/DetailedCheckBox.qml";
|
||||||
|
}
|
||||||
|
roomScene.popupBox.sourceComponent = Qt.createComponent(qmlSrc);
|
||||||
|
const box = roomScene.popupBox.item;
|
||||||
|
box.options = choices;
|
||||||
|
box.skill_name = skill_name;
|
||||||
|
box.all_options = all_choices;
|
||||||
|
box.min_num = min_num;
|
||||||
|
box.max_num = max_num;
|
||||||
|
box.cancelable = cancelable;
|
||||||
|
box.accepted.connect(() => {
|
||||||
|
const ret = [];
|
||||||
|
box.result.forEach(id => {
|
||||||
|
ret.push(all_choices[id]);
|
||||||
|
});
|
||||||
|
replyToServer(JSON.stringify(ret));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
callbacks["AskForCardChosen"] = (jsonData) => {
|
callbacks["AskForCardChosen"] = (jsonData) => {
|
||||||
// jsonData: [ int[] handcards, int[] equips, int[] delayedtricks,
|
// jsonData: [ int[] handcards, int[] equips, int[] delayedtricks,
|
||||||
// string reason ]
|
// string reason ]
|
||||||
|
|
|
@ -6,6 +6,7 @@ GeneralsOverview 1.0 GeneralsOverview.qml
|
||||||
Init 1.0 Init.qml
|
Init 1.0 Init.qml
|
||||||
Lobby 1.0 Lobby.qml
|
Lobby 1.0 Lobby.qml
|
||||||
MetroButton 1.0 MetroButton.qml
|
MetroButton 1.0 MetroButton.qml
|
||||||
|
MetroToggleButton 1.0 MetroToggleButton.qml
|
||||||
ModesOverview 1.0 ModesOverview.qml
|
ModesOverview 1.0 ModesOverview.qml
|
||||||
PackageManage 1.0 PackageManage.qml
|
PackageManage 1.0 PackageManage.qml
|
||||||
Room 1.0 Room.qml
|
Room 1.0 Room.qml
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Fk.Pages
|
||||||
|
|
||||||
|
GraphicsBox {
|
||||||
|
property var options: []
|
||||||
|
property var all_options: []
|
||||||
|
property bool cancelable: false
|
||||||
|
property int min_num: 0
|
||||||
|
property int max_num: 0
|
||||||
|
property string skill_name: ""
|
||||||
|
property var result: []
|
||||||
|
|
||||||
|
id: root
|
||||||
|
title.text: Backend.translate("$Choice").arg(Backend.translate(skill_name))
|
||||||
|
width: Math.max(140, body.width + 20)
|
||||||
|
height: buttons.height + body.height + title.height + 20
|
||||||
|
|
||||||
|
function processPrompt(prompt) {
|
||||||
|
const data = prompt.split(":");
|
||||||
|
let raw = Backend.translate(data[0]);
|
||||||
|
const src = parseInt(data[1]);
|
||||||
|
const dest = parseInt(data[2]);
|
||||||
|
if (raw.match("%src")) raw = raw.replace(/%src/g, Backend.translate(getPhoto(src).general));
|
||||||
|
if (raw.match("%dest")) raw = raw.replace(/%dest/g, Backend.translate(getPhoto(dest).general));
|
||||||
|
if (raw.match("%arg2")) raw = raw.replace(/%arg2/g, Backend.translate(data[4]));
|
||||||
|
if (raw.match("%arg")) raw = raw.replace(/%arg/g, Backend.translate(data[3]));
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
id: body
|
||||||
|
// x: 10
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
y: title.height + 5
|
||||||
|
flow: GridLayout.TopToBottom
|
||||||
|
rows: 8
|
||||||
|
columnSpacing: 10
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: all_options
|
||||||
|
|
||||||
|
MetroToggleButton {
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
text: processPrompt(modelData)
|
||||||
|
enabled: options.indexOf(modelData) !== -1 && (root.result.length < max_num || triggered)
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (triggered) {
|
||||||
|
root.result.push(index);
|
||||||
|
} else {
|
||||||
|
root.result.splice(root.result.indexOf(index), 1);
|
||||||
|
}
|
||||||
|
root.result = root.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: buttons
|
||||||
|
anchors.margins: 8
|
||||||
|
anchors.top: body.bottom
|
||||||
|
anchors.horizontalCenter: root.horizontalCenter
|
||||||
|
spacing: 32
|
||||||
|
|
||||||
|
MetroButton {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: processPrompt("OK")
|
||||||
|
enabled: root.result.length >= min_num
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MetroButton {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: processPrompt("Cancel")
|
||||||
|
visible: cancelable
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.result = [];
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Fk.Pages
|
||||||
|
|
||||||
|
GraphicsBox {
|
||||||
|
property var options: []
|
||||||
|
property var all_options: []
|
||||||
|
property bool cancelable: false
|
||||||
|
property int min_num: 0
|
||||||
|
property int max_num: 0
|
||||||
|
property string skill_name: ""
|
||||||
|
property var result: []
|
||||||
|
|
||||||
|
id: root
|
||||||
|
title.text: Backend.translate("$Choice").arg(Backend.translate(skill_name))
|
||||||
|
width: Math.max(140, body.width + 20)
|
||||||
|
height: buttons.height + body.height + title.height + 20
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: body
|
||||||
|
x: 10
|
||||||
|
y: title.height + 5
|
||||||
|
width: Math.min(700, 220 * model.length)
|
||||||
|
height: 300
|
||||||
|
orientation: ListView.Horizontal
|
||||||
|
clip: true
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
|
model: all_options
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
width: 200
|
||||||
|
height: 290
|
||||||
|
|
||||||
|
MetroToggleButton {
|
||||||
|
id: choicetitle
|
||||||
|
width: parent.width
|
||||||
|
text: Backend.translate(modelData)
|
||||||
|
enabled: options.indexOf(modelData) !== -1 && (root.result.length < max_num || triggered)
|
||||||
|
textFont.pixelSize: 24
|
||||||
|
anchors.top: choiceDetail.bottom
|
||||||
|
anchors.topMargin: 8
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (triggered) {
|
||||||
|
root.result.push(index);
|
||||||
|
} else {
|
||||||
|
root.result.splice(root.result.indexOf(index), 1);
|
||||||
|
}
|
||||||
|
root.result = root.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Flickable {
|
||||||
|
id: choiceDetail
|
||||||
|
x: 4
|
||||||
|
height: parent.height - choicetitle.height
|
||||||
|
contentHeight: detail.height
|
||||||
|
width: parent.width
|
||||||
|
clip: true
|
||||||
|
Text {
|
||||||
|
id: detail
|
||||||
|
width: parent.width
|
||||||
|
text: Backend.translate(":" + modelData)
|
||||||
|
color: "white"
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 16
|
||||||
|
textFormat: TextEdit.RichText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: buttons
|
||||||
|
anchors.margins: 8
|
||||||
|
anchors.bottom: root.bottom
|
||||||
|
anchors.horizontalCenter: root.horizontalCenter
|
||||||
|
spacing: 32
|
||||||
|
|
||||||
|
MetroButton {
|
||||||
|
width: 120
|
||||||
|
height: 35
|
||||||
|
text: Backend.translate("OK")
|
||||||
|
enabled: root.result.length >= min_num
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MetroButton {
|
||||||
|
width: 120
|
||||||
|
height: 35
|
||||||
|
text: Backend.translate("Cancel")
|
||||||
|
visible: root.cancelable
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
result = [];
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import Fk.Pages
|
||||||
GraphicsBox {
|
GraphicsBox {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
title.text: Backend.callLuaFunction("PoxiPrompt", [poxi_type, card_data])
|
title.text: Backend.callLuaFunction("PoxiPrompt", [poxi_type, card_data, extra_data])
|
||||||
|
|
||||||
// TODO: Adjust the UI design in case there are more than 7 cards
|
// TODO: Adjust the UI design in case there are more than 7 cards
|
||||||
width: 70 + 700
|
width: 70 + 700
|
||||||
|
@ -116,7 +116,7 @@ GraphicsBox {
|
||||||
width: 120
|
width: 120
|
||||||
height: 35
|
height: 35
|
||||||
text: Backend.translate("Cancel")
|
text: Backend.translate("Cancel")
|
||||||
enabled: root.cancelable
|
visible: root.cancelable
|
||||||
onClicked: root.cardsSelected([])
|
onClicked: root.cardsSelected([])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ Item {
|
||||||
x: root.width + 140
|
x: root.width + 140
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
opacity: 0
|
opacity: 0
|
||||||
|
detailed: false
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
|
|
@ -715,11 +715,11 @@ function GetCardProhibitReason(cid, method, pattern)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function PoxiPrompt(poxi_type, data)
|
function PoxiPrompt(poxi_type, data, extra_data)
|
||||||
local poxi = Fk.poxi_methods[poxi_type]
|
local poxi = Fk.poxi_methods[poxi_type]
|
||||||
if not poxi or not poxi.prompt then return "" end
|
if not poxi or not poxi.prompt then return "" end
|
||||||
if type(poxi.prompt) == "string" then return Fk:translate(poxi.prompt) end
|
if type(poxi.prompt) == "string" then return Fk:translate(poxi.prompt) end
|
||||||
return poxi.prompt(data)
|
return poxi.prompt(data, extra_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
function PoxiFilter(poxi_type, to_select, selected, data, extra_data)
|
function PoxiFilter(poxi_type, to_select, selected, data, extra_data)
|
||||||
|
|
|
@ -159,6 +159,7 @@ Fk:loadTranslationTable({
|
||||||
["#AskForLuckCard"] = "Do you want to use luck card (%1 times left)?",
|
["#AskForLuckCard"] = "Do you want to use luck card (%1 times left)?",
|
||||||
["AskForLuckCard"] = "Luck card",
|
["AskForLuckCard"] = "Luck card",
|
||||||
["#AskForChoice"] = "%1: Please choose",
|
["#AskForChoice"] = "%1: Please choose",
|
||||||
|
["#AskForCheck"] = "%1: Please choose",
|
||||||
["#choose-trigger"] = "Please choose the skill to use",
|
["#choose-trigger"] = "Please choose the skill to use",
|
||||||
["trigger"] = "Trigger skill",
|
["trigger"] = "Trigger skill",
|
||||||
-- ["Please arrange cards"] = "请拖拽移动卡牌",
|
-- ["Please arrange cards"] = "请拖拽移动卡牌",
|
||||||
|
@ -169,6 +170,7 @@ Fk:loadTranslationTable({
|
||||||
["AskForGuanxing"] = "Stargazing",
|
["AskForGuanxing"] = "Stargazing",
|
||||||
["AskForExchange"] = "Exchaging",
|
["AskForExchange"] = "Exchaging",
|
||||||
["AskForChoice"] = "Making choice",
|
["AskForChoice"] = "Making choice",
|
||||||
|
["AskForCheck"] = "Making choice",
|
||||||
["AskForKingdom"] = "Choosing kingdom",
|
["AskForKingdom"] = "Choosing kingdom",
|
||||||
["AskForPindian"] = "Point fight",
|
["AskForPindian"] = "Point fight",
|
||||||
["AskForMoveCardInBoard"] = "Moving cards",
|
["AskForMoveCardInBoard"] = "Moving cards",
|
||||||
|
|
|
@ -205,6 +205,7 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下
|
||||||
["#AskForLuckCard"] = "你想使用手气卡吗?还可以使用 %1 次,剩余手气卡∞张",
|
["#AskForLuckCard"] = "你想使用手气卡吗?还可以使用 %1 次,剩余手气卡∞张",
|
||||||
["AskForLuckCard"] = "手气卡",
|
["AskForLuckCard"] = "手气卡",
|
||||||
["#AskForChoice"] = "%1:请选择",
|
["#AskForChoice"] = "%1:请选择",
|
||||||
|
["#AskForCheck"] = "%1:请选择",
|
||||||
["#choose-trigger"] = "请选择一项技能发动",
|
["#choose-trigger"] = "请选择一项技能发动",
|
||||||
["trigger"] = "选择技能",
|
["trigger"] = "选择技能",
|
||||||
["Please arrange cards"] = "请拖拽移动卡牌",
|
["Please arrange cards"] = "请拖拽移动卡牌",
|
||||||
|
@ -215,6 +216,7 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下
|
||||||
["AskForGuanxing"] = "观星",
|
["AskForGuanxing"] = "观星",
|
||||||
["AskForExchange"] = "换牌",
|
["AskForExchange"] = "换牌",
|
||||||
["AskForChoice"] = "选择",
|
["AskForChoice"] = "选择",
|
||||||
|
["AskForCheck"] = "选择",
|
||||||
["AskForKingdom"] = "选择势力",
|
["AskForKingdom"] = "选择势力",
|
||||||
["AskForPindian"] = "拼点",
|
["AskForPindian"] = "拼点",
|
||||||
["AskForMoveCardInBoard"] = "移动卡牌",
|
["AskForMoveCardInBoard"] = "移动卡牌",
|
||||||
|
|
|
@ -52,6 +52,24 @@ Util.convertSubtypeAndEquipSlot = function(value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- 根据花色文字描述(如 黑桃、红桃、梅花、方块)或者符号(如♠♥♣♦,带颜色)返回花色ID。
|
||||||
|
---@param symbol string @ 描述/符号(原文,确保没被翻译过)
|
||||||
|
---@return Suit @ 花色ID
|
||||||
|
Util.getSuitFromString = function(symbol)
|
||||||
|
assert(type(symbol) == "string")
|
||||||
|
if symbol:find("spade") then
|
||||||
|
return Card.Spade
|
||||||
|
elseif symbol:find("heart") then
|
||||||
|
return Card.Heart
|
||||||
|
elseif symbol:find("club") then
|
||||||
|
return Card.Club
|
||||||
|
elseif symbol:find("diamond") then
|
||||||
|
return Card.Diamond
|
||||||
|
else
|
||||||
|
return Card.NoSuit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function printf(fmt, ...)
|
function printf(fmt, ...)
|
||||||
print(string.format(fmt, ...))
|
print(string.format(fmt, ...))
|
||||||
end
|
end
|
||||||
|
@ -118,14 +136,22 @@ function table:map(func)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- frequenly used filter & map functions
|
-- frequenly used filter & map functions
|
||||||
|
|
||||||
|
--- 返回ID
|
||||||
Util.IdMapper = function(e) return e.id end
|
Util.IdMapper = function(e) return e.id end
|
||||||
|
--- 根据卡牌ID返回卡牌
|
||||||
Util.Id2CardMapper = function(id) return Fk:getCardById(id) end
|
Util.Id2CardMapper = function(id) return Fk:getCardById(id) end
|
||||||
|
--- 根据玩家ID返回玩家
|
||||||
Util.Id2PlayerMapper = function(id)
|
Util.Id2PlayerMapper = function(id)
|
||||||
return Fk:currentRoom():getPlayerById(id)
|
return Fk:currentRoom():getPlayerById(id)
|
||||||
end
|
end
|
||||||
|
--- 返回武将名
|
||||||
Util.NameMapper = function(e) return e.name end
|
Util.NameMapper = function(e) return e.name end
|
||||||
|
--- 根据武将名返回武将
|
||||||
Util.Name2GeneralMapper = function(e) return Fk.generals[e] end
|
Util.Name2GeneralMapper = function(e) return Fk.generals[e] end
|
||||||
|
--- 根据技能名返回技能
|
||||||
Util.Name2SkillMapper = function(e) return Fk.skills[e] end
|
Util.Name2SkillMapper = function(e) return Fk.skills[e] end
|
||||||
|
--- 返回译文
|
||||||
Util.TranslateMapper = function(str) return Fk:translate(str) end
|
Util.TranslateMapper = function(str) return Fk:translate(str) end
|
||||||
|
|
||||||
-- for card preset
|
-- for card preset
|
||||||
|
|
|
@ -179,7 +179,7 @@ end
|
||||||
---@field public on_effect nil|fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): bool
|
---@field public on_effect nil|fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): bool
|
||||||
---@field public on_nullified nil|fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): bool
|
---@field public on_nullified nil|fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): bool
|
||||||
---@field public mod_target_filter nil|fun(self: ActiveSkill, to_select: integer, selected: integer[], user: integer, card: Card, distance_limited: boolean): bool
|
---@field public mod_target_filter nil|fun(self: ActiveSkill, to_select: integer, selected: integer[], user: integer, card: Card, distance_limited: boolean): bool
|
||||||
---@field public prompt nil|string|fun(self: ActiveSkill, selected: integer[], selected_cards: integer[]): string
|
---@field public prompt nil|string|fun(self: ActiveSkill, selected_cards: integer[], selected_targets: integer[]): string
|
||||||
---@field public interaction any
|
---@field public interaction any
|
||||||
|
|
||||||
---@param spec ActiveSkillSpec
|
---@param spec ActiveSkillSpec
|
||||||
|
|
|
@ -18,7 +18,8 @@ math.randomseed(os.time())
|
||||||
|
|
||||||
-- 加载实用类,让Lua编写起来更轻松。
|
-- 加载实用类,让Lua编写起来更轻松。
|
||||||
local Utils = require "core.util"
|
local Utils = require "core.util"
|
||||||
TargetGroup, AimGroup, Util = table.unpack(Utils)
|
-- TargetGroup, AimGroup, Util = table.unpack(Utils)
|
||||||
|
TargetGroup, AimGroup, Util = Utils[1], Utils[2], Utils[3]
|
||||||
dofile "lua/core/debug.lua"
|
dofile "lua/core/debug.lua"
|
||||||
|
|
||||||
-- 加载游戏核心类
|
-- 加载游戏核心类
|
||||||
|
|
|
@ -1052,7 +1052,7 @@ end
|
||||||
---@param cancelable bool @ 是否可以点取消
|
---@param cancelable bool @ 是否可以点取消
|
||||||
---@param extra_data table|nil @ 额外信息,因技能而异了
|
---@param extra_data table|nil @ 额外信息,因技能而异了
|
||||||
---@param no_indicate bool @ 是否不显示指示线
|
---@param no_indicate bool @ 是否不显示指示线
|
||||||
---@return boolean, table
|
---@return boolean, table|nil
|
||||||
function Room:askForUseActiveSkill(player, skill_name, prompt, cancelable, extra_data, no_indicate)
|
function Room:askForUseActiveSkill(player, skill_name, prompt, cancelable, extra_data, no_indicate)
|
||||||
prompt = prompt or ""
|
prompt = prompt or ""
|
||||||
cancelable = (cancelable == nil) and true or cancelable
|
cancelable = (cancelable == nil) and true or cancelable
|
||||||
|
@ -1322,6 +1322,55 @@ function Room:askForChooseCardAndPlayers(player, targets, minNum, maxNum, patter
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- 询问玩家选择X张牌和Y名角色。
|
||||||
|
---
|
||||||
|
--- 返回两个值,第一个是选择的目标列表,第二个是选择的那张牌的id
|
||||||
|
---@param player ServerPlayer @ 要询问的玩家
|
||||||
|
---@param minCardNum integer @ 选卡牌最小值
|
||||||
|
---@param maxCardNum integer @ 选卡牌最大值
|
||||||
|
---@param targets integer[] @ 选择目标的id范围
|
||||||
|
---@param minTargetNum integer @ 选目标最小值
|
||||||
|
---@param maxTargetNum integer @ 选目标最大值
|
||||||
|
---@param pattern string|nil @ 选牌规则
|
||||||
|
---@param prompt string|nil @ 提示信息
|
||||||
|
---@param cancelable bool @ 能否点取消
|
||||||
|
---@param no_indicate bool @ 是否不显示指示线
|
||||||
|
---@return integer[], integer[]
|
||||||
|
function Room:askForChooseBoth(player, minCardNum, maxCardNum, targets, minTargetNum, maxTargetNum, pattern, prompt, skillName, cancelable, no_indicate)
|
||||||
|
if minCardNum < 1 or minTargetNum < 1 then
|
||||||
|
return table.unpack({}, {})
|
||||||
|
end
|
||||||
|
cancelable = (cancelable == nil) and true or cancelable
|
||||||
|
no_indicate = no_indicate or false
|
||||||
|
pattern = pattern or "."
|
||||||
|
|
||||||
|
local pcards = table.filter(player:getCardIds({ Player.Hand, Player.Equip }), function(id)
|
||||||
|
local c = Fk:getCardById(id)
|
||||||
|
return c:matchPattern(pattern)
|
||||||
|
end)
|
||||||
|
if #pcards < minCardNum and not cancelable then return table.unpack({}, {}) end
|
||||||
|
|
||||||
|
local data = {
|
||||||
|
targets = targets,
|
||||||
|
max_target_num = maxTargetNum,
|
||||||
|
min_target_num = minTargetNum,
|
||||||
|
max_card_num = maxCardNum,
|
||||||
|
min_card_num = minCardNum,
|
||||||
|
pattern = pattern,
|
||||||
|
skillName = skillName,
|
||||||
|
}
|
||||||
|
local _, ret = self:askForUseActiveSkill(player, "ex__choose_skill", prompt or "", cancelable, data, no_indicate)
|
||||||
|
if ret then
|
||||||
|
return ret.targets, ret.cards
|
||||||
|
else
|
||||||
|
if cancelable then
|
||||||
|
return table.unpack({}, {})
|
||||||
|
else
|
||||||
|
return table.random(targets, minTargetNum), table.random(pcards, minCardNum)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- 抽个武将
|
--- 抽个武将
|
||||||
---
|
---
|
||||||
--- 同getNCards,抽出来就没有了,所以记得放回去。
|
--- 同getNCards,抽出来就没有了,所以记得放回去。
|
||||||
|
@ -1609,6 +1658,35 @@ function Room:askForChoice(player, choices, skill_name, prompt, detailed, all_ch
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- 询问一名玩家从众多选项中勾选任意项。
|
||||||
|
---@param player ServerPlayer @ 要询问的玩家
|
||||||
|
---@param choices string[] @ 可选选项列表
|
||||||
|
---@param minNum number @ 最少选择项数
|
||||||
|
---@param maxNum number @ 最多选择项数
|
||||||
|
---@param skill_name string|nil @ 技能名
|
||||||
|
---@param prompt string|nil @ 提示信息
|
||||||
|
---@param cancelable bool|nil @ 是否可取消
|
||||||
|
---@param detailed bool @ 选项详细描述
|
||||||
|
---@param all_choices string[]|nil @ 所有选项(不可选变灰)
|
||||||
|
---@return string[] @ 选择的选项
|
||||||
|
function Room:askForCheck(player, choices, minNum, maxNum, skill_name, prompt, cancelable, detailed, all_choices)
|
||||||
|
cancelable = (cancelable == nil) and true or cancelable
|
||||||
|
if #choices <= minNum and not all_choices then return choices end
|
||||||
|
assert(minNum <= maxNum)
|
||||||
|
assert(not all_choices or table.every(choices, function(c) return table.contains(all_choices, c) end))
|
||||||
|
local command = "AskForCheck"
|
||||||
|
skill_name = skill_name or ""
|
||||||
|
prompt = prompt or ""
|
||||||
|
all_choices = all_choices or choices
|
||||||
|
detailed = detailed or false
|
||||||
|
self:notifyMoveFocus(player, skill_name)
|
||||||
|
local result = self:doRequest(player, command, json.encode{
|
||||||
|
choices, all_choices, {minNum, maxNum}, cancelable, skill_name, prompt, detailed
|
||||||
|
})
|
||||||
|
if result == "" then return {} end
|
||||||
|
return json.decode(result)
|
||||||
|
end
|
||||||
|
|
||||||
--- 询问玩家是否发动技能。
|
--- 询问玩家是否发动技能。
|
||||||
---@param player ServerPlayer @ 要询问的玩家
|
---@param player ServerPlayer @ 要询问的玩家
|
||||||
---@param skill_name string @ 技能名
|
---@param skill_name string @ 技能名
|
||||||
|
|
|
@ -92,6 +92,23 @@ local choosePlayersSkill = fk.CreateActiveSkill{
|
||||||
max_target_num = function(self) return self.num end,
|
max_target_num = function(self) return self.num end,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local exChooseSkill = fk.CreateActiveSkill{
|
||||||
|
name = "ex__choose_skill",
|
||||||
|
card_filter = function(self, to_select, selected)
|
||||||
|
return self.pattern ~= "" and Exppattern:Parse(self.pattern):match(Fk:getCardById(to_select)) and #selected < self.max_card_num
|
||||||
|
end,
|
||||||
|
target_filter = function(self, to_select, selected, cards)
|
||||||
|
if self.pattern ~= "" and #cards < self.min_card_num then return end
|
||||||
|
if #selected < self.max_target_num then
|
||||||
|
return table.contains(self.targets, to_select)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
min_target_num = function(self) return self.min_target_num end,
|
||||||
|
max_target_num = function(self) return self.max_target_num end,
|
||||||
|
min_card_num = function(self) return self.min_card_num end,
|
||||||
|
max_card_num = function(self) return self.max_card_num end,
|
||||||
|
}
|
||||||
|
|
||||||
local maxCardsSkill = fk.CreateMaxCardsSkill{
|
local maxCardsSkill = fk.CreateMaxCardsSkill{
|
||||||
name = "max_cards_skill",
|
name = "max_cards_skill",
|
||||||
global = true,
|
global = true,
|
||||||
|
@ -222,6 +239,7 @@ AuxSkills = {
|
||||||
discardSkill,
|
discardSkill,
|
||||||
chooseCardsSkill,
|
chooseCardsSkill,
|
||||||
choosePlayersSkill,
|
choosePlayersSkill,
|
||||||
|
exChooseSkill,
|
||||||
maxCardsSkill,
|
maxCardsSkill,
|
||||||
choosePlayersToMoveCardInBoardSkill,
|
choosePlayersToMoveCardInBoardSkill,
|
||||||
uncompulsoryInvalidity,
|
uncompulsoryInvalidity,
|
||||||
|
|
Loading…
Reference in New Issue