FreeKill/Fk/RoomElement/Dashboard.qml

510 lines
13 KiB
QML
Raw Permalink 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
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);
}
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] = [];
let ids, footnote;
if (pile === "_equip") {
ids = self.equipArea.getAllCards().map(e => e.cid);
footnote = "$Equip";
} else if (pile === "_extra") {
ids = extra_ids;
extra_cards = ids;
footnote = extra_footnote;
} else {
ids = lcall("GetPile", self.playerid, pile);
footnote = pile;
}
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);
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;
}
}
function extractWoodenOx() {
const pile_data = lcall("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;
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");
}
}
})
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]) {
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();
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);
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);
}
}