Heg (#242)
- 游戏结束时离线玩家增加逃率 - 退出房间时取消准备状态 - 副技能的 `main_skill` - 预亮相关优化 - 自定义身份,图从拓展包随便找一张 - 无懈可击使用时带1200毫秒延迟 - 未开始的房间显示开启的所有牌堆,衍生牌灰色字体化 - 可以随意打开fk.rep文件并播放录像 - 服务器Shell新增重置密码命令
This commit is contained in:
parent
4bee447327
commit
0745863863
|
@ -3,6 +3,7 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Dialogs
|
||||||
import Fk
|
import Fk
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -29,6 +30,12 @@ Item {
|
||||||
Menu {
|
Menu {
|
||||||
id: menu
|
id: menu
|
||||||
y: bar.height
|
y: bar.height
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Replay from file")
|
||||||
|
onTriggered: {
|
||||||
|
fdialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +111,7 @@ Item {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
config.observing = true;
|
config.observing = true;
|
||||||
config.replaying = true;
|
config.replaying = true;
|
||||||
Backend.playRecord(fileName);
|
Backend.playRecord("recording/" + fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +129,17 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileDialog {
|
||||||
|
id: fdialog
|
||||||
|
nameFilters: ["FK Rep Files (*.fk.rep)"];
|
||||||
|
onAccepted: {
|
||||||
|
config.observing = true;
|
||||||
|
config.replaying = true;
|
||||||
|
let str = selectedFile.toString(); // QUrl -> string
|
||||||
|
Backend.playRecord(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateList() {
|
function updateList() {
|
||||||
model.clear();
|
model.clear();
|
||||||
const data = Backend.ls("recording");
|
const data = Backend.ls("recording");
|
||||||
|
|
|
@ -210,22 +210,55 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
x: parent.width / 2 + 80
|
x: parent.width / 2 + 60
|
||||||
y: parent.height / 2
|
y: parent.height / 2 - 30
|
||||||
color: "snow"
|
color: "snow"
|
||||||
opacity: 0.8
|
opacity: 0.8
|
||||||
radius: 6
|
radius: 6
|
||||||
height: childrenRect.height + 16
|
|
||||||
width: childrenRect.width + 16
|
|
||||||
visible: !isStarted
|
visible: !isStarted
|
||||||
|
width: 280
|
||||||
|
height: 280
|
||||||
|
|
||||||
Text {
|
Flickable {
|
||||||
x: 8; y: 8
|
id: flickableContainer
|
||||||
Component.onCompleted: {
|
ScrollBar.vertical: ScrollBar {}
|
||||||
const data = JSON.parse(Backend.callLuaFunction("GetRoomConfig", []));
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text = Backend.translate("LuckCardNum") + data.luckTime + "<br />" + Backend.translate("ResponseTime") + config.roomTimeout
|
anchors.top: parent.top
|
||||||
+ "<br />" + Backend.translate("GeneralBoxNum") + data.generalNum + (data.enableFreeAssign ? "<br />" + Backend.translate("IncludeFreeAssign") : "")
|
anchors.topMargin: 10
|
||||||
+ (data.enableDeputy ? "<br />" + Backend.translate("IncludeDeputy") : "")
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
width: parent.width - 10
|
||||||
|
height: parent.height - 10
|
||||||
|
contentHeight: roominfo.height
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: roominfo
|
||||||
|
font.pixelSize: 16
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: TextEdit.WordWrap
|
||||||
|
Component.onCompleted: {
|
||||||
|
const data = JSON.parse(Backend.callLuaFunction("GetRoomConfig", []));
|
||||||
|
let cardpack = JSON.parse(Backend.callLuaFunction("GetAllCardPack", []));
|
||||||
|
cardpack = cardpack.filter(p => !data.disabledPack.includes(p));
|
||||||
|
|
||||||
|
text = "游戏模式:" + Backend.translate(data.gameMode) + "<br />"
|
||||||
|
+ Backend.translate("LuckCardNum") + "<b>" + data.luckTime + "</b><br />"
|
||||||
|
+ Backend.translate("ResponseTime") + "<b>" + config.roomTimeout + "</b><br />"
|
||||||
|
+ Backend.translate("GeneralBoxNum") + "<b>" + data.generalNum + "</b>"
|
||||||
|
+ (data.enableFreeAssign ? "<br />" + Backend.translate("IncludeFreeAssign") : "")
|
||||||
|
+ (data.enableDeputy ? " " + Backend.translate("IncludeDeputy") : "")
|
||||||
|
+ '<br />使用牌堆:' + cardpack.map(e => {
|
||||||
|
let ret = Backend.translate(e);
|
||||||
|
if (ret.search(/特殊牌|衍生牌/) === -1) { // TODO: 这种东西最好还是变量名规范化= =
|
||||||
|
ret = "<b>" + ret + "</b>";
|
||||||
|
} else {
|
||||||
|
ret = '<font color="grey"><i>' + ret + "</i></font>";
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}).join(',')
|
||||||
|
//+ '<br /><b>禁包</b>:' + data.disabledPack.map(e => Backend.translate(e)).join(',')
|
||||||
|
//+ '<br /><b>禁将</b>:' + data.disabledGenerals.map(e => Backend.translate(e)).join(',')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,9 @@ ColumnLayout {
|
||||||
const data = skills.get(i);
|
const data = skills.get(i);
|
||||||
if (data.skillname_ === skill) {
|
if (data.skillname_ === skill) {
|
||||||
data.times = times;
|
data.times = times;
|
||||||
|
if (times == -1) {
|
||||||
|
skills.remove(i);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ Image {
|
||||||
property var options: ["unknown", "loyalist", "rebel", "renegade"]
|
property var options: ["unknown", "loyalist", "rebel", "renegade"]
|
||||||
|
|
||||||
id: root
|
id: root
|
||||||
source: visible ? SkinBank.ROLE_DIR + value : ""
|
source: visible ? SkinBank.getRolePic(value) : ""
|
||||||
visible: value != "hidden"
|
visible: value != "hidden"
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
|
|
|
@ -55,6 +55,7 @@ function getCardPicture(cidOrName) {
|
||||||
return path;
|
return path;
|
||||||
} else {
|
} else {
|
||||||
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
||||||
|
if (dir.endsWith(".disabled")) continue;
|
||||||
path = AppPath + "/packages/" + dir + "/image/card/" + name + ".png";
|
path = AppPath + "/packages/" + dir + "/image/card/" + name + ".png";
|
||||||
if (Backend.exists(path)) return path;
|
if (Backend.exists(path)) return path;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +71,7 @@ function getDelayedTrickPicture(name) {
|
||||||
return path;
|
return path;
|
||||||
} else {
|
} else {
|
||||||
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
||||||
|
if (dir.endsWith(".disabled")) continue;
|
||||||
path = AppPath + "/packages/" + dir + "/image/card/delayedTrick/" + name + ".png";
|
path = AppPath + "/packages/" + dir + "/image/card/delayedTrick/" + name + ".png";
|
||||||
if (Backend.exists(path)) return path;
|
if (Backend.exists(path)) return path;
|
||||||
}
|
}
|
||||||
|
@ -87,6 +89,7 @@ function getEquipIcon(cid, icon) {
|
||||||
return path;
|
return path;
|
||||||
} else {
|
} else {
|
||||||
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
||||||
|
if (dir.endsWith(".disabled")) continue;
|
||||||
path = AppPath + "/packages/" + dir + "/image/card/equipIcon/" + name + ".png";
|
path = AppPath + "/packages/" + dir + "/image/card/equipIcon/" + name + ".png";
|
||||||
if (Backend.exists(path)) return path;
|
if (Backend.exists(path)) return path;
|
||||||
}
|
}
|
||||||
|
@ -98,6 +101,7 @@ function getPhotoBack(kingdom) {
|
||||||
let path = PHOTO_BACK_DIR + kingdom + ".png";
|
let path = PHOTO_BACK_DIR + kingdom + ".png";
|
||||||
if (!Backend.exists(path)) {
|
if (!Backend.exists(path)) {
|
||||||
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
||||||
|
if (dir.endsWith(".disabled")) continue;
|
||||||
path = AppPath + "/packages/" + dir + "/image/kingdom/" + kingdom + "-back.png";
|
path = AppPath + "/packages/" + dir + "/image/kingdom/" + kingdom + "-back.png";
|
||||||
if (Backend.exists(path)) return path;
|
if (Backend.exists(path)) return path;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +115,7 @@ function getGeneralCardDir(kingdom) {
|
||||||
let path = GENERALCARD_DIR + kingdom + ".png";
|
let path = GENERALCARD_DIR + kingdom + ".png";
|
||||||
if (!Backend.exists(path)) {
|
if (!Backend.exists(path)) {
|
||||||
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
||||||
|
if (dir.endsWith(".disabled")) continue;
|
||||||
path = AppPath + "/packages/" + dir + "/image/kingdom/" + kingdom + "-back.png";
|
path = AppPath + "/packages/" + dir + "/image/kingdom/" + kingdom + "-back.png";
|
||||||
if (Backend.exists(path))
|
if (Backend.exists(path))
|
||||||
return AppPath + "/packages/" + dir + "/image/kingdom/";
|
return AppPath + "/packages/" + dir + "/image/kingdom/";
|
||||||
|
@ -119,3 +124,17 @@ function getGeneralCardDir(kingdom) {
|
||||||
return GENERALCARD_DIR;
|
return GENERALCARD_DIR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRolePic(role) {
|
||||||
|
let path = ROLE_DIR + role + ".png";
|
||||||
|
if (Backend.exists(path)) {
|
||||||
|
return path;
|
||||||
|
} else {
|
||||||
|
for (let dir of Backend.ls(AppPath + "/packages/")) {
|
||||||
|
if (dir.endsWith(".disabled")) continue;
|
||||||
|
path = AppPath + "/packages/" + dir + "/image/role/" + name + ".png";
|
||||||
|
if (Backend.exists(path)) return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ROLE_DIR + "unknown.png";
|
||||||
|
}
|
||||||
|
|
|
@ -585,21 +585,6 @@ fk.client_callback["ShowCard"] = function(jsonData)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
fk.client_callback["LoseSkill"] = function(jsonData)
|
|
||||||
-- jsonData: [ int player_id, string skill_name ]
|
|
||||||
local data = json.decode(jsonData)
|
|
||||||
local id, skill_name, prelight = data[1], data[2], data[3]
|
|
||||||
local target = ClientInstance:getPlayerById(id)
|
|
||||||
local skill = Fk.skills[skill_name]
|
|
||||||
if not prelight then
|
|
||||||
target:loseSkill(skill)
|
|
||||||
end
|
|
||||||
|
|
||||||
if skill.visible then
|
|
||||||
ClientInstance:notifyUI("LoseSkill", jsonData)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 说是限定技,其实也适用于觉醒技、转换技、使命技
|
-- 说是限定技,其实也适用于觉醒技、转换技、使命技
|
||||||
---@param skill Skill
|
---@param skill Skill
|
||||||
---@param times integer
|
---@param times integer
|
||||||
|
@ -613,15 +598,99 @@ local function updateLimitSkill(pid, skill, times)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
fk.client_callback["LoseSkill"] = function(jsonData)
|
||||||
|
-- jsonData: [ int player_id, string skill_name ]
|
||||||
|
local data = json.decode(jsonData)
|
||||||
|
local id, skill_name, fake = data[1], data[2], data[3]
|
||||||
|
local target = ClientInstance:getPlayerById(id)
|
||||||
|
local skill = Fk.skills[skill_name]
|
||||||
|
|
||||||
|
if not fake then
|
||||||
|
target:loseSkill(skill)
|
||||||
|
if skill.visible then
|
||||||
|
ClientInstance:notifyUI("LoseSkill", jsonData)
|
||||||
|
end
|
||||||
|
elseif skill.visible then
|
||||||
|
-- 按理说能弄得更好的但还是复制粘贴舒服
|
||||||
|
local sks = { table.unpack(skill.related_skills) }
|
||||||
|
--[[ 需要大伙都适配好main_skill或者讨论出更好方案才行。不敢轻举妄动
|
||||||
|
local sks = table.filter(skill.related_skills, function(s)
|
||||||
|
return s.main_skill == skill
|
||||||
|
end)
|
||||||
|
--]]
|
||||||
|
table.insert(sks, skill)
|
||||||
|
table.removeOne(target.player_skills, skill)
|
||||||
|
local chk = false
|
||||||
|
|
||||||
|
if table.find(sks, function(s) return s:isInstanceOf(TriggerSkill) end) then
|
||||||
|
chk = true
|
||||||
|
ClientInstance:notifyUI("LoseSkill", jsonData)
|
||||||
|
end
|
||||||
|
|
||||||
|
local active = table.filter(sks, function(s)
|
||||||
|
return s:isInstanceOf(ActiveSkill) or s:isInstanceOf(ViewAsSkill)
|
||||||
|
end)
|
||||||
|
|
||||||
|
if #active > 0 then
|
||||||
|
chk = true
|
||||||
|
ClientInstance:notifyUI("LoseSkill", json.encode {
|
||||||
|
id, skill_name,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if not chk then
|
||||||
|
ClientInstance:notifyUI("LoseSkill", json.encode {
|
||||||
|
id, skill_name,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
updateLimitSkill(id, skill, -1)
|
||||||
|
end
|
||||||
|
|
||||||
fk.client_callback["AddSkill"] = function(jsonData)
|
fk.client_callback["AddSkill"] = function(jsonData)
|
||||||
-- jsonData: [ int player_id, string skill_name ]
|
-- jsonData: [ int player_id, string skill_name ]
|
||||||
local data = json.decode(jsonData)
|
local data = json.decode(jsonData)
|
||||||
local id, skill_name = data[1], data[2]
|
local id, skill_name, fake = data[1], data[2], data[3]
|
||||||
local target = ClientInstance:getPlayerById(id)
|
local target = ClientInstance:getPlayerById(id)
|
||||||
local skill = Fk.skills[skill_name]
|
local skill = Fk.skills[skill_name]
|
||||||
target:addSkill(skill)
|
|
||||||
if skill.visible then
|
if not fake then
|
||||||
ClientInstance:notifyUI("AddSkill", jsonData)
|
target:addSkill(skill)
|
||||||
|
if skill.visible then
|
||||||
|
ClientInstance:notifyUI("AddSkill", jsonData)
|
||||||
|
end
|
||||||
|
elseif skill.visible then
|
||||||
|
-- 添加假技能:服务器只会传一个主技能来。
|
||||||
|
-- 若有主动技则添加按钮,若有触发技则添加预亮按钮。
|
||||||
|
-- 无视状态技。
|
||||||
|
local sks = { table.unpack(skill.related_skills) }
|
||||||
|
table.insert(sks, skill)
|
||||||
|
table.insert(target.player_skills, skill)
|
||||||
|
local chk = false
|
||||||
|
|
||||||
|
if table.find(sks, function(s) return s:isInstanceOf(TriggerSkill) end) then
|
||||||
|
chk = true
|
||||||
|
ClientInstance:notifyUI("AddSkill", jsonData)
|
||||||
|
end
|
||||||
|
|
||||||
|
local active = table.filter(sks, function(s)
|
||||||
|
return s:isInstanceOf(ActiveSkill) or s:isInstanceOf(ViewAsSkill)
|
||||||
|
end)
|
||||||
|
|
||||||
|
if #active > 0 then
|
||||||
|
chk = true
|
||||||
|
ClientInstance:notifyUI("AddSkill", json.encode {
|
||||||
|
id, skill_name,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 面板上总得有点啥东西表明自己有技能吧 = =
|
||||||
|
if not chk then
|
||||||
|
ClientInstance:notifyUI("AddSkill", json.encode {
|
||||||
|
id, skill_name,
|
||||||
|
})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if skill.frequency == Skill.Quest then
|
if skill.frequency == Skill.Quest then
|
||||||
|
|
|
@ -678,6 +678,13 @@ function Player:hasSkill(skill, ignoreNullified, ignoreAlive)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self:isInstanceOf(ServerPlayer) and -- isInstanceOf(nil) will return false
|
||||||
|
table.contains(self._fake_skills, skill) and
|
||||||
|
table.contains(self.prelighted_skills, skill) then
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
for _, v in pairs(self.derivative_skills) do
|
for _, v in pairs(self.derivative_skills) do
|
||||||
if table.contains(v, skill) then
|
if table.contains(v, skill) then
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -56,8 +56,15 @@ end
|
||||||
-- do cost and skill effect.
|
-- do cost and skill effect.
|
||||||
-- DO NOT modify this function
|
-- DO NOT modify this function
|
||||||
function TriggerSkill:doCost(event, target, player, data)
|
function TriggerSkill:doCost(event, target, player, data)
|
||||||
|
local start_time = os.getms()
|
||||||
local ret = self:cost(event, target, player, data)
|
local ret = self:cost(event, target, player, data)
|
||||||
|
local end_time = os.getms()
|
||||||
|
|
||||||
local room = player.room
|
local room = player.room
|
||||||
|
-- 对于那种cost直接返回true的锁定技,如果是预亮技,那么还是询问一下好
|
||||||
|
if ret and player:isFakeSkill(self) and end_time - start_time < 10000 then
|
||||||
|
ret = room:askForSkillInvoke(player, self.name)
|
||||||
|
end
|
||||||
|
|
||||||
local cost_data_bak = self.cost_data
|
local cost_data_bak = self.cost_data
|
||||||
room.logic:trigger(fk.BeforeTriggerSkillUse, player, { skill = self, willUse = ret })
|
room.logic:trigger(fk.BeforeTriggerSkillUse, player, { skill = self, willUse = ret })
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
---@class UsableSkill : Skill
|
---@class UsableSkill : Skill
|
||||||
|
---@field public main_skill UsableSkill
|
||||||
---@field public max_use_time integer[]
|
---@field public max_use_time integer[]
|
||||||
---@field public expand_pile string
|
---@field public expand_pile string
|
||||||
local UsableSkill = Skill:subclass("UsableSkill")
|
local UsableSkill = Skill:subclass("UsableSkill")
|
||||||
|
|
|
@ -42,6 +42,8 @@ end
|
||||||
|
|
||||||
local function readUsableSpecToSkill(skill, spec)
|
local function readUsableSpecToSkill(skill, spec)
|
||||||
readCommonSpecToSkill(skill, spec)
|
readCommonSpecToSkill(skill, spec)
|
||||||
|
assert(spec.main_skill == nil or spec.main_skill:isInstanceOf(UsableSkill))
|
||||||
|
skill.main_skill = spec.main_skill
|
||||||
skill.target_num = spec.target_num or skill.target_num
|
skill.target_num = spec.target_num or skill.target_num
|
||||||
skill.min_target_num = spec.min_target_num or skill.min_target_num
|
skill.min_target_num = spec.min_target_num or skill.min_target_num
|
||||||
skill.max_target_num = spec.max_target_num or skill.max_target_num
|
skill.max_target_num = spec.max_target_num or skill.max_target_num
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
GameEvent.functions[GameEvent.SkillEffect] = function(self)
|
GameEvent.functions[GameEvent.SkillEffect] = function(self)
|
||||||
local effect_cb, player, skill = table.unpack(self.data)
|
local effect_cb, player, _skill = table.unpack(self.data)
|
||||||
local room = self.room
|
local room = self.room
|
||||||
local logic = room.logic
|
local logic = room.logic
|
||||||
|
local skill = _skill.main_skill and _skill.main_skill or _skill
|
||||||
|
|
||||||
|
if player then
|
||||||
|
player:addSkillUseHistory(skill.name)
|
||||||
|
end
|
||||||
|
|
||||||
local cost_data_bak = skill.cost_data
|
local cost_data_bak = skill.cost_data
|
||||||
logic:trigger(fk.SkillEffect, player, skill)
|
logic:trigger(fk.SkillEffect, player, skill)
|
||||||
|
|
|
@ -829,6 +829,15 @@ function Room:notifyMoveFocus(players, command)
|
||||||
table.insert(ids, p.id)
|
table.insert(ids, p.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local tempSk = Fk.skills[command]
|
||||||
|
if tempSk and #players == 1 then
|
||||||
|
local p = players[1]
|
||||||
|
if p:isFakeSkill(tempSk) then
|
||||||
|
command = ""
|
||||||
|
ids = table.map(self.alive_players, Util.IdMapper)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
self:doBroadcastNotify("MoveFocus", json.encode{
|
self:doBroadcastNotify("MoveFocus", json.encode{
|
||||||
ids,
|
ids,
|
||||||
command
|
command
|
||||||
|
@ -2987,7 +2996,6 @@ function Room:useSkill(player, skill, effect_cb)
|
||||||
player:getSwitchSkillState(switchSkillName, true)
|
player:getSwitchSkillState(switchSkillName, true)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
player:addSkillUseHistory(skill.name)
|
|
||||||
|
|
||||||
if effect_cb then
|
if effect_cb then
|
||||||
return execGameEvent(GameEvent.SkillEffect, effect_cb, player, skill)
|
return execGameEvent(GameEvent.SkillEffect, effect_cb, player, skill)
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
---@field public phase_state table[]
|
---@field public phase_state table[]
|
||||||
---@field public phase_index integer
|
---@field public phase_index integer
|
||||||
---@field public role_shown boolean
|
---@field public role_shown boolean
|
||||||
|
---@field private _fake_skills Skill[]
|
||||||
|
---@field public prelighted_skills Skill[]
|
||||||
---@field private _timewaste_count integer
|
---@field private _timewaste_count integer
|
||||||
---@field public ai AI
|
---@field public ai AI
|
||||||
---@field public ai_data any
|
---@field public ai_data any
|
||||||
|
@ -35,6 +37,11 @@ function ServerPlayer:initialize(_self)
|
||||||
self.reply_cancel = false
|
self.reply_cancel = false
|
||||||
self.phases = {}
|
self.phases = {}
|
||||||
self.skipped_phases = {}
|
self.skipped_phases = {}
|
||||||
|
|
||||||
|
self._fake_skills = {}
|
||||||
|
self.prelighted_skills = {}
|
||||||
|
self._prelighted_skills = {}
|
||||||
|
|
||||||
self._timewaste_count = 0
|
self._timewaste_count = 0
|
||||||
self.ai = RandomAI:new(self)
|
self.ai = RandomAI:new(self)
|
||||||
end
|
end
|
||||||
|
@ -702,13 +709,70 @@ end
|
||||||
|
|
||||||
-- Hegemony func
|
-- Hegemony func
|
||||||
|
|
||||||
|
---@param skill Skill
|
||||||
|
function ServerPlayer:addFakeSkill(skill)
|
||||||
|
assert(skill:isInstanceOf(Skill))
|
||||||
|
if table.contains(self._fake_skills, skill) then return end
|
||||||
|
|
||||||
|
table.insert(self._fake_skills, skill)
|
||||||
|
for _, s in ipairs(skill.related_skills) do
|
||||||
|
-- if s.main_skill == skill then -- TODO: need more detailed
|
||||||
|
table.insert(self._fake_skills, s)
|
||||||
|
-- end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO
|
||||||
|
self:doNotify("AddSkill", json.encode{ self.id, skill.name, true })
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param skill Skill
|
||||||
|
function ServerPlayer:loseFakeSkill(skill)
|
||||||
|
assert(skill:isInstanceOf(Skill))
|
||||||
|
if not table.contains(self._fake_skills, skill) then return end
|
||||||
|
|
||||||
|
table.removeOne(self._fake_skills, skill)
|
||||||
|
for _, s in ipairs(skill.related_skills) do
|
||||||
|
table.removeOne(self._fake_skills, s)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO
|
||||||
|
self:doNotify("LoseSkill", json.encode{ self.id, skill.name, true })
|
||||||
|
end
|
||||||
|
|
||||||
|
function ServerPlayer:isFakeSkill(skill)
|
||||||
|
if type(skill) == "string" then skill = Fk.skills[skill] end
|
||||||
|
assert(skill:isInstanceOf(Skill))
|
||||||
|
return table.contains(self._fake_skills, skill)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param skill string | Skill
|
||||||
|
---@param isPrelight boolean | nil
|
||||||
function ServerPlayer:prelightSkill(skill, isPrelight)
|
function ServerPlayer:prelightSkill(skill, isPrelight)
|
||||||
if isPrelight then
|
if type(skill) == "string" then skill = Fk.skills[skill] end
|
||||||
|
assert(skill:isInstanceOf(Skill))
|
||||||
|
|
||||||
|
if not self._prelighted_skills[skill] and not self:hasSkill(skill) then
|
||||||
|
self._prelighted_skills[skill] = true
|
||||||
|
-- to attach skill to room
|
||||||
self:addSkill(skill)
|
self:addSkill(skill)
|
||||||
else
|
|
||||||
self:loseSkill(skill)
|
self:loseSkill(skill)
|
||||||
end
|
end
|
||||||
self:doNotify("PrelightSkill", json.encode{ skill, isPrelight })
|
|
||||||
|
if isPrelight then
|
||||||
|
-- self:addSkill(skill)
|
||||||
|
table.insert(self.prelighted_skills, skill)
|
||||||
|
for _, s in ipairs(skill.related_skills) do
|
||||||
|
table.insert(self.prelighted_skills, s)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- self:loseSkill(skill)
|
||||||
|
table.removeOne(self.prelighted_skills, skill)
|
||||||
|
for _, s in ipairs(skill.related_skills) do
|
||||||
|
table.removeOne(self.prelighted_skills, s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:doNotify("PrelightSkill", json.encode{ skill.name, isPrelight })
|
||||||
end
|
end
|
||||||
|
|
||||||
function ServerPlayer:revealGeneral(isDeputy)
|
function ServerPlayer:revealGeneral(isDeputy)
|
||||||
|
@ -725,10 +789,7 @@ function ServerPlayer:revealGeneral(isDeputy)
|
||||||
local general = Fk.generals[generalName]
|
local general = Fk.generals[generalName]
|
||||||
for _, s in ipairs(general:getSkillNameList()) do
|
for _, s in ipairs(general:getSkillNameList()) do
|
||||||
local skill = Fk.skills[s]
|
local skill = Fk.skills[s]
|
||||||
if skill:isInstanceOf(TriggerSkill) or table.find(skill.related_skills,
|
self:loseFakeSkill(skill)
|
||||||
function(s) return s:isInstanceOf(TriggerSkill) end) then
|
|
||||||
self:doNotify("LoseSkill", json.encode{ self.id, s, true })
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local oldKingdom = self.kingdom
|
local oldKingdom = self.kingdom
|
||||||
|
|
|
@ -229,13 +229,7 @@ function HegLogic:attachSkillToPlayers()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- room:handleAddLoseSkills(player, skillName, nil, false)
|
player:addFakeSkill(skill)
|
||||||
player:doNotify("AddSkill", json.encode{ player.id, skillName })
|
|
||||||
|
|
||||||
if skill:isInstanceOf(TriggerSkill) or table.find(skill.related_skills,
|
|
||||||
function(s) return s:isInstanceOf(TriggerSkill) end) then
|
|
||||||
player:doNotify("AddSkill", json.encode{ player.id, skillName, true })
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, p in ipairs(room.alive_players) do
|
for _, p in ipairs(room.alive_players) do
|
||||||
|
|
|
@ -413,6 +413,7 @@ local nullificationSkill = fk.CreateActiveSkill{
|
||||||
can_use = function()
|
can_use = function()
|
||||||
return false
|
return false
|
||||||
end,
|
end,
|
||||||
|
on_use = function() RoomInstance:delay(1200) end,
|
||||||
on_effect = function(self, room, effect)
|
on_effect = function(self, room, effect)
|
||||||
if effect.responseToEvent then
|
if effect.responseToEvent then
|
||||||
effect.responseToEvent.isCancellOut = true
|
effect.responseToEvent.isCancellOut = true
|
||||||
|
|
|
@ -11,7 +11,12 @@ Replayer::Replayer(QObject *parent, const QString &filename) :
|
||||||
{
|
{
|
||||||
setObjectName("Replayer");
|
setObjectName("Replayer");
|
||||||
|
|
||||||
QFile file("recording/" + filename);
|
auto s = filename;
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
if (s.startsWith("file:///"))
|
||||||
|
s.replace(0, 8, "file://");
|
||||||
|
#endif
|
||||||
|
QFile file(QUrl(s).path());
|
||||||
file.open(QIODevice::ReadOnly);
|
file.open(QIODevice::ReadOnly);
|
||||||
QByteArray raw = file.readAll();
|
QByteArray raw = file.readAll();
|
||||||
file.close();
|
file.close();
|
||||||
|
|
|
@ -234,6 +234,7 @@ void Room::removePlayer(ServerPlayer *player) {
|
||||||
if (!gameStarted) {
|
if (!gameStarted) {
|
||||||
// 游戏还没开始的话,直接删除这名玩家
|
// 游戏还没开始的话,直接删除这名玩家
|
||||||
if (players.contains(player) && !players.isEmpty()) {
|
if (players.contains(player) && !players.isEmpty()) {
|
||||||
|
player->setReady(false);
|
||||||
players.removeOne(player);
|
players.removeOne(player);
|
||||||
}
|
}
|
||||||
emit playerRemoved(player);
|
emit playerRemoved(player);
|
||||||
|
@ -533,10 +534,15 @@ void Room::gameOver() {
|
||||||
gameStarted = false;
|
gameStarted = false;
|
||||||
runned_players.clear();
|
runned_players.clear();
|
||||||
// 清理所有状态不是“在线”的玩家
|
// 清理所有状态不是“在线”的玩家
|
||||||
|
auto settings = QJsonDocument::fromJson(this->settings);
|
||||||
|
auto mode = settings["gameMode"].toString();
|
||||||
foreach (ServerPlayer *p, players) {
|
foreach (ServerPlayer *p, players) {
|
||||||
if (p->getState() != Player::Online) {
|
if (p->getState() != Player::Online) {
|
||||||
if (p->getState() == Player::Offline) {
|
if (p->getState() == Player::Offline) {
|
||||||
server->temporarilyBan(p->getId());
|
auto pid = p->getId();
|
||||||
|
addRunRate(pid, mode);
|
||||||
|
addRunRate(pid, mode);
|
||||||
|
server->temporarilyBan(pid);
|
||||||
}
|
}
|
||||||
p->deleteLater();
|
p->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,9 @@ void Shell::helpCommand(QStringList &) {
|
||||||
HELP_MSG("%s: Crash the server. Useful when encounter dead loop.", "crash");
|
HELP_MSG("%s: Crash the server. Useful when encounter dead loop.", "crash");
|
||||||
HELP_MSG("%s: List all online players.", "lsplayer");
|
HELP_MSG("%s: List all online players.", "lsplayer");
|
||||||
HELP_MSG("%s: List all running rooms.", "lsroom");
|
HELP_MSG("%s: List all running rooms.", "lsroom");
|
||||||
HELP_MSG("%s: Reload server config file.", "reloadconf");
|
HELP_MSG("%s: Reload server config file.", "reloadconf/r");
|
||||||
HELP_MSG("%s: Kick a player by his <id>.", "kick");
|
HELP_MSG("%s: Kick a player by his <id>.", "kick");
|
||||||
HELP_MSG("%s: Broadcast message.", "msg");
|
HELP_MSG("%s: Broadcast message.", "msg/m");
|
||||||
HELP_MSG("%s: Ban 1 or more accounts, IP, UUID by their <name>.", "ban");
|
HELP_MSG("%s: Ban 1 or more accounts, IP, UUID by their <name>.", "ban");
|
||||||
HELP_MSG("%s: Unban 1 or more accounts by their <name>.", "unban");
|
HELP_MSG("%s: Unban 1 or more accounts by their <name>.", "unban");
|
||||||
HELP_MSG(
|
HELP_MSG(
|
||||||
|
@ -49,6 +49,7 @@ void Shell::helpCommand(QStringList &) {
|
||||||
"%s: Unban 1 or more UUID. "
|
"%s: Unban 1 or more UUID. "
|
||||||
"At least 1 <name> required.",
|
"At least 1 <name> required.",
|
||||||
"unbanuuid");
|
"unbanuuid");
|
||||||
|
HELP_MSG("%s: reset <name>'s password to 1234.", "resetpassword/rp");
|
||||||
qInfo();
|
qInfo();
|
||||||
qInfo("===== Package commands =====");
|
qInfo("===== Package commands =====");
|
||||||
HELP_MSG("%s: Install a new package from <url>.", "install");
|
HELP_MSG("%s: Install a new package from <url>.", "install");
|
||||||
|
@ -56,7 +57,7 @@ void Shell::helpCommand(QStringList &) {
|
||||||
HELP_MSG("%s: List all packages.", "lspkg");
|
HELP_MSG("%s: List all packages.", "lspkg");
|
||||||
HELP_MSG("%s: Enable a package.", "enable");
|
HELP_MSG("%s: Enable a package.", "enable");
|
||||||
HELP_MSG("%s: Disable a package.", "disable");
|
HELP_MSG("%s: Disable a package.", "disable");
|
||||||
HELP_MSG("%s: Upgrade a package. Leave empty to upgrade all.", "upgrade");
|
HELP_MSG("%s: Upgrade a package. Leave empty to upgrade all.", "upgrade/u");
|
||||||
qInfo("For more commands, check the documentation.");
|
qInfo("For more commands, check the documentation.");
|
||||||
|
|
||||||
#undef HELP_MSG
|
#undef HELP_MSG
|
||||||
|
@ -356,6 +357,21 @@ void Shell::reloadConfCommand(QStringList &) {
|
||||||
qInfo("Reloaded server config file.");
|
qInfo("Reloaded server config file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Shell::resetPasswordCommand(QStringList &list) {
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
qWarning("The 'resetpassword' command needs at least 1 <name>.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto db = ServerInstance->getDatabase();
|
||||||
|
foreach (auto name, list) {
|
||||||
|
// 重置为1234
|
||||||
|
ExecSQL(db, QString("UPDATE userinfo SET password=\
|
||||||
|
'dbdc2ad3d9625407f55674a00b58904242545bfafedac67485ac398508403ade',\
|
||||||
|
salt='00000000' WHERE name='%1';").arg(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Shell::Shell() {
|
Shell::Shell() {
|
||||||
setObjectName("Shell");
|
setObjectName("Shell");
|
||||||
signal(SIGINT, sigintHandler);
|
signal(SIGINT, sigintHandler);
|
||||||
|
@ -369,11 +385,13 @@ Shell::Shell() {
|
||||||
handlers["install"] = &Shell::installCommand;
|
handlers["install"] = &Shell::installCommand;
|
||||||
handlers["remove"] = &Shell::removeCommand;
|
handlers["remove"] = &Shell::removeCommand;
|
||||||
handlers["upgrade"] = &Shell::upgradeCommand;
|
handlers["upgrade"] = &Shell::upgradeCommand;
|
||||||
|
handlers["u"] = &Shell::upgradeCommand;
|
||||||
handlers["lspkg"] = &Shell::lspkgCommand;
|
handlers["lspkg"] = &Shell::lspkgCommand;
|
||||||
handlers["enable"] = &Shell::enableCommand;
|
handlers["enable"] = &Shell::enableCommand;
|
||||||
handlers["disable"] = &Shell::disableCommand;
|
handlers["disable"] = &Shell::disableCommand;
|
||||||
handlers["kick"] = &Shell::kickCommand;
|
handlers["kick"] = &Shell::kickCommand;
|
||||||
handlers["msg"] = &Shell::msgCommand;
|
handlers["msg"] = &Shell::msgCommand;
|
||||||
|
handlers["m"] = &Shell::msgCommand;
|
||||||
handlers["ban"] = &Shell::banCommand;
|
handlers["ban"] = &Shell::banCommand;
|
||||||
handlers["unban"] = &Shell::unbanCommand;
|
handlers["unban"] = &Shell::unbanCommand;
|
||||||
handlers["banip"] = &Shell::banipCommand;
|
handlers["banip"] = &Shell::banipCommand;
|
||||||
|
@ -381,6 +399,9 @@ Shell::Shell() {
|
||||||
handlers["banuuid"] = &Shell::banUuidCommand;
|
handlers["banuuid"] = &Shell::banUuidCommand;
|
||||||
handlers["unbanuuid"] = &Shell::unbanUuidCommand;
|
handlers["unbanuuid"] = &Shell::unbanUuidCommand;
|
||||||
handlers["reloadconf"] = &Shell::reloadConfCommand;
|
handlers["reloadconf"] = &Shell::reloadConfCommand;
|
||||||
|
handlers["r"] = &Shell::reloadConfCommand;
|
||||||
|
handlers["resetpassword"] = &Shell::resetPasswordCommand;
|
||||||
|
handlers["rp"] = &Shell::resetPasswordCommand;
|
||||||
}
|
}
|
||||||
handler_map = handlers;
|
handler_map = handlers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ private:
|
||||||
void unbanipCommand(QStringList &);
|
void unbanipCommand(QStringList &);
|
||||||
void unbanUuidCommand(QStringList &);
|
void unbanUuidCommand(QStringList &);
|
||||||
void reloadConfCommand(QStringList &);
|
void reloadConfCommand(QStringList &);
|
||||||
|
void resetPasswordCommand(QStringList &);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue