FreeKill/Fk/RoomElement/Dashboard.qml
YoumuKon 8df1985b99
目标参数改造和bugfix (#287)
- 重做目标参数相关:
  - 重修`must_targets`参数,必须选择其中**全部**目标后才能选择其他目标/按确定
  - 添加`include_targets`参数,必须选择其中**一个**目标后才能选择其他目标/按确定
- 修复expandPile指定牌堆无卡符合要求则收回的bug
- 优化ex_choose_skill,添加扩展牌堆和包括装备功能
- 添加ReasonRecast理由,现在recastCard会返回该动作后摸的牌
- 移除了重复的DamageFinished时机触发
2023-12-06 21:08:56 +08:00

512 lines
14 KiB
QML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
RowLayout {
id: root
property var self
property alias handcardArea: handcardAreaItem
property string pending_skill: ""
property var pending_card
property var pendings: [] // int[], store cid
property int selected_card: -1
property alias skillButtons: skillPanel.skill_buttons
property var expanded_piles: ({}) // name -> int[]
signal cardSelected(var card)
Item { width: 5 }
HandcardArea {
id: handcardAreaItem
Layout.fillWidth: true
Layout.preferredHeight: 130
Layout.alignment: Qt.AlignBottom
Layout.bottomMargin: 24
onWidthChanged: updateCardPosition(true);
}
SkillArea {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.maximumWidth: width
Layout.maximumHeight: height
Layout.alignment: Qt.AlignBottom
Layout.bottomMargin: 32
Layout.rightMargin: -16
id: skillPanel
}
Item {
width: 175
height: 233
Layout.rightMargin: -175 / 8 + (roomArea.width - 175 * 0.75 * 7) / 8
// handcards: handcardAreaItem.length
}
Connections {
target: handcardAreaItem
function onCardSelected(cardId, selected) {
dashboard.selectCard(cardId, selected);
}
function onLengthChanged() {
self.handcards = handcardAreaItem.length;
}
}
function disableAllCards() {
handcardAreaItem.enableCards([]);
}
function unSelectAll(expectId) {
handcardAreaItem.unselectAll(expectId);
}
function expandPile(pile) {
const expanded_pile_names = Object.keys(expanded_piles);
if (expanded_pile_names.indexOf(pile) !== -1)
return;
const component = Qt.createComponent("../RoomElement/CardItem.qml");
const parentPos = roomScene.mapFromItem(self, 0, 0);
expanded_piles[pile] = [];
if (pile === "_equip") {
const equips = self.equipArea.getAllCards();
equips.forEach(data => {
data.x = parentPos.x;
data.y = parentPos.y;
const card = component.createObject(roomScene, data);
card.footnoteVisible = true;
card.footnote = Backend.translate("$Equip");
handcardAreaItem.add(card);
})
handcardAreaItem.updateCardPosition();
} else {
const ids = JSON.parse(Backend.callLuaFunction("GetPile", [self.playerid, pile]));
ids.forEach(id => {
const data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
data.x = parentPos.x;
data.y = parentPos.y;
const card = component.createObject(roomScene, data);
card.footnoteVisible = true;
card.footnote = Backend.translate(pile);
handcardAreaItem.add(card);
});
handcardAreaItem.updateCardPosition();
}
}
function retractPile(pile) {
const expanded_pile_names = Object.keys(expanded_piles);
if (expanded_pile_names.indexOf(pile) === -1)
return;
const parentPos = roomScene.mapFromItem(self, 0, 0);
delete expanded_piles[pile];
if (pile === "_equip") {
const equips = self.equipArea.getAllCards();
equips.forEach(data => {
const card = handcardAreaItem.remove([data.cid])[0];
card.origX = parentPos.x;
card.origY = parentPos.y;
card.destroyOnStop();
card.goBack(true);
})
handcardAreaItem.updateCardPosition();
} else {
const ids = JSON.parse(Backend.callLuaFunction("GetPile", [self.playerid, pile]));
ids.forEach(id => {
const card = handcardAreaItem.remove([id])[0];
card.origX = parentPos.x;
card.origY = parentPos.y;
card.destroyOnStop();
card.goBack(true);
});
handcardAreaItem.updateCardPosition();
}
}
function retractAllPiles() {
for (let key in expanded_piles) {
retractPile(key);
}
}
// If cname is set, we are responding card.
function enableCards(cname) {
const cardValid = (cid, cname) => {
let ret = JSON.parse(Backend.callLuaFunction(
"CardFitPattern", [cid, cname]));
if (ret) {
if (roomScene.respond_play) {
ret = ret && !JSON.parse(Backend.callLuaFunction(
"CardProhibitedResponse", [cid]));
} else {
ret = ret && !JSON.parse(Backend.callLuaFunction(
"CardProhibitedUse", [cid]));
}
}
return ret;
}
const pile_data = JSON.parse(Backend.callLuaFunction("GetAllPiles", [self.playerid]));
extractWoodenOx();
if (cname) {
const ids = [];
let cards = handcardAreaItem.cards;
for (let i = 0; i < cards.length; i++) {
cards[i].prohibitReason = "";
if (cardValid(cards[i].cid, cname)) {
ids.push(cards[i].cid);
} else {
const prohibitReason = Backend.callLuaFunction(
"GetCardProhibitReason",
[cards[i].cid, roomScene.respond_play ? "response" : "use", cname]
);
if (prohibitReason) {
cards[i].prohibitReason = prohibitReason;
}
}
}
cards = self.equipArea.getAllCards();
cards.forEach(c => {
c.prohibitReason = "";
if (cardValid(c.cid, cname)) {
ids.push(c.cid);
if (!expanded_piles["_equip"]) {
expandPile("_equip");
}
} else {
const prohibitReason = Backend.callLuaFunction(
"GetCardProhibitReason",
[c.cid, roomScene.respond_play ? "response" : "use", cname]
);
if (prohibitReason) {
c.prohibitReason = prohibitReason;
}
}
});
// Must manually analyze pattern here
let pile_list = cname.split("|")[4];
if (pile_list && pile_list !== "." && !(pile_data instanceof Array)) {
pile_list = pile_list.split(",");
for (let pile_name of pile_list) {
pile_data[pile_name] && pile_data[pile_name].forEach(cid => {
if (cardValid(cid, cname)) {
ids.push(cid);
if (!expanded_piles[pile_name]) {
expandPile(pile_name);
}
}
});
}
}
handcardAreaItem.enableCards(ids);
return;
}
const ids = [], cards = handcardAreaItem.cards;
for (let i = 0; i < cards.length; i++) {
cards[i].prohibitReason = "";
if (JSON.parse(Backend.callLuaFunction("CanUseCard", [cards[i].cid, Self.id]))) {
ids.push(cards[i].cid);
} else {
// cannot use? considering special_skills
const skills = JSON.parse(Backend.callLuaFunction("GetCardSpecialSkills", [cards[i].cid]));
for (let j = 0; j < skills.length; j++) {
const s = skills[j];
if (JSON.parse(Backend.callLuaFunction("ActiveCanUse", [s]))) {
ids.push(cards[i].cid);
break;
}
}
// still cannot use? show message on card
if (!ids.includes(cards[i].cid)) {
const prohibitReason = Backend.callLuaFunction("GetCardProhibitReason", [cards[i].cid, "play"]);
if (prohibitReason) {
cards[i].prohibitReason = prohibitReason;
}
}
}
}
handcardAreaItem.enableCards(ids)
if (pending_skill === "") {
cancelButton.enabled = false;
}
}
function selectCard(cardId, selected) {
if (pending_skill !== "") {
if (selected) {
pendings.push(cardId);
} else {
pendings.splice(pendings.indexOf(cardId), 1);
}
updatePending();
} else {
if (selected) {
handcardAreaItem.unselectAll(cardId);
selected_card = cardId;
} else {
handcardAreaItem.unselectAll();
selected_card = -1;
}
cardSelected(selected_card);
}
}
function revertSelection() {
if (pending_skill !== "") {
let to_select_cards = handcardAreaItem.cards.filter(cd => {
if (pendings.indexOf(cd.cid) === -1) {
return true;
} else {
cd.selected = !cd.selected;
cd.clicked();
}
});
to_select_cards.forEach(cd => {
if (cd.selectable) {
cd.selected = !cd.selected;
cd.clicked();
}
});
}
}
function getSelectedCard() {
if (pending_skill !== "") {
return JSON.stringify({
skill: pending_skill,
subcards: pendings
});
} else {
return selected_card;
}
}
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;
}
function extractWoodenOx() {
const pile_data = JSON.parse(Backend.callLuaFunction("GetAllPiles", [self.playerid]));
if (!roomScene.autoPending) { // 先屏蔽AskForUseActiveSkill再说这下只剩使用打出以及出牌阶段了
for (let name in pile_data) {
if (name.endsWith("&")) expandPile(name);
}
}
}
function updatePending() {
roomScene.resetPrompt();
if (pending_skill === "") return;
const enabled_cards = [];
const targets = roomScene.selected_targets;
const prompt = JSON.parse(Backend.callLuaFunction(
"ActiveSkillPrompt",
[pending_skill, pendings, targets]
));
if (prompt !== "") {
roomScene.setPrompt(processPrompt(prompt));
}
handcardAreaItem.cards.forEach((card) => {
if (card.selected || JSON.parse(Backend.callLuaFunction(
"ActiveCardFilter",
[pending_skill, card.cid, pendings, targets]
)))
enabled_cards.push(card.cid);
});
const cards = self.equipArea.getAllCards();
cards.forEach(c => {
if (JSON.parse(Backend.callLuaFunction(
"ActiveCardFilter",
[pending_skill, c.cid, pendings, targets]
))) {
enabled_cards.push(c.cid);
if (!expanded_piles["_equip"]) {
expandPile("_equip");
}
}
})
const pile = Backend.callLuaFunction("GetExpandPileOfSkill", [pending_skill]);
const pile_ids = JSON.parse(Backend.callLuaFunction("GetPile", [self.playerid, pile]));
pile_ids.forEach(cid => {
if (JSON.parse(Backend.callLuaFunction(
"ActiveCardFilter",
[pending_skill, cid, pendings, targets]
))) {
enabled_cards.push(cid);
};
if (!expanded_piles[pile]) {
expandPile(pile);
}
});
handcardAreaItem.enableCards(enabled_cards);
if (JSON.parse(Backend.callLuaFunction(
"CanViewAs",
[pending_skill, pendings]
))) {
pending_card = {
skill: pending_skill,
subcards: pendings
};
cardSelected(JSON.stringify(pending_card));
} else {
pending_card = -1;
cardSelected(pending_card);
}
}
function startPending(skill_name) {
pending_skill = skill_name;
pendings = [];
handcardAreaItem.unselectAll();
retractAllPiles();
for (let i = 0; i < skillButtons.count; i++) {
const item = skillButtons.itemAt(i);
item.enabled = item.pressed;
}
const cards = handcardAreaItem.cards;
for (let i = 0; i < cards.length; i++) {
cards[i].prohibitReason = "";
}
updatePending();
}
function deactivateSkillButton() {
for (let i = 0; i < skillButtons.count; i++) {
let item = skillButtons.itemAt(i);
item.pressed = false;
}
}
function stopPending() {
pending_skill = "";
pending_card = -1;
retractAllPiles();
if (roomScene.state == "playing")
extractWoodenOx();
pendings = [];
handcardAreaItem.adjustCards();
handcardAreaItem.unselectAll();
cardSelected(-1);
roomScene.resetPrompt();
}
function addSkill(skill_name, prelight) {
skillPanel.addSkill(skill_name, prelight);
}
function loseSkill(skill_name, prelight) {
skillPanel.loseSkill(skill_name, prelight);
}
function prelightSkill(skill_name, prelight) {
const btns = skillPanel.prelight_buttons;
for (let i = 0; i < btns.count; i++) {
const btn = btns.itemAt(i);
if (btn.orig === skill_name) {
btn.prelighted = prelight;
btn.enabled = true;
}
}
}
function enableSkills(cname, cardResponsing) {
if (cname) {
// if cname is presented, we are responding use or play.
for (let i = 0; i < skillButtons.count; i++) {
const item = skillButtons.itemAt(i);
const fitpattern = JSON.parse(Backend.callLuaFunction("SkillFitPattern", [item.orig, cname]));
const canresp = JSON.parse(Backend.callLuaFunction("SkillCanResponse", [item.orig, cardResponsing]));
item.enabled = fitpattern && canresp;
}
return;
}
for (let i = 0; i < skillButtons.count; i++) {
const item = skillButtons.itemAt(i);
item.enabled = JSON.parse(Backend.callLuaFunction("ActiveCanUse", [item.orig]));
}
}
function disableSkills() {
for (let i = 0; i < skillButtons.count; i++)
skillButtons.itemAt(i).enabled = false;
}
function tremble() {
self.tremble();
}
function updateHandcards() {
Backend.callLuaFunction("FilterMyHandcards", []);
handcardAreaItem.cards.forEach(v => {
const data = JSON.parse(Backend.callLuaFunction("GetCardData", [v.cid]));
v.setData(data);
});
}
function update() {
unSelectAll();
disableSkills();
let cards = handcardAreaItem.cards;
const toRemove = [];
for (let c of cards) {
toRemove.push(c.cid);
c.origY += 30;
c.origOpacity = 0
c.goBack(true);
c.destroyOnStop();
}
handcardAreaItem.remove(toRemove);
skillPanel.clearSkills();
const skills = JSON.parse(Backend.callLuaFunction("GetPlayerSkills", [Self.id]));
for (let s of skills) {
addSkill(s.name);
}
cards = roomScene.drawPile.remove(JSON.parse(Backend.callLuaFunction("GetPlayerHandcards", [Self.id])));
handcardAreaItem.add(cards);
}
}