Interaction (#61)
* AG (WIP) * fixbug: setemotion in windows * room:askForCardsChosen * fixbug: askForCardChosen
This commit is contained in:
parent
3f077a6d69
commit
3e78466947
|
@ -281,6 +281,27 @@ fk.client_callback["AskForCardChosen"] = function(jsonData)
|
|||
ClientInstance:notifyUI("AskForCardChosen", json.encode(ui_data))
|
||||
end
|
||||
|
||||
fk.client_callback["AskForCardsChosen"] = function(jsonData)
|
||||
-- jsonData: [ int target_id, int min, int max, string flag, int reason ]
|
||||
local data = json.decode(jsonData)
|
||||
local id, min, max, flag, reason = data[1], data[2], data[3], data[4], data[5]
|
||||
local target = ClientInstance:getPlayerById(id)
|
||||
local hand = target.player_cards[Player.Hand]
|
||||
local equip = target.player_cards[Player.Equip]
|
||||
local judge = target.player_cards[Player.Judge]
|
||||
if not string.find(flag, "h") then
|
||||
hand = {}
|
||||
end
|
||||
if not string.find(flag, "e") then
|
||||
equip = {}
|
||||
end
|
||||
if not string.find(flag, "j") then
|
||||
judge = {}
|
||||
end
|
||||
local ui_data = {hand, equip, judge, min, max, reason}
|
||||
ClientInstance:notifyUI("AskForCardsChosen", json.encode(ui_data))
|
||||
end
|
||||
|
||||
--- separated moves to many moves(one card per move)
|
||||
---@param moves CardsMoveStruct[]
|
||||
local function separateMoves(moves)
|
||||
|
|
|
@ -236,7 +236,7 @@ function Card.static:getIdList(c)
|
|||
-- array
|
||||
local ret = {}
|
||||
for _, c2 in ipairs(c) do
|
||||
table.insertTable(ret, Card:getIdList(c))
|
||||
table.insertTable(ret, Card:getIdList(c2))
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
|
|
@ -142,12 +142,12 @@ function table.random(tab, n)
|
|||
if #tab == 0 then return nil end
|
||||
local tmp = {table.unpack(tab)}
|
||||
local ret = {}
|
||||
while n > 0 do
|
||||
while n > 0 and #tmp > 0 do
|
||||
local i = math.random(1, #tmp)
|
||||
table.insert(ret, table.remove(tmp, i))
|
||||
n = n - 1
|
||||
end
|
||||
return #ret == 1 and ret[1] or ret
|
||||
return n == 1 and ret[1] or ret
|
||||
end
|
||||
|
||||
---@param delimiter string
|
||||
|
|
|
@ -842,6 +842,7 @@ end
|
|||
---@param target ServerPlayer
|
||||
---@param flag string @ "hej", h for handcard, e for equip, j for judge
|
||||
---@param reason string
|
||||
---@return integer
|
||||
function Room:askForCardChosen(chooser, target, flag, reason)
|
||||
local command = "AskForCardChosen"
|
||||
self:notifyMoveFocus(chooser, command)
|
||||
|
@ -849,12 +850,6 @@ function Room:askForCardChosen(chooser, target, flag, reason)
|
|||
local result = self:doRequest(chooser, command, json.encode(data))
|
||||
|
||||
if result == "" then
|
||||
result = -1
|
||||
else
|
||||
result = tonumber(result)
|
||||
end
|
||||
|
||||
if result == -1 then
|
||||
local areas = {}
|
||||
if string.find(flag, "h") then table.insert(areas, Player.Hand) end
|
||||
if string.find(flag, "e") then table.insert(areas, Player.Equip) end
|
||||
|
@ -862,11 +857,55 @@ function Room:askForCardChosen(chooser, target, flag, reason)
|
|||
local handcards = target:getCardIds(areas)
|
||||
if #handcards == 0 then return end
|
||||
result = handcards[math.random(1, #handcards)]
|
||||
else
|
||||
result = tonumber(result)
|
||||
end
|
||||
|
||||
if result == -1 then
|
||||
local handcards = target:getCardIds(Player.Hand)
|
||||
if #handcards == 0 then return end
|
||||
result = table.random(handcards)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
---@param chooser ServerPlayer
|
||||
---@param target ServerPlayer
|
||||
---@param min integer
|
||||
---@param max integer
|
||||
---@param flag string @ "hej", h for handcard, e for equip, j for judge
|
||||
---@param reason string
|
||||
---@return integer[]
|
||||
function Room:askForCardsChosen(chooser, target, min, max, flag, reason)
|
||||
if min == 1 and max == 1 then
|
||||
return { self:askForCardChosen(chooser, target, flag, reason) }
|
||||
end
|
||||
|
||||
local command = "AskForCardsChosen"
|
||||
self:notifyMoveFocus(chooser, command)
|
||||
local data = {target.id, min, max, flag, reason}
|
||||
local result = self:doRequest(chooser, command, json.encode(data))
|
||||
|
||||
local ret
|
||||
if result ~= "" then
|
||||
ret = json.decode(result)
|
||||
else
|
||||
local areas = {}
|
||||
if string.find(flag, "h") then table.insert(areas, Player.Hand) end
|
||||
if string.find(flag, "e") then table.insert(areas, Player.Equip) end
|
||||
if string.find(flag, "j") then table.insert(areas, Player.Judge) end
|
||||
local handcards = target:getCardIds(areas)
|
||||
if #handcards == 0 then return {} end
|
||||
ret = table.random(handcards, math.min(min, #handcards))
|
||||
end
|
||||
|
||||
local new_ret = table.filter(ret, function(id) return id ~= -1 end)
|
||||
table.insertTable(new_ret, table.random(target:getCardIds(Player.Hand), #ret - #new_ret))
|
||||
|
||||
return new_ret
|
||||
end
|
||||
|
||||
---@param player ServerPlayer
|
||||
---@param choices string[]
|
||||
---@param skill_name string
|
||||
|
@ -1056,6 +1095,51 @@ function Room:askForNullification(players, card_name, pattern, prompt, cancelabl
|
|||
return nil
|
||||
end
|
||||
|
||||
-- AG(a.k.a. Amazing Grace) functions
|
||||
-- Popup a box that contains many cards, then ask player to choose one
|
||||
|
||||
---@param player ServerPlayer
|
||||
---@param id_list integer[] | Card[]
|
||||
---@param cancelable boolean
|
||||
---@param reason string
|
||||
---@return integer
|
||||
function Room:askForAG(player, id_list, cancelable, reason)
|
||||
id_list = Card:getIdList(id_list)
|
||||
if #id_list == 1 and not cancelable then
|
||||
return id_list[1]
|
||||
end
|
||||
|
||||
local command = "AskForAG"
|
||||
self:notifyMoveFocus(player, reason or command)
|
||||
local data = { id_list, cancelable, reason }
|
||||
local ret = self:doRequest(player, command, json.encode(data))
|
||||
if ret == "" and not cancelable then
|
||||
ret = table.random(id_list)
|
||||
end
|
||||
return tonumber(ret)
|
||||
end
|
||||
|
||||
---@param player ServerPlayer
|
||||
---@param id_list integer[] | Card[]
|
||||
---@param disable_ids integer[] | Card[]
|
||||
function Room:fillAG(player, id_list, disable_ids)
|
||||
id_list = Card:getIdList(id_list)
|
||||
-- disable_ids = Card:getIdList(disable_ids)
|
||||
player:doNotify("FillAG", json.encode{ id_list, disable_ids })
|
||||
end
|
||||
|
||||
---@param player ServerPlayer
|
||||
---@param id integer
|
||||
function Room:takeAG(taker, id, notify_list)
|
||||
self:doBroadcastNotify("TakeAG", json.encode{ taker.id, id }, notify_list)
|
||||
end
|
||||
|
||||
---@param player ServerPlayer
|
||||
function Room:closeAG(player)
|
||||
if player then player:doNotify("CloseAG", "")
|
||||
else self:doBroadcastNotify("CloseAG", "") end
|
||||
end
|
||||
|
||||
-- Show a qml dialog and return qml's ClientInstance.replyToServer
|
||||
-- Do anything you like through this function
|
||||
|
||||
|
|
|
@ -60,11 +60,20 @@ local test_active = fk.CreateActiveSkill{
|
|||
can_use = function(self, player)
|
||||
return true
|
||||
end,
|
||||
target_filter = function() return true end,
|
||||
on_use = function(self, room, effect)
|
||||
--room:doSuperLightBox("packages/test/qml/Test.qml")
|
||||
local from = room:getPlayerById(effect.from)
|
||||
local result = room:askForCustomDialog(from, "simayi", "packages/test/qml/TestDialog.qml", "Hello, world. FROM LUA")
|
||||
print(result)
|
||||
-- local result = room:askForCustomDialog(from, "simayi", "packages/test/qml/TestDialog.qml", "Hello, world. FROM LUA")
|
||||
-- print(result)
|
||||
|
||||
-- room:fillAG(from, { 1, 43, 77 })
|
||||
-- local id = room:askForAG(from, { 1, 43, 77 })
|
||||
-- room:takeAG(from, id)
|
||||
-- room:delay(2000)
|
||||
-- room:closeAG(from)
|
||||
local cards = room:askForCardsChosen(from, room:getPlayerById(effect.tos[1]), 2, 3, "hej", "")
|
||||
p(cards)
|
||||
end,
|
||||
}
|
||||
local test2 = General(extension, "mouxusheng", "wu", 4, 4, General.Female)
|
||||
|
|
|
@ -18,6 +18,7 @@ Item {
|
|||
property bool isStarted: false
|
||||
|
||||
property alias popupBox: popupBox
|
||||
property alias manualBox: manualBox
|
||||
property alias bigAnim: bigAnim
|
||||
property alias promptText: prompt.text
|
||||
property alias okCancel: okCancel
|
||||
|
@ -388,6 +389,26 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// manualBox: same as popupBox, but must be closed manually
|
||||
Loader {
|
||||
id: manualBox
|
||||
z: 999
|
||||
onSourceChanged: {
|
||||
if (item === null)
|
||||
return;
|
||||
item.finished.connect(() => source = "");
|
||||
item.widthChanged.connect(() => manualBox.moveToCenter());
|
||||
item.heightChanged.connect(() => manualBox.moveToCenter());
|
||||
moveToCenter();
|
||||
}
|
||||
|
||||
function moveToCenter()
|
||||
{
|
||||
item.x = Math.round((roomArea.width - item.width) / 2);
|
||||
item.y = Math.round(roomArea.height * 0.67 - item.height / 2);
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: bigAnim
|
||||
anchors.fill: parent
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import QtQuick
|
||||
|
||||
GraphicsBox {
|
||||
property int spacing: 5
|
||||
property string currentPlayerName: ""
|
||||
property bool interactive: false
|
||||
|
||||
id: root
|
||||
title.text: Backend.translate("Please choose cards")
|
||||
width: cards.count * 100 + spacing * (cards.count - 1) + 25
|
||||
height: 180
|
||||
|
||||
ListModel {
|
||||
id: cards
|
||||
}
|
||||
|
||||
Row {
|
||||
x: 20
|
||||
y: 35
|
||||
spacing: root.spacing
|
||||
|
||||
Repeater {
|
||||
model: cards
|
||||
|
||||
CardItem {
|
||||
cid: model.cid
|
||||
name: model.name
|
||||
suit: model.suit
|
||||
number: model.number
|
||||
autoBack: false
|
||||
selectable: model.selectable
|
||||
footnote: model.footnote
|
||||
footnoteVisible: true
|
||||
onClicked: {
|
||||
if (root.interactive && selectable) {
|
||||
root.interactive = false;
|
||||
roomScene.state = "notactive";
|
||||
ClientInstance.replyToServer("", cid.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addIds(ids) {
|
||||
ids.forEach((id) => {
|
||||
let data = Backend.callLuaFunction("GetCardData", [id]);
|
||||
data = JSON.parse(data);
|
||||
data.selectable = true;
|
||||
data.footnote = "";
|
||||
cards.append(data);
|
||||
});
|
||||
}
|
||||
|
||||
function takeAG(g, cid) {
|
||||
for (let i = 0; i < cards.count; i++) {
|
||||
let item = cards.get(i);
|
||||
if (item.cid !== cid) continue;
|
||||
item.footnote = g;
|
||||
item.selectable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,21 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import ".."
|
||||
|
||||
GraphicsBox {
|
||||
signal cardSelected(int cid)
|
||||
|
||||
id: root
|
||||
title.text: Backend.translate("$ChooseCard")
|
||||
//@to-do: 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 + Math.min(7, Math.max(1, handcards.count, equips.count, delayedTricks.count)) * 100
|
||||
height: 50 + (handcards.count > 0 ? 150 : 0) + (equips.count > 0 ? 150 : 0) + (delayedTricks.count > 0 ? 150 : 0)
|
||||
|
||||
signal cardSelected(int cid)
|
||||
signal cardsSelected(var ids)
|
||||
property bool multiChoose: false
|
||||
property int min: 0
|
||||
property int max: 1
|
||||
property var selected_ids: []
|
||||
|
||||
ListModel {
|
||||
id: handcards
|
||||
}
|
||||
|
@ -66,7 +71,23 @@ GraphicsBox {
|
|||
autoBack: false
|
||||
known: false
|
||||
selectable: true
|
||||
onClicked: root.cardSelected(cid);
|
||||
onClicked: {
|
||||
if (!root.multiChoose) {
|
||||
root.cardSelected(cid);
|
||||
}
|
||||
}
|
||||
onSelectedChanged: {
|
||||
if (selected) {
|
||||
origY = origY - 20;
|
||||
root.selected_ids.push(cid);
|
||||
} else {
|
||||
origY = origY + 20;
|
||||
root.selected_ids.splice(root.selected_ids.indexOf(cid), 1);
|
||||
}
|
||||
origX = x;
|
||||
goBack(true);
|
||||
root.selected_ids = root.selected_ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +128,23 @@ GraphicsBox {
|
|||
number: model.number
|
||||
autoBack: false
|
||||
selectable: true
|
||||
onClicked: root.cardSelected(cid);
|
||||
onClicked: {
|
||||
if (!root.multiChoose) {
|
||||
root.cardSelected(cid);
|
||||
}
|
||||
}
|
||||
onSelectedChanged: {
|
||||
if (selected) {
|
||||
origY = origY - 20;
|
||||
root.selected_ids.push(cid);
|
||||
} else {
|
||||
origY = origY + 20;
|
||||
root.selected_ids.splice(root.selected_ids.indexOf(cid));
|
||||
}
|
||||
origX = x;
|
||||
goBack(true);
|
||||
root.selected_ids = root.selected_ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,11 +185,34 @@ GraphicsBox {
|
|||
number: model.number
|
||||
autoBack: false
|
||||
selectable: true
|
||||
onClicked: root.cardSelected(cid);
|
||||
onClicked: {
|
||||
if (!root.multiChoose) {
|
||||
root.cardSelected(cid);
|
||||
}
|
||||
}
|
||||
onSelectedChanged: {
|
||||
if (selected) {
|
||||
origY = origY - 20;
|
||||
root.selected_ids.push(cid);
|
||||
} else {
|
||||
origY = origY + 20;
|
||||
root.selected_ids.splice(root.selected_ids.indexOf(cid));
|
||||
}
|
||||
origX = x;
|
||||
goBack(true);
|
||||
root.selected_ids = root.selected_ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetroButton {
|
||||
text: Backend.translate("OK")
|
||||
visible: root.multiChoose
|
||||
enabled: root.selected_ids.length <= root.max && root.selected_ids.length >= root.min
|
||||
onClicked: root.cardsSelected(root.selected_ids)
|
||||
}
|
||||
}
|
||||
|
||||
onCardSelected: finished();
|
||||
|
|
|
@ -228,7 +228,7 @@ function setEmotion(id, emotion, isCardId) {
|
|||
}
|
||||
}
|
||||
|
||||
let animation = component.createObject(photo, {source: path});
|
||||
let animation = component.createObject(photo, {source: (OS === "Win" ? "file:///" : "") + path});
|
||||
animation.anchors.centerIn = photo;
|
||||
if (isCardId) {
|
||||
animation.started.connect(() => photo.busy = true);
|
||||
|
@ -669,6 +669,52 @@ callbacks["AskForCardChosen"] = function(jsonData) {
|
|||
});
|
||||
}
|
||||
|
||||
callbacks["AskForCardsChosen"] = function(jsonData) {
|
||||
// jsonData: [ int[] handcards, int[] equips, int[] delayedtricks,
|
||||
// int min, int max, string reason ]
|
||||
let data = JSON.parse(jsonData);
|
||||
let handcard_ids = data[0];
|
||||
let equip_ids = data[1];
|
||||
let delayedTrick_ids = data[2];
|
||||
let min = data[3];
|
||||
let max = data[4];
|
||||
let reason = data[5];
|
||||
let handcards = [];
|
||||
let equips = [];
|
||||
let delayedTricks = [];
|
||||
|
||||
handcard_ids.forEach(id => {
|
||||
let card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
|
||||
handcards.push(card_data);
|
||||
});
|
||||
|
||||
equip_ids.forEach(id => {
|
||||
let card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
|
||||
equips.push(card_data);
|
||||
});
|
||||
|
||||
delayedTrick_ids.forEach(id => {
|
||||
let card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
|
||||
delayedTricks.push(card_data);
|
||||
});
|
||||
|
||||
roomScene.promptText = Backend.translate("#AskForChooseCard")
|
||||
.arg(Backend.translate(reason));
|
||||
roomScene.state = "replying";
|
||||
roomScene.popupBox.source = "RoomElement/PlayerCardBox.qml";
|
||||
let box = roomScene.popupBox.item;
|
||||
box.multiChoose = true;
|
||||
box.min = min;
|
||||
box.max = max;
|
||||
box.addHandcards(handcards);
|
||||
box.addEquips(equips);
|
||||
box.addDelayedTricks(delayedTricks);
|
||||
roomScene.popupBox.moveToCenter();
|
||||
box.cardsSelected.connect((ids) => {
|
||||
replyToServer(JSON.stringify(ids));
|
||||
});
|
||||
}
|
||||
|
||||
callbacks["MoveCards"] = function(jsonData) {
|
||||
// jsonData: merged moves
|
||||
let moves = JSON.parse(jsonData);
|
||||
|
@ -910,6 +956,32 @@ callbacks["GameOver"] = function(jsonData) {
|
|||
roomScene.isStarted = false;
|
||||
}
|
||||
|
||||
callbacks["FillAG"] = (j) => {
|
||||
let data = JSON.parse(j);
|
||||
let ids = data[0];
|
||||
roomScene.manualBox.source = "RoomElement/AG.qml";
|
||||
roomScene.manualBox.item.addIds(ids);
|
||||
}
|
||||
|
||||
callbacks["AskForAG"] = (j) => {
|
||||
roomScene.state = "replying";
|
||||
roomScene.manualBox.item.interactive = true;
|
||||
}
|
||||
|
||||
callbacks["TakeAG"] = (j) => {
|
||||
if (!roomScene.manualBox.item) return;
|
||||
let data = JSON.parse(j);
|
||||
let pid = data[0];
|
||||
let cid = data[1];
|
||||
let item = getPhotoOrSelf(pid);
|
||||
let general = Backend.translate(item.general);
|
||||
|
||||
// the item should be AG box
|
||||
roomScene.manualBox.item.takeAG(general, cid);
|
||||
}
|
||||
|
||||
callbacks["CloseAG"] = () => roomScene.manualBox.item.close();
|
||||
|
||||
callbacks["CustomDialog"] = (j) => {
|
||||
let data = JSON.parse(j);
|
||||
let path = data.path;
|
||||
|
|
Loading…
Reference in New Issue