UI modify (#158)
- 实现移动场上一张牌; - 实现用作记录牌名并可查看的mark; - 将askForChoice和interaction的文本解析方式改为prompt; - 新增属性将牌移至牌堆指定索引位置; - 修改时机“游戏开始时”至正确位置; - 优化衍生牌逻辑; - 新增“卡牌展示后”时机。
This commit is contained in:
parent
c222728a98
commit
1c6304f0f7
|
@ -34,7 +34,7 @@ Rectangle {
|
|||
Layout.preferredHeight: 120
|
||||
cellHeight: 48
|
||||
cellWidth: 48
|
||||
model: 49
|
||||
model: 50
|
||||
visible: false
|
||||
delegate: ItemDelegate {
|
||||
Image {
|
||||
|
|
|
@ -49,7 +49,7 @@ Item {
|
|||
|
||||
TapHandler {
|
||||
onTapped: {
|
||||
lobby_dialog.sourceComponent = Qt.createComponent("Fk.LobbyElement", "EditProfile");
|
||||
lobby_dialog.sourceComponent = Qt.createComponent("EditProfile.qml");
|
||||
lobby_drawer.open();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ Item {
|
|||
icon.name: "media-playback-start"
|
||||
text: Backend.translate("Create Room")
|
||||
onClicked: {
|
||||
lobby_dialog.sourceComponent = Qt.createComponent("Fk.LobbyElement", "CreateRoom");
|
||||
lobby_dialog.sourceComponent = Qt.createComponent("../LobbyElement/CreateRoom.qml");
|
||||
lobby_drawer.open();
|
||||
config.observing = false;
|
||||
}
|
||||
|
|
|
@ -487,14 +487,14 @@ Item {
|
|||
Backend.callLuaFunction("SetInteractionDataOfSkill", [skill_name, "null"]);
|
||||
switch (data.type) {
|
||||
case "combo":
|
||||
skillInteraction.sourceComponent = Qt.createComponent("Fk.SkillInteraction", "SkillCombo");
|
||||
skillInteraction.sourceComponent = Qt.createComponent("../SkillInteraction/SkillCombo.qml");
|
||||
skillInteraction.item.skill = skill_name;
|
||||
skillInteraction.item.default_choice = data["default"];
|
||||
skillInteraction.item.choices = data.choices;
|
||||
// skillInteraction.item.clicked();
|
||||
break;
|
||||
case "spin":
|
||||
skillInteraction.sourceComponent = Qt.createComponent("Fk.SkillInteraction", "SkillSpin");
|
||||
skillInteraction.sourceComponent = Qt.createComponent("../SkillInteraction/SkillSpin.qml");
|
||||
skillInteraction.item.skill = skill_name;
|
||||
skillInteraction.item.from = data.from;
|
||||
skillInteraction.item.to = data.to;
|
||||
|
@ -816,7 +816,7 @@ Item {
|
|||
}
|
||||
|
||||
function startCheat(type, data) {
|
||||
cheatLoader.sourceComponent = Qt.createComponent("Fk.Cheat", type);
|
||||
cheatLoader.sourceComponent = Qt.createComponent(`../Cheat/${type}.qml`);
|
||||
cheatLoader.item.extra_data = data;
|
||||
cheatDrawer.open();
|
||||
}
|
||||
|
|
|
@ -228,7 +228,7 @@ function setEmotion(id, emotion, isCardId) {
|
|||
// TODO: set picture emotion
|
||||
return;
|
||||
}
|
||||
let component = Qt.createComponent("Fk.RoomElement", "PixmapAnimation");
|
||||
let component = Qt.createComponent("../RoomElement/PixmapAnimation.qml");
|
||||
if (component.status !== Component.Ready)
|
||||
return;
|
||||
|
||||
|
@ -277,7 +277,7 @@ function changeHp(id, delta, losthp) {
|
|||
}
|
||||
|
||||
function doIndicate(from, tos) {
|
||||
let component = Qt.createComponent("Fk.RoomElement", "IndicatorLine");
|
||||
let component = Qt.createComponent("../RoomElement/IndicatorLine.qml");
|
||||
if (component.status !== Component.Ready)
|
||||
return;
|
||||
|
||||
|
@ -594,7 +594,7 @@ callbacks["AskForGeneral"] = function(jsonData) {
|
|||
let heg = data[2];
|
||||
roomScene.promptText = Backend.translate("#AskForGeneral");
|
||||
roomScene.state = "replying";
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("Fk.RoomElement", "ChooseGeneralBox");
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/ChooseGeneralBox.qml");
|
||||
let box = roomScene.popupBox.item;
|
||||
box.accepted.connect(() => {
|
||||
replyToServer(JSON.stringify(box.choices));
|
||||
|
@ -627,7 +627,7 @@ callbacks["AskForGuanxing"] = function(jsonData) {
|
|||
let min_bottom_cards = data.min_bottom_cards;
|
||||
let max_bottom_cards = data.max_bottom_cards;
|
||||
roomScene.state = "replying";
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("Fk.RoomElement", "GuanxingBox");
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/GuanxingBox.qml");
|
||||
data.cards.forEach(id => {
|
||||
let d = Backend.callLuaFunction("GetCardData", [id]);
|
||||
cards.push(JSON.parse(d));
|
||||
|
@ -663,7 +663,7 @@ callbacks["AskForChoice"] = function(jsonData) {
|
|||
roomScene.promptText = processPrompt(prompt);
|
||||
}
|
||||
roomScene.state = "replying";
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("Fk.RoomElement", "ChoiceBox");
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/ChoiceBox.qml");
|
||||
let box = roomScene.popupBox.item;
|
||||
box.options = choices;
|
||||
box.skill_name = skill_name;
|
||||
|
@ -702,7 +702,7 @@ callbacks["AskForCardChosen"] = function(jsonData) {
|
|||
roomScene.promptText = Backend.translate("#AskForChooseCard")
|
||||
.arg(Backend.translate(reason));
|
||||
roomScene.state = "replying";
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("Fk.RoomElement", "PlayerCardBox");
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/PlayerCardBox.qml");
|
||||
let box = roomScene.popupBox.item;
|
||||
box.addHandcards(handcards);
|
||||
box.addEquips(equips);
|
||||
|
@ -745,7 +745,7 @@ callbacks["AskForCardsChosen"] = function(jsonData) {
|
|||
roomScene.promptText = Backend.translate("#AskForChooseCard")
|
||||
.arg(Backend.translate(reason));
|
||||
roomScene.state = "replying";
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("Fk.RoomElement", "PlayerCardBox");
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/PlayerCardBox.qml");
|
||||
let box = roomScene.popupBox.item;
|
||||
box.multiChoose = true;
|
||||
box.min = min;
|
||||
|
@ -759,6 +759,33 @@ callbacks["AskForCardsChosen"] = function(jsonData) {
|
|||
});
|
||||
}
|
||||
|
||||
callbacks["AskForMoveCardInBoard"] = function(jsonData) {
|
||||
const data = JSON.parse(jsonData);
|
||||
const { cards, cardsPosition, generalNames } = data;
|
||||
|
||||
roomScene.state = "replying";
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/MoveCardInBoardBox.qml");
|
||||
|
||||
const boxCards = [];
|
||||
cards.forEach(id => {
|
||||
let d = Backend.callLuaFunction("GetCardData", [id]);
|
||||
boxCards.push(JSON.parse(d));
|
||||
});
|
||||
|
||||
const box = roomScene.popupBox.item;
|
||||
box.cards = boxCards;
|
||||
box.cardsPosition = cardsPosition;
|
||||
box.generalNames = generalNames.map(name => {
|
||||
const namesSplited = name.split('/');
|
||||
return namesSplited.length > 1 ? namesSplited.map(nameSplited => Backend.translate(nameSplited)).join('/') : Backend.translate(name)
|
||||
});
|
||||
|
||||
box.arrangeCards();
|
||||
box.accepted.connect(() => {
|
||||
replyToServer(JSON.stringify(box.getResult()));
|
||||
});
|
||||
}
|
||||
|
||||
callbacks["MoveCards"] = function(jsonData) {
|
||||
// jsonData: merged moves
|
||||
let moves = JSON.parse(jsonData);
|
||||
|
@ -938,7 +965,7 @@ callbacks["Animate"] = function(jsonData) {
|
|||
}
|
||||
case "InvokeSkill": {
|
||||
let id = data.player;
|
||||
let component = Qt.createComponent("Fk.RoomElement", "SkillInvokeAnimation");
|
||||
let component = Qt.createComponent("../RoomElement/SkillInvokeAnimation.qml");
|
||||
if (component.status !== Component.Ready)
|
||||
return;
|
||||
|
||||
|
@ -1002,7 +1029,7 @@ callbacks["LogEvent"] = function(jsonData) {
|
|||
|
||||
callbacks["GameOver"] = function(jsonData) {
|
||||
roomScene.state = "notactive";
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("Fk.RoomElement", "GameOverBox");
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/GameOverBox.qml");
|
||||
let box = roomScene.popupBox.item;
|
||||
box.winner = jsonData;
|
||||
roomScene.isStarted = false;
|
||||
|
@ -1011,7 +1038,7 @@ callbacks["GameOver"] = function(jsonData) {
|
|||
callbacks["FillAG"] = (j) => {
|
||||
let data = JSON.parse(j);
|
||||
let ids = data[0];
|
||||
roomScene.manualBox.sourceComponent = Qt.createComponent("Fk.RoomElement", "AG");
|
||||
roomScene.manualBox.sourceComponent = Qt.createComponent("../RoomElement/AG.qml");
|
||||
roomScene.manualBox.item.addIds(ids);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ Item {
|
|||
width: childrenRect.width
|
||||
height: 22
|
||||
Text {
|
||||
text: Backend.translate(mark_name) + ' ' + mark_extra
|
||||
text: Backend.translate(mark_name) + ' ' + (special_value !== '' ? special_value : mark_extra)
|
||||
font.family: fontLibian.name
|
||||
font.pixelSize: 22
|
||||
font.letterSpacing: -0.6
|
||||
|
@ -53,16 +53,20 @@ Item {
|
|||
TapHandler {
|
||||
enabled: root.parent.state != "candidate" || !root.parent.selectable
|
||||
onTapped: {
|
||||
let data = JSON.parse(Backend.callLuaFunction("GetPile", [root.parent.playerid, mark_name]));
|
||||
data = data.filter((e) => e !== -1);
|
||||
if (data.length === 0)
|
||||
return;
|
||||
const params = { name: mark_name };
|
||||
if (mark_name.startsWith('@$')) {
|
||||
params.cardNames = mark_extra.split(',');
|
||||
} else {
|
||||
let data = JSON.parse(Backend.callLuaFunction("GetPile", [root.parent.playerid, mark_name]));
|
||||
data = data.filter((e) => e !== -1);
|
||||
if (data.length === 0)
|
||||
return;
|
||||
|
||||
params.ids = data;
|
||||
}
|
||||
|
||||
// Just for using room's right drawer
|
||||
roomScene.startCheat("ViewPile", {
|
||||
name: mark_name,
|
||||
ids: data
|
||||
});
|
||||
roomScene.startCheat("../RoomElement/ViewPile", params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,11 +87,18 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
data = (data instanceof Array ? data.map((markText) => Backend.translate(markText)).join(' ') : Backend.translate(data));
|
||||
let special_value = '';
|
||||
if (mark.startsWith('@$')) {
|
||||
special_value = data.length;
|
||||
data = data.join(',');
|
||||
} else {
|
||||
data = data instanceof Array ? data.map((markText) => Backend.translate(markText)).join(' ') : Backend.translate(data);
|
||||
}
|
||||
|
||||
if (modelItem)
|
||||
modelItem.mark_extra = data;
|
||||
else
|
||||
markList.append({ mark_name: mark, mark_extra: data });
|
||||
markList.append({ mark_name: mark, mark_extra: data, special_value });
|
||||
|
||||
arrangeMarks();
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ Item {
|
|||
|
||||
Image {
|
||||
id: cardItem
|
||||
source: known ? SkinBank.getCardPicture(cid)
|
||||
source: known ? SkinBank.getCardPicture(cid || name)
|
||||
: (SkinBank.CARD_DIR + "card-back")
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
|
|
@ -14,6 +14,18 @@ GraphicsBox {
|
|||
width: Math.max(140, body.width + 20)
|
||||
height: body.height + title.height + 20
|
||||
|
||||
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", Backend.translate(getPhoto(src).general));
|
||||
if (raw.match("%dest")) raw = raw.replace("%dest", Backend.translate(getPhoto(dest).general));
|
||||
if (raw.match("%arg")) raw = raw.replace("%arg", Backend.translate(data[3]));
|
||||
if (raw.match("%arg2")) raw = raw.replace("%arg2", Backend.translate(data[4]));
|
||||
return raw;
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: body
|
||||
x: 10
|
||||
|
@ -27,7 +39,7 @@ GraphicsBox {
|
|||
|
||||
MetroButton {
|
||||
Layout.fillWidth: true
|
||||
text: Backend.translate(modelData)
|
||||
text: processPrompt(modelData)
|
||||
|
||||
onClicked: {
|
||||
result = index;
|
||||
|
|
|
@ -73,7 +73,7 @@ RowLayout {
|
|||
if (expanded_pile_names.indexOf(pile) !== -1)
|
||||
return;
|
||||
|
||||
let component = Qt.createComponent("Fk.RoomElement", "CardItem");
|
||||
let component = Qt.createComponent("../RoomElement/CardItem.qml");
|
||||
let parentPos = roomScene.mapFromItem(self, 0, 0);
|
||||
|
||||
expanded_piles[pile] = [];
|
||||
|
|
|
@ -50,7 +50,7 @@ Item {
|
|||
|
||||
function remove(outputs)
|
||||
{
|
||||
let component = Qt.createComponent("Fk.RoomElement", "CardItem");
|
||||
let component = Qt.createComponent("CardItem.qml");
|
||||
if (component.status !== Component.Ready)
|
||||
return [];
|
||||
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Fk.Pages
|
||||
|
||||
GraphicsBox {
|
||||
id: root
|
||||
property var cards: []
|
||||
property var cardsPosition: []
|
||||
property var generalNames: []
|
||||
property var result
|
||||
property int padding: 25
|
||||
|
||||
title.text: Backend.translate("Please click to move card")
|
||||
width: body.width + padding * 2
|
||||
height: title.height + body.height + padding * 2
|
||||
|
||||
ColumnLayout {
|
||||
id: body
|
||||
x: padding
|
||||
y: parent.height - padding - height
|
||||
spacing: 20
|
||||
|
||||
Repeater {
|
||||
id: areaRepeater
|
||||
model: generalNames
|
||||
|
||||
Row {
|
||||
spacing: 5
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: "#6B5D42"
|
||||
width: 20
|
||||
height: 100
|
||||
radius: 5
|
||||
|
||||
Text {
|
||||
anchors.fill: parent
|
||||
width: 20
|
||||
height: 100
|
||||
text: modelData
|
||||
color: "white"
|
||||
font.family: fontLibian.name
|
||||
font.pixelSize: 18
|
||||
style: Text.Outline
|
||||
wrapMode: Text.WrapAnywhere
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: cardRepeater
|
||||
model: cards
|
||||
|
||||
Rectangle {
|
||||
color: "#4A4139"
|
||||
width: 93
|
||||
height: 130
|
||||
opacity: 0.5
|
||||
|
||||
Text {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.centerIn: parent
|
||||
text: Backend.translate(JSON.parse(Backend.callLuaFunction("GetCardData", [modelData.cid])).subtype)
|
||||
color: "#90765F"
|
||||
font.family: fontLibian.name
|
||||
font.pixelSize: 16
|
||||
width: parent.width * 0.8
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
property alias cardRepeater: cardRepeater
|
||||
}
|
||||
}
|
||||
|
||||
MetroButton {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
id: buttonConfirm
|
||||
text: Backend.translate("OK")
|
||||
width: 120
|
||||
height: 35
|
||||
enabled: false
|
||||
|
||||
onClicked: close();
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: cardItem
|
||||
model: cards
|
||||
|
||||
CardItem {
|
||||
x: index
|
||||
y: -1
|
||||
cid: modelData.cid
|
||||
name: modelData.name
|
||||
suit: modelData.suit
|
||||
number: modelData.number
|
||||
|
||||
selectable: !result || result.item === this
|
||||
onClicked: {
|
||||
if (!selectable) return;
|
||||
if ((result || {}).item === this) {
|
||||
result = undefined;
|
||||
} else {
|
||||
result = { item: this };
|
||||
}
|
||||
|
||||
updatePosition(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function arrangeCards() {
|
||||
for (let i = 0; i < cards.length; i++) {
|
||||
const curCard = cardItem.itemAt(i);
|
||||
curCard.origX = i * 98 + 50;
|
||||
curCard.origY = cardsPosition[i] * 150 + body.y;
|
||||
curCard.goBack();
|
||||
}
|
||||
}
|
||||
|
||||
function updatePosition(item) {
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const index = cards.findIndex(data => item.cid === data.cid);
|
||||
result && (result.pos = cardsPosition[index]);
|
||||
|
||||
const cardPos = cardsPosition[index] === 0 ? (result ? 1 : 0) : (result ? 0 : 1);
|
||||
const curArea = areaRepeater.itemAt(cardPos);
|
||||
const curBox = curArea.cardRepeater.itemAt(index);
|
||||
const curPos = mapFromItem(curArea, curBox.x, curBox.y);
|
||||
|
||||
item.origX = curPos.x;
|
||||
item.origY = curPos.y;
|
||||
item.goBack(true);
|
||||
|
||||
buttonConfirm.enabled = !!result;
|
||||
}
|
||||
}
|
||||
|
||||
function getResult() {
|
||||
return result ? { cardId: result.item.cid, pos: result.pos } : '';
|
||||
}
|
||||
}
|
|
@ -39,27 +39,41 @@ Item {
|
|||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
topPadding: 5
|
||||
id: skill
|
||||
font.family: fontLi2.name
|
||||
font.pixelSize: Math.max(26 - text.length, 18)
|
||||
visible: false
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Glow {
|
||||
id: glowItem
|
||||
source: skill
|
||||
anchors.fill: skill
|
||||
radius: 6
|
||||
//samples: 8
|
||||
color: "grey"
|
||||
color: "black"
|
||||
spread: 0.3
|
||||
radius: 5
|
||||
}
|
||||
|
||||
LinearGradient {
|
||||
anchors.fill: skill
|
||||
source: skill
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0; color: "#FFE07C" }
|
||||
GradientStop { position: 1; color: "#B79A5F" }
|
||||
GradientStop {
|
||||
position: 0
|
||||
color: "#FEF7C2"
|
||||
}
|
||||
|
||||
GradientStop {
|
||||
position: 0.5
|
||||
color: "#D2AD4A"
|
||||
}
|
||||
|
||||
GradientStop {
|
||||
position: 1
|
||||
color: "#BE9878"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ Item {
|
|||
columns: 4
|
||||
|
||||
Repeater {
|
||||
model: extra_data.ids
|
||||
model: extra_data.ids || extra_data.cardNames
|
||||
|
||||
CardItem {
|
||||
id: cardItem
|
||||
|
@ -79,7 +79,16 @@ Item {
|
|||
height: cardItem.width * 1.4
|
||||
autoBack: false
|
||||
Component.onCompleted: {
|
||||
let data = JSON.parse(Backend.callLuaFunction("GetCardData", [modelData]));
|
||||
let data = {}
|
||||
if (extra_data.ids) {
|
||||
data = JSON.parse(Backend.callLuaFunction("GetCardData", [modelData]));
|
||||
} else {
|
||||
data.cid = 0;
|
||||
data.name = modelData;
|
||||
data.suit = '';
|
||||
data.number = 0;
|
||||
data.color = '';
|
||||
}
|
||||
setData(data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,20 @@ MetroButton {
|
|||
property var choices: []
|
||||
property string default_choice
|
||||
property string answer: default_choice
|
||||
text: Backend.translate(answer)
|
||||
|
||||
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", Backend.translate(getPhoto(src).general));
|
||||
if (raw.match("%dest")) raw = raw.replace("%dest", Backend.translate(getPhoto(dest).general));
|
||||
if (raw.match("%arg")) raw = raw.replace("%arg", Backend.translate(data[3]));
|
||||
if (raw.match("%arg2")) raw = raw.replace("%arg2", Backend.translate(data[4]));
|
||||
return raw;
|
||||
}
|
||||
|
||||
text: processPrompt(answer)
|
||||
|
||||
onAnswerChanged: {
|
||||
if (!answer) return;
|
||||
|
@ -21,7 +34,7 @@ MetroButton {
|
|||
}
|
||||
|
||||
onClicked: {
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("Fk.RoomElement", "ChoiceBox");
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/ChoiceBox.qml");
|
||||
let box = roomScene.popupBox.item;
|
||||
box.options = choices;
|
||||
box.accepted.connect(() => {
|
||||
|
|
|
@ -29,10 +29,18 @@ function getGeneralPicture(name) {
|
|||
return GENERAL_DIR + "0.jpg";
|
||||
}
|
||||
|
||||
function getCardPicture(cid) {
|
||||
let data = JSON.parse(Backend.callLuaFunction("GetCardData", [cid]));
|
||||
let extension = data.extension;
|
||||
let name = data.name;
|
||||
function getCardPicture(cidOrName) {
|
||||
let extension = "";
|
||||
let name = "unknown";
|
||||
if (typeof cidOrName === 'string') {
|
||||
name = cidOrName;
|
||||
extension = Backend.callLuaFunction("GetCardExtensionByName", [cidOrName]);
|
||||
} else {
|
||||
const data = JSON.parse(Backend.callLuaFunction("GetCardData", [cid]));
|
||||
extension = data.extension;
|
||||
name = data.name;
|
||||
}
|
||||
|
||||
let path = AppPath + "/packages/" + extension + "/image/card/" + name + ".png";
|
||||
if (Backend.exists(path)) {
|
||||
return path;
|
||||
|
|
|
@ -98,6 +98,14 @@ function GetCardData(id)
|
|||
return json.encode(ret)
|
||||
end
|
||||
|
||||
function GetCardExtensionByName(cardName)
|
||||
local card = table.find(Fk.cards, function(card)
|
||||
return card.name == cardName
|
||||
end)
|
||||
|
||||
return card and card.package.extensionName or ""
|
||||
end
|
||||
|
||||
function GetAllGeneralPack()
|
||||
local ret = {}
|
||||
for _, name in ipairs(Fk.package_names) do
|
||||
|
|
|
@ -143,6 +143,7 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下
|
|||
["#choose-trigger"] = "请选择一项技能发动",
|
||||
["trigger"] = "选择技能",
|
||||
["Please arrange cards"] = "请拖拽移动卡牌",
|
||||
["Please click to move card"] = "请点击移动卡牌",
|
||||
|
||||
[" thinking..."] = " 思考中...",
|
||||
["AskForGeneral"] = "选择武将",
|
||||
|
@ -203,10 +204,6 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下
|
|||
["$NoWinner"] = "平局!",
|
||||
["Back To Lobby"] = "返回大厅",
|
||||
|
||||
["basic_char"] = "基",
|
||||
["trick_char"] = "锦",
|
||||
["equip_char"] = "装",
|
||||
|
||||
["Bulletin Info"] = "<h2>更新说明</h2>\
|
||||
1. 实现禁将功能;(在武将一览中,点击查看武将并点击退出按钮下方的“禁将/解禁”进行操作);<br>\
|
||||
2. 实现转换技,新增发动转换技动画;<br>\
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
---@field public skill Skill
|
||||
---@field public special_skills string[] | nil
|
||||
---@field public is_damage_card boolean
|
||||
---@field public is_derived boolean|null
|
||||
local Card = class("Card")
|
||||
|
||||
---@alias Suit integer
|
||||
|
@ -96,6 +97,11 @@ function Card:initialize(name, suit, number, color)
|
|||
self.skillNames = {}
|
||||
self.mark = {}
|
||||
|
||||
if string.sub(name, 1, 1) == "&" then
|
||||
self.name = string.sub(name, 2, #name)
|
||||
self.is_derived = true
|
||||
end
|
||||
|
||||
local mt = table.simpleClone(getmetatable(self))
|
||||
local newidx = mt.__newindex or rawset
|
||||
mt.__newindex = function(t, k, v)
|
||||
|
@ -139,6 +145,7 @@ function Card:clone(suit, number)
|
|||
newCard.equip_skill = self.equip_skill
|
||||
newCard.attack_range = self.attack_range
|
||||
newCard.is_damage_card = self.is_damage_card
|
||||
newCard.is_derived = self.is_derived
|
||||
return newCard
|
||||
end
|
||||
|
||||
|
|
|
@ -742,4 +742,17 @@ function Player:getSwitchSkillState(skillName, afterUse)
|
|||
end
|
||||
end
|
||||
|
||||
function Player:canMoveCardInBoardTo(to, id)
|
||||
local card = Fk:getCardById(id)
|
||||
assert(card.type == Card.TypeEquip or card.sub_type == Card.SubtypeDelayedTrick)
|
||||
|
||||
if card.type == Card.TypeEquip then
|
||||
return not to:getEquipment(card.sub_type)
|
||||
else
|
||||
return not table.find(to:getCardIds(Player.Judge), function(cardId)
|
||||
return Fk:getCardById(cardId).name == card.name
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
return Player
|
||||
|
|
|
@ -208,6 +208,20 @@ function table:slice(begin, _end)
|
|||
return ret
|
||||
end
|
||||
|
||||
function table:assign(targetTbl)
|
||||
for key, value in pairs(targetTbl) do
|
||||
if self[key] then
|
||||
if type(value) == "table" then
|
||||
table.insertTable(self[key], value)
|
||||
else
|
||||
table.insert(self[key], value)
|
||||
end
|
||||
else
|
||||
self[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- allow a = "Hello"; a[1] == "H"
|
||||
local str_mt = getmetatable("")
|
||||
str_mt.__index = function(str, k)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
---@alias Event integer
|
||||
|
||||
fk.NonTrigger = 1
|
||||
fk.GamePrepared = 78
|
||||
fk.GameStart = 2
|
||||
fk.TurnStart = 3
|
||||
fk.TurnEnd = 73
|
||||
|
@ -101,4 +102,8 @@ fk.BeforeTriggerSkillUse = 75
|
|||
|
||||
fk.BeforeDrawCard = 76
|
||||
|
||||
fk.NumOfEvents = 77
|
||||
fk.CardShown = 77
|
||||
|
||||
-- 78 = GamePrepared
|
||||
|
||||
fk.NumOfEvents = 79
|
||||
|
|
|
@ -92,7 +92,7 @@ GameEvent.functions[GameEvent.DrawInitial] = function(self)
|
|||
room:notifyMoveFocus(room.alive_players, "AskForLuckCard")
|
||||
room:doBroadcastNotify("AskForLuckCard", room.settings.luckTime or 4)
|
||||
|
||||
local remainTime = room.timeout
|
||||
local remainTime = room.timeout + 1
|
||||
local currentTime = os.time()
|
||||
local elapsed = 0
|
||||
|
||||
|
@ -127,12 +127,17 @@ GameEvent.functions[GameEvent.Round] = function(self)
|
|||
local logic = room.logic
|
||||
local p
|
||||
|
||||
if room:getTag("FirstRound") then
|
||||
local isFirstRound = room:getTag("FirstRound")
|
||||
if isFirstRound then
|
||||
room:setTag("FirstRound", false)
|
||||
end
|
||||
room:setTag("RoundCount", room:getTag("RoundCount") + 1)
|
||||
room:doBroadcastNotify("UpdateRoundNum", room:getTag("RoundCount"))
|
||||
|
||||
if isFirstRound then
|
||||
logic:trigger(fk.GameStart, room.current)
|
||||
end
|
||||
|
||||
logic:trigger(fk.RoundStart, room.current)
|
||||
|
||||
repeat
|
||||
|
|
|
@ -37,6 +37,7 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
|
|||
moveVisible = cardsMoveInfo.moveVisible,
|
||||
specialName = cardsMoveInfo.specialName,
|
||||
specialVisible = cardsMoveInfo.specialVisible,
|
||||
drawPilePosition = cardsMoveInfo.drawPilePosition,
|
||||
}
|
||||
|
||||
table.insert(cardsMoveStructs, cardsMoveStruct)
|
||||
|
@ -100,7 +101,18 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
|
|||
toAreaIds = self.void
|
||||
end
|
||||
|
||||
table.insert(toAreaIds, data.toArea == Card.DrawPile and 1 or #toAreaIds + 1, info.cardId)
|
||||
if data.toArea == Card.DrawPile then
|
||||
local putIndex = data.drawPilePosition or 1
|
||||
if putIndex == -1 then
|
||||
putIndex = #self.draw_pile + 1
|
||||
elseif putIndex < 1 or putIndex > #self.draw_pile + 1 then
|
||||
putIndex = 1
|
||||
end
|
||||
|
||||
table.insert(toAreaIds, putIndex, info.cardId)
|
||||
else
|
||||
table.insert(toAreaIds, info.cardId)
|
||||
end
|
||||
end
|
||||
self:setCardArea(info.cardId, data.toArea, data.to)
|
||||
if data.toArea == Card.DrawPile or realFromArea == Card.DrawPile then
|
||||
|
|
|
@ -187,7 +187,7 @@ GameEvent.functions[GameEvent.UseCard] = function(self)
|
|||
table.insert(cardUseEvent.responseToEvent.cardsResponded, cardUseEvent.card)
|
||||
end
|
||||
|
||||
for _, event in ipairs({ fk.AfterCardUseDeclared, fk.AfterCardTargetDeclared, fk.BeforeCardUseEffect, fk.CardUsing }) do
|
||||
for _, event in ipairs({ fk.AfterCardUseDeclared, fk.AfterCardTargetDeclared, fk.CardUsing }) do
|
||||
if not cardUseEvent.toCard and #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then
|
||||
break
|
||||
end
|
||||
|
|
|
@ -233,6 +233,16 @@ end
|
|||
function GameLogic:prepareDrawPile()
|
||||
local room = self.room
|
||||
local allCardIds = Fk:getAllCardIds()
|
||||
|
||||
for i = #allCardIds, 1, -1 do
|
||||
if Fk:getCardById(allCardIds[i]).is_derived then
|
||||
local id = allCardIds[i]
|
||||
table.removeOne(allCardIds, id)
|
||||
table.insert(room.void, id)
|
||||
room:setCardArea(id, Card.Void, nil)
|
||||
end
|
||||
end
|
||||
|
||||
table.shuffle(allCardIds)
|
||||
room.draw_pile = allCardIds
|
||||
for _, id in ipairs(room.draw_pile) do
|
||||
|
@ -291,7 +301,7 @@ function GameLogic:prepareForStart()
|
|||
end
|
||||
|
||||
function GameLogic:action()
|
||||
self:trigger(fk.GameStart)
|
||||
self:trigger(fk.GamePrepared)
|
||||
local room = self.room
|
||||
|
||||
execGameEvent(GameEvent.DrawInitial)
|
||||
|
|
|
@ -1572,6 +1572,82 @@ function Room:askForCustomDialog(player, focustxt, qmlPath, extra_data)
|
|||
})
|
||||
end
|
||||
|
||||
---@field player ServerPlayer
|
||||
---@field targetOne ServerPlayer
|
||||
---@field targetTwo ServerPlayer
|
||||
---@field skillName string
|
||||
---@return cardId
|
||||
function Room:askForMoveCardInBoard(player, targetOne, targetTwo, skillName)
|
||||
local cards = {}
|
||||
local cardsPosition = {}
|
||||
for _, equipId in ipairs(targetOne:getCardIds(Player.Equip)) do
|
||||
if targetOne:canMoveCardInBoardTo(targetTwo, equipId) then
|
||||
table.insert(cards, equipId)
|
||||
end
|
||||
end
|
||||
for _, equipId in ipairs(targetTwo:getCardIds(Player.Equip)) do
|
||||
if targetTwo:canMoveCardInBoardTo(targetOne, equipId) then
|
||||
table.insert(cards, equipId)
|
||||
end
|
||||
end
|
||||
|
||||
if #cards > 0 then
|
||||
table.sort(cards, function(prev, next)
|
||||
local prevSubType = Fk:getCardById(prev).sub_type
|
||||
local nextSubType = Fk:getCardById(next).sub_type
|
||||
|
||||
return prevSubType < nextSubType
|
||||
end)
|
||||
|
||||
for _, id in ipairs(cards) do
|
||||
table.insert(cardsPosition, self:getCardOwner(id) == targetOne and 0 or 1)
|
||||
end
|
||||
end
|
||||
|
||||
for _, trickId in ipairs(targetOne:getCardIds(Player.Judge)) do
|
||||
if targetOne:canMoveCardInBoardTo(targetTwo, trickId) then
|
||||
table.insert(cards, trickId)
|
||||
table.insert(cardsPosition, 0)
|
||||
end
|
||||
end
|
||||
for _, trickId in ipairs(targetTwo:getCardIds(Player.Judge)) do
|
||||
if targetTwo:canMoveCardInBoardTo(targetOne, trickId) then
|
||||
table.insert(cards, trickId)
|
||||
table.insert(cardsPosition, 1)
|
||||
end
|
||||
end
|
||||
|
||||
if #cards == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local firstGeneralName = targetOne.general + (targetOne.deputyGeneral ~= "" and ("/" .. targetOne.deputyGeneral) or "")
|
||||
local secGeneralName = targetTwo.general + (targetTwo.deputyGeneral ~= "" and ("/" .. targetTwo.deputyGeneral) or "")
|
||||
|
||||
local data = { cards = cards, cardsPosition = cardsPosition, generalNames = { firstGeneralName, secGeneralName } }
|
||||
local command = "AskForMoveCardInBoard"
|
||||
self:notifyMoveFocus(player, command)
|
||||
local result = self:doRequest(player, command, json.encode(data))
|
||||
|
||||
if result == "" then
|
||||
local randomIndex = math.random(1, #cards)
|
||||
result = { cardId = cards[randomIndex], pos = cardsPosition[randomIndex] }
|
||||
else
|
||||
result = json.decode(result)
|
||||
end
|
||||
|
||||
local cardToMove = Fk:getCardById(result.cardId)
|
||||
self:moveCardTo(
|
||||
cardToMove,
|
||||
cardToMove.type == Card.TypeEquip and Player.Equip or Player.Judge,
|
||||
result.pos == 0 and targetTwo or targetOne,
|
||||
fk.ReasonPut,
|
||||
skillName,
|
||||
nil,
|
||||
true
|
||||
)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- 使用牌
|
||||
------------------------------------------------------------------------
|
||||
|
@ -1712,6 +1788,7 @@ function Room:doCardUseEffect(cardUseEvent)
|
|||
|
||||
local realCardIds = self:getSubcardsByRule(cardUseEvent.card, { Card.Processing })
|
||||
|
||||
self.logic:trigger(fk.BeforeCardUseEffect, cardUseEvent.from, cardUseEvent)
|
||||
-- If using Equip or Delayed trick, move them to the area and return
|
||||
if cardUseEvent.card.type == Card.TypeEquip then
|
||||
if #realCardIds == 0 then
|
||||
|
|
|
@ -343,6 +343,8 @@ function ServerPlayer:showCards(cards)
|
|||
from = self.id,
|
||||
cards = cards,
|
||||
})
|
||||
|
||||
room.logic:trigger(fk.CardShown, self, { cardIds = cards })
|
||||
end
|
||||
|
||||
---@param from_phase Phase
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
---@field public moveVisible boolean|null
|
||||
---@field public specialName string|null
|
||||
---@field public specialVisible boolean|null
|
||||
---@field public drawPilePosition number|null @ 移至牌堆的索引位置,值为-1代表置入牌堆底,或者牌堆牌数+1也为牌堆底
|
||||
|
||||
---@class PindianResult
|
||||
---@field public toCard Card
|
||||
|
|
|
@ -78,31 +78,9 @@ local maxCardsSkill = fk.CreateMaxCardsSkill{
|
|||
end,
|
||||
}
|
||||
|
||||
local moveTokenSkill = fk.CreateTriggerSkill{
|
||||
name = "move_token_skill",
|
||||
global = true,
|
||||
|
||||
refresh_events = {fk.GameStart}, --refresh优先于on_use,不要在正常的游戏开始发牌技能refresh中拿牌
|
||||
can_refresh = function(self, event, target, player, data)
|
||||
return player.seat == 1
|
||||
end,
|
||||
on_refresh = function(self, event, target, player, data)
|
||||
local room = player.room
|
||||
for i = #room.draw_pile, 1, -1 do
|
||||
if Fk:getCardById(room.draw_pile[i]).name[1] == "&" then
|
||||
local id = room.draw_pile[i]
|
||||
table.removeOne(room.draw_pile, id)
|
||||
table.insert(room.void, id)
|
||||
room:setCardArea(id, Card.Void, nil)
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
AuxSkills = {
|
||||
discardSkill,
|
||||
chooseCardsSkill,
|
||||
choosePlayersSkill,
|
||||
maxCardsSkill,
|
||||
moveTokenSkill,
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ end
|
|||
GameRule = fk.CreateTriggerSkill{
|
||||
name = "game_rule",
|
||||
events = {
|
||||
fk.GameStart,
|
||||
fk.GamePrepared,
|
||||
fk.AskForPeaches, fk.AskForPeachesDone,
|
||||
fk.GameOverJudge, fk.BuryVictim,
|
||||
},
|
||||
|
@ -58,7 +58,7 @@ GameRule = fk.CreateTriggerSkill{
|
|||
return false
|
||||
end
|
||||
|
||||
if event == fk.GameStart then
|
||||
if event == fk.GamePrepared then
|
||||
room:setTag("FirstRound", true)
|
||||
room:setTag("RoundCount", 0)
|
||||
return false
|
||||
|
|
|
@ -15,6 +15,17 @@ Fk:loadTranslationTable{
|
|||
["club"] = "梅花",
|
||||
["diamond"] = "方块",
|
||||
|
||||
["basic_char"] = "基",
|
||||
["trick_char"] = "锦",
|
||||
["equip_char"] = "装",
|
||||
|
||||
["weapon"] = "武器牌",
|
||||
["armor"] = "防具牌",
|
||||
["defensive_horse"] = "防御坐骑牌",
|
||||
["offensive_horse"] = "进攻坐骑牌",
|
||||
["treasure"] = "宝物牌",
|
||||
["delayed_trick"] = "延时类锦囊牌",
|
||||
|
||||
["slash"] = "杀",
|
||||
[":slash"] = "基本牌<br /><b>时机</b>:出牌阶段<br /><b>目标</b>:攻击范围内的一名其他角色<br /><b>效果</b>:对目标角色造成1点伤害。",
|
||||
["#slash-jink"] = "%src 对你使用了杀,请使用 %arg 张闪",
|
||||
|
|
Loading…
Reference in New Issue