/** * 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 . * **/ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows.Forms; using GrasscutterTools.Game; using GrasscutterTools.Game.Drop; using GrasscutterTools.Properties; using GrasscutterTools.Utils; using Newtonsoft.Json; namespace GrasscutterTools.Forms { public partial class FormDropEditor : Form { #region - 成员 - /// /// 掉落池 /// Key:怪物ID /// Value:掉落列表 /// private Dictionary> Banners; /// /// 怪物集 /// private readonly string[] Monsters; /// /// 当前选中项的掉落列表 /// (当选中多条时,数据为交集) /// private readonly List SelectedDropList = new List(); /// /// 掉落物剪贴板 /// private readonly List DropClipboard = new List(); #endregion - 成员 - #region - 构造与窗体事件 - public FormDropEditor() { InitializeComponent(); Icon = Resources.IconGrasscutter; Monsters = GameData.Monsters.AllLines.ToArray(); Array.Sort(Monsters); ListMonsters.Items.AddRange(Monsters); ListItems.Items.AddRange(GameData.Items.Lines); Banners = new Dictionary>(); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); try { // 加载文件路径 var path = Settings.Default.DropJsonPath; TxtDropJsonPath.Text = path; if (!string.IsNullOrEmpty(path) && File.Exists(path)) LoadBanners(path); } catch (Exception ex) { MessageBox.Show(ex.ToString(), Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); } } protected override void OnFormClosed(FormClosedEventArgs e) { // 保存文件路径 Settings.Default.DropJsonPath = TxtDropJsonPath.Text; Settings.Default.Save(); base.OnFormClosed(e); } #endregion - 构造与窗体事件 - #region - Drop.json 文件相关 - /// /// 加载按钮点击时触发 /// private void BtnLoad_Click(object sender, EventArgs e) { try { var path = TxtDropJsonPath.Text.Trim(); if (path == string.Empty) { var dialog = new OpenFileDialog { FileName = "Drop.json", Filter = "Drop.Json (*.json)|*.json|All files (*.*)|*.*", }; var result = dialog.ShowDialog(); if (result == DialogResult.OK) path = TxtDropJsonPath.Text = dialog.FileName; else return; } // 反序列化 LoadBanners(path); MessageBox.Show("OK", Resources.Tips, MessageBoxButtons.OK); } catch (Exception ex) { MessageBox.Show(ex.ToString(), Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void LoadBanners(string path) { // 反序列化 var banners = JsonConvert.DeserializeObject>(File.ReadAllText(path)); Banners = new Dictionary>(banners.Count); foreach (var item in banners) Banners.Add(item.MonsterId, item.DropDataList); } /// /// 保存按钮点击时触发 /// private void BtnSave_Click(object sender, EventArgs e) { try { var path = TxtDropJsonPath.Text.Trim(); if (path == string.Empty) { var dialog = new SaveFileDialog { FileName = "Drop.json", Filter = "Drop.json (*.json)|*.json|All files (*.*)|*.*", }; var result = dialog.ShowDialog(); if (result == DialogResult.OK) path = TxtDropJsonPath.Text = dialog.FileName; else return; } // 序列化 var banners = new List(Banners.Count); foreach (var item in Banners) { banners.Add(new DropInfo { MonsterId = item.Key, DropDataList = item.Value, }); } File.WriteAllText(path, JsonConvert.SerializeObject(banners)); MessageBox.Show("OK", Resources.Tips, MessageBoxButtons.OK); } catch (Exception ex) { MessageBox.Show(ex.ToString(), Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); } } #endregion - Drop.json 文件相关 - #region - 怪物列表 - /// /// 怪物列表过滤器文本改变时触发 /// private void TxtMonsterFilter_TextChanged(object sender, EventArgs e) { UIUtil.ListBoxFilter(ListMonsters, Monsters, TxtMonsterFilter.Text); } /// /// 遍历选中项怪物Id集合 /// private IEnumerable SelectedMonsterIds() { foreach (string item in ListMonsters.SelectedItems) yield return ItemMap.ToId(item); } /// /// 怪物列表选中项改变时触发 /// private void ListMonsters_SelectedIndexChanged(object sender, EventArgs e) { if (ListMonsters.SelectedItems.Count == 0) return; // 掉落物列表标题显示 var sp = GrpDropList.Text.IndexOf(" | "); if (sp >= 0) GrpDropList.Text = GrpDropList.Text.Remove(sp); if (ListMonsters.SelectedItems.Count == 1) { var item = ListMonsters.SelectedItem as string; GrpDropList.Text += " | " + item; } else { GrpDropList.Text += " | Monsters x" + ListMonsters.SelectedItems.Count.ToString(); } // 获取选中项中相同的掉落物集合(仅物品、掉落数量、掉落概率完全一致的显示) SelectedDropList.Clear(); var first = true; foreach (var monsterId in SelectedMonsterIds()) { if (Banners.TryGetValue(monsterId, out List dropList)) { if (first) { SelectedDropList.AddRange(dropList); first = false; } else if (SelectedDropList.Count > 0) { // 仅保留交集 var intersect = SelectedDropList.Intersect(dropList).ToList(); SelectedDropList.Clear(); SelectedDropList.AddRange(intersect); } else { break; } } else { SelectedDropList.Clear(); break; } } ShowDropList(SelectedDropList); } /// /// 显示指定掉落列表 /// /// 掉落物列表 private void ShowDropList(List dropList) { // 显示到列表 ListDropData.BeginUpdate(); ListDropData.Items.Clear(); if (dropList.Count > 0) { ListDropData.Items.AddRange(dropList.Select(it => it.ToString()).ToArray()); ListDropData.SelectedIndex = 0; } ListDropData.EndUpdate(); } #endregion - 怪物列表 - #region - 掉落物列表 - /// /// 掉落列表选中项改变时触发 /// private void ListDropData_SelectedIndexChanged(object sender, EventArgs e) { if (ListDropData.SelectedIndex == -1) return; var dropData = SelectedDropList[ListDropData.SelectedIndex]; TxtItem.Text = $"{dropData.ItemId} : {GameData.Items[dropData.ItemId]}"; NUDMinCount.Value = dropData.MinCount; NUDMaxCount.Value = dropData.MaxCount; NUDMinWeight.Value = dropData.MinWeight; NUDMaxWeight.Value = dropData.MaxWeight; //BtnCopy.Enabled = true; //BtnDelete.Enabled = true; //BtnAddOrUpdate.Enabled = true; } /// /// 点击复制按钮时触发 /// private async void BtnCopy_Click(object sender, EventArgs e) { if (ListDropData.SelectedIndex == -1) return; DropClipboard.Clear(); DropClipboard.Add(SelectedDropList[ListDropData.SelectedIndex]); await UIUtil.ButtonComplete(BtnCopy); } /// /// 点击复制全部按钮时触发 /// private async void BtnCopyAll_Click(object sender, EventArgs e) { if (SelectedDropList.Count == 0) return; DropClipboard.Clear(); DropClipboard.AddRange(SelectedDropList); await UIUtil.ButtonComplete(BtnCopyAll); } /// /// 点击粘贴按钮时触发 /// private void BtnPaste_Click(object sender, EventArgs e) { if (DropClipboard.Count == 0) return; foreach (var item in DropClipboard) AddOrUpdateDrop(item); ShowDropList(SelectedDropList); } /// /// 点击删除按钮时触发 /// private void BtnDelete_Click(object sender, EventArgs e) { if (ListDropData.SelectedIndex == -1) return; var dropData = SelectedDropList[ListDropData.SelectedIndex]; RemoveDrop(dropData); ShowDropList(SelectedDropList); } /// /// 点击清空按钮时触发 /// private void BtnClear_Click(object sender, EventArgs e) { if (SelectedDropList.Count == 0) return; if (MessageBox.Show(Resources.AskConfirmDeletion, Resources.Tips, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { for (int i = SelectedDropList.Count - 1; i >= 0; i--) RemoveDrop(SelectedDropList[i]); ShowDropList(SelectedDropList); } } /// /// 点击添加或更新按钮时触发 /// private void BtnAddOrUpdate_Click(object sender, EventArgs e) { if (ListMonsters.SelectedItems.Count == 0) return; try { AddOrUpdateDrop(GetInput()); } catch (FormatException ex) { MessageBox.Show(ex.Message, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); } ShowDropList(SelectedDropList); } /// /// 获取输入 /// /// 掉落物信息 private DropData GetInput() { var dropData = new DropData(); var item = TxtItem.Text; dropData.ItemId = ItemMap.ToId(item); //if (int.TryParse(item.Substring(0, item.IndexOf(':')).Trim(), out int itemId)) //{ // dropData.ItemId = itemId; //} if (NUDMaxCount.Value < NUDMinCount.Value) { dropData.MinCount = (int)NUDMaxCount.Value; dropData.MaxCount = (int)NUDMinCount.Value; } else { dropData.MinCount = (int)NUDMinCount.Value; dropData.MaxCount = (int)NUDMaxCount.Value; } if (NUDMaxWeight.Value < NUDMinWeight.Value) { dropData.MinWeight = (int)NUDMaxWeight.Value; dropData.MaxWeight = (int)NUDMinWeight.Value; } else { dropData.MinWeight = (int)NUDMinWeight.Value; dropData.MaxWeight = (int)NUDMaxWeight.Value; } return dropData; } /// /// 添加或更新掉落物到当前选中项 /// /// 掉落物信息 private void AddOrUpdateDrop(DropData data) { if (ListMonsters.SelectedItems.Count == 0) return; foreach (var monsterId in SelectedMonsterIds()) { if (!Banners.TryGetValue(monsterId, out List dropList)) { dropList = new List(); Banners[monsterId] = dropList; } AddOrUpdateDrop(dropList, data); } AddOrUpdateDrop(SelectedDropList, data); } /// /// 从当前选中项移除掉落物 /// /// 掉落物信息 private void RemoveDrop(DropData data) { if (ListMonsters.SelectedItems.Count == 0) return; foreach (var monsterId in SelectedMonsterIds()) { if (!Banners.TryGetValue(monsterId, out List dropList)) { dropList = new List(); Banners[monsterId] = dropList; } dropList.Remove(data); } SelectedDropList.Remove(data); } /// /// 添加或更新掉落物到指定列表中 /// /// 掉落物列表 /// 掉落物信息 private void AddOrUpdateDrop(List dropList, DropData data) { int i = 0; for (; i < dropList.Count; i++) if (dropList[i].ItemId == data.ItemId) break; if (i == dropList.Count) dropList.Add(data); else dropList[i] = data; } #endregion - 掉落物列表 - #region - 物品列表 - /// /// 物品列表过滤器文本改变时触发 /// private void TxtItemFilter_TextChanged(object sender, EventArgs e) { UIUtil.ListBoxFilter(ListItems, GameData.Items.Lines, TxtItemFilter.Text); } /// /// 物品列表选中项改变时触发 /// private void ListItems_SelectedIndexChanged(object sender, EventArgs e) { TxtItem.Text = ListItems.SelectedItem as string; } #endregion - 物品列表 - } }