mirror of
https://github.com/Qsgs-Fans/FreeKill.git
synced 2024-11-16 11:42:45 +08:00
Modify game core (#294)
- 新增船新“休整”机制; - 修改作废逻辑,并可在当前响应读条禁用该技能(出牌阶段空闲时间点尚未完成限制); - 修复锁视技的相关bug,其cardFilter新增标识是否为判定的参数; - 将护甲扣减融合进体力扣减流程,为伤害流程增加“虚拟伤害”概念,为伤害流程增加“造成过伤害”标识id以供记录搜索使用; - 为变将新增可删除副将。 --------- Co-authored-by: notify <notify-ctrl@qq.com>
This commit is contained in:
parent
94c1107c2e
commit
cec18e0614
20
Fk/Common/Avatar.qml
Normal file
20
Fk/Common/Avatar.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
import QtQuick
|
||||
import Fk
|
||||
|
||||
Image {
|
||||
property string general
|
||||
|
||||
width: 64
|
||||
height: 64
|
||||
source: SkinBank.getGeneralExtraPic(general, "avatar/") ?? SkinBank.getGeneralPicture(general)
|
||||
// sourceSize.width: 250
|
||||
// sourceSize.height: 292
|
||||
property bool useSmallPic: !!SkinBank.getGeneralExtraPic(general, "avatar/")
|
||||
sourceClipRect: useSmallPic ? undefined : Qt.rect(61, 0, 128, 128)
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
}
|
||||
}
|
238
Fk/Common/AvatarChatBox.qml
Normal file
238
Fk/Common/AvatarChatBox.qml
Normal file
|
@ -0,0 +1,238 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Fk.Pages
|
||||
|
||||
Rectangle {
|
||||
property bool isLobby: false
|
||||
|
||||
function append(chatter, data) {
|
||||
let general = data.general;
|
||||
let avatar;
|
||||
if (general == "__server") {
|
||||
general = "";
|
||||
avatar = "__server"
|
||||
} else if (!roomScene.getPhoto(data.sender)) {
|
||||
avatar = "__observer";
|
||||
}
|
||||
chatLogBox.append({
|
||||
avatar: data.general || roomScene.getPhoto(data.sender)?.general || avatar || "unknown",
|
||||
general: general,
|
||||
msg: data.msg,
|
||||
userName: data.userName,
|
||||
time: data.time,
|
||||
isSelf: data.sender === Self.id,
|
||||
})
|
||||
}
|
||||
|
||||
function loadSkills() {
|
||||
for (let i = 1; i <= 16; i++) {
|
||||
skills.append({ name: "fastchat_m", idx: i });
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: opTimer
|
||||
interval: 1500
|
||||
}
|
||||
|
||||
Component {
|
||||
id: avatarDelegate
|
||||
Item {
|
||||
width: chatLogBox.width
|
||||
height: childrenRect.height
|
||||
Avatar {
|
||||
id: avatarPic
|
||||
width: 36
|
||||
height: 36
|
||||
general: avatar
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 8
|
||||
anchors.left: isSelf ? undefined : parent.left
|
||||
anchors.right: !isSelf ? undefined : parent.right
|
||||
}
|
||||
|
||||
Text {
|
||||
id: unameLbl
|
||||
anchors.left: isSelf ? undefined : avatarPic.right
|
||||
anchors.right: !isSelf ? undefined : avatarPic.left
|
||||
anchors.margins: 6
|
||||
font.pixelSize: 14
|
||||
text: userName + (general ? (" (" + Backend.translate(general) + ")") : "")
|
||||
+ ' <font color="grey">[' + time + "]</font>"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: isSelf ? undefined : avatarPic.right
|
||||
anchors.right: !isSelf ? undefined : avatarPic.left
|
||||
anchors.margins: 4
|
||||
anchors.top: unameLbl.bottom
|
||||
width: Math.min(parent.width - 80, childrenRect.width + 12)
|
||||
height: childrenRect.height + 12
|
||||
radius: 8
|
||||
color: isSelf ? "lightgreen" : "lightsteelblue"
|
||||
Text {
|
||||
width: Math.min(contentWidth, parent.parent.width - 80 - 12)
|
||||
x: 6; y: 6
|
||||
text: msg
|
||||
wrapMode: Text.WrapAnywhere
|
||||
font.family: fontLibian.name
|
||||
font.pixelSize: 16
|
||||
}
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.NoButton
|
||||
gesturePolicy: TapHandler.WithinBounds
|
||||
onTapped: chatLogBox.currentIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
LogEdit {
|
||||
id: chatLogBox
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
delegate: avatarDelegate
|
||||
//font.pixelSize: 14
|
||||
}
|
||||
}
|
||||
|
||||
GridView {
|
||||
id: emojiSelector
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 120
|
||||
cellHeight: 48
|
||||
cellWidth: 48
|
||||
model: 59
|
||||
visible: false
|
||||
clip: true
|
||||
delegate: ItemDelegate {
|
||||
Image {
|
||||
height: 32; width: 32
|
||||
anchors.centerIn: parent
|
||||
source: "../../image/emoji/" + index
|
||||
}
|
||||
onClicked: chatEdit.insert(chatEdit.cursorPosition, "{emoji" + index + "}");
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: soundSelector
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 180
|
||||
visible: false
|
||||
clip: true
|
||||
ScrollBar.vertical: ScrollBar {}
|
||||
model: ListModel {
|
||||
id: skills
|
||||
}
|
||||
// onVisibleChanged: {skills.clear(); loadSkills();}
|
||||
|
||||
delegate: ItemDelegate {
|
||||
width: soundSelector.width
|
||||
height: 30
|
||||
text: Backend.translate("$" + name + (idx ? idx.toString() : ""))
|
||||
|
||||
onClicked: {
|
||||
opTimer.start();
|
||||
const general = roomScene.getPhoto(Self.id).general;
|
||||
let skill = "fastchat_m";
|
||||
if (general !== "") {
|
||||
const data = JSON.parse(Backend.callLuaFunction("GetGeneralDetail", [general]));
|
||||
const gender = data.gender;
|
||||
if (gender !== 1) {
|
||||
skill = "fastchat_f";
|
||||
}
|
||||
}
|
||||
ClientInstance.notifyServer(
|
||||
"Chat",
|
||||
JSON.stringify({
|
||||
type: isLobby ? 1 : 2,
|
||||
msg: "$" + skill + ":" + idx
|
||||
})
|
||||
);
|
||||
soundSelector.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 28
|
||||
color: "#040403"
|
||||
radius: 3
|
||||
border.width: 1
|
||||
border.color: "#A6967A"
|
||||
|
||||
TextInput {
|
||||
id: chatEdit
|
||||
anchors.fill: parent
|
||||
anchors.margins: 6
|
||||
color: "white"
|
||||
clip: true
|
||||
font.pixelSize: 14
|
||||
maximumLength: 300
|
||||
|
||||
onAccepted: {
|
||||
if (text != "") {
|
||||
ClientInstance.notifyServer(
|
||||
"Chat",
|
||||
JSON.stringify({
|
||||
type: isLobby ? 1 : 2,
|
||||
msg: text
|
||||
})
|
||||
);
|
||||
text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetroButton {
|
||||
id: soundBtn
|
||||
text: "🗨️"
|
||||
visible: !isLobby
|
||||
enabled: !opTimer.running;
|
||||
onClicked: {
|
||||
emojiSelector.visible = false;
|
||||
soundSelector.visible = !soundSelector.visible;
|
||||
}
|
||||
}
|
||||
|
||||
MetroButton {
|
||||
id: emojiBtn
|
||||
text: "😃"
|
||||
onClicked: {
|
||||
soundSelector.visible = false;
|
||||
emojiSelector.visible = !emojiSelector.visible;
|
||||
}
|
||||
}
|
||||
|
||||
MetroButton {
|
||||
text: "✔️"
|
||||
enabled: !opTimer.running;
|
||||
onClicked: {
|
||||
opTimer.start();
|
||||
chatEdit.accepted();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
loadSkills();
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ Rectangle {
|
|||
property bool isLobby: false
|
||||
|
||||
function append(chatter) {
|
||||
chatLogBox.append(chatter)
|
||||
chatLogBox.append({ logText: chatter })
|
||||
}
|
||||
|
||||
function loadSkills() {
|
||||
|
|
|
@ -33,6 +33,8 @@ ListView {
|
|||
font.pixelSize: 16
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.NoButton
|
||||
gesturePolicy: TapHandler.WithinBounds
|
||||
onTapped: root.currentIndex = index;
|
||||
}
|
||||
}
|
||||
|
@ -43,9 +45,9 @@ ListView {
|
|||
onClicked: root.currentIndex = logModel.count - 1;
|
||||
}
|
||||
|
||||
function append(text) {
|
||||
function append(data) {
|
||||
const autoScroll = root.currentIndex === logModel.count - 1;
|
||||
logModel.append({ logText: text });
|
||||
logModel.append(data);
|
||||
if (autoScroll) {
|
||||
root.currentIndex = logModel.count - 1;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
module Fk.Common
|
||||
ChatBox 1.0 ChatBox.qml
|
||||
LogEdit 1.0 LogEdit.qml
|
||||
Avatar 1.0 Avatar.qml
|
||||
AvatarChatBox 1.0 AvatarChatBox.qml
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Fk
|
||||
import Fk.Common
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
@ -20,19 +21,10 @@ Item {
|
|||
RowLayout {
|
||||
Item { Layout.preferredWidth: 16 }
|
||||
|
||||
Image {
|
||||
Avatar {
|
||||
Layout.preferredWidth: 64
|
||||
Layout.preferredHeight: 64
|
||||
source: SkinBank.getGeneralExtraPic(Self.avatar, "avatar/") ?? SkinBank.getGeneralPicture(Self.avatar)
|
||||
// sourceSize.width: 250
|
||||
// sourceSize.height: 292
|
||||
sourceClipRect: sourceSize.width > 200 ? Qt.rect(61, 0, 128, 128) : undefined
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
}
|
||||
general: Self.avatar
|
||||
}
|
||||
|
||||
Item { Layout.preferredWidth: 8 }
|
||||
|
|
|
@ -5,6 +5,7 @@ import QtQuick.Controls
|
|||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
import Fk
|
||||
import Fk.Common
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
@ -59,21 +60,13 @@ Item {
|
|||
width: root.width
|
||||
height: 64
|
||||
|
||||
Image {
|
||||
Avatar {
|
||||
id: generalPic
|
||||
width: 48; height: 48
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 8
|
||||
width: 48
|
||||
height: 48
|
||||
source: SkinBank.getGeneralExtraPic(general, "avatar/") ?? SkinBank.getGeneralPicture(general)
|
||||
sourceClipRect: sourceSize.width > 200 ? Qt.rect(61, 0, 128, 128) : undefined
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
}
|
||||
general: general
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
|
|
@ -392,6 +392,7 @@ Item {
|
|||
faceup: model.faceup
|
||||
chained: model.chained
|
||||
drank: model.drank
|
||||
rest: model.rest
|
||||
isOwner: model.isOwner
|
||||
ready: model.ready
|
||||
surrendered: model.surrendered
|
||||
|
@ -855,7 +856,7 @@ Item {
|
|||
}
|
||||
Item {
|
||||
visible: !config.replaying
|
||||
ChatBox {
|
||||
AvatarChatBox {
|
||||
id: chat
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
@ -1121,7 +1122,7 @@ Item {
|
|||
if (raw.msg.startsWith("$")) {
|
||||
if (specialChat(pid, raw, raw.msg.slice(1))) return;
|
||||
}
|
||||
chat.append(msg);
|
||||
chat.append(msg, raw);
|
||||
const photo = Logic.getPhoto(pid);
|
||||
if (photo === undefined) {
|
||||
const user = raw.userName;
|
||||
|
@ -1176,10 +1177,11 @@ Item {
|
|||
Backend.playSound("./packages/" + extension + "/audio/death/" + g);
|
||||
|
||||
const m = Backend.translate("~" + g);
|
||||
data.msg = m;
|
||||
if (general === "")
|
||||
chat.append(`[${time}] ${userName}: ${m}`);
|
||||
chat.append(`[${time}] ${userName}: ${m}`, data);
|
||||
else
|
||||
chat.append(`[${time}] ${userName}(${general}): ${m}`);
|
||||
chat.append(`[${time}] ${userName}(${general}): ${m}`, data);
|
||||
|
||||
const photo = Logic.getPhoto(pid);
|
||||
if (photo === undefined) {
|
||||
|
@ -1205,10 +1207,11 @@ Item {
|
|||
}));
|
||||
} catch (e) {}
|
||||
const m = Backend.translate("$" + skill + (gene ? "_" + gene : "") + (idx ? idx.toString() : ""));
|
||||
data.msg = m;
|
||||
if (general === "")
|
||||
chat.append(`[${time}] ${userName}: ${m}`);
|
||||
chat.append(`[${time}] ${userName}: ${m}`, data);
|
||||
else
|
||||
chat.append(`[${time}] ${userName}(${general}): ${m}`);
|
||||
chat.append(`[${time}] ${userName}(${general}): ${m}`, data)
|
||||
|
||||
const photo = Logic.getPhoto(pid);
|
||||
if (photo === undefined) {
|
||||
|
@ -1224,12 +1227,17 @@ Item {
|
|||
}
|
||||
|
||||
function addToLog(msg) {
|
||||
log.append(msg);
|
||||
log.append({ logText: msg });
|
||||
}
|
||||
|
||||
function sendDanmaku(msg) {
|
||||
danmaku.sendLog(msg);
|
||||
chat.append(msg);
|
||||
chat.append(null, {
|
||||
msg: msg,
|
||||
general: "__server", // FIXME: 基于默认读取貂蝉的数据
|
||||
userName: "",
|
||||
time: "Server",
|
||||
});
|
||||
}
|
||||
|
||||
function showDistance(show) {
|
||||
|
@ -1327,6 +1335,7 @@ Item {
|
|||
faceup: true,
|
||||
chained: false,
|
||||
drank: 0,
|
||||
rest: 0,
|
||||
isOwner: false,
|
||||
ready: false,
|
||||
surrendered: false,
|
||||
|
|
|
@ -1319,6 +1319,7 @@ callbacks["AskForUseCard"] = (jsonData) => {
|
|||
const pattern = data[1];
|
||||
const prompt = data[2];
|
||||
const extra_data = data[4];
|
||||
const disabledSkillNames = data[5];
|
||||
if (extra_data != null) {
|
||||
if (extra_data.effectTo !== Self.id && roomScene.skippedUseEventId.find(id => id === extra_data.useEventId)) {
|
||||
doCancelButton();
|
||||
|
@ -1336,6 +1337,7 @@ callbacks["AskForUseCard"] = (jsonData) => {
|
|||
}
|
||||
roomScene.responding_card = pattern;
|
||||
roomScene.respond_play = false;
|
||||
disabledSkillNames && (dashboard.disabledSkillNames = disabledSkillNames);
|
||||
roomScene.state = "responding";
|
||||
okButton.enabled = false;
|
||||
cancelButton.enabled = true;
|
||||
|
@ -1347,6 +1349,7 @@ callbacks["AskForResponseCard"] = (jsonData) => {
|
|||
const cardname = data[0];
|
||||
const pattern = data[1];
|
||||
const prompt = data[2];
|
||||
const disabledSkillNames = data[5];
|
||||
|
||||
if (prompt === "") {
|
||||
roomScene.promptText = Backend.translate("#AskForResponseCard")
|
||||
|
@ -1356,6 +1359,7 @@ callbacks["AskForResponseCard"] = (jsonData) => {
|
|||
}
|
||||
roomScene.responding_card = pattern;
|
||||
roomScene.respond_play = true;
|
||||
disabledSkillNames && (dashboard.disabledSkillNames = disabledSkillNames);
|
||||
roomScene.state = "responding";
|
||||
okButton.enabled = false;
|
||||
cancelButton.enabled = true;
|
||||
|
|
|
@ -19,6 +19,8 @@ RowLayout {
|
|||
|
||||
property var expanded_piles: ({}) // name -> int[]
|
||||
|
||||
property var disabledSkillNames: []
|
||||
|
||||
signal cardSelected(var card)
|
||||
|
||||
Item { width: 5 }
|
||||
|
@ -454,6 +456,11 @@ RowLayout {
|
|||
// 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;
|
||||
|
@ -462,11 +469,17 @@ RowLayout {
|
|||
}
|
||||
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]));
|
||||
}
|
||||
}
|
||||
|
||||
function disableSkills() {
|
||||
disabledSkillNames = [];
|
||||
for (let i = 0; i < skillButtons.count; i++)
|
||||
skillButtons.itemAt(i).enabled = false;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import QtQuick
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Fk
|
||||
import Fk.PhotoElement
|
||||
|
||||
|
@ -29,6 +30,7 @@ Item {
|
|||
property bool faceup: true
|
||||
property bool chained: false
|
||||
property int drank: 0
|
||||
property int rest: 0
|
||||
property bool isOwner: false
|
||||
property bool ready: false
|
||||
property int winGame: 0
|
||||
|
@ -269,6 +271,45 @@ Item {
|
|||
opacity: 0.4 + Math.log(root.drank) * 0.12
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: restRect
|
||||
anchors.centerIn: photoMask
|
||||
anchors.leftMargin: 20
|
||||
visible: root.rest > 0
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
text: "休整中"
|
||||
font.family: fontLibian.name
|
||||
font.pixelSize: 40
|
||||
color: "white"
|
||||
style: Text.Outline
|
||||
textFormat: Text.RichText
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
visible: root.rest > 0 && root.rest < 999
|
||||
text: root.rest
|
||||
font.family: fontLibian.name
|
||||
font.pixelSize: 30
|
||||
color: "white"
|
||||
style: Text.Outline
|
||||
textFormat: Text.RichText
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
visible: root.rest > 0 && root.rest < 999
|
||||
text: "轮次"
|
||||
font.family: fontLibian.name
|
||||
font.pixelSize: 28
|
||||
color: "white"
|
||||
style: Text.Outline
|
||||
textFormat: Text.RichText
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: winRateRect
|
||||
width: 138; x: 31
|
||||
|
@ -389,7 +430,7 @@ Item {
|
|||
|
||||
Image {
|
||||
// id: saveme
|
||||
visible: root.dead || root.dying || root.surrendered
|
||||
visible: (root.dead && !root.rest) || root.dying || root.surrendered
|
||||
source: {
|
||||
if (root.dead) {
|
||||
return SkinBank.getRoleDeathPic(root.role);
|
||||
|
|
|
@ -455,12 +455,12 @@ end
|
|||
---@param player Player @ 和这张牌扯上关系的那名玩家
|
||||
---@param data any @ 随意,目前只用到JudgeStruct,为了影响判定牌
|
||||
function Engine:filterCard(id, player, data)
|
||||
local card = self:getCardById(id, true)
|
||||
if player == nil then
|
||||
self.filtered_cards[id] = nil
|
||||
return
|
||||
end
|
||||
local skills = player:getAllSkills()
|
||||
|
||||
local card = self:getCardById(id, true)
|
||||
local filters = self:currentRoom().status_skills[FilterSkill] or Util.DummyTable
|
||||
|
||||
if #filters == 0 then
|
||||
|
@ -475,7 +475,7 @@ function Engine:filterCard(id, player, data)
|
|||
end
|
||||
|
||||
for _, f in ipairs(filters) do
|
||||
if f:cardFilter(card, player) then
|
||||
if f:cardFilter(card, player, type(data) == "table" and data.isJudgeEvent) then
|
||||
local _card = f:viewAs(card, player)
|
||||
_card.id = id
|
||||
_card.skillName = f.name
|
||||
|
|
|
@ -27,10 +27,14 @@ end
|
|||
---@param victim ServerPlayer @ 死者
|
||||
---@return string @ 胜者阵营
|
||||
function GameMode:getWinner(victim)
|
||||
if victim.rest > 0 then
|
||||
return ""
|
||||
end
|
||||
|
||||
local room = victim.room
|
||||
local winner = ""
|
||||
local alive = table.filter(room.alive_players, function(p)
|
||||
return not p.surrendered
|
||||
local alive = table.filter(room.players, function(p)
|
||||
return not p.surrendered and not (p.dead and p.rest == 0)
|
||||
end)
|
||||
|
||||
if victim.role == "lord" then
|
||||
|
|
|
@ -86,6 +86,7 @@ function Player:initialize()
|
|||
self.dying = false
|
||||
self.dead = false
|
||||
self.drank = 0
|
||||
self.rest = 0
|
||||
|
||||
self.player_skills = {}
|
||||
self.derivative_skills = {}
|
||||
|
@ -570,9 +571,9 @@ end
|
|||
---@param ignoreRemoved? boolean @ 忽略被移除
|
||||
---@param num? integer @ 第几个,默认1
|
||||
---@return ServerPlayer
|
||||
function Player:getNextAlive(ignoreRemoved, num)
|
||||
function Player:getNextAlive(ignoreRemoved, num, ignoreRest)
|
||||
if #Fk:currentRoom().alive_players == 0 then
|
||||
return self
|
||||
return self.rest > 0 and self.next.rest > 0 and self.next or self
|
||||
end
|
||||
local doNotIgnore = not ignoreRemoved
|
||||
if doNotIgnore and table.every(Fk:currentRoom().alive_players, function(p) return p:isRemoved() end) then
|
||||
|
@ -583,7 +584,7 @@ function Player:getNextAlive(ignoreRemoved, num)
|
|||
num = num or 1
|
||||
for _ = 1, num do
|
||||
ret = ret.next
|
||||
while ret.dead or (doNotIgnore and ret:isRemoved()) do
|
||||
while (ret.dead and not ignoreRest) or (doNotIgnore and ret:isRemoved()) do
|
||||
ret = ret.next
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
local FilterSkill = StatusSkill:subclass("FilterSkill")
|
||||
|
||||
---@param card Card
|
||||
function FilterSkill:cardFilter(card, player)
|
||||
function FilterSkill:cardFilter(card, player, isJudgeEvent)
|
||||
return false
|
||||
end
|
||||
|
||||
|
|
|
@ -135,4 +135,6 @@ fk.BeforePropertyChange = 92
|
|||
fk.PropertyChange = 93
|
||||
fk.AfterPropertyChange = 94
|
||||
|
||||
fk.AfterPlayerRevived = 95
|
||||
|
||||
fk.NumOfEvents = 96
|
||||
|
|
|
@ -53,7 +53,11 @@ GameEvent.functions[GameEvent.Death] = function(self)
|
|||
local room = self.room
|
||||
local victim = room:getPlayerById(deathStruct.who)
|
||||
victim.dead = true
|
||||
victim._splayer:setDied(true)
|
||||
|
||||
if victim.rest <= 0 then
|
||||
victim._splayer:setDied(true)
|
||||
end
|
||||
|
||||
table.removeOne(room.alive_players, victim)
|
||||
|
||||
local logic = room.logic
|
||||
|
@ -65,22 +69,26 @@ GameEvent.functions[GameEvent.Death] = function(self)
|
|||
type = "#KillPlayer",
|
||||
to = {killer.id},
|
||||
from = victim.id,
|
||||
arg = victim.role,
|
||||
arg = (victim.rest > 0 and 'unknown' or victim.role),
|
||||
}
|
||||
else
|
||||
room:sendLog{
|
||||
type = "#KillPlayerWithNoKiller",
|
||||
from = victim.id,
|
||||
arg = victim.role,
|
||||
arg = (victim.rest > 0 and 'unknown' or victim.role),
|
||||
}
|
||||
end
|
||||
room:sendLogEvent("Death", {to = victim.id})
|
||||
|
||||
room:broadcastProperty(victim, "role")
|
||||
if victim.rest == 0 then
|
||||
room:broadcastProperty(victim, "role")
|
||||
end
|
||||
room:broadcastProperty(victim, "dead")
|
||||
|
||||
victim.drank = 0
|
||||
room:broadcastProperty(victim, "drank")
|
||||
victim.shield = 0
|
||||
room:broadcastProperty(victim, "shield")
|
||||
|
||||
logic:trigger(fk.GameOverJudge, victim, deathStruct)
|
||||
logic:trigger(fk.Death, victim, deathStruct)
|
||||
|
@ -88,3 +96,23 @@ GameEvent.functions[GameEvent.Death] = function(self)
|
|||
|
||||
logic:trigger(fk.Deathed, victim, deathStruct)
|
||||
end
|
||||
|
||||
GameEvent.functions[GameEvent.Revive] = function(self)
|
||||
local room = self.room
|
||||
local player, sendLog, reason = table.unpack(self.data)
|
||||
|
||||
if not player.dead then return end
|
||||
room:setPlayerProperty(player, "dead", false)
|
||||
player._splayer:setDied(false)
|
||||
room:setPlayerProperty(player, "dying", false)
|
||||
room:setPlayerProperty(player, "hp", player.maxHp)
|
||||
table.insertIfNeed(room.alive_players, player)
|
||||
|
||||
sendLog = (sendLog == nil) and true or sendLog
|
||||
if sendLog then
|
||||
room:sendLog { type = "#Revive", from = player.id }
|
||||
end
|
||||
|
||||
reason = reason or ""
|
||||
room.logic:trigger(fk.AfterPlayerRevived, player, { reason = reason })
|
||||
end
|
||||
|
|
|
@ -161,8 +161,8 @@ GameEvent.functions[GameEvent.Round] = function(self)
|
|||
p = room.current
|
||||
GameEvent(GameEvent.Turn, p):exec()
|
||||
if room.game_finished then break end
|
||||
room.current = room.current:getNextAlive(true)
|
||||
until p.seat >= p:getNextAlive(true).seat
|
||||
room.current = room.current:getNextAlive(true, nil, true)
|
||||
until p.seat >= p:getNextAlive(true, nil, true).seat
|
||||
|
||||
logic:trigger(fk.RoundEnd, p)
|
||||
end
|
||||
|
@ -194,6 +194,15 @@ GameEvent.prepare_funcs[GameEvent.Turn] = function(self)
|
|||
local logic = room.logic
|
||||
local player = room.current
|
||||
|
||||
if player.rest > 0 and player.rest < 999 then
|
||||
room:setPlayerRest(player, player.rest - 1)
|
||||
if player.rest == 0 and player.dead then
|
||||
room:revivePlayer(player, true, "rest")
|
||||
else
|
||||
room:delay(50)
|
||||
end
|
||||
end
|
||||
|
||||
if player.dead then return true end
|
||||
|
||||
room:sendLog{ type = "$AppendSeparator" }
|
||||
|
@ -312,9 +321,9 @@ GameEvent.functions[GameEvent.Phase] = function(self)
|
|||
local result = room:doRequest(player, "PlayCard", player.id)
|
||||
if result == "" then break end
|
||||
|
||||
local use = room:handleUseCardReply(player, result)
|
||||
if use then
|
||||
room:useCard(use)
|
||||
local useResult = room:handleUseCardReply(player, result)
|
||||
if type(useResult) == "table" then
|
||||
room:useCard(useResult)
|
||||
end
|
||||
|
||||
if player._play_phase_end then
|
||||
|
|
|
@ -48,37 +48,50 @@ GameEvent.functions[GameEvent.ChangeHp] = function(self)
|
|||
damageEvent = damageStruct,
|
||||
}
|
||||
|
||||
if reason == "damage" then
|
||||
data.shield_lost = math.min(-num, player.shield)
|
||||
data.num = num + data.shield_lost
|
||||
end
|
||||
|
||||
if logic:trigger(fk.BeforeHpChanged, player, data) then
|
||||
logic:breakEvent(false)
|
||||
end
|
||||
|
||||
assert(not (data.reason == "recover" and data.num < 0))
|
||||
player.hp = math.min(player.hp + data.num, player.maxHp)
|
||||
room:broadcastProperty(player, "hp")
|
||||
if reason == "damage" and data.shield_lost > 0 and not damageStruct.isVirtualDMG then
|
||||
room:changeShield(player, -data.shield_lost)
|
||||
end
|
||||
|
||||
if reason == "damage" then
|
||||
sendDamageLog(room, damageStruct)
|
||||
elseif reason == "loseHp" then
|
||||
room:sendLog{
|
||||
type = "#LoseHP",
|
||||
from = player.id,
|
||||
arg = 0 - num,
|
||||
}
|
||||
room:sendLogEvent("LoseHP", {})
|
||||
elseif reason == "recover" then
|
||||
room:sendLog{
|
||||
type = "#HealHP",
|
||||
from = player.id,
|
||||
arg = num,
|
||||
}
|
||||
end
|
||||
|
||||
room:sendLog{
|
||||
type = "#ShowHPAndMaxHP",
|
||||
from = player.id,
|
||||
arg = player.hp,
|
||||
arg2 = player.maxHp,
|
||||
}
|
||||
if not (reason == "damage" and (data.num == 0 or damageStruct.isVirtualDMG)) then
|
||||
assert(not (data.reason == "recover" and data.num < 0))
|
||||
player.hp = math.min(player.hp + data.num, player.maxHp)
|
||||
room:broadcastProperty(player, "hp")
|
||||
|
||||
if reason == "loseHp" then
|
||||
room:sendLog{
|
||||
type = "#LoseHP",
|
||||
from = player.id,
|
||||
arg = 0 - num,
|
||||
}
|
||||
room:sendLogEvent("LoseHP", {})
|
||||
elseif reason == "recover" then
|
||||
room:sendLog{
|
||||
type = "#HealHP",
|
||||
from = player.id,
|
||||
arg = num,
|
||||
}
|
||||
end
|
||||
|
||||
room:sendLog{
|
||||
type = "#ShowHPAndMaxHP",
|
||||
from = player.id,
|
||||
arg = player.hp,
|
||||
arg2 = player.maxHp,
|
||||
}
|
||||
end
|
||||
|
||||
logic:trigger(fk.HpChanged, player, data)
|
||||
|
||||
|
@ -124,10 +137,12 @@ GameEvent.functions[GameEvent.Damage] = function(self)
|
|||
|
||||
local stages = {
|
||||
{fk.PreDamage, damageStruct.from},
|
||||
{fk.DamageCaused, damageStruct.from},
|
||||
{fk.DamageInflicted, damageStruct.to},
|
||||
}
|
||||
|
||||
if not damageStruct.isVirtualDMG then
|
||||
table.insertTable(stages, { { fk.DamageCaused, damageStruct.from }, { fk.DamageInflicted, damageStruct.to } })
|
||||
end
|
||||
|
||||
for _, struct in ipairs(stages) do
|
||||
local event, player = table.unpack(struct)
|
||||
if logic:trigger(event, player, damageStruct) or damageStruct.damage < 1 then
|
||||
|
@ -141,6 +156,9 @@ GameEvent.functions[GameEvent.Damage] = function(self)
|
|||
return false
|
||||
end
|
||||
|
||||
damageStruct.dealtRecorderId = room.logic.specific_events_id[GameEvent.Damage]
|
||||
room.logic.specific_events_id[GameEvent.Damage] = room.logic.specific_events_id[GameEvent.Damage] + 1
|
||||
|
||||
if damageStruct.card and damageStruct.damage > 0 then
|
||||
local parentUseData = logic:getCurrentEvent():findParent(GameEvent.UseCard)
|
||||
if parentUseData then
|
||||
|
@ -155,23 +173,16 @@ GameEvent.functions[GameEvent.Damage] = function(self)
|
|||
damageStruct.to:setChainState(false)
|
||||
end
|
||||
|
||||
-- 先扣减护甲,再扣体力值
|
||||
local shield_to_lose = math.min(damageStruct.damage, damageStruct.to.shield)
|
||||
room:changeShield(damageStruct.to, -shield_to_lose)
|
||||
|
||||
if shield_to_lose < damageStruct.damage then
|
||||
if not room:changeHp(
|
||||
damageStruct.to,
|
||||
shield_to_lose - damageStruct.damage,
|
||||
"damage",
|
||||
damageStruct.skillName,
|
||||
damageStruct) then
|
||||
logic:breakEvent(false)
|
||||
end
|
||||
else
|
||||
sendDamageLog(room, damageStruct)
|
||||
if not room:changeHp(
|
||||
damageStruct.to,
|
||||
-damageStruct.damage,
|
||||
"damage",
|
||||
damageStruct.skillName,
|
||||
damageStruct) then
|
||||
logic:breakEvent(false)
|
||||
end
|
||||
|
||||
|
||||
stages = {
|
||||
{fk.Damage, damageStruct.from},
|
||||
{fk.Damaged, damageStruct.to},
|
||||
|
@ -201,9 +212,15 @@ GameEvent.exit_funcs[GameEvent.Damage] = function(self)
|
|||
type = "#ChainDamage",
|
||||
from = p.id
|
||||
}
|
||||
local dmg = table.simpleClone(damageStruct)
|
||||
dmg.to = p
|
||||
dmg.chain = true
|
||||
local dmg = {
|
||||
from = damageStruct.from,
|
||||
to = p,
|
||||
damage = damageStruct.damage,
|
||||
card = damageStruct.card,
|
||||
skillName = damageStruct.skillName,
|
||||
chain = true,
|
||||
}
|
||||
|
||||
room:damage(dmg)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,6 +14,7 @@ dofile "lua/server/events/hp.lua"
|
|||
|
||||
GameEvent.Dying = 6
|
||||
GameEvent.Death = 7
|
||||
GameEvent.Revive = 22
|
||||
dofile "lua/server/events/death.lua"
|
||||
|
||||
GameEvent.MoveCards = 8
|
||||
|
@ -64,6 +65,7 @@ local eventTranslations = {
|
|||
[GameEvent.ChangeMaxHp] = "GameEvent.ChangeMaxHp",
|
||||
[GameEvent.Dying] = "GameEvent.Dying",
|
||||
[GameEvent.Death] = "GameEvent.Death",
|
||||
[GameEvent.Revive] = "GameEvent.Revive",
|
||||
[GameEvent.MoveCards] = "GameEvent.MoveCards",
|
||||
[GameEvent.UseCard] = "GameEvent.UseCard",
|
||||
[GameEvent.RespondCard] = "GameEvent.RespondCard",
|
||||
|
|
|
@ -5,6 +5,8 @@ GameEvent.functions[GameEvent.Judge] = function(self)
|
|||
local room = self.room
|
||||
local logic = room.logic
|
||||
local who = data.who
|
||||
|
||||
data.isJudgeEvent = true
|
||||
logic:trigger(fk.StartJudge, who, data)
|
||||
data.card = data.card or Fk:getCardById(room:getNCards(1)[1])
|
||||
|
||||
|
|
|
@ -39,28 +39,33 @@ GameEvent.functions[GameEvent.ChangeProperty] = function(self)
|
|||
room:setPlayerProperty(player, "general", data.general)
|
||||
end
|
||||
|
||||
if data.deputyGeneral and data.deputyGeneral ~= "" and data.deputyGeneral ~= player.deputyGeneral then
|
||||
if data.deputyGeneral and data.deputyGeneral ~= player.deputyGeneral then
|
||||
local originalDeputy = Fk.generals[player.deputyGeneral] or Fk.generals["blank_shibing"]
|
||||
local originalSkills = originalDeputy and originalDeputy:getSkillNameList() or Util.DummyTable
|
||||
table.insertTableIfNeed(skills, table.map(originalSkills, function(e)
|
||||
return "-" .. e
|
||||
end))
|
||||
local newDeputy = Fk.generals[data.deputyGeneral] or Fk.generals["blank_shibing"]
|
||||
for _, name in ipairs(newDeputy:getSkillNameList()) do
|
||||
local s = Fk.skills[name]
|
||||
if not s.relate_to_place or s.relate_to_place == "d" then
|
||||
table.insertIfNeed(skills, name)
|
||||
|
||||
if data.deputyGeneral ~= "" then
|
||||
local newDeputy = Fk.generals[data.deputyGeneral] or Fk.generals["blank_shibing"]
|
||||
for _, name in ipairs(newDeputy:getSkillNameList()) do
|
||||
local s = Fk.skills[name]
|
||||
if not s.relate_to_place or s.relate_to_place == "d" then
|
||||
table.insertIfNeed(skills, name)
|
||||
end
|
||||
end
|
||||
|
||||
if data.sendLog then
|
||||
room:sendLog{
|
||||
type = "#ChangeHero",
|
||||
from = player.id,
|
||||
arg = player.deputyGeneral,
|
||||
arg2 = data.deputyGeneral,
|
||||
arg3 = "deputyGeneral",
|
||||
}
|
||||
end
|
||||
end
|
||||
if data.sendLog then
|
||||
room:sendLog{
|
||||
type = "#ChangeHero",
|
||||
from = player.id,
|
||||
arg = player.deputyGeneral,
|
||||
arg2 = data.deputyGeneral,
|
||||
arg3 = "deputyGeneral",
|
||||
}
|
||||
end
|
||||
|
||||
data.results["deputyChange"] = {player.deputyGeneral, data.deputyGeneral}
|
||||
room:setPlayerProperty(player, "deputyGeneral", data.deputyGeneral)
|
||||
end
|
||||
|
|
|
@ -152,10 +152,18 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
|
|||
room:doBroadcastNotify("UpdateDrawPile", #room.draw_pile)
|
||||
end
|
||||
|
||||
if not (data.to and data.toArea ~= Card.PlayerHand) then
|
||||
Fk:filterCard(info.cardId, room:getPlayerById(data.to))
|
||||
local beforeCard = Fk:getCardById(info.cardId)
|
||||
if
|
||||
realFromArea == Player.Equip and
|
||||
beforeCard.type == Card.TypeEquip and
|
||||
data.from ~= nil and
|
||||
beforeCard.equip_skill
|
||||
then
|
||||
beforeCard:onUninstall(room, room:getPlayerById(data.from))
|
||||
end
|
||||
|
||||
Fk:filterCard(info.cardId, room:getPlayerById(data.to))
|
||||
|
||||
local currentCard = Fk:getCardById(info.cardId)
|
||||
for name, _ in pairs(currentCard.mark) do
|
||||
if name:endsWith("-inhand") and
|
||||
|
@ -174,15 +182,6 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
|
|||
then
|
||||
currentCard:onInstall(room, room:getPlayerById(data.to))
|
||||
end
|
||||
|
||||
if
|
||||
realFromArea == Player.Equip and
|
||||
currentCard.type == Card.TypeEquip and
|
||||
data.from ~= nil and
|
||||
currentCard.equip_skill
|
||||
then
|
||||
currentCard:onUninstall(room, room:getPlayerById(data.from))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -155,13 +155,29 @@ local sendCardEmotionAndLog = function(room, cardUseEvent)
|
|||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
GameEvent.functions[GameEvent.UseCard] = function(self)
|
||||
local cardUseEvent = table.unpack(self.data)
|
||||
local room = self.room
|
||||
local logic = room.logic
|
||||
|
||||
if cardUseEvent.card.skill then
|
||||
cardUseEvent.card.skill:onUse(room, cardUseEvent)
|
||||
end
|
||||
|
||||
sendCardEmotionAndLog(room, cardUseEvent)
|
||||
|
||||
room:moveCardTo(cardUseEvent.card, Card.Processing, nil, fk.ReasonUse)
|
||||
|
||||
local card = cardUseEvent.card
|
||||
local useCardIds = card:isVirtual() and card.subcards or { card.id }
|
||||
if #useCardIds == 0 then return end
|
||||
if cardUseEvent.tos and #cardUseEvent.tos > 0 and #cardUseEvent.tos <= 2 then
|
||||
local tos = table.map(cardUseEvent.tos, function(e) return e[1] end)
|
||||
room:sendFootnote(useCardIds, {
|
||||
type = "##UseCardTo",
|
||||
from = from,
|
||||
from = cardUseEvent.from,
|
||||
to = tos,
|
||||
})
|
||||
if card:isVirtual() then
|
||||
|
@ -170,26 +186,12 @@ local sendCardEmotionAndLog = function(room, cardUseEvent)
|
|||
else
|
||||
room:sendFootnote(useCardIds, {
|
||||
type = "##UseCard",
|
||||
from = from,
|
||||
from = cardUseEvent.from,
|
||||
})
|
||||
if card:isVirtual() then
|
||||
room:sendCardVirtName(useCardIds, card.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
GameEvent.functions[GameEvent.UseCard] = function(self)
|
||||
local cardUseEvent = table.unpack(self.data)
|
||||
local room = self.room
|
||||
local logic = room.logic
|
||||
|
||||
room:moveCardTo(cardUseEvent.card, Card.Processing, nil, fk.ReasonUse)
|
||||
|
||||
if cardUseEvent.card.skill then
|
||||
cardUseEvent.card.skill:onUse(room, cardUseEvent)
|
||||
end
|
||||
|
||||
sendCardEmotionAndLog(room, cardUseEvent)
|
||||
|
||||
if logic:trigger(fk.PreCardUse, room:getPlayerById(cardUseEvent.from), cardUseEvent) then
|
||||
logic:breakEvent()
|
||||
|
|
|
@ -23,6 +23,9 @@ function GameLogic:initialize(room)
|
|||
self.all_game_events = {}
|
||||
self.event_recorder = {}
|
||||
self.current_event_id = 0
|
||||
self.specific_events_id = {
|
||||
[GameEvent.Damage] = 0,
|
||||
}
|
||||
|
||||
self.role_table = {
|
||||
{ "lord" },
|
||||
|
|
|
@ -1913,10 +1913,13 @@ function Room:handleUseCardReply(player, data)
|
|||
end
|
||||
use.card = c
|
||||
|
||||
skill:beforeUse(player, use)
|
||||
|
||||
self:useSkill(player, skill, Util.DummyFunc)
|
||||
|
||||
local rejectSkillName = skill:beforeUse(player, use)
|
||||
if type(rejectSkillName) == "string" then
|
||||
return rejectSkillName
|
||||
end
|
||||
|
||||
return use
|
||||
end
|
||||
end
|
||||
|
@ -2007,17 +2010,29 @@ function Room:askForUseCard(player, card_name, pattern, prompt, cancelable, extr
|
|||
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0)
|
||||
return askForUseCardData.result
|
||||
else
|
||||
local data = {card_name, pattern, prompt, cancelable, extra_data}
|
||||
local useResult
|
||||
local disabledSkillNames = {}
|
||||
|
||||
Fk.currentResponsePattern = pattern
|
||||
local result = self:doRequest(player, command, json.encode(data))
|
||||
Fk.currentResponsePattern = nil
|
||||
repeat
|
||||
useResult = nil
|
||||
local data = {card_name, pattern, prompt, cancelable, extra_data, disabledSkillNames}
|
||||
|
||||
if result ~= "" then
|
||||
player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 0)
|
||||
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0)
|
||||
return self:handleUseCardReply(player, result)
|
||||
end
|
||||
Fk.currentResponsePattern = pattern
|
||||
local result = self:doRequest(player, command, json.encode(data))
|
||||
Fk.currentResponsePattern = nil
|
||||
|
||||
if result ~= "" then
|
||||
player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 0)
|
||||
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0)
|
||||
useResult = self:handleUseCardReply(player, result)
|
||||
|
||||
if type(useResult) == "string" and useResult ~= "" then
|
||||
table.insertIfNeed(disabledSkillNames, useResult)
|
||||
end
|
||||
end
|
||||
until type(useResult) ~= "string"
|
||||
|
||||
return useResult
|
||||
end
|
||||
player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 0)
|
||||
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0)
|
||||
|
@ -2056,17 +2071,28 @@ function Room:askForResponse(player, card_name, pattern, prompt, cancelable, ext
|
|||
if eventData.result then
|
||||
return eventData.result
|
||||
else
|
||||
local data = {card_name, pattern, prompt, cancelable, extra_data}
|
||||
local useResult
|
||||
local disabledSkillNames = {}
|
||||
|
||||
Fk.currentResponsePattern = pattern
|
||||
local result = self:doRequest(player, command, json.encode(data))
|
||||
Fk.currentResponsePattern = nil
|
||||
repeat
|
||||
useResult = nil
|
||||
local data = {card_name, pattern, prompt, cancelable, extra_data, disabledSkillNames}
|
||||
|
||||
if result ~= "" then
|
||||
local use = self:handleUseCardReply(player, result)
|
||||
if use then
|
||||
return use.card
|
||||
Fk.currentResponsePattern = pattern
|
||||
local result = self:doRequest(player, command, json.encode(data))
|
||||
Fk.currentResponsePattern = nil
|
||||
|
||||
if result ~= "" then
|
||||
useResult = self:handleUseCardReply(player, result)
|
||||
|
||||
if type(useResult) == "string" and useResult ~= "" then
|
||||
table.insertIfNeed(disabledSkillNames, useResult)
|
||||
end
|
||||
end
|
||||
until type(useResult) ~= "string"
|
||||
|
||||
if useResult then
|
||||
return useResult.card
|
||||
end
|
||||
end
|
||||
return nil
|
||||
|
@ -2094,20 +2120,31 @@ function Room:askForNullification(players, card_name, pattern, prompt, cancelabl
|
|||
prompt = prompt or ""
|
||||
pattern = pattern or card_name
|
||||
|
||||
self:notifyMoveFocus(self.alive_players, card_name)
|
||||
self:doBroadcastNotify("WaitForNullification", "")
|
||||
local useResult
|
||||
local disabledSkillNames = {}
|
||||
|
||||
local data = {card_name, pattern, prompt, cancelable, extra_data}
|
||||
repeat
|
||||
useResult = nil
|
||||
self:notifyMoveFocus(self.alive_players, card_name)
|
||||
self:doBroadcastNotify("WaitForNullification", "")
|
||||
|
||||
Fk.currentResponsePattern = pattern
|
||||
local winner = self:doRaceRequest(command, players, json.encode(data))
|
||||
local data = {card_name, pattern, prompt, cancelable, extra_data, disabledSkillNames}
|
||||
|
||||
if winner then
|
||||
local result = winner.client_reply
|
||||
return self:handleUseCardReply(winner, result)
|
||||
end
|
||||
Fk.currentResponsePattern = nil
|
||||
return nil
|
||||
Fk.currentResponsePattern = pattern
|
||||
local winner = self:doRaceRequest(command, players, json.encode(data))
|
||||
|
||||
if winner then
|
||||
local result = winner.client_reply
|
||||
useResult = self:handleUseCardReply(winner, result)
|
||||
|
||||
if type(useResult) == "string" and useResult ~= "" then
|
||||
table.insertIfNeed(disabledSkillNames, useResult)
|
||||
end
|
||||
end
|
||||
Fk.currentResponsePattern = nil
|
||||
until type(useResult) ~= "string"
|
||||
|
||||
return useResult
|
||||
end
|
||||
|
||||
-- AG(a.k.a. Amazing Grace) functions
|
||||
|
@ -2409,9 +2446,8 @@ local onAim = function(room, cardUseEvent, aimEventCollaborators)
|
|||
|
||||
firstTarget = false
|
||||
|
||||
if room.logic:trigger(stage, (stage == fk.TargetSpecifying or stage == fk.TargetSpecified) and room:getPlayerById(aimStruct.from) or room:getPlayerById(aimStruct.to), aimStruct) then
|
||||
return false
|
||||
end
|
||||
room.logic:trigger(stage, (stage == fk.TargetSpecifying or stage == fk.TargetSpecified) and room:getPlayerById(aimStruct.from) or room:getPlayerById(aimStruct.to), aimStruct)
|
||||
|
||||
AimGroup:removeDeadTargets(room, aimStruct)
|
||||
|
||||
local aimEventTargetGroup = aimStruct.targetGroup
|
||||
|
@ -3292,19 +3328,9 @@ function Room:useSkill(player, skill, effect_cb)
|
|||
end
|
||||
|
||||
---@param player ServerPlayer
|
||||
---@param sendLog? boolean
|
||||
function Room:revivePlayer(player, sendLog)
|
||||
if not player.dead then return end
|
||||
self:setPlayerProperty(player, "dead", false)
|
||||
player._splayer:setDied(false)
|
||||
self:setPlayerProperty(player, "dying", false)
|
||||
self:setPlayerProperty(player, "hp", player.maxHp)
|
||||
table.insertIfNeed(self.alive_players, player)
|
||||
|
||||
sendLog = (sendLog == nil) and true or sendLog
|
||||
if sendLog then
|
||||
self:sendLog { type = "#Revive", from = player.id }
|
||||
end
|
||||
---@param sendLog? bool
|
||||
function Room:revivePlayer(player, sendLog, reason)
|
||||
return execGameEvent(GameEvent.Revive, player, sendLog, reason)
|
||||
end
|
||||
|
||||
---@param room Room
|
||||
|
@ -3573,4 +3599,9 @@ function Room:resumePlayerArea(player, playerSlots)
|
|||
end
|
||||
end
|
||||
|
||||
function Room:setPlayerRest(player, roundNum)
|
||||
player.rest = roundNum
|
||||
self:broadcastProperty(player, "rest")
|
||||
end
|
||||
|
||||
return Room
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
--- 描述和一次体力变化有关的数据
|
||||
---@class HpChangedData
|
||||
---@field public num integer @ 体力变化量,可能是正数或者负数
|
||||
---@field public shield_lost integer|nil
|
||||
---@field public reason string @ 体力变化原因
|
||||
---@field public skillName string @ 引起体力变化的技能名
|
||||
---@field public damageEvent? DamageStruct @ 引起这次体力变化的伤害数据
|
||||
|
|
|
@ -82,7 +82,7 @@ GameRule = fk.CreateTriggerSkill{
|
|||
end,
|
||||
[fk.BuryVictim] = function()
|
||||
player:bury()
|
||||
if room.tag["SkipNormalDeathProcess"] then
|
||||
if room.tag["SkipNormalDeathProcess"] or player.rest > 0 then
|
||||
return false
|
||||
end
|
||||
local damage = data.damage
|
||||
|
|
BIN
packages/standard/image/generals/avatar/__observer.jpg
Normal file
BIN
packages/standard/image/generals/avatar/__observer.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
packages/standard/image/generals/avatar/__server.jpg
Normal file
BIN
packages/standard/image/generals/avatar/__server.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
BIN
packages/standard/image/generals/avatar/anjiang.jpg
Normal file
BIN
packages/standard/image/generals/avatar/anjiang.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
|
@ -423,6 +423,31 @@ local jijiang = fk.CreateViewAsSkill{
|
|||
c.skillName = self.name
|
||||
return c
|
||||
end,
|
||||
before_use = function(self, player, use)
|
||||
local room = player.room
|
||||
if use.tos then
|
||||
room:doIndicate(player.id, TargetGroup:getRealTargets(use.tos))
|
||||
end
|
||||
|
||||
for _, p in ipairs(room:getOtherPlayers(player)) do
|
||||
if p.kingdom == "shu" then
|
||||
local cardResponded = room:askForResponse(p, "slash", "slash", "#jijiang-ask:" .. player.id, true)
|
||||
if cardResponded then
|
||||
room:responseCard({
|
||||
from = p.id,
|
||||
card = cardResponded,
|
||||
skipDrop = true,
|
||||
})
|
||||
|
||||
use.card = cardResponded
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
room:setPlayerMark(player, "jijiang-failed-phase", 1)
|
||||
return self.name
|
||||
end,
|
||||
enabled_at_play = function(self, player)
|
||||
return player:getMark("jijiang-failed-phase") == 0 and not table.every(Fk:currentRoom().alive_players, function(p)
|
||||
return p == player or p.kingdom ~= "shu"
|
||||
|
@ -434,51 +459,6 @@ local jijiang = fk.CreateViewAsSkill{
|
|||
end)
|
||||
end,
|
||||
}
|
||||
local jijiangResponse = fk.CreateTriggerSkill{
|
||||
name = "#jijiangResponse",
|
||||
events = {fk.PreCardUse, fk.PreCardRespond},
|
||||
mute = true,
|
||||
priority = 10,
|
||||
can_trigger = function(self, event, target, player, data)
|
||||
return target == player and player:hasSkill(self.name, true) and table.contains(data.card.skillNames, "jijiang")
|
||||
end,
|
||||
on_cost = function(self, event, target, player, data)
|
||||
local room = player.room
|
||||
room:doIndicate(player.id, TargetGroup:getRealTargets(data.tos))
|
||||
return true
|
||||
end,
|
||||
on_use = function(self, event, target, player, data)
|
||||
local room = player.room
|
||||
for _, p in ipairs(room:getOtherPlayers(player)) do
|
||||
if p.kingdom == "shu" then
|
||||
local cardResponded = room:askForResponse(p, "slash", "slash", "#jijiang-ask:" .. player.id, true)
|
||||
if cardResponded then
|
||||
room:responseCard({
|
||||
from = p.id,
|
||||
card = cardResponded,
|
||||
skipDrop = true,
|
||||
})
|
||||
|
||||
data.card = cardResponded
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if event == fk.PreCardUse and player.phase == Player.Play then
|
||||
room:setPlayerMark(player, "jijiang-failed-phase", 1)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
refresh_events = {fk.CardUsing},
|
||||
can_refresh = function(self, event, target, player, data)
|
||||
return target == player and player:hasSkill(self.name, true) and player:getMark("jijiang-failed-phase") > 0
|
||||
end,
|
||||
on_refresh = function(self, event, target, player, data)
|
||||
player.room:setPlayerMark(player, "jijiang-failed-phase", 0)
|
||||
end,
|
||||
}
|
||||
jijiang:addRelatedSkill(jijiangResponse)
|
||||
|
||||
local liubei = General:new(extension, "liubei", "shu", 4)
|
||||
liubei:addSkill(rende)
|
||||
|
|
|
@ -338,6 +338,7 @@ local test_feichu = fk.CreateActiveSkill{
|
|||
room:abortPlayerArea(from, eqipSlots)
|
||||
end,
|
||||
}
|
||||
|
||||
local test2 = General(extension, "mouxusheng", "wu", 4, 4, General.Female)
|
||||
test2.shield = 3
|
||||
test2.hidden = true
|
||||
|
|
Loading…
Reference in New Issue
Block a user