diff --git a/Desktop/GameMapTesting/GameMapController.cs b/Desktop/GameMapTesting/GameMapController.cs index 2ab13c8..4e64c60 100644 --- a/Desktop/GameMapTesting/GameMapController.cs +++ b/Desktop/GameMapTesting/GameMapController.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Interface.Entity; using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Constant; @@ -11,6 +10,8 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting public GameMapViewer UI => ui; private GameMapTesting? _game; + public bool TeamMode => _game?.TeamMode ?? false; + // 输入请求器实例 private readonly UserInputRequester _characterSelectionRequester = new(); private readonly UserInputRequester _actionTypeRequester = new(); @@ -27,6 +28,28 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting await _game.StartGame(false, true); } + public List GetTeams() + { + return _game?.GetTeams() ?? []; + } + + public async Task SetTeamCharacters(IEnumerable teammates, IEnumerable enemies) + { + await UI.InvokeAsync(() => + { + UI.TeammateCharacters.Clear(); + foreach (Character character in teammates) + { + UI.TeammateCharacters.Add(new CharacterViewModel(character)); + } + UI.EnemyCharacters.Clear(); + foreach (Character character in enemies) + { + UI.EnemyCharacters.Add(new CharacterViewModel(character)); + } + }); + } + public async Task SetPreCastSuperSkill(Character character, Skill skill) { if (_game != null) diff --git a/Desktop/GameMapTesting/GameMapTesting.cs b/Desktop/GameMapTesting/GameMapTesting.cs index 12902c6..268e3df 100644 --- a/Desktop/GameMapTesting/GameMapTesting.cs +++ b/Desktop/GameMapTesting/GameMapTesting.cs @@ -95,9 +95,10 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting } // 创建顺序表并排序 + Team? team1 = null, team2 = null; if (isTeam) { - tgq = new(characters, WriteLine) + tgq = new(WriteLine) { GameplayEquilibriumConstant = OshimaGameModuleConstant.GameplayEquilibriumConstant }; @@ -138,12 +139,17 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting { c.Promotion = 300; } + team1 = team; } else { team.Members.ForEach(c => c.Promotion = 400); + team2 = team; } } + + // 初始化角色 + _gamingQueue.InitCharacters(characters); } else { @@ -153,6 +159,7 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting }; _gamingQueue = mgq; } + if (team1 != null && team2 != null) await Controller.SetTeamCharacters(team1.Members, team2.Members); // 加载地图和绑定事件 _gamingQueue.LoadGameMap(GameMap); @@ -322,6 +329,7 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting await Controller.UpdateBottomInfoPanel(); await Controller.UpdateQueue(); await Controller.UpdateCharacterPositionsOnMap(); + if (team1 != null && team2 != null) await Controller.SetTeamCharacters(team1.Members, team2.Members); if (roundMsg != "") { @@ -748,5 +756,14 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting if (totalStats.ActionTurn != 0) totalStats.DamagePerTurn = Calculation.Round2Digits(totalStats.TotalDamage / totalStats.ActionTurn); if (totalStats.LiveTime != 0) totalStats.DamagePerSecond = Calculation.Round2Digits(totalStats.TotalDamage / totalStats.LiveTime); } + + public List GetTeams() + { + if (_gamingQueue is TeamGamingQueue tgq) + { + return [.. tgq.Teams.Values]; + } + return []; + } } } diff --git a/Desktop/GameMapTesting/GameMapViewer.xaml b/Desktop/GameMapTesting/GameMapViewer.xaml index f909054..40cbf54 100644 --- a/Desktop/GameMapTesting/GameMapViewer.xaml +++ b/Desktop/GameMapTesting/GameMapViewer.xaml @@ -117,6 +117,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -540,6 +574,47 @@ Visibility="Collapsed" Text="0 秒后继续..." /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -744,7 +819,7 @@ - + - - - - - - + + + + diff --git a/Desktop/GameMapTesting/GameMapViewer.xaml.cs b/Desktop/GameMapTesting/GameMapViewer.xaml.cs index 2ca0fe4..8db6f8c 100644 --- a/Desktop/GameMapTesting/GameMapViewer.xaml.cs +++ b/Desktop/GameMapTesting/GameMapViewer.xaml.cs @@ -1,7 +1,9 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; using System.Windows; using System.Windows.Controls; +using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; @@ -151,6 +153,8 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting // 用于 UI 绑定的 ViewModel 集合 public ObservableCollection CharacterQueueDisplayItems { get; } = []; + public ObservableCollection TeammateCharacters { get; set; } = []; + public ObservableCollection EnemyCharacters { get; set; } = []; // 技能组 public CharacterSkillsAndItemsViewModel CharacterSkillsAndItems { get; set; } = new(); @@ -340,7 +344,7 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting return; } - int maxLines = 300; + int maxLines = 150; // 获取 FlowDocument FlowDocument doc = DebugLogRichTextBox.Document; @@ -423,7 +427,7 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting Canvas.SetLeft(rect, grid.X * CurrentGameMap.Size); Canvas.SetTop(rect, grid.Y * CurrentGameMap.Size); - Panel.SetZIndex(rect, 0); // 确保格子在底部 + Panel.SetZIndex(rect, 5); // 确保格子在底部,但留出一些空间。 rect.MouseLeftButtonDown += Grid_MouseLeftButtonDown; @@ -438,6 +442,22 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting GameMapCanvas.Width = maxCanvasWidth; GameMapCanvas.Height = maxCanvasHeight; + + if (_controller.TeamMode && PlayerCharacter != null) + { + List teams = _controller.GetTeams(); + foreach (Team team in teams) + { + if (team.IsOnThisTeam(PlayerCharacter)) + { + TeammateTextBlock.Text = team.Name; + } + else + { + EnemyTextBlock.Text = team.Name; + } + } + } } /// @@ -519,6 +539,14 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting characterBorder.Background = Brushes.Gray; } characterBorder.Child = characterText; + characterBorder.BorderBrush = character.Promotion switch + { + 200 => Brushes.BurlyWood, + 300 => Brushes.SkyBlue, + 400 => Brushes.Orchid, + _ => Brushes.Salmon + }; + characterBorder.BorderThickness = new Thickness(2); // 设置位置 Canvas.SetLeft(characterBorder, grid.X * CurrentGameMap.Size + offset); @@ -533,25 +561,26 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting _uiElementToCharacter.Add(characterBorder, character); } - // 清除所有角色的高亮 - foreach (Character character in _characterToUiElement.Keys) - { - Border border = _characterToUiElement[character]; - border.BorderBrush = character.Promotion switch - { - 200 => Brushes.BurlyWood, - 300 => Brushes.SkyBlue, - 400 => Brushes.Orchid, - _ => Brushes.Salmon - }; - border.BorderThickness = new Thickness(2); - } - // 如果处于目标选择模式,重新应用高亮 if (_isSelectingTargets) { UpdateCharacterHighlights(); } + + if (_controller.TeamMode && PlayerCharacter != null) + { + List teams = _controller.GetTeams(); + if (teams.Count > 0) + { + PointsTextBlock.Visibility = Visibility.Visible; + PointsTextBlock.Text = $"{string.Join(" : ", teams.OrderBy(t => t.IsOnThisTeam(PlayerCharacter) ? 0 : 1).Select(t => $"{t.Name} ({t.Score})"))}"; + } + } + else + { + PointsTextBlock.Visibility = Visibility.Visible; + PointsTextBlock.Text = $"剩余 {CharacterQueueDisplayItems.Count} 人"; + } } /// @@ -829,14 +858,10 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting } // 清空所有统计文本块 - StatsRatingKillsAssistsDeathsTextBlock.Text = ""; - StatsLiveTimeRoundTurnTextBlock.Text = ""; - StatsControlHealShieldTextBlock.Text = ""; - StatsTotalDamageTextBlock.Text = ""; - StatsTotalTakenDamageTextBlock.Text = ""; - StatsTrueDamageTextBlock.Text = ""; - StatsDamagePerSecondTurnTextBlock.Text = ""; - StatsTrueDamageTextBlock.Visibility = Visibility.Collapsed; // 默认隐藏真实伤害行 + StatsTextBlock1.Text = ""; + StatsTextBlock2.Text = ""; + StatsTextBlock3.Text = ""; + StatsTextBlock4.Text = ""; // 尝试将传入的 CharacterStatistics 对象转换为 dynamic 类型,以便访问其属性 Dictionary dict = CharacterStatistics; @@ -845,46 +870,19 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting CharacterStatistics? stats = dict.Where(kv => kv.Key == CurrentCharacter).Select(kv => kv.Value).FirstOrDefault(); if (stats != null) { - // 第一行:技术得分 / 击杀数 / 助攻数 / 死亡数 - StatsRatingKillsAssistsDeathsTextBlock.Text = $"技术得分:{FunGameService.CalculateRating(stats):0.0#} / 击杀数:{stats.Kills} / 助攻数:{stats.Assists} / 死亡数:{stats.Deaths}"; - - // 第二行:存活时长 / 存活回合数 / 行动回合数 - StatsLiveTimeRoundTurnTextBlock.Text = $"存活时长:{stats.LiveTime:0.##} / 存活回合数:{stats.LiveRound} / 行动回合数:{stats.ActionTurn}"; - - // 第三行:控制时长 / 总计治疗 / 护盾抵消 - StatsControlHealShieldTextBlock.Text = $"控制时长:{stats.ControlTime:0.##} / 总计治疗:{stats.TotalHeal:0.##} / 护盾抵消:{stats.TotalShield:0.##}"; - - // 第四行:总计伤害 / 总计物理伤害 / 总计魔法伤害 - StatsTotalDamageTextBlock.Text = $"总计伤害:{stats.TotalDamage:0.##} / 总计物理伤害:{stats.TotalPhysicalDamage:0.##} / 总计魔法伤害:{stats.TotalMagicDamage:0.##}"; - - // 第五行:总承受伤害 / 总承受物理伤害 / 总承受魔法伤害 - StatsTotalTakenDamageTextBlock.Text = $"总承受伤害:{stats.TotalTakenDamage:0.##} / 总承受物理伤害:{stats.TotalTakenPhysicalDamage:0.##} / 总承受魔法伤害:{stats.TotalTakenMagicDamage:0.##}"; - - // 第六行:总计真实伤害 / 总承受真实伤害 (如果存在真实伤害则显示) - if (stats.TotalTrueDamage > 0 || stats.TotalTakenTrueDamage > 0) - { - StatsTrueDamageTextBlock.Text = $"总计真实伤害:{stats.TotalTrueDamage:0.##} / 总承受真实伤害:{stats.TotalTakenTrueDamage:0.##}"; - StatsTrueDamageTextBlock.Visibility = Visibility.Visible; - } - else - { - StatsTrueDamageTextBlock.Visibility = Visibility.Collapsed; - } - - // 第七行:每秒伤害 / 每回合伤害 - StatsDamagePerSecondTurnTextBlock.Text = $"每秒伤害:{stats.DamagePerSecond:0.##} / 每回合伤害:{stats.DamagePerTurn:0.##}"; + StatsTextBlock1.Text = $"击杀数:{stats.Kills} / 助攻数:{stats.Assists} / 死亡数:{stats.Deaths} / 每秒伤害:{stats.DamagePerSecond:0.##} / 每回合伤害:{stats.DamagePerTurn:0.##}"; + StatsTextBlock2.Text = $"存活时长:{stats.LiveTime:0.##} / 存活回合数:{stats.LiveRound} / 行动回合数:{stats.ActionTurn} / 控制时长:{stats.ControlTime:0.##} / 总计治疗:{stats.TotalHeal:0.##} / 护盾抵消:{stats.TotalShield:0.##}"; + StatsTextBlock3.Text = $"总计伤害:{stats.TotalDamage:0.##} / 总计物理伤害:{stats.TotalPhysicalDamage:0.##} / 总计魔法伤害:{stats.TotalMagicDamage:0.##} / 总计真实伤害:{stats.TotalTrueDamage:0.##}"; + StatsTextBlock4.Text = $"总承受伤害:{stats.TotalTakenDamage:0.##} / 总承受物理伤害:{stats.TotalTakenPhysicalDamage:0.##} / 总承受魔法伤害:{stats.TotalTakenMagicDamage:0.##} / 总承受真实伤害:{stats.TotalTakenTrueDamage:0.##}"; } } else { // 当没有统计数据时,显示默认文本 - StatsRatingKillsAssistsDeathsTextBlock.Text = "技术得分: - / 击杀数: - / 助攻数: -"; - StatsLiveTimeRoundTurnTextBlock.Text = "存活时长: - / 存活回合数: - / 行动回合数: -"; - StatsControlHealShieldTextBlock.Text = "控制时长: - / 总计治疗: - / 护盾抵消: -"; - StatsTotalDamageTextBlock.Text = "总计伤害: - / 总计物理伤害: - / 总计魔法伤害: -"; - StatsTotalTakenDamageTextBlock.Text = "总承受伤害: - / 总承受物理伤害: - / 总承受魔法伤害: -"; - StatsTrueDamageTextBlock.Text = "总计真实伤害: - / 总承受真实伤害: -"; - StatsDamagePerSecondTurnTextBlock.Text = "每秒伤害: - / 每回合伤害: -"; + StatsTextBlock1.Text = "击杀数:- / 助攻数:- / 死亡数:- / 每秒伤害:- / 每回合伤害:-"; + StatsTextBlock2.Text = "存活时长:- / 存活回合数:- / 行动回合数:- / 控制时长:- / 总计治疗:- / 护盾抵消:-"; + StatsTextBlock3.Text = "总计伤害:- / 总计物理伤害:- / 总计魔法伤害:- / 总计真实伤害:-"; + StatsTextBlock4.Text = "总承受伤害:- / 总承受物理伤害:- / 总承受魔法伤害:- / 总承受真实伤害:-"; } } @@ -945,17 +943,57 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting } } + /// + /// 处理角色列表项的点击事件。模拟地图上点击角色的行为。 + /// + private async void CharacterSummary_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + // 确保点击的是一个 Border 且其 Tag 绑定了 CharacterViewModel + if (sender is Border border && border.Tag is CharacterViewModel vm) + { + Character clickedCharacter = vm.Character; // 从 ViewModel 中获取实际的 Character 对象 + + if (_isSelectingTargets) + { + await HandleTargetSelectionClick(clickedCharacter); + } + else if (CurrentGameMap != null && CurrentGameMap.Characters.TryGetValue(clickedCharacter, out Grid? characterGrid)) + { + ClearGridHighlights(); + + if (_gridIdToUiElement.TryGetValue(characterGrid.Id, out Rectangle? gridRect)) + { + gridRect.Stroke = Brushes.Red; + gridRect.StrokeThickness = 2; + } + + UpdateGridInfoPanel(characterGrid); + + await AppendDebugLog($"选中角色: {clickedCharacter.ToStringWithLevel()} (通过侧边面板点击)"); + } + else + { + await AppendDebugLog($"错误: 无法找到角色 {clickedCharacter.NickName} 所在的格子。"); + // 此时可以隐藏格子信息面板 + GridInfoPanel.Visibility = Visibility.Collapsed; + } + + // 标记事件已处理,防止冒泡到下方的 Grid_MouseLeftButtonDown 或 GameMapCanvas_MouseLeftButtonDown + e.Handled = true; + } + } + /// /// 处理角色图标点击事件:选中角色并高亮其所在格子,或进行目标选择。 /// - private void CharacterIcon_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + private async void CharacterIcon_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (sender is Border clickedBorder && _uiElementToCharacter.TryGetValue(clickedBorder, out Character? character)) { if (_isSelectingTargets) { // 如果处于目标选择模式,则处理目标选择逻辑 - HandleTargetSelectionClick(character); + await HandleTargetSelectionClick(character); } else { @@ -974,7 +1012,7 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting } UpdateGridInfoPanel(grid); } - _ = AppendDebugLog($"选中角色: {character.ToStringWithLevel()} (通过点击图标)"); + await AppendDebugLog($"选中角色: {character.ToStringWithLevel()} (通过点击图标)"); } e.Handled = true; // 阻止事件冒泡到下方的Grid_MouseLeftButtonDown 或 GameMapCanvas_MouseLeftButtonDown } @@ -1570,12 +1608,12 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting /// 处理在目标选择模式下点击角色图标的逻辑。 /// /// 被点击的角色。 - private void HandleTargetSelectionClick(Character clickedCharacter) + private async Task HandleTargetSelectionClick(Character clickedCharacter) { // 检查是否是潜在目标 if (_potentialTargetsForSelection == null || !_potentialTargetsForSelection.Contains(clickedCharacter)) { - _ = AppendDebugLog($"无法选择 {clickedCharacter.NickName}:不是潜在目标。"); + await AppendDebugLog($"无法选择 {clickedCharacter.NickName}:不是潜在目标。"); return; } @@ -1600,7 +1638,7 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting if (!isValidTarget) { - _ = AppendDebugLog($"无法选择 {clickedCharacter.NickName}:不符合目标选择规则。"); + await AppendDebugLog($"无法选择 {clickedCharacter.NickName}:不符合目标选择规则。"); return; } @@ -1612,7 +1650,7 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting } else { - _ = AppendDebugLog($"已达到最大目标数量 ({_maxTargetsForSelection})。"); + await AppendDebugLog($"已达到最大目标数量 ({_maxTargetsForSelection})。"); } } UpdateCharacterHighlights(); // 更新地图上的高亮显示 @@ -1623,27 +1661,32 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting /// private void UpdateCharacterHighlights() { - // 高亮潜在目标(黄色边框) - if (_potentialTargetsForSelection != null) + foreach (Character character in _characterToUiElement.Keys) { - foreach (Character potentialTarget in _potentialTargetsForSelection) - { - if (_characterToUiElement.TryGetValue(potentialTarget, out Border? border)) - { - border.BorderBrush = Brushes.Yellow; - border.BorderThickness = new Thickness(4); - } - } - } + Border border = _characterToUiElement[character]; - // 高亮当前已选目标(红色边框) - foreach (Character selectedTarget in SelectedTargets) - { - if (_characterToUiElement.TryGetValue(selectedTarget, out Border? border)) + // 恢复默认 + border.BorderBrush = character.Promotion switch { + 200 => Brushes.BurlyWood, + 300 => Brushes.SkyBlue, + 400 => Brushes.Orchid, + _ => Brushes.Salmon + }; + border.BorderThickness = new Thickness(2); + + if (SelectedTargets.Contains(character)) + { + // 高亮当前已选目标(红色边框) border.BorderBrush = Brushes.Red; // 已选目标颜色 border.BorderThickness = new Thickness(6); } + else if (_potentialTargetsForSelection.Contains(character)) + { + // 高亮潜在目标(黄色边框) + border.BorderBrush = Brushes.Yellow; + border.BorderThickness = new Thickness(4); + } } } diff --git a/Desktop/GameMapTesting/ViewModels.cs b/Desktop/GameMapTesting/ViewModels.cs index 3749f2a..1fcef93 100644 --- a/Desktop/GameMapTesting/ViewModels.cs +++ b/Desktop/GameMapTesting/ViewModels.cs @@ -110,4 +110,24 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting public Character Character { get; set; } = character; public double ATDelay { get; set; } = atDelay; } + + public class CharacterViewModel(Character character) : INotifyPropertyChanged + { + public Character Character + { + get => _character; + set + { + _character = value; + OnPropertyChanged(); + } + } + private Character _character = character; + + public event PropertyChangedEventHandler? PropertyChanged; + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } } diff --git a/Library/Main.cs b/Library/Main.cs index 5319837..7b90e6d 100644 --- a/Library/Main.cs +++ b/Library/Main.cs @@ -30,11 +30,11 @@ FunGameService.InitFunGame(); FunGameSimulation.InitFunGameSimulation(); FunGameController controller = new(new Logger(new LoggerFactory())); -HorseTest.HorseTest1(); +//HorseTest.HorseTest1(); -StoreTest.StoreTest1(); +//StoreTest.StoreTest1(); -await CharacterTest.CharacterTest2(); +//await CharacterTest.CharacterTest2(); //ActivityTest.Test2(); @@ -50,14 +50,14 @@ await CharacterTest.CharacterTest2(); // m.Level = 1; // Console.WriteLine(m.GetInfo()); //} -foreach (Character c in FunGameConstant.Characters) -{ - Character character = c.Copy(); - character.Level = 1; - character.Recovery(); - FunGameService.AddCharacterSkills(character, 1, 6, 6); - Console.WriteLine(character.GetInfo()); -} +//foreach (Character c in FunGameConstant.Characters) +//{ +// Character character = c.Copy(); +// character.Level = 1; +// character.Recovery(); +// FunGameService.AddCharacterSkills(character, 1, 6, 6); +// Console.WriteLine(character.GetInfo()); +//} //foreach (Skill s in FunGameConstant.Skills) //{ // s.Level = 6; @@ -74,15 +74,15 @@ Console.ReadKey(); //Console.WriteLine(rounds.Count); //Console.ReadKey(); //rounds.Clear(); -while (true) -{ - await FunGameBO5.StartBO5(); - ConsoleKeyInfo key = Console.ReadKey(); - if (key.Key == ConsoleKey.Escape) - { - break; - } -} +//while (true) +//{ +// await FunGameBO5.StartBO5(); +// ConsoleKeyInfo key = Console.ReadKey(); +// if (key.Key == ConsoleKey.Escape) +// { +// break; +// } +//} //await FunGameTesting.StartGame(true, false); //Console.ReadKey();