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

View File

@ -11,6 +11,7 @@ Item {
ColumnLayout {
anchors.fill: parent
RowLayout {
Layout.fillWidth: true
anchors.rightMargin: 8
spacing: 16
Text {
@ -19,65 +20,94 @@ Item {
ComboBox {
id: banCombo
textRole: "name"
Layout.fillWidth: true
model: ListModel {
id: banComboList
}
onCurrentIndexChanged: {
config.disableSchemeIdx = currentIndex;
config.disabledGenerals = config.disableGeneralSchemes[currentIndex];
word.text = "";
config.disableSchemes[config.currentDisableIdx] = config.curScheme;
config.currentDisableIdx = currentIndex;
config.curScheme = config.disableSchemes[currentIndex];
}
}
Button {
text: luatr("New")
onClicked: {
const i = config.disableGeneralSchemes.length;
banComboList.append({
name: luatr("List") + (i + 1),
});
config.disableGeneralSchemes.push([]);
}
}
GridLayout {
columns: 2
Button {
text: luatr("Clear")
onClicked: {
config.disabledGenerals = [];
}
}
Button {
text: luatr("Export")
onClicked: {
Backend.copyToClipboard(JSON.stringify(config.disabledGenerals));
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;
Button {
text: luatr("New")
onClicked: {
const i = config.disableSchemes.length;
banComboList.append({
name: luatr("List") + (i + 1),
});
config.disableSchemes.push({
name: "",
banPkg: {},
normalPkg: {},
banCardPkg: [],
});
}
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) {
d.push(e);
}
Button {
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")
}
GridView {
id: listView
GridLayout {
id: grid
flow: GridLayout.TopToBottom
rows: 2
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
cellWidth: width / 4
cellHeight: 24
model: config.disabledGenerals
delegate: Text {
width: listView.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_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.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: {
for (let i = 0; i < config.disableGeneralSchemes.length; i++) {
for (let i = 0; i < config.disableSchemes.length; i++) {
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
anchors.rightMargin: 8
visible: {
//config.disabledPack; // visible
const avail = lcall("GetAvailableGeneralsNum");
const ret = avail <
config.preferredGeneralNum * config.preferedPlayerNum;
@ -164,36 +163,32 @@ Flickable {
config.saveConf();
root.finished();
mainWindow.busy = true;
let k, arr;
let disabledGenerals = config.disabledGenerals.slice();
if (disabledGenerals.length) {
const availablePack = lcall("GetAllGeneralPack").
filter((pack) => !config.disabledPack.includes(pack));
disabledGenerals = disabledGenerals.filter((general) => {
return availablePack.find(pack =>
lcall("GetGenerals", pack).includes(general));
});
disabledGenerals = Array.from(new Set(disabledGenerals));
let disabledGenerals = [];
for (k in config.curScheme.banPkg) {
arr = config.curScheme.banPkg[k];
if (arr.length !== 0) {
const generals = lcall("GetGenerals", k);
disabledGenerals.push(...generals.filter(g => !arr.includes(g)));
}
}
for (k in config.curScheme.normalPkg) {
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 => {
if (!disabledPack.includes(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(
"CreateRoom",
@ -232,8 +227,12 @@ Flickable {
playerNum.value = config.preferedPlayerNum;
config.disabledPack.forEach(p => lcall("UpdatePackageEnable", p, false));
config.disabledPackChanged();
for (let k in config.curScheme.banPkg) {
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
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) {
const packs = config.disabledPack;
if (checked) {
const idx = packs.indexOf(orig_name);
if (idx !== -1) packs.splice(idx, 1);
const s = config.curScheme;
if (!checked) {
s.banPkg[orig_name] = [];
s.normalPkg[orig_name] = undefined;
} else {
packs.push(orig_name);
s.normalPkg[orig_name] = undefined;
s.banPkg[orig_name] = undefined;
}
lcall("UpdatePackageEnable", orig_name, checked);
config.disabledPackChanged();
config.curSchemeChanged();
}
Component.onCompleted: {
@ -143,7 +152,7 @@ Flickable {
gpacklist.append({
name: luatr(orig),
orig_name: orig,
pkg_enabled: !config.disabledPack.includes(orig),
pkg_enabled: !config.curScheme.banPkg[orig],
});
}
@ -155,7 +164,7 @@ Flickable {
cpacklist.append({
name: luatr(orig),
orig_name: orig,
pkg_enabled: !config.disabledPack.includes(orig),
pkg_enabled: !config.curScheme.banCardPkg.includes(orig),
});
}
loading = false;

View File

@ -11,39 +11,97 @@ Item {
id: root
property bool loaded: false
property int stat: 0 // 0=normal 1=banPkg 2=banChara
Rectangle {
anchors.fill: listView
color: "#88EEEEEE"
id: listBg
width: 260; height: parent.height
color: "snow"
radius: 6
}
ListView {
id: listView
id: modList
width: 130; height: parent.height
anchors.top: listBg.top; anchors.left: listBg.left
clip: true
width: 130
height: parent.height - 20
y: 10
ScrollBar.vertical: ScrollBar {}
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
delegate: Item {
width: listView.width
width: modList.width
height: 40
Text {
text: luatr(name)
color: modList.currentIndex === index ? "black" : "white"
anchors.centerIn: parent
}
TapHandler {
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(); }
}
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 {
id: gridView
clip: true
width: root.width - listView.width - generalDetail.width - 16
height: parent.height - 20
y: 10
anchors.left: listView.right
width: root.width - listBg.width - 16
height: parent.height - bar.height - 24
y: 16 + bar.height
anchors.left: listBg.right
anchors.leftMargin: 8 + (width % 100) / 2
cellHeight: 140
cellWidth: 100
@ -66,24 +213,77 @@ Item {
autoBack: false
name: modelData
onClicked: {
generalText.clear();
generalDetail.general = modelData;
generalDetail.updateGeneral();
// generalDetail.open();
if (stat === 2) {
const s = config.curScheme;
const gdata = lcall("GetGeneralData", modelData);
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 {
anchors.fill: parent
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 {
NumberAnimation {}
}
}
GlowText {
visible: config.disabledGenerals.includes(modelData)
text: '禁'
id: banText
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
font.family: fontLi2.name
color: "#E4D5A0"
@ -108,7 +308,7 @@ Item {
PropertyAnimation {
target: gridView
property: "y"
to: 30
to: 36 + bar.height
duration: 150
easing.type: Easing.InOutQuad
}
@ -117,7 +317,7 @@ Item {
gridView.model = lcall("SearchAllGenerals", word.text);
} else {
gridView.model = lcall("SearchGenerals",
listView.model.get(listView.currentIndex).name, word.text);
pkgList.model[pkgList.currentIndex], word.text);
}
word.text = "";
appearAnim.start();
@ -138,23 +338,78 @@ Item {
PropertyAnimation {
target: gridView
property: "y"
from: 20
to: 10
from: 36 + bar.height
to: 16 + bar.height
duration: 150
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
width: 310
height: parent.height - searcher.height - 20
y: 10
anchors.right: parent.right
anchors.rightMargin: 10
color: "#88EEEEEE"
radius: 8
width: realMainWin.width * 0.6
height: realMainWin.height * 0.8
anchors.centerIn: parent
background: Rectangle {
color: "#EEEEEEEE"
radius: 5
border.color: "#A6967A"
border.width: 1
}
property string general: "caocao"
@ -196,7 +451,7 @@ Item {
function findDeathAudio(general) {
const extension = lcall("GetGeneralData", general).extension;
const fname = AppPath + "/packages/" + extension + "/audio/death/"
+ general + ".mp3";
+ general + ".mp3";
if (Backend.exists(fname)) {
audioDeath.visible = true;
} else {
@ -212,7 +467,7 @@ Item {
if (data.companions.length > 0){
let ret = "<font color=\"slategrey\"><b>" + luatr("Companions")
+ "</b>: ";
+ "</b>: ";
data.companions.forEach(t => {
ret += luatr(t) + ' '
});
@ -236,223 +491,153 @@ Item {
addSkillAudio(general + "_win_audio");
}
Flickable {
flickableDirection: Flickable.VerticalFlick
contentHeight: detailLayout.height
width: parent.width - 40
height: parent.height - 40
clip: true
Item {
anchors.centerIn: parent
ScrollBar.vertical: ScrollBar {}
width: parent.width / mainWindow.scale
height: parent.height / mainWindow.scale
scale: mainWindow.scale
ColumnLayout {
id: detailLayout
width: parent.width
GeneralCardItem {
id: detailGeneralCard
Layout.alignment: Qt.AlignHCenter
name: "caocao"
}
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 {
id: generalInfo
width: 150
ColumnLayout {
width: parent.width
GeneralCardItem {
id: detailGeneralCard
name: "caocao"
scale: 1.5; transformOrigin: Item.TopLeft
}
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 {
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
contentItem: ColumnLayout {
Text {
Layout.fillWidth: true
text: {
if (name.endsWith("_win_audio")) {
return "胜利语音";
}
return luatr(name) + (idx ? " (" + idx.toString() + ")"
: "");
}
text: luatr("Death audio")
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;
const orig = "~" + generalDetail.general;
const tr = luatr(orig);
if (tr === orig) {
return "";
}
if (orig_trans !== orig) {
return orig_trans;
}
return "";
return tr;
}
wrapMode: Text.WordWrap
}
}
onClicked: {
callbacks["LogEvent"](JSON.stringify({
type: "PlaySkillSound",
name: name,
general: detailGeneralCard.name,
i: idx,
}));
const general = generalDetail.general
const extension = lcall("GetGeneralData", general).extension;
Backend.playSound("./packages/" + extension + "/audio/death/"
+ general);
}
}
}
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() {
if (loaded) return;
const _mods = lcall("GetAllModNames")
const modData = lcall("GetAllMods")
const packs = lcall("GetAllGeneralPack");
packs.forEach(name => {
if (!config.serverHiddenPacks.includes(name)) {
packages.append({ name: name });
}
_mods.forEach(name => {
const pkgs = modData[name].filter(p => packs.includes(p)
&& !config.serverHiddenPacks.includes(p));
if (pkgs.length > 0)
mods.append({ name: name, pkgs: JSON.stringify(pkgs) });
});
generalDetail.updateGeneral();
loaded = true;
}
}

View File

@ -64,11 +64,21 @@ Item {
Text {
horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true
text: (hasPassword ? luatr("Has Password") : "") + roomName
text: roomName
font.pixelSize: 20
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: luatr(gameMode)
}

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
.import Fk.Util as Util
const Card = {
Unknown : 0,
PlayerHand : 1,
@ -479,6 +477,22 @@ function doIndicate(from, tos) {
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) => {
const data = JSON.parse(jsonData);
const id = data.id;
@ -936,7 +950,7 @@ callbacks["AskForSkillInvoke"] = (jsonData) => {
const data = JSON.parse(jsonData);
const skill = data[0];
const prompt = data[1];
roomScene.promptText = prompt ? Util.processPrompt(prompt)
roomScene.promptText = prompt ? processPrompt(prompt)
: luatr("#AskForSkillInvoke").arg(luatr(skill));
roomScene.state = "replying";
roomScene.okCancel.visible = true;
@ -1025,7 +1039,7 @@ callbacks["AskForChoice"] = (jsonData) => {
roomScene.promptText = luatr("#AskForChoice")
.arg(luatr(skill_name));
} else {
roomScene.setPrompt(Util.processPrompt(prompt), true);
roomScene.setPrompt(processPrompt(prompt), true);
}
roomScene.state = "replying";
let qmlSrc;
@ -1060,7 +1074,7 @@ callbacks["AskForChoices"] = (jsonData) => {
roomScene.promptText = luatr("#AskForChoices")
.arg(luatr(skill_name));
} else {
roomScene.setPrompt(Util.processPrompt(prompt), true);
roomScene.setPrompt(processPrompt(prompt), true);
}
roomScene.state = "replying";
let qmlSrc;
@ -1096,7 +1110,7 @@ callbacks["AskForCardChosen"] = (jsonData) => {
roomScene.promptText = luatr("#AskForChooseCard")
.arg(luatr(reason));
} else {
roomScene.setPrompt(Util.processPrompt(prompt), true);
roomScene.setPrompt(processPrompt(prompt), true);
}
roomScene.state = "replying";
roomScene.popupBox.sourceComponent =
@ -1128,7 +1142,7 @@ callbacks["AskForCardsChosen"] = (jsonData) => {
roomScene.promptText = luatr("#AskForChooseCards")
.arg(luatr(reason)).arg(min).arg(max);
} else {
roomScene.setPrompt(Util.processPrompt(prompt), true);
roomScene.setPrompt(processPrompt(prompt), true);
}
roomScene.state = "replying";
@ -1268,7 +1282,7 @@ callbacks["AskForUseActiveSkill"] = (jsonData) => {
roomScene.promptText = luatr("#AskForUseActiveSkill")
.arg(luatr(skill_name));
} else {
roomScene.setPrompt(Util.processPrompt(prompt), true);
roomScene.setPrompt(processPrompt(prompt), true);
}
roomScene.respond_play = false;
@ -1315,7 +1329,7 @@ callbacks["AskForUseCard"] = (jsonData) => {
roomScene.promptText = luatr("#AskForUseCard")
.arg(luatr(cardname));
} else {
roomScene.setPrompt(Util.processPrompt(prompt), true);
roomScene.setPrompt(processPrompt(prompt), true);
}
roomScene.responding_card = pattern;
roomScene.respond_play = false;
@ -1337,7 +1351,7 @@ callbacks["AskForResponseCard"] = (jsonData) => {
roomScene.promptText = luatr("#AskForResponseCard")
.arg(luatr(cardname));
} else {
roomScene.setPrompt(Util.processPrompt(prompt), true);
roomScene.setPrompt(processPrompt(prompt), true);
}
roomScene.responding_card = pattern;
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)
end
function GetAllModNames()
return json.encode(Fk.extension_names)
end
function GetAllGeneralPack()
local ret = {}
for _, name in ipairs(Fk.package_names) do
@ -142,6 +146,7 @@ function GetAllGeneralPack()
end
function GetGenerals(pack_name)
if not Fk.packages[pack_name] then return "{}" end
local ret = {}
for _, g in ipairs(Fk.packages[pack_name].generals) do
if not g.total_hidden then

View File

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

View File

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