Enhancement (#286)

1. 头像界面更换头像和密码增加计时器
2. 武将界面增加设为头像,搜索框文字输入栏微调
3. 整理手牌将不同的pile分开
4. askForCard(s)Chosen自由prompt
5. 开大动画区分主将副将,特化语音
6. 观星框显示卡牌标记
7. 禁止打出修复
8. random_ai禁止技修复
9. 记录器整局游戏修复
10. 禁止亮将修复封杀已亮的将
This commit is contained in:
Nyutanislavsky 2023-11-07 21:14:51 +08:00 committed by GitHub
parent 513fcf36d7
commit 4b1c43f4c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 144 additions and 44 deletions

View File

@ -19,6 +19,11 @@ ColumnLayout {
}
}
Timer {
id: opTimer
interval: 1000
}
RowLayout {
anchors.rightMargin: 8
spacing: 16
@ -34,9 +39,10 @@ ColumnLayout {
}
Button {
text: Backend.translate("Update Avatar")
enabled: avatarName.text !== ""
enabled: avatarName.text !== "" && !opTimer.running
onClicked: {
mainWindow.busy = true;
opTimer.start();
ClientInstance.notifyServer(
"UpdateAvatar",
JSON.stringify([avatarName.text])
@ -74,9 +80,10 @@ ColumnLayout {
}
Button {
text: Backend.translate("Update Password")
enabled: oldPassword.text !== "" && newPassword.text !== ""
enabled: oldPassword.text !== "" && newPassword.text !== "" && !opTimer.running
onClicked: {
mainWindow.busy = true;
opTimer.start();
ClientInstance.notifyServer(
"UpdatePassword",
JSON.stringify([oldPassword.text, newPassword.text])

View File

@ -359,6 +359,8 @@ Item {
id: word
Layout.fillWidth: true
clip: true
leftPadding: 5
rightPadding: 5
}
Button {
@ -408,6 +410,24 @@ Item {
config.disabledGeneralsChanged();
}
}
Timer {
id: opTimer
interval: 4000
}
Button {
text: Backend.translate("Set as Avatar")
enabled: detailGeneralCard.name !== "" && !opTimer.running && Self.avatar !== detailGeneralCard.name
onClicked: {
mainWindow.busy = true;
opTimer.start();
ClientInstance.notifyServer(
"UpdateAvatar",
JSON.stringify([detailGeneralCard.name])
);
}
}
}
function loadPackages() {

View File

@ -298,6 +298,7 @@ function resortHandcards() {
}
dashboard.handcardArea.cards.sort((prev, next) => {
if (prev.footnote === next.footnote) {
if (prev.type === next.type) {
const prevSubtypeNumber = subtypeString2Number[prev.subtype];
const nextSubtypeNumber = subtypeString2Number[next.subtype];
@ -318,6 +319,9 @@ function resortHandcards() {
} else {
return prev.type - next.type;
}
} else {
return prev.footnote > next.footnote ? 1 : -1;
}
});
dashboard.handcardArea.updateCardPosition(true);
@ -1055,13 +1059,18 @@ callbacks["AskForCardChosen"] = (jsonData) => {
// string reason ]
const data = JSON.parse(jsonData);
const reason = data._reason;
const prompt = data._prompt;
if (prompt === "") {
roomScene.promptText = Backend.translate("#AskForChooseCard")
.arg(Backend.translate(reason));
} else {
roomScene.setPrompt(processPrompt(prompt), true);
}
roomScene.state = "replying";
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/PlayerCardBox.qml");
const box = roomScene.popupBox.item;
box.prompt = prompt;
for (let d of data.card_data) {
const arr = [];
const ids = d[1];
@ -1086,15 +1095,21 @@ callbacks["AskForCardsChosen"] = (jsonData) => {
const min = data._min;
const max = data._max;
const reason = data._reason;
const prompt = data._prompt;
if (prompt === "") {
roomScene.promptText = Backend.translate("#AskForChooseCards")
.arg(Backend.translate(reason)).arg(min).arg(max);
} else {
roomScene.setPrompt(processPrompt(prompt), true);
}
roomScene.state = "replying";
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/PlayerCardBox.qml");
const box = roomScene.popupBox.item;
box.multiChoose = true;
box.min = min;
box.max = max;
box.prompt = prompt;
for (let d of data.card_data) {
const arr = [];
const ids = d[1];
@ -1384,7 +1399,7 @@ callbacks["Animate"] = (jsonData) => {
roomScene.bigAnim.source = "../RoomElement/UltSkillAnimation.qml";
roomScene.bigAnim.item.loadData({
skill_name: data.name,
general: photo.general,
general: data.deputy ? photo.deputyGeneral : photo.general,
});
break;
}

View File

@ -100,6 +100,7 @@ GraphicsBox {
name: modelData.name
suit: modelData.suit
number: modelData.number
mark: modelData.mark
draggable: true
onReleased: arrangeCards();
}

View File

@ -6,8 +6,9 @@ import Fk.Pages
GraphicsBox {
id: root
property string prompt
title.text: root.multiChoose ? Backend.translate("$ChooseCards").arg(root.min).arg(root.max) : Backend.translate("$ChooseCard")
title.text: prompt === "" ? (root.multiChoose ? Backend.translate("$ChooseCards").arg(root.min).arg(root.max) : Backend.translate("$ChooseCard")) : processPrompt(prompt)
// TODO: Adjust the UI design in case there are more than 7 cards
width: 70 + 700
@ -102,6 +103,18 @@ GraphicsBox {
onCardSelected: finished();
function processPrompt(prompt) {
const data = prompt.split(":");
let raw = Backend.translate(data[0]);
const src = parseInt(data[1]);
const dest = parseInt(data[2]);
if (raw.match("%src")) raw = raw.replace(/%src/g, Backend.translate(getPhoto(src).general));
if (raw.match("%dest")) raw = raw.replace(/%dest/g, Backend.translate(getPhoto(dest).general));
if (raw.match("%arg2")) raw = raw.replace(/%arg2/g, Backend.translate(data[4]));
if (raw.match("%arg")) raw = raw.replace(/%arg/g, Backend.translate(data[3]));
return raw;
}
function findAreaModel(name) {
let ret;
for (let i = 0; i < cardModel.count; i++) {

View File

@ -27,8 +27,13 @@ Item {
model: 40
Text {
text: {
const o = "$" + skillName + (index % 2 + 1);
const p = Backend.translate(o);
let o = "$" + skillName + "_" + generalName + (index % 2 + 1);
let p = Backend.translate(o);
if (o !== p) {
return p;
}
o = "$" + skillName + (index % 2 + 1);
p = Backend.translate(o);
if (o === p) {
return "Ultimate Skill Invoked!";
}
@ -53,8 +58,13 @@ Item {
model: 40
Text {
text: {
const o = "$" + skillName + ((index + 1) % 2 + 1);
const p = Backend.translate(o);
let o = "$" + skillName + "_" + generalName + ((index + 1) % 2 + 1);
let p = Backend.translate(o);
if (o !== p) {
return p;
}
o = "$" + skillName + ((index + 1) % 2 + 1);
p = Backend.translate(o);
if (o === p) {
return "Ultimate Skill Invoked!";
}

View File

@ -370,7 +370,7 @@ end
fk.client_callback["AskForCardChosen"] = function(jsonData)
-- jsonData: [ int target_id, string flag, int reason ]
local data = json.decode(jsonData)
local id, flag, reason = data[1], data[2], data[3]
local id, flag, reason, prompt = data[1], data[2], data[3], data[4]
local target = ClientInstance:getPlayerById(id)
local hand = target.player_cards[Player.Hand]
local equip = target.player_cards[Player.Equip]
@ -390,12 +390,14 @@ fk.client_callback["AskForCardChosen"] = function(jsonData)
ui_data = {
_reason = reason,
card_data = {},
_prompt = prompt,
}
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
ui_data._prompt = prompt
end
ClientInstance:notifyUI("AskForCardChosen", json.encode(ui_data))
end
@ -403,7 +405,7 @@ end
fk.client_callback["AskForCardsChosen"] = function(jsonData)
-- jsonData: [ int target_id, int min, int max, string flag, int reason ]
local data = json.decode(jsonData)
local id, min, max, flag, reason = data[1], data[2], data[3], data[4], data[5]
local id, min, max, flag, reason, prompt = data[1], data[2], data[3], data[4], data[5], data[6]
local target = ClientInstance:getPlayerById(id)
local hand = target.player_cards[Player.Hand]
local equip = target.player_cards[Player.Equip]
@ -424,7 +426,8 @@ fk.client_callback["AskForCardsChosen"] = function(jsonData)
_min = min,
_max = max,
_reason = reason,
card_data = {}
card_data = {},
_prompt = prompt,
}
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
@ -433,6 +436,7 @@ fk.client_callback["AskForCardsChosen"] = function(jsonData)
ui_data._min = min
ui_data._max = max
ui_data._reason = reason
ui_data._prompt = prompt
end
ClientInstance:notifyUI("AskForCardsChosen", json.encode(ui_data))
end

View File

@ -546,7 +546,7 @@ function CardProhibitedResponse(card)
if c == nil then
return "true"
else
ret = Self:prohibitUse(c)
ret = Self:prohibitResponse(c)
end
return json.encode(ret)
end

View File

@ -25,6 +25,7 @@ Fk:loadTranslationTable{
["Disable message audio"] = "禁用聊天语音",
["Hide unselectable cards"] = "下移不可选卡牌",
["Ban General Settings"] = "禁将",
["Set as Avatar"] = "设为头像",
["Search"] = "搜索",
["Back"] = "返回",

View File

@ -15,7 +15,7 @@ local function useActiveSkill(self, skill, card)
filter_func = function() return false end
end
if self.command == "PlayCard" and (not skill:canUse(player, card) or player:prohibitUse(card)) then
if self.command == "PlayCard" and card and (not player:canUse(card) or player:prohibitUse(card)) then
return ""
end
@ -31,7 +31,7 @@ local function useActiveSkill(self, skill, card)
local avail_targets = table.filter(self.room:getAlivePlayers(), function(p)
local ret = skill:targetFilter(p.id, selected_targets, selected_cards, card or Fk:cloneCard'zixing')
if ret and card then
if player:prohibitUse(card) then
if player:isProhibited(p, card) then
ret = false
end
end
@ -135,8 +135,7 @@ random_cb["AskForUseCard"] = function(self, jsonData)
local cancelable = data[4] or true
local exp = Exppattern:Parse(pattern)
local avail_cards = table.map(player:getCardIds("he"),
function(id) return Fk:getCardById(id) end)
local avail_cards = table.map(player:getCardIds("he"), Util.Id2CardMapper)
avail_cards = table.filter(avail_cards, function(c)
return exp:match(c) and not player:prohibitUse(c)
end)
@ -187,8 +186,7 @@ random_cb["AskForResponseCard"] = function(self, jsonData)
end
random_cb["PlayCard"] = function(self, jsonData)
local cards = table.map(self.player:getCardIds(Player.Hand),
function(id) return Fk:getCardById(id) end)
local cards = table.map(self.player:getCardIds(Player.Hand), Util.Id2CardMapper)
local actives = table.filter(self.player:getAllSkills(), function(s)
return s:isInstanceOf(ActiveSkill)
end)

View File

@ -143,7 +143,7 @@ function GameEvent:searchEvents(eventType, n, func, endEvent)
local events = logic.event_recorder[eventType] or Util.DummyTable
local from = self.id
local to = endEvent and endEvent.id or self.end_id
if to == -1 then to = #logic.all_game_events end
if math.abs(to) == 1 then to = #logic.all_game_events end
n = n or 1
func = func or Util.TrueFunc

View File

@ -1020,6 +1020,7 @@ function Room:notifySkillInvoked(player, skill_name, skill_type)
self:doAnimate("InvokeUltSkill", {
name = skill_name,
player = player.id,
deputy = player.deputyGeneral and player.deputyGeneral ~= "" and table.contains(Fk.generals[player.deputyGeneral]:getSkillNameList(), skill_name),
})
self:delay(2000)
end
@ -1520,11 +1521,13 @@ end
---@param target ServerPlayer @ 被选牌的人
---@param flag any @ 用"hej"三个字母的组合表示能选择哪些区域, h 手牌区, e - 装备区, j - 判定区
---@param reason string @ 原因,一般是技能名
---@param prompt string|nil @ 提示信息
---@return integer @ 选择的卡牌id
function Room:askForCardChosen(chooser, target, flag, reason)
function Room:askForCardChosen(chooser, target, flag, reason, prompt)
local command = "AskForCardChosen"
prompt = prompt or ""
self:notifyMoveFocus(chooser, command)
local data = {target.id, flag, reason}
local data = {target.id, flag, reason, prompt}
local result = self:doRequest(chooser, command, json.encode(data))
if result == "" then
@ -1564,15 +1567,17 @@ end
---@param max integer @ 最大选牌数
---@param flag any @ 用"hej"三个字母的组合表示能选择哪些区域, h 手牌区, e - 装备区, j - 判定区
---@param reason string @ 原因,一般是技能名
---@param prompt string|nil @ 提示信息
---@return integer[] @ 选择的id
function Room:askForCardsChosen(chooser, target, min, max, flag, reason)
function Room:askForCardsChosen(chooser, target, min, max, flag, reason, prompt)
if min == 1 and max == 1 then
return { self:askForCardChosen(chooser, target, flag, reason) }
end
local command = "AskForCardsChosen"
prompt = prompt or ""
self:notifyMoveFocus(chooser, command)
local data = {target.id, min, max, flag, reason}
local data = {target.id, min, max, flag, reason, prompt}
local result = self:doRequest(chooser, command, json.encode(data))
local ret

View File

@ -920,7 +920,28 @@ function ServerPlayer:revealGeneral(isDeputy, no_trigger)
}
if not no_trigger then
room.logic:trigger(fk.GeneralRevealed, self, generalName)
local current_event = room.logic:getCurrentEvent()
if table.contains({GameEvent.Round, GameEvent.Turn, GameEvent.Phase}, current_event.event) then
room.logic:trigger(fk.GeneralRevealed, self, {[isDeputy and "d" or "m"] = generalName})
else
current_event:addExitFunc(function ()
room.logic:trigger(fk.GeneralRevealed, self, {[isDeputy and "d" or "m"] = generalName})
end)
end
end
end
function ServerPlayer:revealGenerals()
self:revealGeneral(false, true)
self:revealGeneral(true, true)
local room = self.room
local current_event = room.logic:getCurrentEvent()
if table.contains({GameEvent.Round, GameEvent.Turn, GameEvent.Phase}, current_event.event) then
room.logic:trigger(fk.GeneralRevealed, self, {["m"] = self:getMark("__heg_general"), ["d"] = self:getMark("__heg_deputy")})
else
current_event:addExitFunc(function ()
room.logic:trigger(fk.GeneralRevealed, self, {["m"] = self:getMark("__heg_general"), ["d"] = self:getMark("__heg_deputy")})
end)
end
end

View File

@ -184,8 +184,13 @@ local revealProhibited = fk.CreateInvaliditySkill {
if type(from._fake_skills) == "table" and not table.contains(from._fake_skills, skill) then return false end
local sname = skill.name
for _, g in ipairs(generals) do
local ret = g == "m" and from:getMark("__heg_general") or from:getMark("__heg_deputy")
local general = Fk.generals[ret]
if g == "m" then
if from.general ~= "anjiang" then return false end
else
if from.deputyGeneral ~= "anjiang" then return false end
end
local generalName = g == "m" and from:getMark("__heg_general") or from:getMark("__heg_deputy")
local general = Fk.generals[generalName]
if table.contains(general:getSkillNameList(), sname) then
return true
end