禁将功能改进 (#309)

RT 不影响Lua API
This commit is contained in:
notify 2024-01-26 14:02:55 +08:00 committed by GitHub
parent be03b04ef0
commit 3031131e1b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 707 additions and 347 deletions

View File

@ -15,7 +15,7 @@ QtObject {
property string roomBg property string roomBg
property string bgmFile property string bgmFile
property string language property string language
property list<string> disabledPack: [] // property list<string> disabledPack: []
property string preferedMode property string preferedMode
property int preferedPlayerNum property int preferedPlayerNum
property int preferredGeneralNum property int preferredGeneralNum
@ -23,9 +23,12 @@ QtObject {
property real bgmVolume property real bgmVolume
property bool disableMsgAudio property bool disableMsgAudio
property bool hideUseless property bool hideUseless
property list<string> disabledGenerals: [] // property list<string> disabledGenerals: []
property list<var> disableGeneralSchemes: [] // property list<var> disableGeneralSchemes: []
property int disableSchemeIdx: 0 // property int disableSchemeIdx: 0
property list<var> disableSchemes: []
property int currentDisableIdx: 0
property var curScheme
property int preferredTimeout property int preferredTimeout
property int preferredLuckTime property int preferredLuckTime
@ -52,9 +55,9 @@ QtObject {
property list<string> blockedUsers: [] property list<string> blockedUsers: []
property int totalTime: 0 // FIXME: only for notifying property int totalTime: 0 // FIXME: only for notifying
onDisabledGeneralsChanged: { // onDisabledGeneralsChanged: {
disableGeneralSchemes[disableSchemeIdx] = disabledGenerals; // disableGeneralSchemes[disableSchemeIdx] = disabledGenerals;
} // }
function loadConf() { function loadConf() {
conf = JSON.parse(Backend.loadConf()); conf = JSON.parse(Backend.loadConf());
@ -75,7 +78,7 @@ QtObject {
return 'en_US'; return 'en_US';
} }
})(); })();
disabledPack = conf.disabledPack ?? [ "test_p_0" ]; // disabledPack = conf.disabledPack ?? [ "test_p_0" ];
preferedMode = conf.preferedMode ?? "aaa_role_mode"; preferedMode = conf.preferedMode ?? "aaa_role_mode";
preferedPlayerNum = conf.preferedPlayerNum ?? 2; preferedPlayerNum = conf.preferedPlayerNum ?? 2;
preferredGeneralNum = conf.preferredGeneralNum ?? 3; preferredGeneralNum = conf.preferredGeneralNum ?? 3;
@ -87,9 +90,17 @@ QtObject {
preferredTimeout = conf.preferredTimeout ?? 15; preferredTimeout = conf.preferredTimeout ?? 15;
preferredLuckTime = conf.preferredLuckTime ?? 0; preferredLuckTime = conf.preferredLuckTime ?? 0;
firstRun = conf.firstRun ?? true; firstRun = conf.firstRun ?? true;
disabledGenerals = conf.disabledGenerals ?? []; // disabledGenerals = conf.disabledGenerals ?? [];
disableGeneralSchemes = conf.disableGeneralSchemes ?? [ disabledGenerals ]; // disableGeneralSchemes = conf.disableGeneralSchemes ?? [ disabledGenerals ];
disableSchemeIdx = conf.disableSchemeIdx ?? 0; // disableSchemeIdx = conf.disableSchemeIdx ?? 0;
disableSchemes = conf.disableSchemes ?? [{
name: "",
banPkg: {}, // :
normalPkg: {}, // :
banCardPkg: [], //
}];
currentDisableIdx = conf.currentDisableIdx ?? 0;
curScheme = disableSchemes[currentDisableIdx];
blockedUsers = conf.blockedUsers ?? []; blockedUsers = conf.blockedUsers ?? [];
} }
@ -104,7 +115,7 @@ QtObject {
conf.roomBg = roomBg; conf.roomBg = roomBg;
conf.bgmFile = bgmFile; conf.bgmFile = bgmFile;
conf.language = language; conf.language = language;
conf.disabledPack = disabledPack; // conf.disabledPack = disabledPack;
conf.preferedMode = preferedMode; conf.preferedMode = preferedMode;
conf.preferedPlayerNum = preferedPlayerNum; conf.preferedPlayerNum = preferedPlayerNum;
conf.ladyImg = ladyImg; conf.ladyImg = ladyImg;
@ -116,9 +127,12 @@ QtObject {
conf.preferredTimeout = preferredTimeout; conf.preferredTimeout = preferredTimeout;
conf.preferredLuckTime = preferredLuckTime; conf.preferredLuckTime = preferredLuckTime;
conf.firstRun = firstRun; conf.firstRun = firstRun;
conf.disabledGenerals = disabledGenerals; // conf.disabledGenerals = disabledGenerals;
conf.disableGeneralSchemes = disableGeneralSchemes; // conf.disableGeneralSchemes = disableGeneralSchemes;
conf.disableSchemeIdx = disableSchemeIdx; // conf.disableSchemeIdx = disableSchemeIdx;
disableSchemes[currentDisableIdx] = curScheme;
conf.disableSchemes = disableSchemes;
conf.currentDisableIdx = currentDisableIdx;
conf.blockedUsers = blockedUsers; conf.blockedUsers = blockedUsers;
Backend.saveConf(JSON.stringify(conf, undefined, 2)); Backend.saveConf(JSON.stringify(conf, undefined, 2));

View File

@ -11,6 +11,7 @@ Item {
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
RowLayout { RowLayout {
Layout.fillWidth: true
anchors.rightMargin: 8 anchors.rightMargin: 8
spacing: 16 spacing: 16
Text { Text {
@ -19,65 +20,94 @@ Item {
ComboBox { ComboBox {
id: banCombo id: banCombo
textRole: "name" textRole: "name"
Layout.fillWidth: true
model: ListModel { model: ListModel {
id: banComboList id: banComboList
} }
onCurrentIndexChanged: { onCurrentIndexChanged: {
config.disableSchemeIdx = currentIndex; word.text = "";
config.disabledGenerals = config.disableGeneralSchemes[currentIndex]; config.disableSchemes[config.currentDisableIdx] = config.curScheme;
config.currentDisableIdx = currentIndex;
config.curScheme = config.disableSchemes[currentIndex];
} }
} }
Button { GridLayout {
text: luatr("New") columns: 2
onClicked: {
const i = config.disableGeneralSchemes.length;
banComboList.append({
name: luatr("List") + (i + 1),
});
config.disableGeneralSchemes.push([]);
}
}
Button { Button {
text: luatr("Clear") text: luatr("New")
onClicked: { onClicked: {
config.disabledGenerals = []; const i = config.disableSchemes.length;
} banComboList.append({
} name: luatr("List") + (i + 1),
});
Button { config.disableSchemes.push({
text: luatr("Export") name: "",
onClicked: { banPkg: {},
Backend.copyToClipboard(JSON.stringify(config.disabledGenerals)); normalPkg: {},
toast.show(luatr("Export Success")); banCardPkg: [],
} });
}
Button {
text: luatr("Import")
onClicked: {
const str = Backend.readClipboard();
let data;
try {
data = JSON.parse(str);
} catch (e) {
toast.show(luatr("Not Legal"));
return;
} }
if (!data instanceof Array) { }
toast.show(luatr("Not JSON"));
return; Button {
text: luatr("Clear")
onClicked: {
config.curScheme.banPkg = {};
config.curScheme.normalPkg = {};
config.curScheme.banCardPkg = [];
config.curSchemeChanged();
} }
let d = []; }
for (let e of data) {
if (typeof e === "string" && luatr(e) !== e) { Button {
d.push(e); text: luatr("Export")
onClicked: {
Backend.copyToClipboard(JSON.stringify(config.curScheme));
toast.show(luatr("Export Success"));
}
}
Button {
text: luatr("Import")
onClicked: {
const str = Backend.readClipboard();
let data;
try {
data = JSON.parse(str);
} catch (e) {
toast.show(luatr("Not Legal"));
return;
}
if (!data instanceof Object || !data.banPkg || !data.normalPkg
|| !data.banCardPkg) {
toast.show(luatr("Not JSON"));
return;
}
config.curScheme = data;
if (data.name) {
banComboList.get(banCombo.currentIndex).name = data.name;
} }
} }
config.disabledGenerals = d; }
toast.show(luatr("Import Success")); }
TextField {
id: word
clip: true
leftPadding: 5
rightPadding: 5
}
Button {
text: luatr("Rename")
enabled: word.text !== ""
onClicked: {
banComboList.get(banCombo.currentIndex).name = word.text;
config.curScheme.name = word.text;
word.text = "";
} }
} }
} }
@ -89,35 +119,119 @@ Item {
text: luatr("Help_Ban_List") text: luatr("Help_Ban_List")
} }
GridView { GridLayout {
id: listView id: grid
flow: GridLayout.TopToBottom
rows: 2
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
clip: true
cellWidth: width / 4 Text {
cellHeight: 24 wrapMode: Text.WrapAnywhere
model: config.disabledGenerals text: luatr("Ban_Generals")
delegate: Text { font.pixelSize: 18
width: listView.width font.bold: true
text: {
const prefix = modelData.split("__")[0];
let name = luatr(modelData);
if (prefix !== modelData) {
name += (" (" + luatr(prefix) + ")");
}
return name;
}
font.pixelSize: 16
} }
GridView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
cellWidth: width / 2
cellHeight: 24
model: {
let ret = [], k;
const s = config.curScheme;
for (k in s.normalPkg) {
ret.push(...s.normalPkg[k]);
}
return ret;
}
delegate: Text {
//width: banChara.width
text: {
const prefix = modelData.split("__")[0];
let name = luatr(modelData);
if (prefix !== modelData) {
name += (" (" + luatr(prefix) + ")");
}
return name;
}
font.pixelSize: 16
}
}
Text {
wrapMode: Text.WrapAnywhere
text: luatr("Ban_Packages")
font.pixelSize: 18
font.bold: true
}
GridView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
cellWidth: width / 2
cellHeight: 24
model: {
let ret = [], k;
const s = config.curScheme;
for (k in s.banPkg) {
ret.push(k);
}
ret.push(...s.banCardPkg)
return ret;
}
delegate: Text {
text: luatr(modelData)
font.pixelSize: 16
}
}
Text {
wrapMode: Text.WrapAnywhere
text: luatr("Whitelist_Generals")
font.pixelSize: 18
font.bold: true
}
GridView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
cellWidth: width / 2
cellHeight: 24
model: {
let ret = [], k;
const s = config.curScheme;
for (k in s.banPkg) {
ret.push(...s.banPkg[k]);
}
return ret;
}
delegate: Text {
text: {
const prefix = modelData.split("__")[0];
let name = luatr(modelData);
if (prefix !== modelData) {
name += (" (" + luatr(prefix) + ")");
}
return name;
}
font.pixelSize: 16
}
}
} }
} }
Component.onCompleted: { Component.onCompleted: {
for (let i = 0; i < config.disableGeneralSchemes.length; i++) { for (let i = 0; i < config.disableSchemes.length; i++) {
banComboList.append({ banComboList.append({
name: luatr("List") + (i + 1), name: config.disableSchemes[i]?.name || (luatr("List") + (i + 1)),
}); });
} }
banCombo.currentIndex = config.disableSchemeIdx; banCombo.currentIndex = config.currentDisableIdx;
} }
} }

