Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
YoumuKon | 9b02623992 | |
YoumuKon | 0d2dd3a623 | |
YoumuKon | 5a1bd8c81e | |
YoumuKon | e30b9aa451 | |
YoumuKon | 5baf58279b | |
YoumuKon | 87bc525f0b | |
YoumuKon | aff3f4e7a9 | |
YoumuKon | 874e681868 |
|
@ -1192,6 +1192,45 @@ callbacks["AskForPoxi"] = (jsonData) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callbacks["AskForYuqi"] = (jsonData) => {
|
||||||
|
const { type, data, extra_data, cancelable } = JSON.parse(jsonData);
|
||||||
|
|
||||||
|
roomScene.state = "replying";
|
||||||
|
roomScene.popupBox.sourceComponent =
|
||||||
|
Qt.createComponent("../RoomElement/YuqiBox.qml");
|
||||||
|
const box = roomScene.popupBox.item;
|
||||||
|
const area_names = [];
|
||||||
|
const card_data = [];
|
||||||
|
const card_items = [];
|
||||||
|
const carditems = [];
|
||||||
|
for (let d of data) {
|
||||||
|
const arr = d[0];
|
||||||
|
const card_arr = [];
|
||||||
|
const ids = d[1];
|
||||||
|
|
||||||
|
area_names.push(arr);
|
||||||
|
card_data.push(ids);
|
||||||
|
ids.forEach(id => {
|
||||||
|
const cdata = lcall("GetCardData", id)
|
||||||
|
card_arr.push(cdata);
|
||||||
|
carditems.push(cdata);
|
||||||
|
});
|
||||||
|
card_items.push(card_arr);
|
||||||
|
}
|
||||||
|
box.yuqi_type = type;
|
||||||
|
box.areaNames = area_names;
|
||||||
|
box.pilecards = card_data;
|
||||||
|
box.extra_data = extra_data;
|
||||||
|
box.cancelable = cancelable;
|
||||||
|
|
||||||
|
box.cards = carditems;
|
||||||
|
box.initializeCards();
|
||||||
|
roomScene.popupBox.moveToCenter();
|
||||||
|
box.cardsSelected.connect((ids) => {
|
||||||
|
replyToServer(JSON.stringify(ids));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
callbacks["AskForMoveCardInBoard"] = (jsonData) => {
|
callbacks["AskForMoveCardInBoard"] = (jsonData) => {
|
||||||
const data = JSON.parse(jsonData);
|
const data = JSON.parse(jsonData);
|
||||||
const { cards, cardsPosition, generalNames, playerIds } = data;
|
const { cards, cardsPosition, generalNames, playerIds } = data;
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Fk
|
||||||
|
import Fk.Pages
|
||||||
|
|
||||||
|
GraphicsBox {
|
||||||
|
id: root
|
||||||
|
property string yuqi_type
|
||||||
|
property var cards: [] //全体卡牌枚举
|
||||||
|
property var result: [] //最终牌堆
|
||||||
|
property var pilecards: [] //初始牌堆
|
||||||
|
property var areaNames: [] //牌堆名
|
||||||
|
property bool cancelable: true
|
||||||
|
property var extra_data
|
||||||
|
property int padding: 25
|
||||||
|
|
||||||
|
signal cardsSelected(var ids)
|
||||||
|
|
||||||
|
title.text: ""
|
||||||
|
|
||||||
|
width: body.width + padding * 2
|
||||||
|
height: title.height + body.height + padding * 2
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: body
|
||||||
|
x: padding
|
||||||
|
y: parent.height - padding - height
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: areaRepeater
|
||||||
|
model: pilecards
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
color: "#6B5D42"
|
||||||
|
width: 20
|
||||||
|
height: 100
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
width: 20
|
||||||
|
height: 100
|
||||||
|
text: areaNames.length > index ? qsTr(areaNames[index]) : ""
|
||||||
|
color: "white"
|
||||||
|
font.family: fontLibian.name
|
||||||
|
font.pixelSize: 18
|
||||||
|
style: Text.Outline
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: cardsArea
|
||||||
|
color: "#1D1E19"
|
||||||
|
width: 800
|
||||||
|
height: 130
|
||||||
|
|
||||||
|
}
|
||||||
|
property alias cardsArea: cardsArea
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.margins: 8
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
spacing: 32
|
||||||
|
|
||||||
|
MetroButton {
|
||||||
|
width: 120
|
||||||
|
height: 35
|
||||||
|
text: luatr("OK")
|
||||||
|
enabled: lcall("YuqiFeasible", root.yuqi_type, root.getResult(),
|
||||||
|
root.pilecards, root.extra_data);
|
||||||
|
onClicked: root.cardsSelected(root.getResult())
|
||||||
|
}
|
||||||
|
|
||||||
|
MetroButton {
|
||||||
|
width: 120
|
||||||
|
height: 35
|
||||||
|
text: luatr("Cancel")
|
||||||
|
visible: root.cancelable
|
||||||
|
onClicked: root.cardsSelected([])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: cardsItem
|
||||||
|
model: cards
|
||||||
|
|
||||||
|
CardItem {
|
||||||
|
x: index
|
||||||
|
y: -1
|
||||||
|
cid: modelData.cid
|
||||||
|
name: modelData.name
|
||||||
|
suit: modelData.suit
|
||||||
|
number: modelData.number
|
||||||
|
draggable: true
|
||||||
|
onReleased: updateCardsReleased(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCardsReleased(card) {
|
||||||
|
let orig, from, to;
|
||||||
|
let i, j;
|
||||||
|
const result_cards = getResult();
|
||||||
|
for (i = 0; i < pilecards.count; i++) {
|
||||||
|
const _pile = result[i];
|
||||||
|
const box = pile.cardsArea;
|
||||||
|
const pos = mapFromItem(pile, box.x, box.y);
|
||||||
|
const posid = _pile.indexOf(card)
|
||||||
|
if (posid !== -1) {
|
||||||
|
from = i;
|
||||||
|
orig = posid;
|
||||||
|
}
|
||||||
|
const spacing = (_pile.length > 8) ? (700 / (_pile.length - 1)) : 100
|
||||||
|
if (Math.abs(card.y - pos.y) <= spacing / 2) {
|
||||||
|
to = i
|
||||||
|
}
|
||||||
|
console.log(pos.x, pos.y);
|
||||||
|
console.log(card.x, card.y);
|
||||||
|
console.log(from, to);
|
||||||
|
if (from !== null && to !== null) {
|
||||||
|
if (pilecards[to].indexOf(card) === -1 && !lcall("YuqiEntryFilter", root.yuqi_type, card.cid, from, to,
|
||||||
|
result_cards, root.extra_data) ) break;
|
||||||
|
result[from].splice(orig, 1)
|
||||||
|
for (j = 0; j < result[0].length; j++) {
|
||||||
|
let _card = result[orig][i]
|
||||||
|
if (Math.abs(card.x - _card.x) <= card.width / 2) {
|
||||||
|
result[to].splice(j, 0, card);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arrangeCards();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeCards() {
|
||||||
|
result = new Array(areaNames.length);
|
||||||
|
let i;
|
||||||
|
for (i = 0; i < result.length; i++){
|
||||||
|
result[i] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
let card;
|
||||||
|
let j = 0;
|
||||||
|
for (i = 0; i < cardsItem.count; i++) {
|
||||||
|
card = cardsItem.itemAt(i);
|
||||||
|
console.log(pilecards[j]);
|
||||||
|
if (i < pilecards[j].length) {
|
||||||
|
result[j].push(card);
|
||||||
|
} else {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arrangeCards();
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrangeCards() {
|
||||||
|
let i, j;
|
||||||
|
let card, box, pos, pile;
|
||||||
|
let spacing;
|
||||||
|
const result_cards = getResult();
|
||||||
|
for (j = 0; j < pilecards.length; j++){
|
||||||
|
pile = areaRepeater.itemAt(j);
|
||||||
|
if (pile.y === 0){
|
||||||
|
pile.y = j * 150
|
||||||
|
}
|
||||||
|
spacing = (result[j].length > 8) ? (700 / (result[j].length - 1)) : 100
|
||||||
|
for (i = 0; i < result[j].length; i++) {
|
||||||
|
box = pile.cardsArea;
|
||||||
|
pos = mapFromItem(pile, box.x, box.y);
|
||||||
|
card = result[j][i];
|
||||||
|
card.draggable = lcall("YuqiOutFilter", root.yuqi_type, card.cid, j,
|
||||||
|
result_cards, root.extra_data);
|
||||||
|
card.origX = pos.x + i * spacing;
|
||||||
|
card.origY = pos.y;
|
||||||
|
card.z = i + 1;
|
||||||
|
card.initialZ = i + 1;
|
||||||
|
card.maxZ = result[j].length;
|
||||||
|
card.goBack(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refreshPrompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getResult() {
|
||||||
|
const ret = [];
|
||||||
|
result.forEach(t => {
|
||||||
|
const t2 = [];
|
||||||
|
t.forEach(v => t2.push(v.cid));
|
||||||
|
ret.push(t2);
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshPrompt() {
|
||||||
|
root.title.text = Util.processPrompt(lcall("YuqiPrompt", yuqi_type, root.result, root.pilecards, extra_data))
|
||||||
|
}
|
||||||
|
}
|
|
@ -781,4 +781,29 @@ function GetMiniGame(gtype, p, data)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function YuqiPrompt(yuqi_type, data, extra_data)
|
||||||
|
local yuqi = Fk.yuqi_methods[yuqi_type]
|
||||||
|
if not yuqi or not yuqi.prompt then return "" end
|
||||||
|
if type(yuqi.prompt) == "string" then return Fk:translate(yuqi.prompt) end
|
||||||
|
return yuqi.prompt(data, extra_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
function YuqiEntryFilter(yuqi_type, to_select, from_pile, to_pile, data, extra_data)
|
||||||
|
local yuqi = Fk.yuqi_methods[yuqi_type]
|
||||||
|
if not yuqi then return "false" end
|
||||||
|
return json.encode(yuqi.entry_filter(to_select, from_pile + 1, to_pile + 1, data, extra_data))
|
||||||
|
end
|
||||||
|
|
||||||
|
function YuqiOutFilter(yuqi_type, to_select, from_pile, data, extra_data)
|
||||||
|
local yuqi = Fk.yuqi_methods[yuqi_type]
|
||||||
|
if not yuqi then return "false" end
|
||||||
|
return json.encode(yuqi.out_filter(to_select, from_pile + 1, data, extra_data))
|
||||||
|
end
|
||||||
|
|
||||||
|
function YuqiFeasible(yuqi_type, current, origin, extra_data)
|
||||||
|
local yuqi = Fk.yuqi_methods[yuqi_type]
|
||||||
|
if not yuqi then return "false" end
|
||||||
|
return json.encode(yuqi.feasible(current, origin, extra_data))
|
||||||
|
end
|
||||||
|
|
||||||
dofile "lua/client/i18n/init.lua"
|
dofile "lua/client/i18n/init.lua"
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
---@field public poxi_methods table<string, PoxiSpec> @ “魄袭”框操作方法表
|
---@field public poxi_methods table<string, PoxiSpec> @ “魄袭”框操作方法表
|
||||||
---@field public qml_marks table<string, QmlMarkSpec> @ 自定义Qml标记的表
|
---@field public qml_marks table<string, QmlMarkSpec> @ 自定义Qml标记的表
|
||||||
---@field public mini_games table<string, MiniGameSpec> @ 自定义多人交互表
|
---@field public mini_games table<string, MiniGameSpec> @ 自定义多人交互表
|
||||||
|
---@field public yuqi_methods table<string, YuqiSpec> @ “隅泣”框操作方法表
|
||||||
local Engine = class("Engine")
|
local Engine = class("Engine")
|
||||||
|
|
||||||
--- Engine的构造函数。
|
--- Engine的构造函数。
|
||||||
|
@ -71,6 +72,7 @@ function Engine:initialize()
|
||||||
self.poxi_methods = {}
|
self.poxi_methods = {}
|
||||||
self.qml_marks = {}
|
self.qml_marks = {}
|
||||||
self.mini_games = {}
|
self.mini_games = {}
|
||||||
|
self.yuqi_methods = {}
|
||||||
|
|
||||||
self:loadPackages()
|
self:loadPackages()
|
||||||
self:loadDisabled()
|
self:loadDisabled()
|
||||||
|
@ -357,6 +359,7 @@ function Engine:addGameEvent(name, pfunc, mfunc, cfunc, efunc)
|
||||||
table.insert(self._custom_events, { name = name, p = pfunc, m = mfunc, c = cfunc, e = efunc })
|
table.insert(self._custom_events, { name = name, p = pfunc, m = mfunc, c = cfunc, e = efunc })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- 向Engine中添加一个魄袭用方法。
|
||||||
---@param spec PoxiSpec
|
---@param spec PoxiSpec
|
||||||
function Engine:addPoxiMethod(spec)
|
function Engine:addPoxiMethod(spec)
|
||||||
assert(type(spec.name) == "string")
|
assert(type(spec.name) == "string")
|
||||||
|
@ -370,6 +373,7 @@ function Engine:addPoxiMethod(spec)
|
||||||
spec.post_select = spec.post_select or function(s) return s end
|
spec.post_select = spec.post_select or function(s) return s end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- 向Engine中添加一个QML标记方法。
|
||||||
---@param spec QmlMarkSpec
|
---@param spec QmlMarkSpec
|
||||||
function Engine:addQmlMark(spec)
|
function Engine:addQmlMark(spec)
|
||||||
assert(type(spec.name) == "string")
|
assert(type(spec.name) == "string")
|
||||||
|
@ -379,6 +383,7 @@ function Engine:addQmlMark(spec)
|
||||||
self.qml_marks[spec.name] = spec
|
self.qml_marks[spec.name] = spec
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- 向Engine中添加一个多人交互用方法。
|
||||||
---@param spec MiniGameSpec
|
---@param spec MiniGameSpec
|
||||||
function Engine:addMiniGame(spec)
|
function Engine:addMiniGame(spec)
|
||||||
assert(type(spec.name) == "string")
|
assert(type(spec.name) == "string")
|
||||||
|
@ -388,6 +393,16 @@ function Engine:addMiniGame(spec)
|
||||||
self.mini_games[spec.name] = spec
|
self.mini_games[spec.name] = spec
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- 向Engine中添加一个隅泣用方法。
|
||||||
|
---@param spec YuqiSpec
|
||||||
|
function Engine:addYuqiMethod(spec)
|
||||||
|
assert(type(spec.name) == "string")
|
||||||
|
self.yuqi_methods[spec.name] = spec
|
||||||
|
spec.entry_filter = spec.entry_filter or Util.TrueFunc
|
||||||
|
spec.out_filter = spec.out_filter or Util.TrueFunc
|
||||||
|
spec.feasible = spec.feasible or Util.TrueFunc
|
||||||
|
end
|
||||||
|
|
||||||
--- 从已经开启的拓展包中,随机选出若干名武将。
|
--- 从已经开启的拓展包中,随机选出若干名武将。
|
||||||
---
|
---
|
||||||
--- 对于同名武将不会重复选取。
|
--- 对于同名武将不会重复选取。
|
||||||
|
|
|
@ -632,3 +632,10 @@ end
|
||||||
---@field qml_path string | fun(player: Player, data: any): string
|
---@field qml_path string | fun(player: Player, data: any): string
|
||||||
---@field update_func? fun(player: ServerPlayer, data: any)
|
---@field update_func? fun(player: ServerPlayer, data: any)
|
||||||
---@field default_choice? fun(player: ServerPlayer, data: any): any
|
---@field default_choice? fun(player: ServerPlayer, data: any): any
|
||||||
|
|
||||||
|
---@class YuqiSpec
|
||||||
|
---@field name string
|
||||||
|
---@field feasible? fun(current_data: any, old_data: any, extra_data: any): bool
|
||||||
|
---@field entry_filter? fun(card: int, from_pile: int, to_pile: int, data: any, extra_data: any): bool
|
||||||
|
---@field out_filter? fun(card: int, from_pile: int, data: any, extra_data: any): bool
|
||||||
|
---@field prompt? string | fun(data: any, extra_data: any): string
|
||||||
|
|
|
@ -1756,6 +1756,31 @@ function Room:askForPoxi(player, poxi_type, data, extra_data, cancelable)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- 咕了太久的隅泣
|
||||||
|
---
|
||||||
|
--- data填入所有卡的列表(类似ui.card_data)
|
||||||
|
---@param player ServerPlayer
|
||||||
|
---@param yuqi_type string
|
||||||
|
---@param data any
|
||||||
|
---@param extra_data any
|
||||||
|
---@param cancelable? boolean
|
||||||
|
---@return integer[]
|
||||||
|
function Room:askForYuqi(player, yuqi_type, data, extra_data, cancelable)
|
||||||
|
local yuqi = Fk.yuqi_methods[yuqi_type]
|
||||||
|
if not yuqi then return {} end
|
||||||
|
|
||||||
|
local command = "AskForYuqi"
|
||||||
|
self:notifyMoveFocus(player, yuqi_type)
|
||||||
|
local result = self:doRequest(player, command, json.encode {
|
||||||
|
type = yuqi_type,
|
||||||
|
data = data,
|
||||||
|
extra_data = extra_data,
|
||||||
|
cancelable = (cancelable == nil) and true or cancelable
|
||||||
|
})
|
||||||
|
|
||||||
|
return result == "" and {} or json.decode(result)
|
||||||
|
end
|
||||||
|
|
||||||
--- 询问一名玩家从众多选项中选择一个。
|
--- 询问一名玩家从众多选项中选择一个。
|
||||||
---@param player ServerPlayer @ 要询问的玩家
|
---@param player ServerPlayer @ 要询问的玩家
|
||||||
---@param choices string[] @ 可选选项列表
|
---@param choices string[] @ 可选选项列表
|
||||||
|
|
|
@ -83,6 +83,11 @@ local control = fk.CreateActiveSkill{
|
||||||
-- p(room:askForYiji(from, from:getCardIds(Player.Hand), table.map(effect.tos, Util.Id2PlayerMapper), self.name, 2, 10, nil, false, nil, false, 3, true))
|
-- p(room:askForYiji(from, from:getCardIds(Player.Hand), table.map(effect.tos, Util.Id2PlayerMapper), self.name, 2, 10, nil, false, nil, false, 3, true))
|
||||||
for _, pid in ipairs(effect.tos) do
|
for _, pid in ipairs(effect.tos) do
|
||||||
local to = room:getPlayerById(pid)
|
local to = room:getPlayerById(pid)
|
||||||
|
p(room:askForYuqi(from, "test", {
|
||||||
|
{"牌堆顶", table.slice(room.draw_pile, 1, 7)},
|
||||||
|
{"你自己", {}},
|
||||||
|
{"对方", {}},
|
||||||
|
}, to.hp, true))
|
||||||
-- p(room:askForPoxi(from, "test", {
|
-- p(room:askForPoxi(from, "test", {
|
||||||
-- { "你自己", from:getCardIds "h" },
|
-- { "你自己", from:getCardIds "h" },
|
||||||
-- { "对方", to:getCardIds "h" },
|
-- { "对方", to:getCardIds "h" },
|
||||||
|
@ -130,6 +135,16 @@ local control = fk.CreateActiveSkill{
|
||||||
-- room:useVirtualCard("slash", nil, from, room:getOtherPlayers(from), self.name, true)
|
-- room:useVirtualCard("slash", nil, from, room:getOtherPlayers(from), self.name, true)
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
Fk:addYuqiMethod{
|
||||||
|
name = "test",
|
||||||
|
prompt = "隅泣:请分配这些卡牌",
|
||||||
|
entry_filter = function(card, from_pile, to_pile, data, extra_data)
|
||||||
|
if table.contains({2, 3}, to_pile) and #data[to_pile] >= 5 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
}
|
||||||
--[[
|
--[[
|
||||||
Fk:addMiniGame{
|
Fk:addMiniGame{
|
||||||
name = "test",
|
name = "test",
|
||||||
|
|
Loading…
Reference in New Issue