GrasscutterCommandGenerator/Source/GrasscutterTools/Forms/FormMain.cs

2694 lines
94 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Grasscutter Tools
* Copyright (C) 2022 jie65535
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
**/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using GrasscutterTools.DispatchServer;
using GrasscutterTools.Game;
using GrasscutterTools.Game.Mail;
using GrasscutterTools.GOOD;
using GrasscutterTools.OpenCommand;
using GrasscutterTools.Properties;
using GrasscutterTools.Utils;
using Newtonsoft.Json;
namespace GrasscutterTools.Forms
{
public partial class FormMain : Form
{
#region - Init -
public FormMain()
{
InitializeComponent();
Icon = Resources.IconGrasscutter;
// 加载版本信息
LoadVersion();
// 加载设置
LoadSettings();
#if !DEBUG // 仅正式版
// 检查更新,但不要弹窗
Task.Run(async () => { try { await LoadUpdate(); } catch { /* 启动时检查更新,忽略异常 */ }});
#endif
}
/// <summary>
/// 窗体载入时触发(切换语言时会重新载入)
/// </summary>
private void FormMain_Load(object sender, EventArgs e)
{
Text += " - by jie65535 - v" + AppVersion.ToString(3);
#if DEBUG
Text += "-debug";
//Text += "-debug -攻击修改特供版";
#endif
GameData.LoadResources();
LoadCustomCommands();
InitArtifactList();
InitGameItemList();
InitWeapons();
InitAvatars();
InitEntityList();
InitScenes();
InitStatList();
InitPermList();
InitQuestList();
InitMailPage();
ChangeTPArtifact();
}
/// <summary>
/// 第一次显示窗体时触发
/// </summary>
protected override void OnShown(EventArgs e)
{
// 还原窗体位置
if (Settings.Default.MainFormLocation != default)
Location = Settings.Default.MainFormLocation;
// 还原窗体大小
if (Settings.Default.MainFormSize != default)
Size = Settings.Default.MainFormSize;
base.OnShown(e);
}
/// <summary>
/// 窗口关闭后触发
/// </summary>
private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
{
// 保存当前设置
SaveSettings();
}
/// <summary>
/// 应用版本
/// </summary>
private Version AppVersion;
/// <summary>
/// 加载应用版本
/// </summary>
private void LoadVersion()
{
AppVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
}
/// <summary>
/// 载入设置
/// </summary>
private void LoadSettings()
{
try
{
// 恢复自动复制选项状态
ChkAutoCopy.Checked = Settings.Default.AutoCopy;
// 初始化首页设置
InitHomeSettings();
// 初始化获取物品记录
InitGiveItemRecord();
// 初始化生成记录
InitSpawnRecord();
// 初始化开放命令
InitOpenCommand();
// 初始化邮件列表
InitMailList();
}
catch (Exception ex)
{
MessageBox.Show(Resources.SettingLoadError + ex.Message, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 保存设置
/// </summary>
private void SaveSettings()
{
try
{
// 记录界面状态
Settings.Default.AutoCopy = ChkAutoCopy.Checked;
Settings.Default.MainFormLocation = Location;
Settings.Default.MainFormSize = Size;
// 保存自定义命令
SaveCustomCommands();
// 保存开放命令设置
SaveOpenCommand();
// 保存邮件设置
SaveMailSettings();
// 保存默认设置
Settings.Default.Save();
}
catch (Exception ex)
{
MessageBox.Show(Resources.SettingSaveError + ex.Message, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private ReleaseAPI.ReleaseInfo LastestInfo = null;
private Version lastestVersion = null;
private async Task LoadUpdate()
{
var info = await ReleaseAPI.GetReleasesLastest("jie65535", "GrasscutterCommandGenerator");
if (Version.TryParse(info.TagName.Substring(1), out lastestVersion) && AppVersion < lastestVersion)
{
if (!string.IsNullOrEmpty(Settings.Default.CheckedLastVersion)
&& Version.TryParse(Settings.Default.CheckedLastVersion, out Version checkedVersion)
&& checkedVersion >= lastestVersion)
return;
LastestInfo = info;
BeginInvoke(new Action(() =>
{
LnkNewVersion.Visible = true;
LnkNewVersion.Text = Resources.CheckToNewVersion;
this.Text += " - " + Resources.CheckToNewVersion;
}));
}
}
#endregion - Init -
#region - Home -
/// <summary>
/// 命令版本
/// </summary>
private CommandVersion CommandVersion;
/// <summary>
/// 初始化首页设置
/// </summary>
private void InitHomeSettings()
{
// 玩家UID
NUDUid.Value = Settings.Default.Uid;
NUDUid.ValueChanged += (o, e) => Settings.Default.Uid = NUDUid.Value;
// 置顶
ChkTopMost.Checked = Settings.Default.IsTopMost;
ChkTopMost.CheckedChanged += (o, e) => Settings.Default.IsTopMost = TopMost = ChkTopMost.Checked;
// 命令版本初始化
CommandVersion = Version.TryParse(Settings.Default.CommandVersion, out Version current) ? new CommandVersion(current) : CommandVersion.Latest();
CmbGcVersions.DataSource = CommandVersion.List.Select(it => it.ToString(3)).ToList();
CmbGcVersions.SelectedIndex = Array.IndexOf(CommandVersion.List, CommandVersion.Current);
CmbGcVersions.SelectedIndexChanged += (o, e) => CommandVersion.Current = CommandVersion.List[CmbGcVersions.SelectedIndex];
CommandVersion.VersionChanged += OnCommandVersionChanged;
// 初始化多语言
CmbLanguage.DataSource = MultiLanguage.LanguageNames;
if (string.IsNullOrEmpty(Settings.Default.DefaultLanguage))
{
// 如果未选择语言,则默认载入本地语言
var i = Array.IndexOf(MultiLanguage.Languages, Thread.CurrentThread.CurrentUICulture);
// 仅支持时切换,避免重复加载
if (i > 0) CmbLanguage.SelectedIndex = i;
}
else
{
CmbLanguage.SelectedIndex = Array.IndexOf(MultiLanguage.Languages, Settings.Default.DefaultLanguage);
}
CmbLanguage.SelectedIndexChanged += CmbLanguage_SelectedIndexChanged;
}
private static void ToTop(Form form)
{
form.TopMost = true;
form.TopMost = false;
}
/// <summary>
/// 卡池编辑器窗口实例
/// </summary>
private Form GachaBannerEditor;
/// <summary>
/// 点击打开卡池编辑器时触发
/// </summary>
private void BtnOpenGachaBannerEditor_Click(object sender, EventArgs e)
{
if (GachaBannerEditor == null || GachaBannerEditor.IsDisposed)
{
GachaBannerEditor = new FormGachaBannerEditor2();
GachaBannerEditor.Show();
}
else
{
ToTop(GachaBannerEditor);
}
}
/// <summary>
/// 文本浏览器窗口实例
/// </summary>
private FormTextMapBrowser TextMapBrowser;
private void BtnOpenTextMap_Click(object sender, EventArgs e)
{
if (TextMapBrowser == null || TextMapBrowser.IsDisposed)
{
TextMapBrowser = new FormTextMapBrowser();
TextMapBrowser.Show();
}
else
{
ToTop(TextMapBrowser);
}
}
/// <summary>
/// 掉落物编辑器窗口实例
/// </summary>
private FormDropEditor DropEditor;
/// <summary>
/// 点击打开掉落物编辑器时触发
/// </summary>
private void BtnOpenDropEditor_Click(object sender, EventArgs e)
{
if (DropEditor == null || DropEditor.IsDisposed)
{
DropEditor = new FormDropEditor();
DropEditor.Show();
}
else
{
ToTop(DropEditor);
}
}
/// <summary>
/// 商店编辑器窗口实例
/// </summary>
private FormShopEditor ShopEditor;
/// <summary>
/// 点击打开商店编辑器时触发
/// </summary>
private void BtnOpenShopEditor_Click(object sender, EventArgs e)
{
if (ShopEditor == null || ShopEditor.IsDisposed)
{
ShopEditor = new FormShopEditor();
ShopEditor.Show();
}
else
{
ToTop(ShopEditor);
}
}
/// <summary>
/// 语言选中项改变时触发
/// </summary>
private void CmbLanguage_SelectedIndexChanged(object sender, EventArgs e)
{
if (CmbLanguage.SelectedIndex < 0) return;
// 切换默认语言
MultiLanguage.SetDefaultLanguage(MultiLanguage.Languages[CmbLanguage.SelectedIndex]);
// 动态更改语言
MultiLanguage.LoadLanguage(this, typeof(FormMain));
// 重新载入页面资源
FormMain_Load(this, EventArgs.Empty);
}
/// <summary>
/// 命令版本改变时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnCommandVersionChanged(object sender, EventArgs e)
{
Settings.Default.CommandVersion = CommandVersion.Current.ToString(3);
ChangeTPArtifact();
}
/// <summary>
/// 点击检查更新时触发
/// </summary>
private void LnkNewVersion_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
if (LastestInfo != null)
{
var r = MessageBox.Show(
string.Format(Resources.NewVersionInfo, LastestInfo.Name, LastestInfo.CraeteTime.ToLocalTime(), LastestInfo.Body),
Resources.CheckToNewVersion,
MessageBoxButtons.YesNo,
MessageBoxIcon.Information);
if (r == DialogResult.Yes)
OpenURL(LastestInfo.Url);
else if (r == DialogResult.No)
Settings.Default.CheckedLastVersion = lastestVersion.ToString();
}
else
{
// 没有更新,隐藏
LnkNewVersion.Visible = false;
}
}
#endregion - Home -
#region - Custom -
/// <summary>
/// 自定义命令保存位置
/// </summary>
private readonly string CustomCommandsFilePath = Path.Combine(Application.LocalUserAppDataPath, "CustomCommands.txt");
/// <summary>
/// 自定义命令是否存在更改
/// </summary>
private bool CustomCommandsChanged;
/// <summary>
/// 加载自定义命令
/// </summary>
private void LoadCustomCommands()
{
if (File.Exists(CustomCommandsFilePath))
LoadCustomCommandControls(File.ReadAllText(CustomCommandsFilePath));
else
LoadCustomCommandControls(Resources.CustomCommands);
}
/// <summary>
/// 加载自定义命令控件列表
/// </summary>
/// <param name="commands">命令集(示例:"标签1\n命令1\n标签2\n命令2"</param>
private void LoadCustomCommandControls(string commands)
{
FLPCustomCommands.Controls.Clear();
var lines = commands.Split('\n');
for (int i = 0; i < lines.Length - 1; i += 2)
AddCustomCommand(lines[i].Trim(), lines[i + 1].Trim());
}
/// <summary>
/// 保存自定义命令
/// </summary>
private void SaveCustomCommands()
{
if (CustomCommandsChanged)
File.WriteAllText(CustomCommandsFilePath, SaveCustomCommandControls());
}
/// <summary>
/// 保存自定义命令控件列表
/// </summary>
/// <returns>命令集(示例:"标签1\n命令1\n标签2\n命令2"</returns>
private string SaveCustomCommandControls()
{
StringBuilder builder = new StringBuilder();
foreach (LinkLabel lnk in FLPCustomCommands.Controls)
{
builder.AppendLine(lnk.Text);
builder.AppendLine(lnk.Tag as string);
}
return builder.ToString();
}
/// <summary>
/// 自定义命令点击时触发
/// </summary>
private void CustomCommand_Click(object sender, LinkLabelLinkClickedEventArgs e)
{
if (sender is LinkLabel lnk && lnk.Tag is string command)
{
TxtCustomName.Text = lnk.Text;
SetCommand(command);
}
}
/// <summary>
/// 点击保存自定义命令列表时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void BtnSaveCustomCommand_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(TxtCustomName.Text))
{
MessageBox.Show(Resources.CommandTagCannotBeEmpty, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (string.IsNullOrWhiteSpace(TxtCommand.Text))
{
MessageBox.Show(Resources.CommandContentCannotBeEmpty, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var name = TxtCustomName.Text.Trim();
var command = TxtCommand.Text.Trim();
foreach (LinkLabel lnk in FLPCustomCommands.Controls)
{
if (lnk.Text == name)
{
lnk.Tag = command;
CustomCommandsChanged = true;
await UIUtil.ButtonComplete(BtnSaveCustomCommand);
return;
}
}
CustomCommandsChanged = true;
AddCustomCommand(name, command);
await UIUtil.ButtonComplete(BtnSaveCustomCommand);
}
/// <summary>
/// 添加自定义命令
/// </summary>
/// <param name="name">标签</param>
/// <param name="command">命令</param>
private void AddCustomCommand(string name, string command)
{
var lnk = new LinkLabel
{
Text = name,
Tag = command,
AutoSize = true,
};
lnk.LinkClicked += CustomCommand_Click;
FLPCustomCommands.Controls.Add(lnk);
}
/// <summary>
/// 点击移除自定义命令按钮时触发
/// </summary>
private async void BtnRemoveCustomCommand_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(TxtCustomName.Text))
{
MessageBox.Show(Resources.CommandTagCannotBeEmpty, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var name = TxtCustomName.Text.Trim();
foreach (LinkLabel lnk in FLPCustomCommands.Controls)
{
if (lnk.Text == name && MessageBox.Show(Resources.AskConfirmDeletion, Resources.Tips, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
FLPCustomCommands.Controls.Remove(lnk);
CustomCommandsChanged = true;
//TxtCustomName.Text = "";
//TxtCommand.Text = "";
await UIUtil.ButtonComplete(BtnRemoveCustomCommand);
return;
}
}
MessageBox.Show(Resources.CommandNotFound, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
/// <summary>
/// 点击导入自定义命令时触发
/// </summary>
private void BtnImport_Click(object sender, EventArgs e)
{
var dialog = new OpenFileDialog
{
Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
using (var stream = dialog.OpenFile())
using (var reader = new StreamReader(stream))
{
LoadCustomCommandControls(reader.ReadToEnd());
CustomCommandsChanged = true;
}
}
}
/// <summary>
/// 点击导出自定义命令时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnExport_Click(object sender, EventArgs e)
{
var dialog = new SaveFileDialog
{
FileName = "Commands.txt",
Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
using (var stream = dialog.OpenFile())
using (var writer = new StreamWriter(stream))
{
writer.Write(SaveCustomCommandControls());
}
}
}
/// <summary>
/// 点击重置链接按钮时触发
/// </summary>
private void LnkResetCustomCommands_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
if (MessageBox.Show(Resources.RestoreCustomCommands, Resources.Tips, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
{
if (File.Exists(CustomCommandsFilePath))
File.Delete(CustomCommandsFilePath);
LoadCustomCommandControls(Resources.CustomCommands);
}
}
#endregion - Custom -
#region - Artifact -
/// <summary>
/// 副词条集
/// </summary>
private Dictionary<string, List<KeyValuePair<int, string>>> subAttrs;
/// <summary>
/// 部位标签集
/// </summary>
private string[] ArtifactPartLabels;
/// <summary>
/// 初始化圣遗物列表
/// </summary>
private void InitArtifactList()
{
CmbArtifactSet.Items.Clear();
CmbArtifactSet.Items.AddRange(GameData.ArtifactCats.Names);
CmbMainAttribution.Items.Clear();
CmbMainAttribution.Items.AddRange(GameData.ArtifactMainAttribution.Lines);
subAttrs = new Dictionary<string, List<KeyValuePair<int, string>>>();
for (int i = 0; i < GameData.ArtifactSubAttribution.Count; i++)
{
var name = GameData.ArtifactSubAttribution.Names[i];
var pi = name.IndexOf('+');
var prefix = name.Substring(0, pi);
var value = name.Substring(pi);
if (!subAttrs.TryGetValue(prefix, out List<KeyValuePair<int, string>> list))
{
list = new List<KeyValuePair<int, string>>();
subAttrs[prefix] = list;
}
list.Add(new KeyValuePair<int, string>(GameData.ArtifactSubAttribution.Ids[i], value));
}
CmbSubAttribution.Items.Clear();
CmbSubAttribution.Items.AddRange(subAttrs.Keys.ToArray());
ArtifactPartLabels = Resources.ArtifactPartLabels.Split(',');
}
/// <summary>
/// 福词条下拉框选中项改变时触发
/// </summary>
private void CmbSubAttribution_SelectedIndexChanged(object sender, EventArgs e)
{
CmbSubAttributionValue.Items.Clear();
if (CmbSubAttribution.SelectedIndex >= 0)
{
CmbSubAttributionValue.Items.AddRange(subAttrs[CmbSubAttribution.SelectedItem as string].Select(kv => kv.Value).ToArray());
CmbSubAttributionValue.SelectedIndex = 0;
}
}
/// <summary>
/// 点击添加副词条按钮时触发
/// </summary>
private void BtnAddSubAttr_Click(object sender, EventArgs e)
{
if (CmbSubAttribution.SelectedIndex >= 0 && CmbSubAttributionValue.SelectedIndex >= 0)
{
var name = CmbSubAttribution.SelectedItem as string;
var kv = subAttrs[name][CmbSubAttributionValue.SelectedIndex];
ListSubAttributionChecked.Items.Add($"{kv.Key}:{name}{kv.Value} x{NUDSubAttributionTimes.Value}");
ArtifactInputChanged(null, EventArgs.Empty);
}
}
/// <summary>
/// 圣遗物套装下拉框选中项改变时触发
/// </summary>
private void CmbArtifactSet_SelectedIndexChanged(object sender, EventArgs e)
{
if (CmbArtifactSet.SelectedIndex < 0)
return;
var setId = GameData.ArtifactCats.Ids[CmbArtifactSet.SelectedIndex];
var beginIndex = Array.FindIndex(GameData.Artifacts.Ids, id => id / 1000 == setId);
var endIndex = Array.FindLastIndex(GameData.Artifacts.Ids, id => id / 1000 == setId);
// 限制星级输入范围
NUDArtifactStars.Minimum = GameData.Artifacts.Ids[beginIndex] / 100 % 10;
NUDArtifactStars.Maximum = GameData.Artifacts.Ids[endIndex] / 100 % 10;
var parts = GameData.Artifacts.Names.Skip(beginIndex).Take(endIndex - beginIndex + 1).Distinct().ToArray();
var i = CmbArtifactPart.SelectedIndex;
CmbArtifactPart.Items.Clear();
CmbArtifactPart.Items.AddRange(parts);
if (i < parts.Length) // 重新选中
CmbArtifactPart.SelectedIndex = i;
ArtifactInputChanged(sender, e);
}
/// <summary>
/// 圣遗物部件选中项改变时触发
/// </summary>
private void CmbArtifactPart_SelectedIndexChanged(object sender, EventArgs e)
{
if (CmbArtifactPart.SelectedIndex < 0)
{
LblArtifactName.Text = "";
return;
}
var name = CmbArtifactPart.SelectedItem as string;
var id = GameData.Artifacts.Ids[Array.IndexOf(GameData.Artifacts.Names, name)];
var pardIndex = id / 10 % 10 - 1;
if (pardIndex < ArtifactPartLabels?.Length)
LblArtifactName.Text = ArtifactPartLabels[pardIndex];
else
LblArtifactName.Text = "";
ArtifactInputChanged(sender, e);
}
/// <summary>
/// 圣遗物页面输入改变时调用
/// </summary>
private void ArtifactInputChanged(object sender, EventArgs e)
{
// 圣遗物ID五位数ABCDE其中AB是圣遗物类型魔女/水/风套......
// C是星级5就是五星D是圣遗物部位E是初始词条数量
if (CmbArtifactSet.SelectedIndex < 0 || CmbArtifactPart.SelectedIndex < 0)
return;
//var setId = GameData.ArtifactCats.Ids[CmbArtifactSet.SelectedIndex];
//var part = CmbArtifactPart.SelectedIndex+1;
//var index = Array.FindLastIndex(
// GameData.Artifacts.Ids,
// it => it / 1000 == setId // 套装ID
// //&& it / 100 % 10 == NUDArtifactStars.Value // 星级
// && it / 10 % 10 == part // 部位
// );
var name = CmbArtifactPart.SelectedItem as string;
var id = GameData.Artifacts.Ids[Array.LastIndexOf(GameData.Artifacts.Names, name)];
id = id / 1000 * 1000 + (int)NUDArtifactStars.Value * 100 + id % 100;
if (CmbMainAttribution.SelectedIndex < 0)
{
if (CommandVersion.Check(CommandVersion.V1_2_2))
SetCommand("/give", $"{id} lv{NUDArtifactLevel.Value}");
else
SetCommand("/giveart", $"{id} {NUDArtifactLevel.Value}");
}
else
{
var t = CmbMainAttribution.SelectedItem as string;
var mainAttr = ItemMap.ToId(t);
var subAttrs = "";
if (ListSubAttributionChecked.Items.Count > 0)
{
var subAttrDir = new Dictionary<int, int>(ListSubAttributionChecked.Items.Count);
foreach (string item in ListSubAttributionChecked.Items)
{
var subId = ItemMap.ToId(item);
var times = int.Parse(item.Substring(item.LastIndexOf('x') + 1));
if (subAttrDir.ContainsKey(subId))
subAttrDir[subId] += times;
else
subAttrDir[subId] = times;
}
foreach (var kv in subAttrDir)
{
if (kv.Value > 1)
subAttrs += $"{kv.Key},{kv.Value} ";
else
subAttrs += $"{kv.Key} ";
}
}
if (CommandVersion.Check(CommandVersion.V1_2_2))
SetCommand("/give", $"{id} lv{NUDArtifactLevel.Value} {mainAttr} {subAttrs}");
else
SetCommand("/giveart", $"{id} {mainAttr} {subAttrs}{NUDArtifactLevel.Value}");
}
}
/// <summary>
/// 已添加的副词条列表选中项改变时触发
/// </summary>
private void ListSubAttributionChecked_SelectedIndexChanged(object sender, EventArgs e)
{
if (ListSubAttributionChecked.SelectedIndex >= 0)
{
ListSubAttributionChecked.Items.RemoveAt(ListSubAttributionChecked.SelectedIndex);
ListSubAttributionChecked.ClearSelected();
ArtifactInputChanged(null, EventArgs.Empty);
}
}
/// <summary>
/// 清除词条链接标签点击时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void LblClearSubAttrCheckedList_Click(object sender, EventArgs e)
{
CmbMainAttribution.SelectedIndex = -1;
ListSubAttributionChecked.Items.Clear();
ArtifactInputChanged(null, EventArgs.Empty);
}
/// <summary>
/// 改变圣遗物等级输入范围旧版本范围是1-21
/// </summary>
private void ChangeTPArtifact()
{
if (CommandVersion.Check(CommandVersion.V1_2_2))
{
NUDArtifactLevel.Minimum = 0;
NUDArtifactLevel.Maximum = 20;
}
else
{
NUDArtifactLevel.Minimum = 1;
NUDArtifactLevel.Maximum = 21;
}
LblArtifactLevelTip.Text = $"[{NUDArtifactLevel.Minimum}-{NUDArtifactLevel.Maximum}]";
}
#endregion - Artifact -
#region - Weapons -
/// <summary>
/// 初始化武器列表
/// </summary>
private void InitWeapons()
{
ListWeapons.Items.Clear();
ListWeapons.Items.AddRange(GameData.Weapons.Lines);
}
/// <summary>
/// 武器列表过滤器文本改变时触发
/// </summary>
private void TxtWeaponFilter_TextChanged(object sender, EventArgs e)
{
UIUtil.ListBoxFilter(ListWeapons, GameData.Weapons.Lines, TxtWeaponFilter.Text);
}
/// <summary>
/// 武器页面输入改变时触发
/// </summary>
private void WeaponValueChanged(object sender, EventArgs e)
{
var name = ListWeapons.SelectedItem as string;
if (!string.IsNullOrEmpty(name))
{
var id = ItemMap.ToId(name);
if (CommandVersion.Check(CommandVersion.V1_2_2))
SetCommand("/give", $"{id} x{NUDWeaponAmout.Value} lv{NUDWeaponLevel.Value} r{NUDWeaponRefinement.Value}");
else
SetCommand("/give", $"{id} {NUDWeaponAmout.Value} {NUDWeaponLevel.Value} {NUDWeaponRefinement.Value}");
}
}
/// <summary>
/// 点击获取所有武器按钮时触发
/// </summary>
private void BtnGiveAllWeapons_Click(object sender, EventArgs e)
{
SetCommand("/give", $"weapons x{NUDWeaponAmout.Value} lv{NUDWeaponLevel.Value} r{NUDWeaponRefinement.Value}");
}
#endregion - Weapons -
#region - Items -
/// <summary>
/// 初始化游戏物品列表
/// </summary>
private void InitGameItemList()
{
ListGameItems.Items.Clear();
ListGameItems.Items.AddRange(GameData.Items.Lines);
}
/// <summary>
/// 物品列表过滤器文本改变时触发
/// </summary>
private void TxtGameItemFilter_TextChanged(object sender, EventArgs e)
{
UIUtil.ListBoxFilter(ListGameItems, GameData.Items.Lines, TxtGameItemFilter.Text);
}
/// <summary>
/// 生成获取物品命令
/// </summary>
/// <returns>是否生成成功</returns>
private bool GenGiveItemCommand()
{
var name = ListGameItems.SelectedItem as string;
if (!string.IsNullOrEmpty(name))
{
var id = ItemMap.ToId(name);
if (ChkDrop.Checked)
{
NUDGameItemLevel.Enabled = false;
SetCommand("/drop", $"{id} {NUDGameItemAmout.Value}");
}
else
{
NUDGameItemLevel.Enabled = true;
if (CommandVersion.Check(CommandVersion.V1_2_2))
SetCommand("/give", $"{id} x{NUDGameItemAmout.Value} lv{NUDGameItemLevel.Value}");
else
SetCommand("/give", $"{id} {NUDGameItemAmout.Value} {NUDGameItemLevel.Value}");
}
return true;
}
return false;
}
/// <summary>
/// 获取物品输入改变时触发
/// </summary>
private void GiveItemsInputChanged(object sender, EventArgs e)
{
GenGiveItemCommand();
}
#region -- --
/// <summary>
/// 获取物品记录文件路径
/// </summary>
private readonly string GiveItemCommandsRecordPath = Path.Combine(Application.LocalUserAppDataPath, "GiveItemCommands.txt");
/// <summary>
/// 获取物品记录
/// </summary>
private List<GameCommand> GiveItemCommands;
/// <summary>
/// 初始化获取物品记录
/// </summary>
private void InitGiveItemRecord()
{
if (File.Exists(GiveItemCommandsRecordPath))
{
GiveItemCommands = GetCommands(File.ReadAllText(GiveItemCommandsRecordPath));
ListGiveItemLogs.Items.AddRange(GiveItemCommands.Select(c => c.Name).ToArray());
}
else
{
GiveItemCommands = new List<GameCommand>();
}
}
/// <summary>
/// 保存获取物品记录
/// </summary>
private void SaveGiveItemRecord()
{
File.WriteAllText(GiveItemCommandsRecordPath, GetCommandsText(GiveItemCommands));
}
/// <summary>
/// 获取物品记录列表选中项改变时触发
/// </summary>
private void ListGiveItemLogs_SelectedIndexChanged(object sender, EventArgs e)
{
if (ListGiveItemLogs.SelectedIndex >= 0)
{
BtnRemoveGiveItemLog.Enabled = true;
SetCommand(GiveItemCommands[ListGiveItemLogs.SelectedIndex].Command);
}
else
{
BtnRemoveGiveItemLog.Enabled = false;
}
}
/// <summary>
/// 点击保存记录按钮时触发
/// </summary>
private void BtnSaveGiveItemLog_Click(object sender, EventArgs e)
{
if (GenGiveItemCommand())
{
var cmd = new GameCommand($"{ListGameItems.SelectedItem} x{NUDGameItemAmout.Value}", TxtCommand.Text);
GiveItemCommands.Add(cmd);
ListGiveItemLogs.Items.Add(cmd.Name);
SaveGiveItemRecord();
}
}
/// <summary>
/// 点击移除获取物品记录时触发
/// </summary>
private void BtnRemoveGiveItemLog_Click(object sender, EventArgs e)
{
if (ListGiveItemLogs.SelectedIndex >= 0)
{
GiveItemCommands.RemoveAt(ListGiveItemLogs.SelectedIndex);
ListGiveItemLogs.Items.RemoveAt(ListGiveItemLogs.SelectedIndex);
SaveGiveItemRecord();
}
}
/// <summary>
/// 点击清空获取物品记录时触发
/// </summary>
private void LblClearGiveItemLogs_Click(object sender, EventArgs e)
{
if (MessageBox.Show(Resources.AskConfirmDeletion, Resources.Tips, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
GiveItemCommands.Clear();
ListGiveItemLogs.Items.Clear();
SaveGiveItemRecord();
}
}
#endregion -- --
#endregion - Items -
#region - Avatars -
#region -- --
/// <summary>
/// 初始化角色列表
/// </summary>
private void InitAvatars()
{
CmbAvatar.Items.Clear();
CmbAvatar.Items.AddRange(GameData.Avatars.Names);
}
/// <summary>
/// 角色下拉框选中项改变时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CmbAvatar_SelectedIndexChanged(object sender, EventArgs e)
{
// TODO: Load Avatar Image
AvatarInputChanged();
}
/// <summary>
/// 角色等级输入框数值改变时触发
/// </summary>
private void NUDAvatarLevel_ValueChanged(object sender, EventArgs e)
{
AvatarInputChanged();
}
/// <summary>
/// 角色命座输入框数值改变时触发
/// </summary>
private void NUDAvatarConstellation_ValueChanged(object sender, EventArgs e)
{
AvatarInputChanged();
}
/// <summary>
/// 角色页面输入改变时触发
/// </summary>
private void AvatarInputChanged()
{
if (CmbAvatar.SelectedIndex >= 0)
GenAvatar((int)NUDAvatarLevel.Value, (int)NUDAvatarConstellation.Value, (int)NUDAvatarSkillLevel.Value);
}
/// <summary>
/// 获取角色命令
/// </summary>
/// <param name="level">等级</param>
private void GenAvatar(int level, int constellation, int skillLevel)
{
if (CommandVersion.Check(CommandVersion.V1_4_1))
{
int avatarId = GameData.Avatars.Ids[CmbAvatar.SelectedIndex];
SetCommand("/give", $"{avatarId} lv{level} c{constellation} sl{skillLevel}");
}
else if (CommandVersion.Check(CommandVersion.V1_2_2))
{
int avatarId = GameData.Avatars.Ids[CmbAvatar.SelectedIndex];
SetCommand("/give", $"{avatarId} lv{level} c{constellation}");
}
else
{
int avatarId = GameData.Avatars.Ids[CmbAvatar.SelectedIndex] - 1000 + 10000000;
SetCommand("/givechar", $"{avatarId} {level}");
}
}
/// <summary>
/// 点击获取所有角色按钮时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnGiveAllChar_Click(object sender, EventArgs e)
{
var level = NUDAvatarLevel.Value;
var constellation = NUDAvatarConstellation.Value;
var skillLevel = NUDAvatarSkillLevel.Value;
if (CommandVersion.Check(CommandVersion.V1_4_1))
SetCommand("/give avatars", $"lv{level} c{constellation} sl{skillLevel}");
else
SetCommand("/give avatars", $"lv{level} c{constellation}");
}
#endregion
#region -- --
/// <summary>
/// 点击切换主角元素链接标签时触发
/// </summary>
private void LnkSwitchElement_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
OpenURL("https://github.com/Penelopeep/SwitchElementTraveller");
}
/// <summary>
/// 元素参数
/// </summary>
private readonly string[] Elements = { "white", "fire", "water", "wind", "ice", "rock", "electro", "grass" };
/// <summary>
/// 切换元素下拉框选中项改变时触发
/// </summary>
private void CmbSwitchElement_SelectedIndexChanged(object sender, EventArgs e)
{
if (CmbSwitchElement.SelectedIndex == -1 || CmbSwitchElement.SelectedIndex >= Elements.Length) return;
SetCommand("/se", Elements[CmbSwitchElement.SelectedIndex]);
}
#endregion
#region -- --
/// <summary>
/// 初始化数据列表
/// </summary>
private void InitStatList()
{
LblStatTip.Text = "";
SetStatsCommand.InitStats();
CmbStat.Items.Clear();
CmbStat.Items.AddRange(SetStatsCommand.Stats.Select(s => s.Name).ToArray());
}
/// <summary>
/// 数据页面输入改变时触发
/// </summary>
private void SetStatsInputChanged(object sender, EventArgs e)
{
if (CmbStat.SelectedIndex < 0)
return;
else
BtnLockStat.Enabled = BtnUnlockStat.Enabled = true;
var stat = SetStatsCommand.Stats[CmbStat.SelectedIndex];
LblStatPercent.Visible = stat.Percent;
LblStatTip.Text = stat.Tip;
SetCommand("/setstats", $"{stat.ArgName} {NUDStat.Value}{(stat.Percent ? "%" : "")}");
}
/// <summary>
/// 点击锁定按钮时触发
/// </summary>
private void BtnLockStat_Click(object sender, EventArgs e)
{
var stat = SetStatsCommand.Stats[CmbStat.SelectedIndex];
SetCommand("/setstats", $"lock {stat.ArgName} {NUDStat.Value}{(stat.Percent ? "%" : "")}");
}
/// <summary>
/// 点击解锁按钮时触发
/// </summary>
private void BtnUnlockStat_Click(object sender, EventArgs e)
{
var stat = SetStatsCommand.Stats[CmbStat.SelectedIndex];
SetCommand("/setstats", $"unlock {stat.ArgName}");
}
#endregion
#region -- --
/// <summary>
/// 点击设置技能按钮时触发
/// </summary>
private void LnkSetTalentClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
SetCommand("/talent", $"{(sender as LinkLabel).Tag} {NUDTalentLevel.Value}");
}
#endregion
#region -- --
/// <summary>
/// 设置命座链接标签点击时触发
/// </summary>
private void LnkSetConst_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
if (NUDSetConstellation.Value >= 0)
SetCommand("/setConst", $"{NUDSetConstellation.Value}" + (sender == LnkSetAllConst ? " all" : string.Empty));
else
SetCommand("/resetConst", (sender == LnkSetAllConst ? "all" : string.Empty));
}
#endregion
#endregion - Avatars -
#region - Spawns -
#region -- --
/// <summary>
/// 初始化实体列表
/// </summary>
private void InitEntityList()
{
// 初始化列表类型过滤器
MenuSpawnEntityFilter.SuspendLayout();
MenuSpawnEntityFilter.Items.Clear();
void AddTypes(ItemMapGroup group)
{
foreach (var kv in group)
{
var item = new ToolStripMenuItem
{
Text = kv.Key,
Tag = kv.Value.Lines,
};
item.Click += OnEntityTypeFilterClick;
MenuSpawnEntityFilter.Items.Add(item);
}
}
//MenuSpawnEntityFilter.Items.Add(new ToolStripLabel("Monsters"));
AddTypes(GameData.Monsters);
MenuSpawnEntityFilter.Items.Add(new ToolStripSeparator());
//MenuSpawnEntityFilter.Items.Add(new ToolStripLabel("Gadgets"));
AddTypes(GameData.Gadgets);
MenuSpawnEntityFilter.ResumeLayout();
// 默认显示所有
SelectedEntityTypeLines = GameData.Monsters.AllLines.Concat(GameData.Gadgets.AllLines).ToArray();
LoadEntityList();
}
/// <summary>
/// 当前选中的实体类型行
/// </summary>
private string[] SelectedEntityTypeLines;
/// <summary>
/// 实体类型过滤器类型选中时触发
/// </summary>
private void OnEntityTypeFilterClick(object sender, EventArgs e)
{
var btn = sender as ToolStripMenuItem;
SelectedEntityTypeLines = btn.Tag as string[];
LoadEntityList();
}
/// <summary>
/// 加载实体列表
/// </summary>
private void LoadEntityList()
{
UIUtil.ListBoxFilter(ListEntity, SelectedEntityTypeLines, TxtEntityFilter.Text);
}
/// <summary>
/// 实体列表过滤器文本改变时触发
/// </summary>
private void TxtEntityFilter_TextChanged(object sender, EventArgs e)
{
LoadEntityList();
}
/// <summary>
/// 实体列表类型过滤按钮点击时触发
/// </summary>
private void BtnFilterEntity_Click(object sender, EventArgs e)
{
MenuSpawnEntityFilter.Show(BtnFilterEntity, 0, BtnFilterEntity.Height);
}
/// <summary>
/// 实体列表选中项改变时触发
/// </summary>
private void ListEntity_SelectedIndexChanged(object sender, EventArgs e)
{
// 根据当前所在页面确定要做的事情
// 攻击修改界面
if (TCSpawnSettings.SelectedTab == TPAttackModArgs)
{
OnAttackModifierInputChanged(sender, e);
}
// 攻击注入界面
else if (TCSpawnSettings.SelectedTab == TPAttackInfusedArgs)
{
// 无事发生,因为要页面上点击按钮才会生成命令
}
// 生成参数界面 或其它
else
{
// 触发输入改变事件
SpawnEntityInputChanged(sender, e);
}
}
#endregion
#region -- --
/// <summary>
/// 生成命令记录文件路径
/// </summary>
private readonly string SpawnCommandsRecordPath = Path.Combine(Application.LocalUserAppDataPath, "SpawnCommands.txt");
/// <summary>
/// 生成命令记录
/// </summary>
private List<GameCommand> SpawnCommands;
/// <summary>
/// 初始化生成记录
/// </summary>
private void InitSpawnRecord()
{
if (File.Exists(SpawnCommandsRecordPath))
{
SpawnCommands = GetCommands(File.ReadAllText(SpawnCommandsRecordPath));
ListSpawnLogs.Items.AddRange(SpawnCommands.Select(c => c.Name).ToArray());
}
else
{
SpawnCommands = new List<GameCommand>();
}
}
/// <summary>
/// 保存生成记录
/// </summary>
private void SaveSpawnRecord()
{
File.WriteAllText(SpawnCommandsRecordPath, GetCommandsText(SpawnCommands));
}
/// <summary>
/// 生成记录列表选中项改变时触发
/// </summary>
private void ListSpawnLogs_SelectedIndexChanged(object sender, EventArgs e)
{
if (ListSpawnLogs.SelectedIndex >= 0)
{
BtnRemoveSpawnLog.Enabled = true;
SetCommand(SpawnCommands[ListSpawnLogs.SelectedIndex].Command);
}
else
{
BtnRemoveSpawnLog.Enabled = false;
}
}
/// <summary>
/// 点击保存生成记录按钮时触发
/// </summary>
private void BtnSaveSpawnLog_Click(object sender, EventArgs e)
{
// 不再重新生成,直接记录当前命令行的内容
//if (GenSpawnEntityCommand())
{
var cmd = new GameCommand($"{ListEntity.SelectedItem} | {TxtCommand.Text}", TxtCommand.Text);
SpawnCommands.Add(cmd);
ListSpawnLogs.Items.Add(cmd.Name);
SaveSpawnRecord();
}
}
/// <summary>
/// 点击移除生成记录按钮时触发
/// </summary>
private void BtnRemoveSpawnLog_Click(object sender, EventArgs e)
{
if (ListSpawnLogs.SelectedIndex >= 0)
{
SpawnCommands.RemoveAt(ListSpawnLogs.SelectedIndex);
ListSpawnLogs.Items.RemoveAt(ListSpawnLogs.SelectedIndex);
SaveSpawnRecord();
}
}
/// <summary>
/// 点击清空生成记录按钮时触发
/// </summary>
private void LblClearSpawnLogs_Click(object sender, EventArgs e)
{
if (MessageBox.Show(Resources.AskConfirmDeletion, Resources.Tips, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
SpawnCommands.Clear();
ListSpawnLogs.Items.Clear();
SaveSpawnRecord();
}
}
#endregion -- --
#region -- --
/// <summary>
/// 生成页面输入改变时触发
/// </summary>
private void SpawnEntityInputChanged(object sender, EventArgs e)
{
if (ListEntity.SelectedIndex == -1) return;
var selectedItem = ListEntity.SelectedItem as string;
var id = ItemMap.ToId(selectedItem);
if (CommandVersion.Check(CommandVersion.V1_3_1))
{
var args = id.ToString();
void CheckAndConnect(NumericUpDown input, int value, string prefix)
{
if (input.Value > value)
args += prefix + input.Value;
}
CheckAndConnect(NUDEntityAmout, 1, " x");
CheckAndConnect(NUDEntityLevel, 1, " lv");
CheckAndConnect(NUDEntityHp, -1, " hp");
CheckAndConnect(NUDEntityMaxHp, 0, " maxhp");
CheckAndConnect(NUDEntityAtk, -1, " atk");
CheckAndConnect(NUDEntityDef, -1, " def");
if (NUDEntityPosX.Value != 0 || NUDEntityPosY.Value != 0 || NUDEntityPosZ.Value != 0)
args += $" {NUDEntityPosX.Value} {NUDEntityPosY.Value} {NUDEntityPosZ.Value}";
SetCommand("/spawn", args);
}
else
{
SetCommand("/spawn", $"{id} {NUDEntityAmout.Value} {NUDEntityLevel.Value}");
}
}
#endregion
#region -- --
/// <summary>
/// 攻击修改插件链接标签点击时触发
/// </summary>
private void LnkAttackModifierPlugin_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
OpenURL("https://github.com/NotThorny/AttackModifier");
}
/// <summary>
/// 攻击修改输入改变事件
/// </summary>
private void OnAttackModifierInputChanged(object sender, EventArgs e)
{
if (ListEntity.SelectedIndex == -1) return;
var selectedItem = ListEntity.SelectedItem as string;
var id = ItemMap.ToId(selectedItem);
char skill;
if (RbAtE.Checked)
{
skill = 'e';
TxtAtEntityE.Text = selectedItem;
}
else if (RbAtQ.Checked)
{
skill = 'q';
TxtAtEntityQ.Text = selectedItem;
}
else
{
skill = 'n';
TxtAtEntityN.Text = selectedItem;
}
SetCommand("/at", $"set {skill} {id}");
}
/// <summary>
/// 攻击修改页面命令事件
/// </summary>
private void OnAttackModifierCommand(object sender, EventArgs e)
{
SetCommand("/at", (sender as Control).Tag as string);
}
#endregion
#region -- --
/// <summary>
/// 攻击注入插件链接标签点击时触发
/// </summary>
private void LnkAttackInfusedWithItem_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
OpenURL("https://github.com/snoobi-seggs/AttackInfusedWithItem");
}
/// <summary>
/// 攻击注入页面命令事件
/// </summary>
private void OnAttackInfusedCommand(object sender, EventArgs e)
{
SetCommand("/at", (sender as Control).Tag as string);
}
/// <summary>
/// 点击攻击注入按钮时触发
/// </summary>
private void BtnAttackInfuse_Click(object sender, EventArgs e)
{
if (ListEntity.SelectedIndex == -1) return;
var selectedItem = ListEntity.SelectedItem as string;
var id = ItemMap.ToId(selectedItem);
var args = string.Empty;
var flag = false;
void ConnectArg(NumericUpDown input)
{
if (flag || input.Value != 0)
{
flag = true;
args = " " + input.Value + args;
}
}
ConnectArg(NUDAiwiRotateZ);
ConnectArg(NUDAiwiRotateY);
ConnectArg(NUDAiwiRotateX);
ConnectArg(NUDAiwiSpread);
ConnectArg(NUDAiwiCount);
ConnectArg(NUDAiwiHeight);
ConnectArg(NUDAiwiRadius);
SetCommand("/at", id.ToString() + args);
//SetCommand("/at", $"{id} {NUDAiwiRadius.Value} {NUDAiwiHeight.Value} {NUDAiwiCount.Value} {NUDAiwiSpread.Value} {NUDAiwiRotateX.Value} {NUDAiwiRotateY.Value} {NUDAiwiRotateZ.Value}");
}
#endregion
#endregion - Spawns -
#region - Scenes -
/// <summary>
/// 初始化场景列表
/// </summary>
private void InitScenes()
{
ListScenes.Items.Clear();
ListScenes.Items.AddRange(GameData.Scenes.Lines);
CmbClimateType.Items.Clear();
CmbClimateType.Items.AddRange(Resources.ClimateType.Split(','));
}
/// <summary>
/// 场景列表过滤器输入项改变时触发
/// </summary>
private void TxtSceneFilter_TextChanged(object sender, EventArgs e)
{
UIUtil.ListBoxFilter(ListScenes, GameData.Scenes.Lines, TxtSceneFilter.Text);
}
/// <summary>
/// 场景列表选中项改变时触发
/// </summary>
private void ListScenes_SelectedIndexChanged(object sender, EventArgs e)
{
if (ListScenes.SelectedIndex < 0)
{
ChkIncludeSceneId.Enabled = false;
return;
}
ChkIncludeSceneId.Enabled = true;
// 可以直接弃用 scene 命令
var name = ListScenes.SelectedItem as string;
var id = ItemMap.ToId(name);
if (CommandVersion.Check(CommandVersion.V1_2_2))
{
SetCommand("/scene", id.ToString());
}
else
{
SetCommand("/tp ~ ~ ~", id.ToString());
}
}
/// <summary>
/// 气候类型列表
/// </summary>
static readonly string[] climateTypes = { "none", "sunny", "cloudy", "rain", "thunderstorm", "snow", "mist" };
/// <summary>
/// 气候类型下拉框选中项改变时触发
/// </summary>
private void CmbClimateType_SelectedIndexChanged(object sender, EventArgs e)
{
if (CmbClimateType.SelectedIndex < 0)
return;
if (CommandVersion.Check(CommandVersion.V1_2_2))
SetCommand("/weather", CmbClimateType.SelectedIndex < climateTypes.Length ? climateTypes[CmbClimateType.SelectedIndex] : "none");
else
SetCommand("/weather", $"0 {CmbClimateType.SelectedIndex}");
}
/// <summary>
/// 点击传送按钮时触发
/// </summary>
private void BtnTeleport_Click(object sender, EventArgs e)
{
string args = $"{NUDTpX.Value} {NUDTpY.Value} {NUDTpZ.Value}";
if (ChkIncludeSceneId.Checked && ListScenes.SelectedIndex != -1)
args += $" {GameData.Scenes.Ids[ListScenes.SelectedIndex]}";
SetCommand("/tp", args);
}
#endregion - Scenes -
#region - Management -
/// <summary>
/// 初始化权限列表
/// </summary>
private void InitPermList()
{
CmbPerm.Items.Clear();
CmbPerm.Items.AddRange(Resources.Permissions.Split('\n').Select(l => l.Trim()).ToArray());
}
/// <summary>
/// 点击授权按钮时触发
/// </summary>
private void BtnPermClick(object sender, EventArgs e)
{
var uid = NUDPermUID.Value;
var perm = CmbPerm.Text.Trim();
var act = (sender as Button).Tag.ToString();
if (act == "list" || act == "clear")
{
SetCommand($"/permission {act} @{uid}");
}
else
{
if (string.IsNullOrEmpty(perm))
{
MessageBox.Show(Resources.PermissionCannotBeEmpty, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
SetCommand($"/permission {act} @{uid} {perm}");
}
}
/// <summary>
/// 账号相关按钮点击时触发Tag包含子命令
/// </summary>
private void AccountButtonClicked(object sender, EventArgs e)
{
var username = TxtAccountUserName.Text.Trim();
if (string.IsNullOrEmpty(username))
{
MessageBox.Show(Resources.UsernameCannotBeEmpty, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
SetCommand($"/account {(sender as Button).Tag} {username} {(ChkAccountSetUid.Checked ? NUDAccountUid.Value.ToString() : "")}");
}
/// <summary>
/// 点击封禁按钮时触发
/// </summary>
private void BtnBan_Click(object sender, EventArgs e)
{
var uid = NUDBanUID.Value;
var endTime = DTPBanEndTime.Value;
var command = $"/ban @{uid} {new DateTimeOffset(endTime).ToUnixTimeSeconds()}";
var reaseon = Regex.Replace(TxtBanReason.Text.Trim(), @"\s+", "-");
if (!string.IsNullOrEmpty(reaseon))
command += $" {reaseon}";
SetCommand(command);
}
/// <summary>
/// 点击解封按钮时触发
/// </summary>
private void BtnUnban_Click(object sender, EventArgs e)
{
SetCommand($"/unban @{NUDBanUID.Value}");
}
#endregion - Management -
#region - Mail -
/// <summary>
/// 初始化邮件页面
/// </summary>
private void InitMailPage()
{
TxtMailSender.Text = Settings.Default.DefaultMailSender;
LoadMailSelectableItems();
}
/// <summary>
/// 保存邮件设置
/// </summary>
private void SaveMailSettings()
{
Settings.Default.DefaultMailSender = TxtMailSender.Text;
}
/// <summary>
/// 点击清空邮件内容时触发
/// </summary>
private void LblClearMailContent_Click(object sender, EventArgs e)
{
TxtMailContent.Clear();
}
/// <summary>
/// 点击发送邮件时触发
/// </summary>
private void BtnSendMail_Click(object sender, EventArgs e)
{
var mail = new Mail
{
Title = TxtMailTitle.Text.Trim(),
Sender = TxtMailSender.Text.Trim(),
Content = TxtMailContent.Text.Trim(),
Recipient = RbMailSendToAll.Checked ? 0 : (int)NUDMailRecipient.Value,
ItemList = new List<MailItem>(MailItems),
SendTime = DateTime.Now,
};
if (mail.Title == "" || mail.Sender == "" || mail.Content == "")
{
MessageBox.Show(Resources.EmptyInputTip, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (mail.SendToAll)
{
MessageBox.Show(Resources.MailSendToAllWarning, Resources.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
var cmd = $"/sendMail {(mail.SendToAll ? "all" : mail.Recipient.ToString())} |" +
$"/sendMail {mail.Title} |" +
$"/sendMail {mail.Content.Replace("\r", "\\r").Replace("\n", "\\n")} |" +
$"/sendMail {mail.Sender} |";
foreach (var item in mail.ItemList)
cmd += $"/sendMail {item.ItemId} {item.ItemCount} {item.ItemLevel} |";
cmd += "/sendMail finish";
SetCommand(cmd);
AddMailToList(mail);
}
/// <summary>
/// 展示邮件
/// </summary>
/// <param name="mail"></param>
private void ShowMail(Mail mail)
{
TxtMailTitle.Text = mail.Title;
TxtMailSender.Text = mail.Sender;
TxtMailContent.Text = mail.Content;
NUDMailRecipient.Value = mail.Recipient;
RbMailSendToAll.Checked = mail.SendToAll;
RbMailSendToPlayer.Checked = !mail.SendToAll;
ShowMailItems(mail.ItemList);
}
#region -- Mail items --
/// <summary>
/// 当前邮件附件列表
/// </summary>
private readonly List<MailItem> MailItems = new List<MailItem>();
/// <summary>
/// 展示邮件附件列表
/// </summary>
/// <param name="items"></param>
private void ShowMailItems(List<MailItem> items)
{
MailItems.Clear();
MailItems.AddRange(items);
ListMailItems.BeginUpdate();
ListMailItems.Items.Clear();
ListMailItems.Items.AddRange(items.Select(it => it.ToString()).ToArray());
ListMailItems.EndUpdate();
}
/// <summary>
/// 点击添加邮件附件项时触发
/// </summary>
private void BtnAddMailItem_Click(object sender, EventArgs e)
{
if (ListMailSelectableItems.SelectedIndex == -1)
return;
var item = ListMailSelectableItems.SelectedItem as string;
var itemId = ItemMap.ToId(item);
var mailItem = new MailItem
{
ItemId = itemId,
ItemCount = (int)NUDMailItemCount.Value,
ItemLevel = (int)NUDMailItemLevel.Value,
};
MailItems.Add(mailItem);
ListMailItems.Items.Add(mailItem.ToString());
}
/// <summary>
/// 点击删除邮件附件项时触发
/// </summary>
private void BtnDeleteMailItem_Click(object sender, EventArgs e)
{
if (ListMailItems.SelectedIndex == -1) return;
MailItems.RemoveAt(ListMailItems.SelectedIndex);
ListMailItems.Items.RemoveAt(ListMailItems.SelectedIndex);
}
#endregion
#region -- Mail item selectable list --
private string[] MailSelectableItems;
/// <summary>
/// 加载附件可选项列表
/// </summary>
private void LoadMailSelectableItems()
{
MailSelectableItems = new string[GameData.Items.Count + GameData.Weapons.Count + GameData.Artifacts.Count];
int i = 0;
GameData.Items.Lines.CopyTo(MailSelectableItems, i); i += GameData.Items.Count;
GameData.Weapons.Lines.CopyTo(MailSelectableItems, i); i += GameData.Weapons.Count;
GameData.Artifacts.Lines.CopyTo(MailSelectableItems, i); i += GameData.Artifacts.Count;
Array.Sort(MailSelectableItems, (a, b) => ItemMap.ToId(a) - ItemMap.ToId(b));
ListMailSelectableItems.Items.Clear();
ListMailSelectableItems.Items.AddRange(MailSelectableItems);
}
/// <summary>
/// 邮件页面物品列表过滤器文本改变时触发
/// </summary>
private void TxtMailSelectableItemFilter_TextChanged(object sender, EventArgs e)
{
UIUtil.ListBoxFilter(ListMailSelectableItems, MailSelectableItems, TxtMailSelectableItemFilter.Text);
}
#endregion
#region -- Mail list --
/// <summary>
/// 获取物品记录文件路径
/// </summary>
private readonly string MailListPath = Path.Combine(Application.LocalUserAppDataPath, "MailList.json");
/// <summary>
/// 邮件列表
/// </summary>
private List<Mail> MailList = new List<Mail>();
/// <summary>
/// 初始化邮件列表
/// </summary>
private void InitMailList()
{
if (File.Exists(MailListPath))
{
MailList = JsonConvert.DeserializeObject<List<Mail>>(File.ReadAllText(MailListPath));
ListMailList.Items.AddRange(MailList.Select(it => it.ToString()).ToArray());
}
else
{
MailList = new List<Mail>();
}
}
/// <summary>
/// 保存邮件列表
/// </summary>
private void SaveMailList()
{
File.WriteAllText(MailListPath, JsonConvert.SerializeObject(MailList));
}
/// <summary>
/// 添加邮件到列表
/// </summary>
/// <param name="mail">邮件</param>
private void AddMailToList(Mail mail)
{
MailList.Add(mail);
ListMailList.Items.Add(mail.ToString());
SaveMailList();
}
/// <summary>
/// 邮件列表选中项改变时发生
/// </summary>
private void ListMailList_SelectedIndexChanged(object sender, EventArgs e)
{
if (ListMailList.SelectedIndex == -1) return;
// 显示选中邮件
var mail = MailList[ListMailList.SelectedIndex];
ShowMail(mail);
}
/// <summary>
/// 点击删除邮件按钮时触发
/// </summary>
private void BtnRemoveMail_Click(object sender, EventArgs e)
{
if (ListMailList.SelectedIndex == -1) return;
MailList.RemoveAt(ListMailList.SelectedIndex);
ListMailList.Items.RemoveAt(ListMailList.SelectedIndex);
SaveMailList();
}
/// <summary>
/// 点击清空邮件列表按钮时触发
/// </summary>
private void BtnClearMail_Click(object sender, EventArgs e)
{
if (MailList.Count == 0) return;
if (MessageBox.Show(Resources.AskConfirmDeletion, Resources.Tips, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
ListMailList.Items.Clear();
MailList.Clear();
SaveMailList();
}
}
#endregion
#endregion
#region - About -
/// <summary>
/// 点击Github链接时触发
/// </summary>
private void LnkGithub_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
OpenURL("https://github.com/jie65535/GrasscutterCommandGenerator");
}
#endregion - About -
#region - Command -
/// <summary>
/// 设置命令
/// </summary>
/// <param name="command">命令</param>
private void SetCommand(string command)
{
TxtCommand.Text = command;
if (ChkAutoCopy.Checked)
CopyCommand();
if (ModifierKeys == Keys.Control)
OnOpenCommandInvoke();
}
/// <summary>
/// 设置带参数的命令
/// </summary>
/// <param name="command">命令</param>
/// <param name="args">参数</param>
private void SetCommand(string command, string args)
{
if (ChkIncludeUID.Checked)
SetCommand($"{command} @{NUDUid.Value} {args.Trim()}");
else
SetCommand($"{command} {args.Trim()}");
}
/// <summary>
/// 点击复制按钮时触发
/// </summary>
private async void BtnCopy_Click(object sender, EventArgs e)
{
CopyCommand();
await UIUtil.ButtonComplete(BtnCopy);
}
/// <summary>
/// 复制命令
/// </summary>
private void CopyCommand()
{
if (!string.IsNullOrEmpty(TxtCommand.Text))
Clipboard.SetText(TxtCommand.Text);
}
/// <summary>
/// 开放命令执行时触发
/// </summary>
private void OnOpenCommandInvoke()
{
BtnInvokeOpenCommand_Click(BtnInvokeOpenCommand, EventArgs.Empty);
}
/// <summary>
/// 点击执行开放命令按钮时触发
/// </summary>
private async void BtnInvokeOpenCommand_Click(object sender, EventArgs e)
{
if (!BtnInvokeOpenCommand.Enabled) return;
if (TxtCommand.Text.Length < 2)
{
ShowTip(Resources.CommandContentCannotBeEmpty, TxtCommand);
return;
}
if (TxtCommand.Text.IndexOf('|') == -1)
await RunCommands(FormatCommand(TxtCommand.Text));
else
await RunCommands(TxtCommand.Text.Split('|').Select(it => FormatCommand(it)).ToArray());
}
/// <summary>
/// 格式化命令
/// (去除收尾空白,替换换行)
/// </summary>
/// <param name="raw">原始输入</param>
/// <returns>格式化后可执行命令</returns>
private string FormatCommand(string raw)
{
return raw.Trim().Replace("\\r", "\r").Replace("\\n", "\n");
}
/// <summary>
/// 运行命令
/// </summary>
/// <param name="commands">命令列表</param>
/// <returns>是否执行成功</returns>
private async Task<bool> RunCommands(params string[] commands)
{
if (OC == null || !OC.CanInvoke)
{
ShowTip(Resources.RequireOpenCommandTip, BtnInvokeOpenCommand);
TCMain.SelectedTab = TPRemoteCall;
return false;
}
ExpandCommandRunLog();
try
{
BtnInvokeOpenCommand.Enabled = false;
BtnInvokeOpenCommand.Cursor = Cursors.WaitCursor;
int i = 0;
foreach (var command in commands)
{
TxtCommandRunLog.AppendText(">");
TxtCommandRunLog.AppendText(command);
if (commands.Length > 1)
TxtCommandRunLog.AppendText($" ({++i}/{commands.Length})");
TxtCommandRunLog.AppendText(Environment.NewLine);
var cmd = command.TrimStart('/');
try
{
var msg = await OC.Invoke(cmd);
TxtCommandRunLog.AppendText(string.IsNullOrEmpty(msg) ? "OK" : msg);
TxtCommandRunLog.AppendText(Environment.NewLine);
}
catch (Exception ex)
{
TxtCommandRunLog.AppendText("Error: ");
TxtCommandRunLog.AppendText(ex.Message);
TxtCommandRunLog.AppendText(Environment.NewLine);
MessageBox.Show(ex.Message, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
TxtCommandRunLog.ScrollToCaret();
}
}
finally
{
BtnInvokeOpenCommand.Cursor = Cursors.Default;
BtnInvokeOpenCommand.Enabled = true;
}
return true;
}
/// <summary>
/// 命令日志最小高度
/// </summary>
private const int TxtCommandRunLogMinHeight = 150;
/// <summary>
/// 命令日志文本框
/// </summary>
private TextBox TxtCommandRunLog;
/// <summary>
/// 展开命令记录(可重入)
/// </summary>
private void ExpandCommandRunLog()
{
if (GrpCommand.Height < TxtCommandRunLogMinHeight)
{
if (WindowState == FormWindowState.Maximized)
WindowState = FormWindowState.Normal;
TCMain.Anchor &= ~AnchorStyles.Bottom;
GrpCommand.Anchor |= AnchorStyles.Top;
Size = new Size(Width, Height + TxtCommandRunLogMinHeight);
MinimumSize = new Size(MinimumSize.Width, MinimumSize.Height + TxtCommandRunLogMinHeight);
TCMain.Anchor |= AnchorStyles.Bottom;
GrpCommand.Anchor &= ~AnchorStyles.Top;
}
if (TxtCommandRunLog == null)
{
TxtCommandRunLog = new TextBox
{
Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom,
Multiline = true,
Font = new Font("Consolas", 9F),
Location = new Point(BtnInvokeOpenCommand.Left, BtnInvokeOpenCommand.Bottom + 6),
Size = new Size(GrpCommand.Width - BtnInvokeOpenCommand.Left * 2, TxtCommandRunLogMinHeight),
ReadOnly = true,
BackColor = Color.White,
ScrollBars = ScrollBars.Vertical,
};
GrpCommand.Controls.Add(TxtCommandRunLog);
}
}
#endregion - Command -
#region - General -
/// <summary>
/// 窗口按键按下时触发
/// </summary>
private void FormMain_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F5)
{
// F5 为执行命令
OnOpenCommandInvoke();
}
}
/// <summary>
/// 提示气泡对象
/// </summary>
private readonly ToolTip TTip = new ToolTip();
/// <summary>
/// 在指定控件上显示提示气泡
/// </summary>
/// <param name="message">消息</param>
/// <param name="control">控件</param>
private void ShowTip(string message, Control control)
{
TTip.Show(message, control, 0, control.Size.Height, 3000);
}
#endregion - General -
#region - Command Logs -
/// <summary>
/// 获取命令记录
/// (反序列化)
/// </summary>
/// <param name="commandsText">命令记录文本(示例:"标签1\n命令1\n标签2\n命令2..."</param>
/// <returns>命令列表</returns>
private List<GameCommand> GetCommands(string commandsText)
{
var lines = commandsText.Split('\n');
List<GameCommand> commands = new List<GameCommand>(lines.Length / 2);
for (int i = 0; i < lines.Length - 1; i += 2)
commands.Add(new GameCommand(lines[i].Trim(), lines[i + 1].Trim()));
return commands;
}
/// <summary>
/// 获取命令记录文本
/// (序列化)
/// </summary>
/// <param name="commands">命令列表</param>
/// <returns>命令记录文本(示例:"标签1\n命令1\n标签2\n命令2..."</returns>
private string GetCommandsText(List<GameCommand> commands)
{
StringBuilder builder = new StringBuilder();
foreach (var cmd in commands)
{
builder.AppendLine(cmd.Name);
builder.AppendLine(cmd.Command);
}
return builder.ToString();
}
#endregion - Command Logs -
#region - Remote -
/// <summary>
/// 开放命令接口
/// </summary>
private OpenCommandAPI OC;
/// <summary>
/// 进入远程页面时触发
/// </summary>
private void TPRemoteCall_Enter(object sender, EventArgs e)
{
#if !DEBUG
if (string.IsNullOrEmpty(Settings.Default.Host) || string.IsNullOrEmpty(Settings.Default.TokenCache))
{
// 自动尝试查询本地服务端地址,降低使用门槛
Task.Run(async () =>
{
var localhosts = new string[] {
"http://127.0.0.1:443",
"https://127.0.0.1",
"http://127.0.0.1",
"https://127.0.0.1:80",
"http://127.0.0.1:8080",
"https://127.0.0.1:8080",
};
foreach (var host in localhosts)
{
try
{
await UpdateServerStatus(host);
// 自动填写本地服务端地址
TxtHost.Text = host;
break;
}
catch (Exception)
{
// Ignore
}
}
});
}
#endif
}
/// <summary>
/// 初始化开放命令
/// </summary>
private void InitOpenCommand()
{
NUDRemotePlayerId.Value = Settings.Default.RemoteUid;
TxtHost.Text = Settings.Default.Host;
if (!string.IsNullOrEmpty(Settings.Default.Host) && !string.IsNullOrEmpty(Settings.Default.TokenCache))
{
OC = new OpenCommandAPI(Settings.Default.Host, Settings.Default.TokenCache);
TxtToken.Text = Settings.Default.TokenCache;
Task.Run(async () =>
{
await Task.Delay(1000);
BeginInvoke(new Action(() => ShowTip(Resources.TokenRestoredFromCache, BtnInvokeOpenCommand)));
});
}
}
/// <summary>
/// 保存开放命令参数
/// </summary>
private void SaveOpenCommand()
{
Settings.Default.RemoteUid = NUDRemotePlayerId.Value;
Settings.Default.Host = TxtHost.Text;
Settings.Default.TokenCache = OC?.Token;
}
/// <summary>
/// 更新服务器状态
/// </summary>
/// <param name="host">主机地址</param>
private async Task UpdateServerStatus(string host)
{
// "http://127.0.0.1/" -> "http://127.0.0.1"
host = host.TrimEnd('/');
var status = await DispatchServerAPI.QueryServerStatus(host);
LblServerVersion.Text = status.Version;
if (status.MaxPlayer >= 0)
LblPlayerCount.Text = $"{status.PlayerCount}/{status.MaxPlayer}";
else
LblPlayerCount.Text = status.PlayerCount.ToString();
}
/// <summary>
/// 点击查询服务器状态按钮时触发
/// </summary>
private async void BtnQueryServerStatus_Click(object sender, EventArgs e)
{
var btn = sender as Button;
btn.Enabled = false;
btn.Cursor = Cursors.WaitCursor;
try
{
try
{
await UpdateServerStatus(TxtHost.Text);
}
catch (Exception ex)
{
MessageBox.Show(Resources.QueryServerStatusFailed + ex.Message, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
OC = new OpenCommandAPI(TxtHost.Text);
if (await OC.Ping())
{
LblOpenCommandSupport.Text = "√";
LblOpenCommandSupport.ForeColor = Color.Green;
GrpRemoteCommand.Enabled = true;
}
else
{
LblOpenCommandSupport.Text = "×";
LblOpenCommandSupport.ForeColor = Color.Red;
GrpRemoteCommand.Enabled = false;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
btn.Cursor = Cursors.Default;
btn.Enabled = true;
}
}
/// <summary>
/// 点击发送校验码按钮时触发
/// </summary>
private async void BtnSendVerificationCode_Click(object sender, EventArgs e)
{
var btn = sender as Button;
var t = btn.Text;
btn.Enabled = false;
NUDRemotePlayerId.Enabled = false;
try
{
btn.Text = Resources.CodeSending;
await OC.SendCode((int)NUDRemotePlayerId.Value);
BtnConnectOpenCommand.Enabled = true;
NUDVerificationCode.Enabled = true;
NUDVerificationCode.Focus();
for (int i = 60; i > 0 && !OC.CanInvoke; i--)
{
btn.Text = string.Format(Resources.CodeResendTip, i);
await Task.Delay(1000);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
btn.Text = t;
btn.Enabled = true;
NUDRemotePlayerId.Enabled = true;
}
}
/// <summary>
/// 点击连接到开放命令按钮时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void BtnConnectOpenCommand_Click(object sender, EventArgs e)
{
var btn = sender as Button;
btn.Enabled = false;
try
{
await OC.Verify((int)NUDVerificationCode.Value);
GrpRemoteCommand.Enabled = false;
BtnInvokeOpenCommand.Focus();
ShowTip(Resources.ConnectedTip, BtnInvokeOpenCommand);
ButtonOpenGOODImport.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
btn.Cursor = Cursors.Default;
btn.Enabled = true;
}
}
/// <summary>
/// 点击控制台连接按钮时触发
/// </summary>
private void BtnConsoleConnect_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(TxtToken.Text))
{
MessageBox.Show(Resources.TokenCannotBeEmpty, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
OC.Token = TxtToken.Text;
BtnConnectOpenCommand_Click(sender, e);
}
/// <summary>
/// 点击开放命令标签时触发
/// </summary>
private void LnkOpenCommandLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
OpenURL("https://github.com/jie65535/gc-opencommand-plugin");
}
/// <summary>
/// 点击帮助连接标签时触发
/// </summary>
private void LnkRCHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
MessageBox.Show(Resources.OpenCommandHelp, Resources.Help, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
/// <summary>
/// 点击库存扫描链接标签时触发
/// </summary>
private void LnkInventoryKamera_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
OpenURL("https://github.com/Andrewthe13th/Inventory_Kamera");
}
/// <summary>
/// 点击GOOD帮助链接标签时触发
/// </summary>
private void LnkGOODHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
OpenURL("https://frzyc.github.io/genshin-optimizer/#/doc");
}
/// <summary>
/// 点击链接帮助标签时触发
/// </summary>
private void LnkLinks_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
var links = new List<string>
{
"https://frzyc.github.io/genshin-optimizer/",
"https://genshin.aspirine.su/",
"https://genshin.mingyulab.com/",
"https://genshin-center.com/",
"https://github.com/Andrewthe13th/Inventory_Kamera",
"https://github.com/daydreaming666/Amenoma",
"https://seelie.me/",
"https://www.mona-uranai.com/",
};
MessageBox.Show(string.Join("\n", links), "Links", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
/// <summary>
/// 使用浏览器打开网址
/// </summary>
/// <param name="url">网址</param>
private void OpenURL(string url)
{
try
{
System.Diagnostics.Process.Start(url);
}
catch (Exception)
{
MessageBox.Show(Resources.BrowserOpenFailedTip + "\n " + url,
Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
#endregion - Remote -
#region - GOOD -
/// <summary>
/// 点击GOOD导入存档按钮时触发
/// </summary>
async private void ButtonOpenGOODImport_Click(object sender, EventArgs e)
{
if (OC == null || !OC.CanInvoke)
{
ShowTip(Resources.RequireOpenCommandTip, BtnInvokeOpenCommand);
return;
}
OpenFileDialog openFileDialog1 = new OpenFileDialog
{
Filter = "GOOD file (*.GOOD;*.json)|*.GOOD;*.json|All files (*.*)|*.*",
};
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
if (DialogResult.Yes != MessageBox.Show(Resources.GOODImportText + openFileDialog1.FileName + "?",
Resources.GOODImportTitle, MessageBoxButtons.YesNo))
return;
try
{
GOOD.GOOD good = JsonConvert.DeserializeObject<GOOD.GOOD>(File.ReadAllText(openFileDialog1.FileName));
var commands_list = new List<string>();
var missingItems = new List<string>();
if (good.Characters != null)
{
foreach (var character in good.Characters)
{
if (character.Name != "Traveler")
{
if (GOODData.Avatars.TryGetValue(character.Name, out var character_id))
{
if (CommandVersion.Check(CommandVersion.V1_4_1))
{
// 取最低的技能等级
var skillLevel = Math.Min(Math.Min(character.Talents.Auto, character.Talents.Skill), character.Talents.Burst);
commands_list.Add($"/give {character_id} lv{character.Level} c{character.Constellation} sl{skillLevel}");
}
else
commands_list.Add($"/give {character_id} lv{character.Level} c{character.Constellation}");
}
else
missingItems.Add(character.Name);
// TODO: Implement command to set talent level when giving character in Grasscutter
}
}
}
if (good.Weapons != null)
{
foreach (var weapon in good.Weapons)
{
if (GOODData.Weapons.TryGetValue(weapon.Name, out var weapon_id))
commands_list.Add($"/give {weapon_id} lv{weapon.Level} r{weapon.RefinementLevel}");
else
missingItems.Add(weapon.Name);
// TODO: Implement command to give weapon directly to character in Grasscutter
}
}
if (good.Artifacts != null)
{
foreach (var artifact in good.Artifacts)
{
// Format: set rarity slot
if (!GOODData.ArtifactCats.TryGetValue(artifact.SetName, out var artifact_set_id))
{
missingItems.Add(artifact.SetName);
continue;
}
var artifact_id = artifact_set_id * 1000 + artifact.Rarity * 100 + GOODData.ArtifactSlotMap[artifact.GearSlot] * 10;
for (int i = 4; i > 0; i--)
{
if (Array.IndexOf(GameData.Artifacts.Ids, artifact_id + i) != -1)
{
artifact_id += i;
break;
}
}
if (artifact_id % 10 == 0)
artifact_id += 4;
var artifact_mainStat_id = GOODData.ArtifactMainAttribution[artifact.MainStat];
var artifact_substats = "";
var artifact_substat_prefix = artifact.Rarity + "0";
int substat_count = 0;
foreach (var substat in artifact.SubStats)
{
if (substat.Value <= 0)
continue;
substat_count++;
var substat_key = substat.Stat;
var substat_key_id = GOODData.ArtifactSubAttribution[substat_key];
var substat_indices = ArtifactUtils.SplitSubstats(substat_key, artifact.Rarity, substat.Value);
foreach (int index in substat_indices)
{
artifact_substats += artifact_substat_prefix + substat_key_id + index.ToString() + " ";
}
}
// HACK: Add def+2 substat to counteract Grasscutter automatically adding another substat
if (substat_count == 4)
artifact_substats += "101081 ";
commands_list.Add($"/give {artifact_id} lv{artifact.Level} {artifact_mainStat_id} {artifact_substats}");
// TODO: Implement command to give artifact directly to character in Grasscutter
}
}
// TODO: Materials
//if (good.Materials != null)
//{
// foreach (var material in good.Materials)
// {
// }
//}
var msg = string.Format("Loaded {0} Characters\nLoaded {1} Weapons\nLoaded {2} Artifacts\n",
good.Characters?.Count ?? 0,
good.Weapons?.Count ?? 0,
good.Artifacts?.Count ?? 0
);
if (missingItems.Count > 0)
{
msg += string.Format("There are {0} pieces of data that cannot be parsed, including:\n{1}",
missingItems.Count,
string.Join("\n", missingItems.Take(10)));
if (missingItems.Count > 10)
msg += "......";
}
msg += "Do you want to start?";
if (DialogResult.Yes != MessageBox.Show(msg, Resources.Tips, MessageBoxButtons.YesNo, MessageBoxIcon.Information))
return;
if (await RunCommands(commands_list.ToArray()))
MessageBox.Show(Resources.GOODImportSuccess);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
#endregion
#region - Quests -
/// <summary>
/// 初始化任务列表
/// </summary>
private void InitQuestList()
{
QuestFilterChanged(null, EventArgs.Empty);
}
/// <summary>
/// 任务列表过滤器文本改变时触发
/// </summary>
private void QuestFilterChanged(object sender, EventArgs e)
{
ListQuest.BeginUpdate();
ListQuest.Items.Clear();
ListQuest.Items.AddRange(GameData.Quests.Lines.Where(l =>
{
if (!ChkQuestFilterHIDDEN.Checked && l.Contains((string)ChkQuestFilterHIDDEN.Tag))
return false;
if (!ChkQuestFilterUNRELEASED.Checked && l.Contains((string)ChkQuestFilterUNRELEASED.Tag))
return false;
if (!ChkQuestFilterTEST.Checked && l.Contains((string)ChkQuestFilterTEST.Tag))
return false;
if (!string.IsNullOrEmpty(TxtQuestFilter.Text))
return l.Contains(TxtQuestFilter.Text);
return true;
}).ToArray());
ListQuest.EndUpdate();
}
/// <summary>
/// 任务相关按钮点击时触发Tag带子命令
/// </summary>
private void QuestButsClicked(object sender, EventArgs e)
{
if (ListQuest.SelectedIndex == -1)
return;
var item = ListQuest.SelectedItem as string;
var id = ItemMap.ToId(item);
SetCommand("/quest", $"{(sender as Button).Tag} {id}");
}
#endregion - Quests -
}
}