View File

@ -113,7 +113,6 @@ Flickable {
id: warning id: warning
anchors.rightMargin: 8 anchors.rightMargin: 8
visible: { visible: {
//config.disabledPack; // visible
const avail = lcall("GetAvailableGeneralsNum"); const avail = lcall("GetAvailableGeneralsNum");
const ret = avail < const ret = avail <
config.preferredGeneralNum * config.preferedPlayerNum; config.preferredGeneralNum * config.preferedPlayerNum;
@ -164,36 +163,32 @@ Flickable {
config.saveConf(); config.saveConf();
root.finished(); root.finished();
mainWindow.busy = true; mainWindow.busy = true;
let k, arr;
let disabledGenerals = config.disabledGenerals.slice(); let disabledGenerals = [];
if (disabledGenerals.length) { for (k in config.curScheme.banPkg) {
const availablePack = lcall("GetAllGeneralPack"). arr = config.curScheme.banPkg[k];
filter((pack) => !config.disabledPack.includes(pack)); if (arr.length !== 0) {
disabledGenerals = disabledGenerals.filter((general) => { const generals = lcall("GetGenerals", k);
return availablePack.find(pack => disabledGenerals.push(...generals.filter(g => !arr.includes(g)));
lcall("GetGenerals", pack).includes(general)); }
}); }
for (k in config.curScheme.normalPkg) {
disabledGenerals = Array.from(new Set(disabledGenerals)); arr = config.curScheme.normalPkg[k] ?? [];
if (arr.length !== 0)
disabledGenerals.push(...arr);
} }
let disabledPack = config.disabledPack.slice(); let disabledPack = config.curScheme.banCardPkg.slice();
for (k in config.curScheme.banPkg) {
if (config.curScheme.banPkg[k].length === 0)
disabledPack.push(k);
}
config.serverHiddenPacks.forEach(p => { config.serverHiddenPacks.forEach(p => {
if (!disabledPack.includes(p)) { if (!disabledPack.includes(p)) {
disabledPack.push(p); disabledPack.push(p);
} }
}); });
const generalPacks = lcall("GetAllGeneralPack");
for (let pk of generalPacks) {
if (disabledPack.includes(pk)) continue;
let generals = lcall("GetGenerals", pk);
let t = generals.filter(g => !disabledGenerals.includes(g));
if (t.length === 0) {
disabledPack.push(pk);
disabledGenerals = disabledGenerals
.filter(g1 => !generals.includes(g1));
}
}
ClientInstance.notifyServer( ClientInstance.notifyServer(
"CreateRoom", "CreateRoom",
@ -232,8 +227,12 @@ Flickable {
playerNum.value = config.preferedPlayerNum; playerNum.value = config.preferedPlayerNum;
config.disabledPack.forEach(p => lcall("UpdatePackageEnable", p, false)); for (let k in config.curScheme.banPkg) {
config.disabledPackChanged(); lcall("UpdatePackageEnable", k, false);
}
config.curScheme.banCardPkg.forEach(p =>
lcall("UpdatePackageEnable", p, false));
config.curSchemeChanged();
} }
} }
} }

View File

@ -113,7 +113,15 @@ Flickable {
checked: pkg_enabled checked: pkg_enabled
onCheckedChanged: { onCheckedChanged: {
checkPackage(orig_name, checked); const packs = config.curScheme.banCardPkg;
if (checked) {
const idx = packs.indexOf(orig_name);
if (idx !== -1) packs.splice(idx, 1);
} else {
packs.push(orig_name);
}
lcall("UpdatePackageEnable", orig_name, checked);
config.curSchemeChanged();
} }
} }
} }
@ -121,15 +129,16 @@ Flickable {
} }
function checkPackage(orig_name, checked) { function checkPackage(orig_name, checked) {
const packs = config.disabledPack; const s = config.curScheme;
if (checked) { if (!checked) {
const idx = packs.indexOf(orig_name); s.banPkg[orig_name] = [];
if (idx !== -1) packs.splice(idx, 1); s.normalPkg[orig_name] = undefined;
} else { } else {
packs.push(orig_name); s.normalPkg[orig_name] = undefined;
s.banPkg[orig_name] = undefined;
} }
lcall("UpdatePackageEnable", orig_name, checked); lcall("UpdatePackageEnable", orig_name, checked);
config.disabledPackChanged(); config.curSchemeChanged();
} }
Component.onCompleted: { Component.onCompleted: {
@ -143,7 +152,7 @@ Flickable {
gpacklist.append({ gpacklist.append({
name: luatr(orig), name: luatr(orig),
orig_name: orig, orig_name: orig,
pkg_enabled: !config.disabledPack.includes(orig), pkg_enabled: !config.curScheme.banPkg[orig],
}); });
} }
@ -155,7 +164,7 @@ Flickable {
cpacklist.append({ cpacklist.append({
name: luatr(orig), name: luatr(orig),
orig_name: orig, orig_name: orig,
pkg_enabled: !config.disabledPack.includes(orig), pkg_enabled: !config.curScheme.banCardPkg.includes(orig),
}); });
} }
loading = false; loading = false;

