FreeKill/Fk/RoomElement/Dashboard.qml
YoumuKon 21e4c65204
终结标记与界bugfix (#307)
-
正式移除了作为临时手段的-tmp标记,现在can_use和target_filter支持读取extra_data(card_filter暂时搁置)
-
规范了askForUseCard中card_name和pattern的关系,现在的格式将以pattern为主,若无pattern才会将card_name视为pattern
- 将withinDistanceLimit迁移至ActiveSkill内
- 添加了令卡牌无距离/次数限制的标记判断
- 添加放大了⑨倍的冰伤音效
- 优化了同将判断的逻辑,使其能够准确读取trueName
- 身份场主公选将后其他角色能看见主公技能(只是看见,无实际功能)
- 开局添加不存在的技能时会放出警报
- 修复了findParent在当前事件无parent时报错的bug
- 修复了人工洗牌后不刷新摸牌堆的bug
- 修复了getPile返回牌堆实例的bug
- 修复了getSkillNameList无法过滤主公技的bug
- 修复了死亡后武将牌没有圆角效果的bug
2024-01-25 03:13:57 +08:00

526 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[]
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) {
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, JSON.stringify(roomScene.extra_data)]))) {
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, 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 = 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;
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 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);
if (disabledSkillNames.includes(item.orig)) {
item.enabled = false;
continue;
}
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);
if (disabledSkillNames.includes(item.orig)) {
item.enabled = false;
continue;
}
item.enabled = JSON.parse(Backend.callLuaFunction("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() {
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);
}
}