FreeKill/Fk/RoomElement/Dashboard.qml

510 lines
13 KiB
QML
Raw Normal View History

// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Fk
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[]
property var extra_cards: []
property var disabledSkillNames: []
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);
}
2024-01-26 14:56:07 +08:00
function expandPile(pile, extra_ids, extra_footnote) {
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] = [];
2024-01-26 14:56:07 +08:00
let ids, footnote;
if (pile === "_equip") {
2024-01-26 16:01:41 +08:00
ids = self.equipArea.getAllCards().map(e => e.cid);
2024-01-26 14:56:07 +08:00
footnote = "$Equip";
} else if (pile === "_extra") {
ids = extra_ids;
extra_cards = ids;
2024-01-26 14:56:07 +08:00
footnote = extra_footnote;
} else {
2024-01-26 14:56:07 +08:00
ids = lcall("GetPile", self.playerid, pile);
footnote = pile;
}
2024-01-26 14:56:07 +08:00
ids.forEach(id => {
const data = lcall("GetCardData", id);
data.x = parentPos.x;
data.y = parentPos.y;
const card = component.createObject(roomScene, data);
card.footnoteVisible = true;
card.footnote = luatr(footnote);
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 {
let ids = [];
if (pile === "_extra") {
ids = extra_cards;
extra_cards = [];
} else {
ids = lcall("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 = lcall("CardFitPattern", cid, cname);
if (ret) {
if (roomScene.respond_play) {
ret = ret && !lcall("CardProhibitedResponse", cid);
} else {
ret = ret && !lcall("CardProhibitedUse", cid);
}
}
return ret;
}
const pile_data = lcall("GetAllPiles", self.playerid);
2023-08-12 00:50:17 +08:00
extractWoodenOx();
const handleMethod = roomScene.respond_play ? "response" : "use";
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 = lcall("GetCardProhibitReason", cards[i].cid,
handleMethod, 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 = lcall("GetCardProhibitReason", c.cid,
handleMethod, 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 (lcall("CanUseCard", cards[i].cid, Self.id,
JSON.stringify(roomScene.extra_data))) {
ids.push(cards[i].cid);
} else {
// cannot use? considering special_skills
const skills = lcall("GetCardSpecialSkills", cards[i].cid);
for (let j = 0; j < skills.length; j++) {
const s = skills[j];
if (lcall("ActiveCanUse", s, JSON.stringify(roomScene.extra_data))) {
ids.push(cards[i].cid);
break;
}
}
// still cannot use? show message on card
if (!ids.includes(cards[i].cid)) {
const prohibitReason = lcall("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;
roomScene.resetPrompt();
}
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;
}
}
2023-08-12 00:50:17 +08:00
function extractWoodenOx() {
const pile_data = lcall("GetAllPiles", self.playerid);
if (!roomScene.autoPending) {
// 先屏蔽AskForUseActiveSkill再说这下只剩使用打出以及出牌阶段了
2023-08-12 00:50:17 +08:00
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;
handcardAreaItem.cards.forEach((card) => {
if (card.selected || lcall("ActiveCardFilter", pending_skill, card.cid,
pendings, targets))
enabled_cards.push(card.cid);
});
const cards = self.equipArea.getAllCards();
cards.forEach(c => {
if (lcall("ActiveCardFilter", pending_skill, c.cid, pendings, targets)) {
enabled_cards.push(c.cid);
if (!expanded_piles["_equip"]) {
expandPile("_equip");
}
}
})
2024-01-26 14:56:07 +08:00
let pile = lcall("GetExpandPileOfSkill", pending_skill);
let pile_ids = pile;
if (typeof pile === "string") {
pile_ids = lcall("GetPile", self.playerid, pile);
} else {
pile = "_extra";
}
pile_ids.forEach(cid => {
if (lcall("ActiveCardFilter", pending_skill, cid, pendings, targets)) {
enabled_cards.push(cid);
};
if (!expanded_piles[pile]) {
2024-01-26 14:56:07 +08:00
expandPile(pile, pile_ids, pending_skill);
}
});
handcardAreaItem.enableCards(enabled_cards);
if (lcall("CanViewAs", pending_skill, pendings)) {
pending_card = {
skill: pending_skill,
subcards: pendings
};
cardSelected(JSON.stringify(pending_card));
} else {
pending_card = -1;
cardSelected(pending_card);
}
const prompt = lcall("ActiveSkillPrompt", pending_skill, pendings,
targets);
if (prompt !== "") {
roomScene.setPrompt(Util.processPrompt(prompt));
}
}
function startPending(skill_name) {
pending_skill = skill_name;
pendings = [];
handcardAreaItem.unselectAll();
2023-08-12 00:50:17 +08:00
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();
2023-08-12 00:50:17 +08:00
if (roomScene.state == "playing")
extractWoodenOx();
pendings = [];
handcardAreaItem.adjustCards();
handcardAreaItem.unselectAll();
cardSelected(-1);
roomScene.resetPrompt();
}
2023-04-23 21:10:07 +08:00
function addSkill(skill_name, prelight) {
skillPanel.addSkill(skill_name, prelight);
}
2023-04-23 21:10:07 +08:00
function loseSkill(skill_name, prelight) {
skillPanel.loseSkill(skill_name, prelight);
}
function prelightSkill(skill_name, prelight) {
const btns = skillPanel.prelight_buttons;
2023-04-23 21:10:07 +08:00
for (let i = 0; i < btns.count; i++) {
const btn = btns.itemAt(i);
2023-04-23 21:10:07 +08:00
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);
if (disabledSkillNames.includes(item.orig)) {
item.enabled = false;
continue;
}
const fitpattern = lcall("SkillFitPattern", item.orig, cname);
const canresp = lcall("SkillCanResponse", item.orig, cardResponsing);
item.enabled = fitpattern && canresp;
}
return;
}
for (let i = 0; i < skillButtons.count; i++) {
const item = skillButtons.itemAt(i);
if (disabledSkillNames.includes(item.orig)) {
item.enabled = false;
continue;
}
item.enabled = lcall("ActiveCanUse", item.orig,
JSON.stringify(roomScene.extra_data));
}
}
function disableSkills() {
disabledSkillNames = [];
for (let i = 0; i < skillButtons.count; i++)
skillButtons.itemAt(i).enabled = false;
}
function tremble() {
self.tremble();
}
function updateHandcards() {
lcall("FilterMyHandcards");
handcardAreaItem.cards.forEach(v => {
v.setData(lcall("GetCardData", v.cid));
});
}
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 = lcall("GetPlayerSkills", Self.id);
for (let s of skills) {
addSkill(s.name);
}
cards = roomScene.drawPile.remove(lcall("GetPlayerHandcards", Self.id));
handcardAreaItem.add(cards);
}
}