Enhancement (#253)

- 修复clone狮子的bug
- 支持拓展自定义游戏事件
- 修复反选拓展包时极其卡顿的bug
- 修复自订身份无法正常显示的bug
- 谋攻篇askForCard(s)Chosen
- 修复了倾国时点取消的bug
- player:broadcastSkillInvoke
- 修复客户端白名单忘记屏蔽的bug
This commit is contained in:
notify 2023-08-24 21:37:24 +08:00 committed by GitHub
parent d0913e42ce
commit 607d3b010c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 269 additions and 252 deletions

View File

@ -88,7 +88,7 @@ Flickable {
id: warning id: warning
anchors.rightMargin: 8 anchors.rightMargin: 8
visible: { visible: {
config.disabledPack; // visible //config.disabledPack; // visible
const avail = JSON.parse(Backend.callLuaFunction("GetAvailableGeneralsNum", [])); const avail = JSON.parse(Backend.callLuaFunction("GetAvailableGeneralsNum", []));
const ret = avail < config.preferredGeneralNum * config.preferedPlayerNum; const ret = avail < config.preferredGeneralNum * config.preferedPlayerNum;
return ret; return ret;

View File

@ -94,13 +94,19 @@ function doOkButton() {
replyToServer("1"); replyToServer("1");
} }
let _is_canceling = false;
function doCancelButton() { function doCancelButton() {
if (_is_canceling) return;
_is_canceling = true;
if (roomScene.state === "playing") { if (roomScene.state === "playing") {
dashboard.stopPending(); dashboard.stopPending();
dashboard.deactivateSkillButton(); dashboard.deactivateSkillButton();
dashboard.unSelectAll(); dashboard.unSelectAll();
dashboard.enableCards(); dashboard.enableCards();
dashboard.enableSkills(); dashboard.enableSkills();
_is_canceling = false;
return; return;
} else if (roomScene.state === "responding") { } else if (roomScene.state === "responding") {
const p = dashboard.pending_skill; const p = dashboard.pending_skill;
@ -113,6 +119,8 @@ function doCancelButton() {
dashboard.enableCards(roomScene.responding_card); dashboard.enableCards(roomScene.responding_card);
dashboard.enableSkills(roomScene.responding_card); dashboard.enableSkills(roomScene.responding_card);
} }
_is_canceling = false;
return; return;
} }
@ -121,9 +129,13 @@ function doCancelButton() {
"luckcard", false "luckcard", false
].join(",")); ].join(","));
roomScene.state = "notactive"; roomScene.state = "notactive";
_is_canceling = false;
return; return;
} }
replyToServer("__cancel"); replyToServer("__cancel");
_is_canceling = false;
} }
function replyToServer(jsonData) { function replyToServer(jsonData) {
@ -934,37 +946,25 @@ callbacks["AskForCardChosen"] = (jsonData) => {
// jsonData: [ int[] handcards, int[] equips, int[] delayedtricks, // jsonData: [ int[] handcards, int[] equips, int[] delayedtricks,
// string reason ] // string reason ]
const data = JSON.parse(jsonData); const data = JSON.parse(jsonData);
const handcard_ids = data[0]; const reason = data._reason;
const equip_ids = data[1];
const delayedTrick_ids = data[2];
const reason = data[3];
const handcards = [];
const equips = [];
const delayedTricks = [];
handcard_ids.forEach(id => {
const card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
handcards.push(card_data);
});
equip_ids.forEach(id => {
const card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
equips.push(card_data);
});
delayedTrick_ids.forEach(id => {
const card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
delayedTricks.push(card_data);
});
roomScene.promptText = Backend.translate("#AskForChooseCard") roomScene.promptText = Backend.translate("#AskForChooseCard")
.arg(Backend.translate(reason)); .arg(Backend.translate(reason));
roomScene.state = "replying"; roomScene.state = "replying";
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/PlayerCardBox.qml"); roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/PlayerCardBox.qml");
const box = roomScene.popupBox.item; const box = roomScene.popupBox.item;
box.addHandcards(handcards); for (let d of data.card_data) {
box.addEquips(equips); const arr = [];
box.addDelayedTricks(delayedTricks); const ids = d[1];
ids.forEach(id => {
const card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
arr.push(card_data);
});
box.addCustomCards(d[0], arr);
}
roomScene.popupBox.moveToCenter(); roomScene.popupBox.moveToCenter();
box.cardSelected.connect(function(cid){ box.cardSelected.connect(function(cid){
replyToServer(cid); replyToServer(cid);
@ -975,30 +975,9 @@ callbacks["AskForCardsChosen"] = (jsonData) => {
// jsonData: [ int[] handcards, int[] equips, int[] delayedtricks, // jsonData: [ int[] handcards, int[] equips, int[] delayedtricks,
// int min, int max, string reason ] // int min, int max, string reason ]
const data = JSON.parse(jsonData); const data = JSON.parse(jsonData);
const handcard_ids = data[0]; const min = data._min;
const equip_ids = data[1]; const max = data._max;
const delayedTrick_ids = data[2]; const reason = data._reason;
const min = data[3];
const max = data[4];
const reason = data[5];
const handcards = [];
const equips = [];
const delayedTricks = [];
handcard_ids.forEach(id => {
const card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
handcards.push(card_data);
});
equip_ids.forEach(id => {
const card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
equips.push(card_data);
});
delayedTrick_ids.forEach(id => {
const card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
delayedTricks.push(card_data);
});
roomScene.promptText = Backend.translate("#AskForChooseCards") roomScene.promptText = Backend.translate("#AskForChooseCards")
.arg(Backend.translate(reason)).arg(min).arg(max); .arg(Backend.translate(reason)).arg(min).arg(max);
@ -1008,9 +987,17 @@ callbacks["AskForCardsChosen"] = (jsonData) => {
box.multiChoose = true; box.multiChoose = true;
box.min = min; box.min = min;
box.max = max; box.max = max;
box.addHandcards(handcards); for (let d of data.card_data) {
box.addEquips(equips); const arr = [];
box.addDelayedTricks(delayedTricks); const ids = d[1];
ids.forEach(id => {
const card_data = JSON.parse(Backend.callLuaFunction("GetCardData", [id]));
arr.push(card_data);
});
box.addCustomCards(d[0], arr);
}
roomScene.popupBox.moveToCenter(); roomScene.popupBox.moveToCenter();
box.cardsSelected.connect((ids) => { box.cardsSelected.connect((ids) => {
replyToServer(JSON.stringify(ids)); replyToServer(JSON.stringify(ids));
@ -1295,12 +1282,38 @@ callbacks["LogEvent"] = (jsonData) => {
} }
case "PlaySkillSound": { case "PlaySkillSound": {
const skill = data.name; const skill = data.name;
let extension = data.extension; // let extension = data.extension;
if (!extension) { let extension;
const data = JSON.parse(Backend.callLuaFunction("GetSkillData", [skill])); let path;
extension = data.extension; let dat;
// try main general
if (data.general) {
dat = JSON.parse(Backend.callLuaFunction("GetGeneralData", [data.general]));
extension = dat.extension;
path = "./packages/" + extension + "/audio/skill/" + skill + "_" + data.general;
if (Backend.exists(path + ".mp3") || Backend.exists(path + "1.mp3")) {
Backend.playSound(path, data.i);
break;
} }
Backend.playSound("./packages/" + extension + "/audio/skill/" + skill, data.i); }
// secondly try deputy general
if (data.deputy) {
dat = JSON.parse(Backend.callLuaFunction("GetGeneralData", [data.deputy]));
extension = dat.extension;
path = "./packages/" + extension + "/audio/skill/" + skill + "_" + data.deputy;
if (Backend.exists(path + ".mp3") || Backend.exists(path + "1.mp3")) {
Backend.playSound(path, data.i);
break;
}
}
// finally normal skill
dat = JSON.parse(Backend.callLuaFunction("GetSkillData", [skill]));
extension = dat.extension;
path = "./packages/" + extension + "/audio/skill/" + skill;
Backend.playSound(path, data.i);
break; break;
} }
case "PlaySound": { case "PlaySound": {

View File

@ -377,7 +377,8 @@ RowLayout {
function deactivateSkillButton() { function deactivateSkillButton() {
for (let i = 0; i < skillButtons.count; i++) { for (let i = 0; i < skillButtons.count; i++) {
skillButtons.itemAt(i).pressed = false; let item = skillButtons.itemAt(i);
item.pressed = false;
} }
} }

View File

@ -10,8 +10,8 @@ GraphicsBox {
title.text: root.multiChoose ? Backend.translate("$ChooseCards").arg(root.min).arg(root.max) : Backend.translate("$ChooseCard") title.text: root.multiChoose ? Backend.translate("$ChooseCards").arg(root.min).arg(root.max) : Backend.translate("$ChooseCard")
// TODO: Adjust the UI design in case there are more than 7 cards // TODO: Adjust the UI design in case there are more than 7 cards
width: 70 + Math.min(7, Math.max(1, handcards.count, equips.count, delayedTricks.count)) * 100 width: 70 + 700
height: 50 + (handcards.count > 0 ? 150 : 0) + (equips.count > 0 ? 150 : 0) + (delayedTricks.count > 0 ? 150 : 0) height: 50 + Math.min(cardView.contentHeight, 400) + (multiChoose ? 20 : 0)
signal cardSelected(int cid) signal cardSelected(int cid)
signal cardsSelected(var ids) signal cardsSelected(var ids)
@ -21,39 +21,35 @@ GraphicsBox {
property var selected_ids: [] property var selected_ids: []
ListModel { ListModel {
id: handcards id: cardModel
} }
ListModel { ListView {
id: equips id: cardView
}
ListModel {
id: delayedTricks
}
ColumnLayout {
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 40 anchors.topMargin: 40
anchors.leftMargin: 20 anchors.leftMargin: 20
anchors.rightMargin: 20 anchors.rightMargin: 20
anchors.bottomMargin: 20 anchors.bottomMargin: 20
spacing: 20
model: cardModel
clip: true
Row { delegate: RowLayout {
height: 130
spacing: 15 spacing: 15
visible: handcards.count > 0 visible: areaCards.count > 0
Rectangle { Rectangle {
border.color: "#A6967A" border.color: "#A6967A"
radius: 5 radius: 5
color: "transparent" color: "transparent"
width: 18 width: 18
height: parent.height height: 130
Layout.alignment: Qt.AlignTop
Text { Text {
color: "#E4D5A0" color: "#E4D5A0"
text: Backend.translate("$Hand") text: Backend.translate(areaName)
anchors.fill: parent anchors.fill: parent
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@ -62,10 +58,10 @@ GraphicsBox {
} }
} }
Row { GridLayout {
spacing: 7 columns: 7
Repeater { Repeater {
model: handcards model: areaCards
CardItem { CardItem {
cid: model.cid cid: model.cid
@ -82,147 +78,50 @@ GraphicsBox {
} }
onSelectedChanged: { onSelectedChanged: {
if (selected) { if (selected) {
origY = origY - 20; virt_name = "$Selected";
root.selected_ids.push(cid);
} else { } else {
origY = origY + 20; virt_name = "";
root.selected_ids.splice(root.selected_ids.indexOf(cid), 1);
} }
origX = x;
goBack(true);
root.selected_ids = root.selected_ids; root.selected_ids = root.selected_ids;
} }
} }
} }
} }
} }
Row {
height: 130
spacing: 15
visible: equips.count > 0
Rectangle {
border.color: "#A6967A"
radius: 5
color: "transparent"
width: 18
height: parent.height
Text {
color: "#E4D5A0"
text: Backend.translate("$Equip")
anchors.fill: parent
wrapMode: Text.WrapAnywhere
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 15
}
}
Row {
spacing: 7
Repeater {
model: equips
CardItem {
cid: model.cid
name: model.name
suit: model.suit
number: model.number
autoBack: false
selectable: true
onClicked: {
if (!root.multiChoose) {
root.cardSelected(cid);
}
}
onSelectedChanged: {
if (selected) {
origY = origY - 20;
root.selected_ids.push(cid);
} else {
origY = origY + 20;
root.selected_ids.splice(root.selected_ids.indexOf(cid));
}
origX = x;
goBack(true);
root.selected_ids = root.selected_ids;
}
}
}
}
}
Row {
height: 130
spacing: 15
visible: delayedTricks.count > 0
Rectangle {
border.color: "#A6967A"
radius: 5
color: "transparent"
width: 18
height: parent.height
Text {
color: "#E4D5A0"
text: Backend.translate("$Judge")
anchors.fill: parent
wrapMode: Text.WrapAnywhere
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 15
}
}
Row {
spacing: 7
Repeater {
model: delayedTricks
CardItem {
cid: model.cid
name: model.name
suit: model.suit
number: model.number
autoBack: false
selectable: true
onClicked: {
if (!root.multiChoose) {
root.cardSelected(cid);
}
}
onSelectedChanged: {
if (selected) {
origY = origY - 20;
root.selected_ids.push(cid);
} else {
origY = origY + 20;
root.selected_ids.splice(root.selected_ids.indexOf(cid));
}
origX = x;
goBack(true);
root.selected_ids = root.selected_ids;
}
}
}
}
} }
MetroButton { MetroButton {
anchors.bottom: parent.bottom
text: Backend.translate("OK") text: Backend.translate("OK")
visible: root.multiChoose visible: root.multiChoose
enabled: root.selected_ids.length <= root.max && root.selected_ids.length >= root.min enabled: root.selected_ids.length <= root.max && root.selected_ids.length >= root.min
onClicked: root.cardsSelected(root.selected_ids) onClicked: root.cardsSelected(root.selected_ids)
} }
}
onCardSelected: finished(); onCardSelected: finished();
function addHandcards(cards) function findAreaModel(name) {
{ let ret;
for (let i = 0; i < cardModel.count; i++) {
let item = cardModel.get(i);
if (item.areaName == name) {
ret = item;
break;
}
}
if (!ret) {
ret = {
areaName: name,
areaCards: [],
}
cardModel.append(ret);
ret = findAreaModel(name);
}
return ret;
}
function addHandcards(cards) {
let handcards = findAreaModel('$Hand').areaCards;
if (cards instanceof Array) { if (cards instanceof Array) {
for (let i = 0; i < cards.length; i++) for (let i = 0; i < cards.length; i++)
handcards.append(cards[i]); handcards.append(cards[i]);
@ -233,6 +132,7 @@ GraphicsBox {
function addEquips(cards) function addEquips(cards)
{ {
let equips = findAreaModel('$Equip').areaCards;
if (cards instanceof Array) { if (cards instanceof Array) {
for (let i = 0; i < cards.length; i++) for (let i = 0; i < cards.length; i++)
equips.append(cards[i]); equips.append(cards[i]);
@ -243,6 +143,7 @@ GraphicsBox {
function addDelayedTricks(cards) function addDelayedTricks(cards)
{ {
let delayedTricks = findAreaModel('$Judge').areaCards;
if (cards instanceof Array) { if (cards instanceof Array) {
for (let i = 0; i < cards.length; i++) for (let i = 0; i < cards.length; i++)
delayedTricks.append(cards[i]); delayedTricks.append(cards[i]);
@ -250,4 +151,14 @@ GraphicsBox {
delayedTricks.append(cards); delayedTricks.append(cards);
} }
} }
function addCustomCards(name, cards) {
let area = findAreaModel(name).areaCards;
if (cards instanceof Array) {
for (let i = 0; i < cards.length; i++)
area.append(cards[i]);
} else {
area.append(cards);
}
}
} }

View File

@ -132,7 +132,7 @@ function getRolePic(role) {
} else { } else {
for (let dir of Backend.ls(AppPath + "/packages/")) { for (let dir of Backend.ls(AppPath + "/packages/")) {
if (dir.endsWith(".disabled")) continue; if (dir.endsWith(".disabled")) continue;
path = AppPath + "/packages/" + dir + "/image/role/" + name + ".png"; path = AppPath + "/packages/" + dir + "/image/role/" + role + ".png";
if (Backend.exists(path)) return path; if (Backend.exists(path)) return path;
} }
} }

View File

@ -261,6 +261,10 @@ fk.client_callback["EnterRoom"] = function(jsonData)
local data = _data[3] local data = _data[3]
ClientInstance.enter_room_data = jsonData; ClientInstance.enter_room_data = jsonData;
ClientInstance.room_settings = data ClientInstance.room_settings = data
table.insertTableIfNeed(
data.disabledPack,
Fk.game_mode_disabled[data.gameMode]
)
ClientInstance.disabled_packs = data.disabledPack ClientInstance.disabled_packs = data.disabledPack
ClientInstance.disabled_generals = data.disabledGenerals ClientInstance.disabled_generals = data.disabledGenerals
ClientInstance:notifyUI("EnterRoom", jsonData) ClientInstance:notifyUI("EnterRoom", jsonData)
@ -371,11 +375,11 @@ fk.client_callback["AskForCardChosen"] = function(jsonData)
local hand = target.player_cards[Player.Hand] local hand = target.player_cards[Player.Hand]
local equip = target.player_cards[Player.Equip] local equip = target.player_cards[Player.Equip]
local judge = target.player_cards[Player.Judge] local judge = target.player_cards[Player.Judge]
local ui_data = flag
if type(flag) == "string" then
if not string.find(flag, "h") then if not string.find(flag, "h") then
hand = {} hand = {}
elseif target.id ~= Self.id then
-- FIXME: can not see other's handcard
hand = table.map(hand, function() return -1 end)
end end
if not string.find(flag, "e") then if not string.find(flag, "e") then
equip = {} equip = {}
@ -383,7 +387,16 @@ fk.client_callback["AskForCardChosen"] = function(jsonData)
if not string.find(flag, "j") then if not string.find(flag, "j") then
judge = {} judge = {}
end end
local ui_data = {hand, equip, judge, reason} ui_data = {
_reason = reason,
card_data = {},
}
if #hand ~= 0 then table.insert(ui_data.card_data, { "$Hand", hand }) end
if #equip ~= 0 then table.insert(ui_data.card_data, { "$Equip", equip }) end
if #judge ~= 0 then table.insert(ui_data.card_data, { "$Judge", judge }) end
else
ui_data._reason = reason
end
ClientInstance:notifyUI("AskForCardChosen", json.encode(ui_data)) ClientInstance:notifyUI("AskForCardChosen", json.encode(ui_data))
end end
@ -395,6 +408,9 @@ fk.client_callback["AskForCardsChosen"] = function(jsonData)
local hand = target.player_cards[Player.Hand] local hand = target.player_cards[Player.Hand]
local equip = target.player_cards[Player.Equip] local equip = target.player_cards[Player.Equip]
local judge = target.player_cards[Player.Judge] local judge = target.player_cards[Player.Judge]
local ui_data = flag
if type(flag) == "string" then
if not string.find(flag, "h") then if not string.find(flag, "h") then
hand = {} hand = {}
end end
@ -404,7 +420,20 @@ fk.client_callback["AskForCardsChosen"] = function(jsonData)
if not string.find(flag, "j") then if not string.find(flag, "j") then
judge = {} judge = {}
end end
local ui_data = {hand, equip, judge, min, max, reason} ui_data = {
_min = min,
_max = max,
_reason = reason,
card_data = {}
}
if #hand ~= 0 then table.insert(ui_data.card_data, { "$Hand", hand }) end
if #equip ~= 0 then table.insert(ui_data.card_data, { "$Equip", equip }) end
if #judge ~= 0 then table.insert(ui_data.card_data, { "$Judge", judge }) end
else
ui_data._min = min
ui_data._max = max
ui_data._reason = reason
end
ClientInstance:notifyUI("AskForCardsChosen", json.encode(ui_data)) ClientInstance:notifyUI("AskForCardsChosen", json.encode(ui_data))
end end

View File

@ -224,6 +224,7 @@ FreeKill使用的是libgit2的C API与此同时使用Git完成拓展包的下
["$Hand"] = "手牌区", ["$Hand"] = "手牌区",
["$Equip"] = "装备区", ["$Equip"] = "装备区",
["$Judge"] = "判定区", ["$Judge"] = "判定区",
['$Selected'] = "已选择",
["#AskForUseActiveSkill"] = "请使用技能 %1", ["#AskForUseActiveSkill"] = "请使用技能 %1",
["#AskForUseCard"] = "请使用卡牌 %1", ["#AskForUseCard"] = "请使用卡牌 %1",
["#AskForResponseCard"] = "请打出卡牌 %1", ["#AskForResponseCard"] = "请打出卡牌 %1",

View File

@ -143,8 +143,6 @@ function Card:clone(suit, number)
local newCard = self.class:new(self.name, suit, number) local newCard = self.class:new(self.name, suit, number)
newCard.skill = self.skill newCard.skill = self.skill
newCard.special_skills = self.special_skills newCard.special_skills = self.special_skills
newCard.equip_skill = self.equip_skill
newCard.attack_range = self.attack_range
newCard.is_damage_card = self.is_damage_card newCard.is_damage_card = self.is_damage_card
newCard.multiple_targets = self.multiple_targets newCard.multiple_targets = self.multiple_targets
newCard.is_derived = self.is_derived newCard.is_derived = self.is_derived

View File

@ -26,7 +26,16 @@ function EquipCard:onUninstall(room, player)
end end
end end
function EquipCard:clone(suit, number)
local ret = Card.clone(self, suit, number)
ret.equip_skill = self.equip_skill
ret.onInstall = self.onInstall
ret.onUninstall = self.onUninstall
return ret
end
---@class Weapon : EquipCard ---@class Weapon : EquipCard
---@field public attack_range integer
local Weapon = EquipCard:subclass("Weapon") local Weapon = EquipCard:subclass("Weapon")
function Weapon:initialize(name, suit, number, attackRange) function Weapon:initialize(name, suit, number, attackRange)
@ -35,6 +44,12 @@ function Weapon:initialize(name, suit, number, attackRange)
self.attack_range = attackRange or 1 self.attack_range = attackRange or 1
end end
function Weapon:clone(suit, number)
local ret = EquipCard.clone(self, suit, number)
ret.attack_range = self.attack_range
return ret
end
---@class Armor : EquipCard ---@class Armor : EquipCard
local Armor = EquipCard:subclass("armor") local Armor = EquipCard:subclass("armor")

View File

@ -24,6 +24,7 @@
---@field public currentResponseReason string @ 要求用牌的原因(如濒死,被特定牌指定,使用特定技能···) ---@field public currentResponseReason string @ 要求用牌的原因(如濒死,被特定牌指定,使用特定技能···)
---@field public filtered_cards table<integer, Card> @ 被锁视技影响的卡牌 ---@field public filtered_cards table<integer, Card> @ 被锁视技影响的卡牌
---@field public printed_cards table<integer, Card> @ 被某些房间现场打印的卡牌id都是负数且从-2开始 ---@field public printed_cards table<integer, Card> @ 被某些房间现场打印的卡牌id都是负数且从-2开始
---@field private _custom_events any[] @ 自定义事件列表
local Engine = class("Engine") local Engine = class("Engine")
--- Engine的构造函数。 --- Engine的构造函数。
@ -53,6 +54,7 @@ function Engine:initialize()
self.game_modes = {} self.game_modes = {}
self.game_mode_disabled = {} self.game_mode_disabled = {}
self.kingdoms = {} self.kingdoms = {}
self._custom_events = {}
self:loadPackages() self:loadPackages()
self:loadDisabled() self:loadDisabled()
@ -247,8 +249,10 @@ end
local function canUseGeneral(g) local function canUseGeneral(g)
local r = Fk:currentRoom() local r = Fk:currentRoom()
return not table.contains(r.disabled_packs, Fk.generals[g].package.name) and local general = Fk.generals[g]
not table.contains(r.disabled_generals, g) and not g.hidden and not g.total_hidden if not general then return false end
return not table.contains(r.disabled_packs, general.package.name) and
not table.contains(r.disabled_generals, g) and not general.hidden and not general.total_hidden
end end
--- 根据武将名称,获取它的同名武将。 --- 根据武将名称,获取它的同名武将。
@ -323,6 +327,10 @@ function Engine:addGameMode(game_mode)
self.game_modes[game_mode.name] = game_mode self.game_modes[game_mode.name] = game_mode
end end
function Engine:addGameEvent(name, pfunc, mfunc, cfunc, efunc)
table.insert(self._custom_events, { name = name, p = pfunc, m = mfunc, c = cfunc, e = efunc })
end
--- 从已经开启的拓展包中,随机选出若干名武将。 --- 从已经开启的拓展包中,随机选出若干名武将。
--- ---
--- 对于同名武将不会重复选取。 --- 对于同名武将不会重复选取。
@ -440,7 +448,7 @@ function Engine:filterCard(id, player, data)
_card.skillName = f.name _card.skillName = f.name
if modify and RoomInstance then if modify and RoomInstance then
if not f.mute then if not f.mute then
RoomInstance:broadcastSkillInvoke(f.name) player:broadcastSkillInvoke(f.name)
end end
RoomInstance:doAnimate("InvokeSkill", { RoomInstance:doAnimate("InvokeSkill", {
name = f.name, name = f.name,

View File

@ -44,6 +44,14 @@ dofile "lua/server/events/pindian.lua"
-- TODO: fix this -- TODO: fix this
GameEvent.BreakEvent = 999 GameEvent.BreakEvent = 999
for _, l in ipairs(Fk._custom_events) do
local name, p, m, c, e = l.name, l.p, l.m, l.c, l.e
GameEvent.prepare_funcs[name] = p
GameEvent.functions[name] = m
GameEvent.cleaners[name] = c
GameEvent.exit_funcs[name] = e
end
local eventTranslations = { local eventTranslations = {
[GameEvent.ChangeHp] = "GameEvent.ChangeHp", [GameEvent.ChangeHp] = "GameEvent.ChangeHp",
[GameEvent.Damage] = "GameEvent.Damage", [GameEvent.Damage] = "GameEvent.Damage",
@ -68,5 +76,7 @@ local eventTranslations = {
} }
function GameEvent.static:translate(id) function GameEvent.static:translate(id)
return eventTranslations[id] local ret = eventTranslations[id]
if not ret then ret = id end
return ret
end end

View File

@ -187,7 +187,7 @@ function GameEvent:clear()
local logic = RoomInstance.logic local logic = RoomInstance.logic
local end_id = logic.current_event_id + 1 local end_id = logic.current_event_id + 1
if self.id ~= end_id - 1 then if self.id ~= end_id - 1 then
logic.all_game_events[end_id] = -self.event logic.all_game_events[end_id] = self.event
logic.current_event_id = end_id logic.current_event_id = end_id
self.end_id = end_id self.end_id = end_id
else else

View File

@ -494,7 +494,7 @@ function GameLogic:dumpAllEvents(from, to)
local tab = " " local tab = " "
for i = from, to, 1 do for i = from, to, 1 do
local v = self.all_game_events[i] local v = self.all_game_events[i]
if type(v) == "number" then if type(v) ~= "table" then
indent = math.max(indent - 1, 0) indent = math.max(indent - 1, 0)
-- v = "End" -- v = "End"
-- print(tab:rep(indent) .. string.format("#%d: %s", i, v)) -- print(tab:rep(indent) .. string.format("#%d: %s", i, v))

View File

@ -934,9 +934,10 @@ function Room:sendLogEvent(type, data, players)
end end
--- 播放技能的语音。 --- 播放技能的语音。
---@param skill_name string @ 技能名 ---@param skill_name nil @ 技能名
---@param index integer | nil @ 语音编号,默认为-1也就是随机播放 ---@param index integer | nil @ 语音编号,默认为-1也就是随机播放
function Room:broadcastSkillInvoke(skill_name, index) function Room:broadcastSkillInvoke(skill_name, index)
print 'Room:broadcastSkillInvoke deprecated; use SPlayer:broadcastSkillInvoke'
index = index or -1 index = index or -1
self:sendLogEvent("PlaySkillSound", { self:sendLogEvent("PlaySkillSound", {
name = skill_name, name = skill_name,
@ -1361,7 +1362,7 @@ end
--- 询问chooser选择target的一张牌。 --- 询问chooser选择target的一张牌。
---@param chooser ServerPlayer @ 要被询问的人 ---@param chooser ServerPlayer @ 要被询问的人
---@param target ServerPlayer @ 被选牌的人 ---@param target ServerPlayer @ 被选牌的人
---@param flag string @ 用"hej"三个字母的组合表示能选择哪些区域, h 手牌区, e - 装备区, j - 判定区 ---@param flag any @ 用"hej"三个字母的组合表示能选择哪些区域, h 手牌区, e - 装备区, j - 判定区
---@param reason string @ 原因,一般是技能名 ---@param reason string @ 原因,一般是技能名
---@return integer @ 选择的卡牌id ---@return integer @ 选择的卡牌id
function Room:askForCardChosen(chooser, target, flag, reason) function Room:askForCardChosen(chooser, target, flag, reason)
@ -1372,10 +1373,18 @@ function Room:askForCardChosen(chooser, target, flag, reason)
if result == "" then if result == "" then
local areas = {} local areas = {}
local handcards
if type(flag) == "string" then
if string.find(flag, "h") then table.insert(areas, Player.Hand) end if string.find(flag, "h") then table.insert(areas, Player.Hand) end
if string.find(flag, "e") then table.insert(areas, Player.Equip) end if string.find(flag, "e") then table.insert(areas, Player.Equip) end
if string.find(flag, "j") then table.insert(areas, Player.Judge) end if string.find(flag, "j") then table.insert(areas, Player.Judge) end
local handcards = target:getCardIds(areas) handcards = target:getCardIds(areas)
else
handcards = {}
for _, t in ipairs(flag.card_data) do
table.insertTable(handcards, t[2])
end
end
if #handcards == 0 then return end if #handcards == 0 then return end
result = handcards[math.random(1, #handcards)] result = handcards[math.random(1, #handcards)]
else else
@ -1397,7 +1406,7 @@ end
---@param target ServerPlayer @ 被选牌的人 ---@param target ServerPlayer @ 被选牌的人
---@param min integer @ 最小选牌数 ---@param min integer @ 最小选牌数
---@param max integer @ 最大选牌数 ---@param max integer @ 最大选牌数
---@param flag string @ 用"hej"三个字母的组合表示能选择哪些区域, h 手牌区, e - 装备区, j - 判定区 ---@param flag any @ 用"hej"三个字母的组合表示能选择哪些区域, h 手牌区, e - 装备区, j - 判定区
---@param reason string @ 原因,一般是技能名 ---@param reason string @ 原因,一般是技能名
---@return integer[] @ 选择的id ---@return integer[] @ 选择的id
function Room:askForCardsChosen(chooser, target, min, max, flag, reason) function Room:askForCardsChosen(chooser, target, min, max, flag, reason)
@ -1415,10 +1424,18 @@ function Room:askForCardsChosen(chooser, target, min, max, flag, reason)
ret = json.decode(result) ret = json.decode(result)
else else
local areas = {} local areas = {}
local handcards
if type(flag) == "string" then
if string.find(flag, "h") then table.insert(areas, Player.Hand) end if string.find(flag, "h") then table.insert(areas, Player.Hand) end
if string.find(flag, "e") then table.insert(areas, Player.Equip) end if string.find(flag, "e") then table.insert(areas, Player.Equip) end
if string.find(flag, "j") then table.insert(areas, Player.Judge) end if string.find(flag, "j") then table.insert(areas, Player.Judge) end
local handcards = target:getCardIds(areas) handcards = target:getCardIds(areas)
else
handcards = {}
for _, t in ipairs(flag.card_data) do
table.insertTable(handcards, t[2])
end
end
if #handcards == 0 then return {} end if #handcards == 0 then return {} end
ret = table.random(handcards, math.min(min, #handcards)) ret = table.random(handcards, math.min(min, #handcards))
end end
@ -3020,7 +3037,7 @@ function Room:useSkill(player, skill, effect_cb)
self:broadcastPlaySound(soundName) self:broadcastPlaySound(soundName)
self:setEmotion(player, pkgPath .. "/image/anim/" .. equip.name) self:setEmotion(player, pkgPath .. "/image/anim/" .. equip.name)
else else
self:broadcastSkillInvoke(skill.name) player:broadcastSkillInvoke(skill.name)
self:notifySkillInvoked(player, skill.name) self:notifySkillInvoked(player, skill.name)
end end
end end

View File

@ -716,6 +716,20 @@ function ServerPlayer:pindian(tos, skillName, initialCard)
return pindianData return pindianData
end end
--- 播放技能的语音。
---@param skill_name string @ 技能名
---@param index integer | nil @ 语音编号,默认为-1也就是随机播放
function ServerPlayer:broadcastSkillInvoke(skill_name, index)
print 'Room:broadcastSkillInvoke deprecated; use SPlayer:broadcastSkillInvoke'
index = index or -1
self.room:sendLogEvent("PlaySkillSound", {
name = skill_name,
i = index,
general = self.general,
deputy = self.deputyGeneral,
})
end
-- Hegemony func -- Hegemony func
---@param skill Skill ---@param skill Skill

View File

@ -231,7 +231,7 @@ local luoyi_trigger = fk.CreateTriggerSkill{
end, end,
on_use = function(self, event, target, player, data) on_use = function(self, event, target, player, data)
local room = player.room local room = player.room
room:broadcastSkillInvoke("luoyi") player:broadcastSkillInvoke("luoyi")
room:notifySkillInvoked(player, "luoyi") room:notifySkillInvoked(player, "luoyi")
data.damage = data.damage + 1 data.damage = data.damage + 1
end, end,
@ -540,7 +540,7 @@ local paoxiaoAudio = fk.CreateTriggerSkill{
player:usedCardTimes("slash") > 1 player:usedCardTimes("slash") > 1
end, end,
on_refresh = function(self, event, target, player, data) on_refresh = function(self, event, target, player, data)
player.room:broadcastSkillInvoke("paoxiao") player:broadcastSkillInvoke("paoxiao")
player.room:doAnimate("InvokeSkill", { player.room:doAnimate("InvokeSkill", {
name = "paoxiao", name = "paoxiao",
player = player.id, player = player.id,
@ -592,7 +592,7 @@ local kongchengAudio = fk.CreateTriggerSkill{
end end
end, end,
on_refresh = function(self, event, target, player, data) on_refresh = function(self, event, target, player, data)
player.room:broadcastSkillInvoke("kongcheng") player:broadcastSkillInvoke("kongcheng")
player.room:notifySkillInvoked(player, "kongcheng", "defensive") player.room:notifySkillInvoked(player, "kongcheng", "defensive")
end, end,
} }