View File

@ -11,39 +11,97 @@ Item {
id: root id: root
property bool loaded: false property bool loaded: false
property int stat: 0 // 0=normal 1=banPkg 2=banChara
Rectangle { Rectangle {
anchors.fill: listView id: listBg
color: "#88EEEEEE" width: 260; height: parent.height
color: "snow"
radius: 6 radius: 6
} }
ListView { ListView {
id: listView id: modList
width: 130; height: parent.height
anchors.top: listBg.top; anchors.left: listBg.left
clip: true clip: true
width: 130
height: parent.height - 20
y: 10
ScrollBar.vertical: ScrollBar {}
model: ListModel { model: ListModel {
id: packages id: mods
} }
highlight: Rectangle { color: "#E91E63"; radius: 5 } Rectangle {
anchors.fill: parent
color: "#A48959"
z: -1
}
highlight: Rectangle { color: "snow" }
highlightMoveDuration: 500 highlightMoveDuration: 500
delegate: Item { delegate: Item {
width: listView.width width: modList.width
height: 40 height: 40
Text { Text {
text: luatr(name) text: luatr(name)
color: modList.currentIndex === index ? "black" : "white"
anchors.centerIn: parent anchors.centerIn: parent
} }
TapHandler { TapHandler {
onTapped: { onTapped: {
listView.currentIndex = index; modList.currentIndex = index;
}
}
}
}
ListView {
id: pkgList
width: 130; height: parent.height
anchors.top: listBg.top; anchors.left: modList.right
clip: true
model: JSON.parse(mods.get(modList.currentIndex)?.pkgs ?? "[]")
highlight: Rectangle { color: "#FFCC3F"; radius: 5; scale: 0.8 }
highlightMoveDuration: 500
delegate: Item {
width: pkgList.width
height: 40
Text {
text: luatr(modelData)
color: !config.curScheme.banPkg[modelData] ? "black" : "grey"
Behavior on color { ColorAnimation { duration: 200 } }
anchors.centerIn: parent
}
Image {
source: AppPath + "/image/button/skill/locked.png"
opacity: !config.curScheme.banPkg[modelData] ? 0 : 1
Behavior on opacity { NumberAnimation { duration: 200 } }
anchors.centerIn: parent
scale: 0.8
}
TapHandler {
onTapped: {
if (stat === 1) {
const name = modelData;
let s = config.curScheme;
if (s.banPkg[name]) {
s.banPkg[name] = undefined;
s.normalPkg[name] = undefined;
} else {
s.normalPkg[name] = undefined;
s.banPkg[name] = [];
}
config.curSchemeChanged();
} else {
pkgList.currentIndex = index;
}
} }
} }
} }
@ -51,13 +109,102 @@ Item {
onCurrentIndexChanged: { vanishAnim.start(); } onCurrentIndexChanged: { vanishAnim.start(); }
} }
ToolBar {
id: bar
width: root.width - listBg.width - 16
anchors.left: listBg.right
anchors.leftMargin: 8
y: 8
background: Rectangle {
color: stat === 0 ? "#5cb3cc" : "#869d9d"
Behavior on color { ColorAnimation { duration: 200 } }
}
RowLayout {
anchors.fill: parent
Item { Layout.preferredWidth: 20 }
Label {
text: {
switch (stat) {
case 0: return luatr("Generals Overview");
case 1: return luatr("$BanPkgHelp");
case 2: return luatr("$BanCharaHelp");
}
}
elide: Label.ElideLeft
verticalAlignment: Qt.AlignVCenter
font.pixelSize: 24
}
Item { Layout.fillWidth: true }
TextField {
id: word
clip: true
leftPadding: 5
rightPadding: 5
}
ToolButton {
text: luatr("Search")
enabled: word.text !== ""
onClicked: {
pkgList.currentIndex = 0;
vanishAnim.start();
}
}
ToolButton {
id: banButton
text: {
if (stat === 2) return luatr("OK");
return luatr("BanGeneral");
}
enabled: stat !== 1
onClicked: {
if (stat === 0) {
stat = 2;
} else {
stat = 0;
}
}
}
ToolButton {
id: banPkgButton
text: {
if (stat === 1) return luatr("OK");
return luatr("BanPackage");
}
enabled: stat !== 2
onClicked: {
if (stat === 0) {
stat = 1;
} else {
stat = 0;
}
}
}
ToolButton {
text: luatr("Quit")
onClicked: {
mainStack.pop();
config.saveConf();
}
}
}
}
GridView { GridView {
id: gridView id: gridView
clip: true clip: true
width: root.width - listView.width - generalDetail.width - 16 width: root.width - listBg.width - 16
height: parent.height - 20 height: parent.height - bar.height - 24
y: 10 y: 16 + bar.height
anchors.left: listView.right anchors.left: listBg.right
anchors.leftMargin: 8 + (width % 100) / 2 anchors.leftMargin: 8 + (width % 100) / 2
cellHeight: 140 cellHeight: 140
cellWidth: 100 cellWidth: 100
@ -66,24 +213,77 @@ Item {
autoBack: false autoBack: false
name: modelData name: modelData
onClicked: { onClicked: {
generalText.clear(); if (stat === 2) {
generalDetail.general = modelData; const s = config.curScheme;
generalDetail.updateGeneral(); const gdata = lcall("GetGeneralData", modelData);
// generalDetail.open(); const pack = gdata.package;
let arr;
if (s.banPkg[pack]) {
arr = s.banPkg[pack];
} else {
if (!s.normalPkg[pack]) {
s.normalPkg[pack] = [];
}
arr = s.normalPkg[pack];
}
// TODO: /
const idx = arr.indexOf(modelData);
if (idx !== -1) {
arr.splice(idx, 1);
} else {
arr.push(modelData);
}
config.curSchemeChanged();
} else {
generalText.clear();
generalDetail.general = modelData;
generalDetail.updateGeneral();
generalDetail.open();
}
} }
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: "black" color: "black"
opacity: config.disabledGenerals.includes(modelData) ? 0.7 : 0 opacity: {
const s = config.curScheme;
const gdata = lcall("GetGeneralData", modelData);
const pack = gdata.package;
if (s.banPkg[pack]) {
if (!s.banPkg[pack].includes(modelData)) return 0.7;
} else {
if (!!s.normalPkg[pack]?.includes(modelData)) return 0.7;
}
return 0;
}
Behavior on opacity { Behavior on opacity {
NumberAnimation {} NumberAnimation {}
} }
} }
GlowText { GlowText {
visible: config.disabledGenerals.includes(modelData) id: banText
text: '禁' visible: {
const s = config.curScheme;
const gdata = lcall("GetGeneralData", modelData);
const pack = gdata.package;
if (s.banPkg[pack]) {
return s.banPkg[pack].includes(modelData);
} else {
return !!s.normalPkg[pack]?.includes(modelData);
}
}
text: {
if (!visible) return '';
const s = config.curScheme;
const gdata = lcall("GetGeneralData", modelData);
const pack = gdata.package;
if (s.banPkg[pack]) {
if (s.banPkg[pack].includes(modelData)) return '启用';
} else {
if (!!s.normalPkg[pack]?.includes(modelData)) return '禁';
}
}
anchors.centerIn: parent anchors.centerIn: parent
font.family: fontLi2.name font.family: fontLi2.name
color: "#E4D5A0" color: "#E4D5A0"
@ -108,7 +308,7 @@ Item {
PropertyAnimation { PropertyAnimation {
target: gridView target: gridView
property: "y" property: "y"
to: 30 to: 36 + bar.height
duration: 150 duration: 150
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
@ -117,7 +317,7 @@ Item {
gridView.model = lcall("SearchAllGenerals", word.text); gridView.model = lcall("SearchAllGenerals", word.text);
} else { } else {
gridView.model = lcall("SearchGenerals", gridView.model = lcall("SearchGenerals",
listView.model.get(listView.currentIndex).name, word.text); pkgList.model[pkgList.currentIndex], word.text);
} }
word.text = ""; word.text = "";
appearAnim.start(); appearAnim.start();
@ -138,23 +338,78 @@ Item {
PropertyAnimation { PropertyAnimation {
target: gridView target: gridView
property: "y" property: "y"
from: 20 from: 36 + bar.height
to: 10 to: 16 + bar.height
duration: 150 duration: 150
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }
} }
} }
Rectangle { Component {
id: skillAudioBtn
Button {
Layout.fillWidth: true
contentItem: ColumnLayout {
Text {
Layout.fillWidth: true
text: {
if (name.endsWith("_win_audio")) {
return "胜利语音";
}
return luatr(name) + (idx ? " (" + idx.toString() + ")"
: "");
}
font.bold: true
font.pixelSize: 14
}
Text {
Layout.fillWidth: true
text: {
const orig = '$' + name + (idx ? idx.toString() : "");
const orig_trans = luatr(orig);
// try general specific
const orig_g = '$' + name + '_' + detailGeneralCard.name
+ (idx ? idx.toString() : "");
const orig_g_trans = luatr(orig_g);
if (orig_g_trans !== orig_g) {
return orig_g_trans;
}
if (orig_trans !== orig) {
return orig_trans;
}
return "";
}
wrapMode: Text.WordWrap
}
}
onClicked: {
callbacks["LogEvent"](JSON.stringify({
type: "PlaySkillSound",
name: name,
general: detailGeneralCard.name,
i: idx,
}));
}
}
}
Popup {
id: generalDetail id: generalDetail
width: 310 width: realMainWin.width * 0.6
height: parent.height - searcher.height - 20 height: realMainWin.height * 0.8
y: 10 anchors.centerIn: parent
anchors.right: parent.right background: Rectangle {
anchors.rightMargin: 10 color: "#EEEEEEEE"
color: "#88EEEEEE" radius: 5
radius: 8 border.color: "#A6967A"
border.width: 1
}
property string general: "caocao" property string general: "caocao"
@ -196,7 +451,7 @@ Item {
function findDeathAudio(general) { function findDeathAudio(general) {
const extension = lcall("GetGeneralData", general).extension; const extension = lcall("GetGeneralData", general).extension;
const fname = AppPath + "/packages/" + extension + "/audio/death/" const fname = AppPath + "/packages/" + extension + "/audio/death/"
+ general + ".mp3"; + general + ".mp3";
if (Backend.exists(fname)) { if (Backend.exists(fname)) {
audioDeath.visible = true; audioDeath.visible = true;
} else { } else {
@ -212,7 +467,7 @@ Item {
if (data.companions.length > 0){ if (data.companions.length > 0){
let ret = "<font color=\"slategrey\"><b>" + luatr("Companions") let ret = "<font color=\"slategrey\"><b>" + luatr("Companions")
+ "</b>: "; + "</b>: ";
data.companions.forEach(t => { data.companions.forEach(t => {
ret += luatr(t) + ' ' ret += luatr(t) + ' '
}); });
@ -236,223 +491,153 @@ Item {
addSkillAudio(general + "_win_audio"); addSkillAudio(general + "_win_audio");
} }
Flickable { Item {
flickableDirection: Flickable.VerticalFlick
contentHeight: detailLayout.height
width: parent.width - 40
height: parent.height - 40
clip: true
anchors.centerIn: parent anchors.centerIn: parent
ScrollBar.vertical: ScrollBar {} width: parent.width / mainWindow.scale
height: parent.height / mainWindow.scale
scale: mainWindow.scale
ColumnLayout { Item {
id: detailLayout id: generalInfo
width: parent.width width: 150
ColumnLayout {
GeneralCardItem { width: parent.width
id: detailGeneralCard GeneralCardItem {
Layout.alignment: Qt.AlignHCenter id: detailGeneralCard
name: "caocao" name: "caocao"
} scale: 1.5; transformOrigin: Item.TopLeft
TextEdit {
id: generalText
Layout.fillWidth: true
readOnly: true
selectByKeyboard: true
selectByMouse: false
wrapMode: TextEdit.WordWrap
textFormat: TextEdit.RichText
font.pixelSize: 16
}
Repeater {
model: ListModel {
id: audioModel
} }
Item { Layout.preferredHeight: 130 * 0.5 }
Text {
Layout.fillWidth: true
textFormat: TextEdit.RichText
font.pixelSize: 16
function trans(str) {
const ret = luatr(str);
if (ret === str) {
return "官方";
}
return ret;
}
text: {
const general = generalDetail.general;
return [
luatr(lcall("GetGeneralData", general).package),
"称号:" + trans("#" + general),
"设计:" + trans("designer:" + general),
"配音:" + trans("cv:" + general),
"画师:" + trans("illustrator:" + general),
].join("<br>");
}
}
Timer {
id: opTimer
interval: 4000
}
Button { Button {
text: luatr("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])
);
}
}
}
}
Flickable {
flickableDirection: Flickable.VerticalFlick
contentHeight: detailLayout.height
width: parent.width - 40 - generalInfo.width
height: parent.height - 40
clip: true
anchors.left: generalInfo.right
anchors.leftMargin: 20
y: 20
ColumnLayout {
id: detailLayout
width: parent.width
TextEdit {
id: generalText
Layout.fillWidth: true
readOnly: true
selectByKeyboard: true
selectByMouse: false
wrapMode: TextEdit.WordWrap
textFormat: TextEdit.RichText
font.pixelSize: 18
}
GridLayout {
Layout.fillWidth: true
columns: 2
Repeater {
model: ListModel {
id: audioModel
}
delegate: skillAudioBtn
}
}
Button {
id: audioDeath
Layout.fillWidth: true Layout.fillWidth: true
contentItem: ColumnLayout { contentItem: ColumnLayout {
Text { Text {
Layout.fillWidth: true Layout.fillWidth: true
text: { text: luatr("Death audio")
if (name.endsWith("_win_audio")) {
return "胜利语音";
}
return luatr(name) + (idx ? " (" + idx.toString() + ")"
: "");
}
font.bold: true font.bold: true
font.pixelSize: 14 font.pixelSize: 14
} }
Text { Text {
Layout.fillWidth: true Layout.fillWidth: true
text: { text: {
const orig = '$' + name + (idx ? idx.toString() : ""); const orig = "~" + generalDetail.general;
const orig_trans = luatr(orig); const tr = luatr(orig);
if (tr === orig) {
// try general specific return "";
const orig_g = '$' + name + '_' + detailGeneralCard.name
+ (idx ? idx.toString() : "");
const orig_g_trans = luatr(orig_g);
if (orig_g_trans !== orig_g) {
return orig_g_trans;
} }
return tr;
if (orig_trans !== orig) {
return orig_trans;
}
return "";
} }
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }
} }
onClicked: { onClicked: {
callbacks["LogEvent"](JSON.stringify({ const general = generalDetail.general
type: "PlaySkillSound", const extension = lcall("GetGeneralData", general).extension;
name: name, Backend.playSound("./packages/" + extension + "/audio/death/"
general: detailGeneralCard.name, + general);
i: idx,
}));
} }
} }
} }
Button {
id: audioDeath
Layout.fillWidth: true
contentItem: ColumnLayout {
Text {
Layout.fillWidth: true
text: luatr("Death audio")
font.bold: true
font.pixelSize: 14
}
Text {
Layout.fillWidth: true
text: {
const orig = "~" + generalDetail.general;
const tr = luatr(orig);
if (tr === orig) {
return "";
}
return tr;
}
wrapMode: Text.WordWrap
}
}
onClicked: {
const general = generalDetail.general
const extension = lcall("GetGeneralData", general).extension;
Backend.playSound("./packages/" + extension + "/audio/death/"
+ general);
}
}
}
}
Rectangle {
id: searcher
width: parent.width
height: childrenRect.height
color: "snow"
opacity: 0.75
anchors.top: parent.bottom
radius: 8
RowLayout {
width: parent.width
TextField {
id: word
Layout.fillWidth: true
clip: true
leftPadding: 5
rightPadding: 5
}
Button {
text: luatr("Search")
enabled: word.text !== ""
onClicked: {
listView.currentIndex = 0;
vanishAnim.start();
}
}
}
}
}
ColumnLayout {
anchors.right: parent.right
Button {
text: luatr("Quit")
onClicked: {
mainStack.pop();
config.saveConf();
}
}
Button {
id: banButton
text: luatr(config.disabledGenerals.includes(detailGeneralCard.name) ?
'ResumeGeneral' : 'BanGeneral')
visible: detailGeneralCard.name
onClicked: {
const { disabledGenerals } = config;
const { name } = detailGeneralCard;
if (banButton.text === luatr('ResumeGeneral')) {
const deleteIndex = disabledGenerals.findIndex(
(general) => general === name);
if (deleteIndex === -1) {
return;
}
disabledGenerals.splice(deleteIndex, 1);
} else {
if (disabledGenerals.includes(name)) {
return;
}
disabledGenerals.push(name);
}
config.disabledGeneralsChanged();
}
}
Timer {
id: opTimer
interval: 4000
}
Button {
text: luatr("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() { function loadPackages() {
if (loaded) return; if (loaded) return;
const _mods = lcall("GetAllModNames")
const modData = lcall("GetAllMods")
const packs = lcall("GetAllGeneralPack"); const packs = lcall("GetAllGeneralPack");
packs.forEach(name => { _mods.forEach(name => {
if (!config.serverHiddenPacks.includes(name)) { const pkgs = modData[name].filter(p => packs.includes(p)
packages.append({ name: name }); && !config.serverHiddenPacks.includes(p));
} if (pkgs.length > 0)
mods.append({ name: name, pkgs: JSON.stringify(pkgs) });
}); });
generalDetail.updateGeneral();
loaded = true; loaded = true;
} }
} }

View File

@ -64,11 +64,21 @@ Item {
Text { Text {
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true Layout.fillWidth: true
text: (hasPassword ? luatr("Has Password") : "") + roomName text: roomName
font.pixelSize: 20 font.pixelSize: 20
elide: Label.ElideRight elide: Label.ElideRight
} }
Item {
Layout.preferredWidth: 16
Image {
source: AppPath + "/image/button/skill/locked.png"
visible: hasPassword
anchors.centerIn: parent
scale: 0.8
}
}
Text { Text {
text: luatr(gameMode) text: luatr(gameMode)
} }

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
.import Fk.Util as Util
const Card = { const Card = {
Unknown : 0, Unknown : 0,
PlayerHand : 1, PlayerHand : 1,
@ -479,6 +477,22 @@ function doIndicate(from, tos) {
line.running = true; line.running = true;
} }
function processPrompt(prompt) {
const data = prompt.split(":");
let raw = luatr(data[0]);
const src = parseInt(data[1]);
const dest = parseInt(data[2]);
if (raw.match("%src"))
raw = raw.replace(/%src/g, luatr(getPhoto(src).general));
if (raw.match("%dest"))
raw = raw.replace(/%dest/g, luatr(getPhoto(dest).general));
if (raw.match("%arg2"))
raw = raw.replace(/%arg2/g, luatr(data[4]));
if (raw.match("%arg"))
raw = raw.replace(/%arg/g, luatr(data[3]));
return raw;
}
callbacks["MaxCard"] = (jsonData) => { callbacks["MaxCard"] = (jsonData) => {
const data = JSON.parse(jsonData); const data = JSON.parse(jsonData);
const id = data.id; const id = data.id;
@ -936,7 +950,7 @@ callbacks["AskForSkillInvoke"] = (jsonData) => {
const data = JSON.parse(jsonData); const data = JSON.parse(jsonData);
const skill = data[0]; const skill = data[0];
const prompt = data[1]; const prompt = data[1];
roomScene.promptText = prompt ? Util.processPrompt(prompt) roomScene.promptText = prompt ? processPrompt(prompt)
: luatr("#AskForSkillInvoke").arg(luatr(skill)); : luatr("#AskForSkillInvoke").arg(luatr(skill));
roomScene.state = "replying"; roomScene.state = "replying";
roomScene.okCancel.visible = true; roomScene.okCancel.visible = true;
@ -1025,7 +1039,7 @@ callbacks["AskForChoice"] = (jsonData) => {
roomScene.promptText = luatr("#AskForChoice") roomScene.promptText = luatr("#AskForChoice")
.arg(luatr(skill_name)); .arg(luatr(skill_name));
} else { } else {
roomScene.setPrompt(Util.processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.state = "replying"; roomScene.state = "replying";
let qmlSrc; let qmlSrc;
@ -1060,7 +1074,7 @@ callbacks["AskForChoices"] = (jsonData) => {
roomScene.promptText = luatr("#AskForChoices") roomScene.promptText = luatr("#AskForChoices")
.arg(luatr(skill_name)); .arg(luatr(skill_name));
} else { } else {
roomScene.setPrompt(Util.processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.state = "replying"; roomScene.state = "replying";
let qmlSrc; let qmlSrc;
@ -1096,7 +1110,7 @@ callbacks["AskForCardChosen"] = (jsonData) => {
roomScene.promptText = luatr("#AskForChooseCard") roomScene.promptText = luatr("#AskForChooseCard")
.arg(luatr(reason)); .arg(luatr(reason));
} else { } else {
roomScene.setPrompt(Util.processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.state = "replying"; roomScene.state = "replying";
roomScene.popupBox.sourceComponent = roomScene.popupBox.sourceComponent =
@ -1128,7 +1142,7 @@ callbacks["AskForCardsChosen"] = (jsonData) => {
roomScene.promptText = luatr("#AskForChooseCards") roomScene.promptText = luatr("#AskForChooseCards")
.arg(luatr(reason)).arg(min).arg(max); .arg(luatr(reason)).arg(min).arg(max);
} else { } else {
roomScene.setPrompt(Util.processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.state = "replying"; roomScene.state = "replying";
@ -1268,7 +1282,7 @@ callbacks["AskForUseActiveSkill"] = (jsonData) => {
roomScene.promptText = luatr("#AskForUseActiveSkill") roomScene.promptText = luatr("#AskForUseActiveSkill")
.arg(luatr(skill_name)); .arg(luatr(skill_name));
} else { } else {
roomScene.setPrompt(Util.processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.respond_play = false; roomScene.respond_play = false;
@ -1315,7 +1329,7 @@ callbacks["AskForUseCard"] = (jsonData) => {
roomScene.promptText = luatr("#AskForUseCard") roomScene.promptText = luatr("#AskForUseCard")
.arg(luatr(cardname)); .arg(luatr(cardname));
} else { } else {
roomScene.setPrompt(Util.processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.responding_card = pattern; roomScene.responding_card = pattern;
roomScene.respond_play = false; roomScene.respond_play = false;
@ -1337,7 +1351,7 @@ callbacks["AskForResponseCard"] = (jsonData) => {
roomScene.promptText = luatr("#AskForResponseCard") roomScene.promptText = luatr("#AskForResponseCard")
.arg(luatr(cardname)); .arg(luatr(cardname));
} else { } else {
roomScene.setPrompt(Util.processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.responding_card = pattern; roomScene.responding_card = pattern;
roomScene.respond_play = true; roomScene.respond_play = true;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -131,6 +131,10 @@ function GetAllMods()
return json.encode(Fk.extensions) return json.encode(Fk.extensions)
end end
function GetAllModNames()
return json.encode(Fk.extension_names)
end
function GetAllGeneralPack() function GetAllGeneralPack()
local ret = {} local ret = {}
for _, name in ipairs(Fk.package_names) do for _, name in ipairs(Fk.package_names) do
@ -142,6 +146,7 @@ function GetAllGeneralPack()
end end
function GetGenerals(pack_name) function GetGenerals(pack_name)
if not Fk.packages[pack_name] then return "{}" end
local ret = {} local ret = {}
for _, g in ipairs(Fk.packages[pack_name].generals) do for _, g in ipairs(Fk.packages[pack_name].generals) do
if not g.total_hidden then if not g.total_hidden then

View File

@ -79,12 +79,16 @@ Fk:loadTranslationTable{
["Clear"] = "清空", ["Clear"] = "清空",
["Help_Ban_List"] = "导出键会将这个方案的内容复制到剪贴板中;" .. ["Help_Ban_List"] = "导出键会将这个方案的内容复制到剪贴板中;" ..
"导入键会自动读取剪贴板,若可以导入则导入,不能导入则报错。", "导入键会自动读取剪贴板,若可以导入则导入,不能导入则报错。",
["Ban_Generals"] = "已禁用武将",
["Ban_Packages"] = "禁用拓展包",
["Whitelist_Generals"] = "白名单武将",
["Export"] = "导出", ["Export"] = "导出",
["Export Success"] = "禁将方案已经复制到剪贴板。", ["Export Success"] = "禁将方案已经复制到剪贴板。",
["Import"] = "导入", ["Import"] = "导入",
["Not Legal"] = "导入失败不是合法的JSON字符串。", ["Not Legal"] = "导入失败不是合法的JSON字符串。",
["Not JSON"] = "导入失败:数据格式不对。", ["Not JSON"] = "导入失败:数据格式不对。",
["Import Success"] = "从剪贴板导入禁将方案成功。", ["Import Success"] = "从剪贴板导入禁将方案成功。",
["Rename"] = "重命名",
["$OnlineInfo"] = "大厅人数:%1总在线人数%2", ["$OnlineInfo"] = "大厅人数:%1总在线人数%2",
@ -184,6 +188,9 @@ FreeKill使用的是libgit2的C API与此同时使用Git完成拓展包的下
-- ["Quit"] = "退出", -- ["Quit"] = "退出",
["BanGeneral"] = "禁将", ["BanGeneral"] = "禁将",
["ResumeGeneral"] = "解禁", ["ResumeGeneral"] = "解禁",
["BanPackage"] = "禁拓展包",
["$BanPkgHelp"] = "正在禁用拓展包",
["$BanCharaHelp"] = "正在禁用武将",
["Companions"] = "珠联璧合", ["Companions"] = "珠联璧合",
["Death audio"] = "阵亡", ["Death audio"] = "阵亡",

View File

@ -8,6 +8,7 @@
--- ---
---@class Engine : Object ---@class Engine : Object
---@field public extensions table<string, string[]> @ 所有mod列表及其包含的拓展包 ---@field public extensions table<string, string[]> @ 所有mod列表及其包含的拓展包
---@field public extension_names string[] @ Mod名字的数组为了方便排序
---@field public packages table<string, Package> @ 所有拓展包的列表 ---@field public packages table<string, Package> @ 所有拓展包的列表
---@field public package_names string[] @ 含所有拓展包名字的数组,为了方便排序 ---@field public package_names string[] @ 含所有拓展包名字的数组,为了方便排序
---@field public skills table<string, Skill> @ 所有的技能 ---@field public skills table<string, Skill> @ 所有的技能
@ -50,6 +51,7 @@ function Engine:initialize()
["standard_cards"] = { "standard_cards" }, ["standard_cards"] = { "standard_cards" },
["maneuvering"] = { "maneuvering" }, ["maneuvering"] = { "maneuvering" },
} }
self.extension_names = { "standard", "standard_cards", "maneuvering" }
self.packages = {} -- name --> Package self.packages = {} -- name --> Package
self.package_names = {} self.package_names = {}
self.skills = {} -- name --> Skill self.skills = {} -- name --> Skill
@ -147,6 +149,7 @@ function Engine:loadPackages()
-- Note that instance of Package is a table too -- Note that instance of Package is a table too
-- so dont use type(pack) == "table" here -- so dont use type(pack) == "table" here
if type(pack) == "table" then if type(pack) == "table" then
table.insert(self.extension_names, dir)
if pack[1] ~= nil then if pack[1] ~= nil then
self.extensions[dir] = {} self.extensions[dir] = {}
for _, p in ipairs(pack) do for _, p in ipairs(pack) do