mirror of
https://github.com/milimoe/FunGame-Testing.git
synced 2025-12-05 16:16:36 +00:00
1
This commit is contained in:
parent
6299259b96
commit
e119aa3b69
@ -1,7 +1,7 @@
|
|||||||
<Application x:Class="Milimoe.FunGame.Testing.Desktop.App"
|
<Application x:Class="Milimoe.FunGame.Testing.Desktop.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
StartupUri="Solutions/NovelEditor/NovelEditor.xaml">
|
StartupUri="GameMapTesting/GameMapViewer.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
using Application = System.Windows.Application;
|
using Oshima.FunGame.OshimaModules;
|
||||||
|
using Oshima.FunGame.OshimaServers.Service;
|
||||||
|
using Application = System.Windows.Application;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Testing.Desktop
|
namespace Milimoe.FunGame.Testing.Desktop
|
||||||
{
|
{
|
||||||
@ -6,7 +8,14 @@ namespace Milimoe.FunGame.Testing.Desktop
|
|||||||
{
|
{
|
||||||
public App()
|
public App()
|
||||||
{
|
{
|
||||||
|
CharacterModule cm = new();
|
||||||
|
cm.Load();
|
||||||
|
SkillModule sm = new();
|
||||||
|
sm.Load();
|
||||||
|
ItemModule im = new();
|
||||||
|
im.Load();
|
||||||
|
FunGameService.InitFunGame();
|
||||||
|
FunGameSimulation.InitFunGameSimulation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,11 @@
|
|||||||
<Page Include="App.xaml" />
|
<Page Include="App.xaml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\OshimaGameModule\OshimaModules\OshimaModules.csproj" />
|
||||||
|
<ProjectReference Include="..\..\OshimaGameModule\OshimaServers\OshimaServers.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="FunGame.Core">
|
<Reference Include="FunGame.Core">
|
||||||
<HintPath>..\..\FunGame.Core\bin\Debug\net9.0\FunGame.Core.dll</HintPath>
|
<HintPath>..\..\FunGame.Core\bin\Debug\net9.0\FunGame.Core.dll</HintPath>
|
||||||
|
|||||||
216
Desktop/GameMapTesting/GameMapController.cs
Normal file
216
Desktop/GameMapTesting/GameMapController.cs
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
|
||||||
|
{
|
||||||
|
public class GameMapController(GameMapViewer ui)
|
||||||
|
{
|
||||||
|
public GameMapViewer UI => ui;
|
||||||
|
private GameMapTesting? _game;
|
||||||
|
|
||||||
|
// 输入请求器实例
|
||||||
|
private readonly UserInputRequester<long> _characterSelectionRequester = new();
|
||||||
|
private readonly UserInputRequester<CharacterActionType> _actionTypeRequester = new();
|
||||||
|
private readonly UserInputRequester<List<Character>> _targetSelectionRequester = new();
|
||||||
|
private readonly UserInputRequester<long> _skillSelectionRequester = new();
|
||||||
|
private readonly UserInputRequester<long> _itemSelectionRequester = new();
|
||||||
|
private readonly UserInputRequester<bool> _continuePromptRequester = new(); // 用于“按任意键继续”提示
|
||||||
|
|
||||||
|
public void WriteLine(string str = "") => UI.AppendDebugLog(str);
|
||||||
|
|
||||||
|
public async Task Start()
|
||||||
|
{
|
||||||
|
_game = new(this);
|
||||||
|
await _game.StartGame(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<long> RequestCharacterSelection(List<Character> availableCharacters)
|
||||||
|
{
|
||||||
|
WriteLine("请选择你想玩的角色。");
|
||||||
|
return await _characterSelectionRequester.RequestInput(
|
||||||
|
(callback) => UI.Invoke(() => UI.ShowCharacterSelectionPrompt(availableCharacters, callback))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<CharacterActionType> RequestActionType(Character character, List<Skill> availableSkills, List<Item> availableItems)
|
||||||
|
{
|
||||||
|
WriteLine($"现在是 {character.NickName} 的回合,请选择行动。");
|
||||||
|
return await _actionTypeRequester.RequestInput(
|
||||||
|
(callback) => UI.Invoke(() => UI.ShowActionButtons(character, availableSkills, availableItems, callback))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Character>> RequestTargetSelection(Character actor, List<Character> potentialTargets, long maxTargets, bool canSelectSelf, bool canSelectEnemy, bool canSelectTeammate)
|
||||||
|
{
|
||||||
|
WriteLine($"请为 {actor.NickName} 选择目标 (最多 {maxTargets} 个)。");
|
||||||
|
List<Character> targetIds = await _targetSelectionRequester.RequestInput(
|
||||||
|
(callback) => UI.Invoke(() => UI.ShowTargetSelectionUI(actor, potentialTargets, maxTargets, canSelectSelf, canSelectEnemy, canSelectTeammate, callback))
|
||||||
|
) ?? [];
|
||||||
|
if (targetIds == null) return [];
|
||||||
|
return [.. potentialTargets.Where(targetIds.Contains)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Skill?> RequestSkillSelection(Character character, List<Skill> availableSkills)
|
||||||
|
{
|
||||||
|
WriteLine($"请为 {character.NickName} 选择一个技能。");
|
||||||
|
long? skillId = await _skillSelectionRequester.RequestInput(
|
||||||
|
(callback) => UI.Invoke(() => UI.ShowSkillSelectionUI(character, availableSkills, callback))
|
||||||
|
);
|
||||||
|
return skillId.HasValue ? availableSkills.FirstOrDefault(s => s.Id == skillId.Value) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Item?> RequestItemSelection(Character character, List<Item> availableItems)
|
||||||
|
{
|
||||||
|
WriteLine($"请为 {character.NickName} 选择一个物品。");
|
||||||
|
long? itemId = await _itemSelectionRequester.RequestInput(
|
||||||
|
(callback) => UI.Invoke(() => UI.ShowItemSelectionUI(availableItems, callback))
|
||||||
|
);
|
||||||
|
return itemId.HasValue ? availableItems.FirstOrDefault(i => i.Id == itemId.Value) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RequestContinuePrompt(string message)
|
||||||
|
{
|
||||||
|
WriteLine(message);
|
||||||
|
await _continuePromptRequester.RequestInput(
|
||||||
|
(callback) => UI.Invoke(() => UI.ShowContinuePrompt(message, callback))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- GameMapViewer 调用这些方法来解决 UI 输入 ---
|
||||||
|
|
||||||
|
public void ResolveCharacterSelection(long characterId)
|
||||||
|
{
|
||||||
|
_characterSelectionRequester.ResolveInput(characterId);
|
||||||
|
UI.Invoke(() => UI.HideCharacterSelectionPrompt());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResolveActionType(CharacterActionType actionType)
|
||||||
|
{
|
||||||
|
_actionTypeRequester.ResolveInput(actionType);
|
||||||
|
UI.Invoke(() => UI.HideActionButtons());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResolveTargetSelection(List<Character> targetIds)
|
||||||
|
{
|
||||||
|
_targetSelectionRequester.ResolveInput(targetIds);
|
||||||
|
UI.Invoke(() => UI.HideTargetSelectionUI());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResolveSkillSelection(long skillId)
|
||||||
|
{
|
||||||
|
_skillSelectionRequester.ResolveInput(skillId);
|
||||||
|
UI.Invoke(() => UI.HideSkillSelectionUI());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResolveItemSelection(long itemId)
|
||||||
|
{
|
||||||
|
_itemSelectionRequester.ResolveInput(itemId);
|
||||||
|
UI.Invoke(() => UI.HideItemSelectionUI());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResolveContinuePrompt()
|
||||||
|
{
|
||||||
|
_continuePromptRequester.ResolveInput(true); // 任何值都可以,只要完成Task
|
||||||
|
UI.Invoke(() => UI.HideContinuePrompt());
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsTeammate(Character actor, Character target)
|
||||||
|
{
|
||||||
|
if (actor == target) return true;
|
||||||
|
if (_game != null && _game.GamingQueue != null)
|
||||||
|
{
|
||||||
|
return _game.GamingQueue.IsTeammate(actor, target);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateBottomInfoPanel()
|
||||||
|
{
|
||||||
|
UI.Invoke(UI.UpdateBottomInfoPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateQueue()
|
||||||
|
{
|
||||||
|
UI.Invoke(UI.UpdateLeftQueuePanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateCharacterPositionsOnMap()
|
||||||
|
{
|
||||||
|
UI.Invoke(UI.UpdateCharacterPositionsOnMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetQueue(Dictionary<Character, double> dict)
|
||||||
|
{
|
||||||
|
UI.Invoke(() =>
|
||||||
|
{
|
||||||
|
UI.CharacterQueueData = dict;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetGameMap(GameMap map)
|
||||||
|
{
|
||||||
|
UI.Invoke(() =>
|
||||||
|
{
|
||||||
|
UI.CurrentGameMap = map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPlayerCharacter(Character character)
|
||||||
|
{
|
||||||
|
UI.Invoke(() =>
|
||||||
|
{
|
||||||
|
UI.PlayerCharacter = character;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCurrentCharacter(Character character)
|
||||||
|
{
|
||||||
|
UI.Invoke(() =>
|
||||||
|
{
|
||||||
|
UI.CurrentCharacter = character;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCharacterStatistics(Dictionary<Character, CharacterStatistics> stats)
|
||||||
|
{
|
||||||
|
UI.Invoke(() =>
|
||||||
|
{
|
||||||
|
UI.CharacterStatistics = stats;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 辅助类,用于管理异步的用户输入请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">期望的用户输入类型。</typeparam>
|
||||||
|
public class UserInputRequester<T>
|
||||||
|
{
|
||||||
|
private TaskCompletionSource<T?>? _tcs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求用户输入,并等待结果。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uiPromptAction">一个Action,用于通知UI显示提示,并传入一个回调函数供UI完成输入后调用。</param>
|
||||||
|
/// <returns>用户输入的结果,如果用户取消则为null。</returns>
|
||||||
|
public async Task<T?> RequestInput(Action<Action<T?>> uiPromptAction)
|
||||||
|
{
|
||||||
|
_tcs = new TaskCompletionSource<T?>();
|
||||||
|
// 调用UI动作,并传入我们的ResolveInput方法作为回调
|
||||||
|
// UI将在获取输入后调用此回调
|
||||||
|
uiPromptAction(ResolveInput);
|
||||||
|
return await _tcs.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解决用户输入请求,将结果传递给等待的Task。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">用户输入的结果。</param>
|
||||||
|
public void ResolveInput(T? result)
|
||||||
|
{
|
||||||
|
_tcs?.TrySetResult(result);
|
||||||
|
_tcs = null; // 清除以防止意外重用
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
648
Desktop/GameMapTesting/GameMapTesting.cs
Normal file
648
Desktop/GameMapTesting/GameMapTesting.cs
Normal file
@ -0,0 +1,648 @@
|
|||||||
|
using System.Text;
|
||||||
|
// using System.Windows; // 不再需要,因为移除了 InputDialog
|
||||||
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Interface.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
using Milimoe.FunGame.Core.Model;
|
||||||
|
using Oshima.Core.Constant;
|
||||||
|
using Oshima.FunGame.OshimaModules.Effects.OpenEffects;
|
||||||
|
using Oshima.FunGame.OshimaModules.Models;
|
||||||
|
using Oshima.FunGame.OshimaModules.Skills;
|
||||||
|
using Oshima.FunGame.OshimaServers.Service;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
|
||||||
|
{
|
||||||
|
public class GameMapTesting
|
||||||
|
{
|
||||||
|
public GamingQueue? GamingQueue => _gamingQueue;
|
||||||
|
public GameMapController Controller { get; }
|
||||||
|
public Dictionary<Character, CharacterStatistics> CharacterStatistics { get; } = [];
|
||||||
|
public PluginConfig StatsConfig { get; } = new(nameof(FunGameSimulation), nameof(CharacterStatistics));
|
||||||
|
public GameMap GameMap { get; } = new TestMap();
|
||||||
|
public bool IsWeb { get; set; } = false;
|
||||||
|
public string Msg { get; set; } = "";
|
||||||
|
|
||||||
|
private GamingQueue? _gamingQueue = null;
|
||||||
|
|
||||||
|
public GameMapTesting(GameMapController controller)
|
||||||
|
{
|
||||||
|
Controller = controller;
|
||||||
|
InitCharacter(); // 初始化角色统计数据
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<string>> StartGame(bool isWeb = false)
|
||||||
|
{
|
||||||
|
IsWeb = isWeb;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
List<string> result = [];
|
||||||
|
Msg = "";
|
||||||
|
List<Character> allCharactersInGame = [.. FunGameConstant.Characters]; // 使用不同的名称以避免与后面的 `characters` 冲突
|
||||||
|
Controller.WriteLine("--- 游戏开始 ---");
|
||||||
|
|
||||||
|
int clevel = 60;
|
||||||
|
int slevel = 6;
|
||||||
|
int mlevel = 8;
|
||||||
|
|
||||||
|
// 升级和赋能
|
||||||
|
List<Character> characters = [];
|
||||||
|
for (int index = 0; index < FunGameConstant.Characters.Count; index++)
|
||||||
|
{
|
||||||
|
Character c = FunGameConstant.Characters[index];
|
||||||
|
c.Level = clevel;
|
||||||
|
c.NormalAttack.Level = mlevel;
|
||||||
|
FunGameService.AddCharacterSkills(c, 1, slevel, slevel);
|
||||||
|
Skill 疾风步 = new 疾风步(c)
|
||||||
|
{
|
||||||
|
Level = slevel
|
||||||
|
};
|
||||||
|
c.Skills.Add(疾风步);
|
||||||
|
characters.Add(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示角色信息
|
||||||
|
characters.ForEach(c => Controller.WriteLine($"角色编号:{c.Id}\r\n{c.GetInfo()}"));
|
||||||
|
|
||||||
|
// 询问玩家需要选择哪个角色 (通过UI界面选择)
|
||||||
|
Character? player = null;
|
||||||
|
long selectedPlayerId = await Controller.RequestCharacterSelection(characters); // 异步等待UI选择
|
||||||
|
Controller.ResolveCharacterSelection(selectedPlayerId);
|
||||||
|
if (selectedPlayerId != -1)
|
||||||
|
{
|
||||||
|
player = characters.FirstOrDefault(c => c.Id == selectedPlayerId);
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
|
Controller.WriteLine($"选择了 [ {player} ]!");
|
||||||
|
Controller.SetCurrentCharacter(player);
|
||||||
|
Controller.SetPlayerCharacter(player);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player is null)
|
||||||
|
{
|
||||||
|
throw new Exception("没有选择角色,游戏结束。");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建顺序表并排序
|
||||||
|
_gamingQueue = new MixGamingQueue(characters, WriteLine)
|
||||||
|
{
|
||||||
|
GameplayEquilibriumConstant = OshimaGameModuleConstant.GameplayEquilibriumConstant
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载地图和绑定事件
|
||||||
|
_gamingQueue.LoadGameMap(GameMap);
|
||||||
|
if (_gamingQueue.Map != null)
|
||||||
|
{
|
||||||
|
GameMap map = _gamingQueue.Map;
|
||||||
|
// 随机放置角色
|
||||||
|
HashSet<Grid> allocated = [];
|
||||||
|
List<Grid> grids = [.. map.Grids.Values];
|
||||||
|
foreach (Character character in characters)
|
||||||
|
{
|
||||||
|
Grid grid = Grid.Empty;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
grid = grids[Random.Shared.Next(grids.Count)];
|
||||||
|
}
|
||||||
|
while (allocated.Contains(grid));
|
||||||
|
allocated.Add(grid);
|
||||||
|
map.SetCharacterCurrentGrid(character, grid);
|
||||||
|
}
|
||||||
|
Controller.SetGameMap(map);
|
||||||
|
_gamingQueue.SelectTargetGrid += GamingQueue_SelectTargetGrid;
|
||||||
|
_gamingQueue.CharacterMove += GamingQueue_CharacterMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定事件
|
||||||
|
Controller.SetQueue(_gamingQueue.HardnessTime);
|
||||||
|
Controller.SetCharacterStatistics(_gamingQueue.CharacterStatistics);
|
||||||
|
_gamingQueue.TurnStart += GamingQueue_TurnStart;
|
||||||
|
_gamingQueue.DecideAction += GamingQueue_DecideAction;
|
||||||
|
_gamingQueue.SelectNormalAttackTargets += GamingQueue_SelectNormalAttackTargets;
|
||||||
|
_gamingQueue.SelectSkill += GamingQueue_SelectSkill;
|
||||||
|
_gamingQueue.SelectSkillTargets += GamingQueue_SelectSkillTargets;
|
||||||
|
_gamingQueue.SelectItem += GamingQueue_SelectItem;
|
||||||
|
_gamingQueue.QueueUpdated += GamingQueue_QueueUpdated;
|
||||||
|
_gamingQueue.TurnEnd += GamingQueue_TurnEnd;
|
||||||
|
|
||||||
|
// 总游戏时长
|
||||||
|
double totalTime = 0;
|
||||||
|
|
||||||
|
// 开始空投
|
||||||
|
Msg = "";
|
||||||
|
int qMagicCardPack = 5;
|
||||||
|
int qWeapon = 5;
|
||||||
|
int qArmor = 5;
|
||||||
|
int qShoes = 5;
|
||||||
|
int qAccessory = 4;
|
||||||
|
WriteLine($"社区送温暖了,现在随机发放空投!!");
|
||||||
|
DropItems(_gamingQueue, qMagicCardPack, qWeapon, qArmor, qShoes, qAccessory);
|
||||||
|
WriteLine("");
|
||||||
|
if (isWeb) result.Add("=== 空投 ===\r\n" + Msg);
|
||||||
|
double nextDropItemTime = 40;
|
||||||
|
if (qMagicCardPack < 5) qMagicCardPack++;
|
||||||
|
if (qWeapon < 5) qWeapon++;
|
||||||
|
if (qArmor < 5) qArmor++;
|
||||||
|
if (qShoes < 5) qShoes++;
|
||||||
|
if (qAccessory < 5) qAccessory++;
|
||||||
|
|
||||||
|
// 显示角色信息
|
||||||
|
characters.ForEach(c => Controller.WriteLine(c.GetInfo()));
|
||||||
|
|
||||||
|
// 初始化队列,准备开始游戏
|
||||||
|
_gamingQueue.InitActionQueue();
|
||||||
|
_gamingQueue.SetCharactersToAIControl(false, characters);
|
||||||
|
_gamingQueue.SetCharactersToAIControl(true, player);
|
||||||
|
_gamingQueue.CustomData.Add("player", player);
|
||||||
|
Controller.WriteLine();
|
||||||
|
|
||||||
|
// 显示初始顺序表
|
||||||
|
_gamingQueue.DisplayQueue();
|
||||||
|
Controller.WriteLine();
|
||||||
|
|
||||||
|
Controller.WriteLine($"你的角色是 [ {player} ],详细信息:{player.GetInfo()}");
|
||||||
|
|
||||||
|
// 总回合数
|
||||||
|
int maxRound = 999;
|
||||||
|
|
||||||
|
// 随机回合奖励
|
||||||
|
Dictionary<long, bool> effects = [];
|
||||||
|
foreach (EffectID id in FunGameConstant.RoundRewards.Keys)
|
||||||
|
{
|
||||||
|
long effectID = (long)id;
|
||||||
|
bool isActive = false;
|
||||||
|
if (effectID > (long)EffectID.Active_Start)
|
||||||
|
{
|
||||||
|
isActive = true;
|
||||||
|
}
|
||||||
|
effects.Add(effectID, isActive);
|
||||||
|
}
|
||||||
|
_gamingQueue.InitRoundRewards(maxRound, 1, effects, id => FunGameConstant.RoundRewards[(EffectID)id]);
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
while (i < maxRound)
|
||||||
|
{
|
||||||
|
Msg = "";
|
||||||
|
if (i == maxRound - 1)
|
||||||
|
{
|
||||||
|
WriteLine($"=== 终局审判 ===");
|
||||||
|
Dictionary<Character, double> hpPercentage = [];
|
||||||
|
foreach (Character c in characters)
|
||||||
|
{
|
||||||
|
hpPercentage.TryAdd(c, c.HP / c.MaxHP);
|
||||||
|
}
|
||||||
|
double max = hpPercentage.Values.Max();
|
||||||
|
Character winner = hpPercentage.Keys.Where(c => hpPercentage[c] == max).First();
|
||||||
|
WriteLine("[ " + winner + " ] 成为了天选之人!!");
|
||||||
|
foreach (Character c in characters.Where(c => c != winner && c.HP > 0))
|
||||||
|
{
|
||||||
|
WriteLine("[ " + winner + " ] 对 [ " + c + " ] 造成了 99999999999 点真实伤害。");
|
||||||
|
await _gamingQueue.DeathCalculationAsync(winner, c);
|
||||||
|
}
|
||||||
|
if (_gamingQueue is MixGamingQueue mix)
|
||||||
|
{
|
||||||
|
await mix.EndGameInfo(winner);
|
||||||
|
}
|
||||||
|
result.Add(Msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有角色可以行动
|
||||||
|
Character? characterToAct = await _gamingQueue.NextCharacterAsync();
|
||||||
|
Controller.UpdateQueue();
|
||||||
|
Controller.UpdateCharacterPositionsOnMap();
|
||||||
|
|
||||||
|
// 处理回合
|
||||||
|
if (characterToAct != null)
|
||||||
|
{
|
||||||
|
WriteLine($"=== 回合 {i++} ===");
|
||||||
|
WriteLine("现在是 [ " + characterToAct + " ] 的回合!");
|
||||||
|
|
||||||
|
bool isGameEnd = await _gamingQueue.ProcessTurnAsync(characterToAct);
|
||||||
|
|
||||||
|
if (isGameEnd)
|
||||||
|
{
|
||||||
|
result.Add(Msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWeb) _gamingQueue.DisplayQueue();
|
||||||
|
WriteLine("");
|
||||||
|
}
|
||||||
|
|
||||||
|
string roundMsg = "";
|
||||||
|
if (_gamingQueue.LastRound.HasKill)
|
||||||
|
{
|
||||||
|
roundMsg = Msg;
|
||||||
|
Msg = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟时间流逝
|
||||||
|
double timeLapse = await _gamingQueue.TimeLapse();
|
||||||
|
totalTime += timeLapse;
|
||||||
|
nextDropItemTime -= timeLapse;
|
||||||
|
Controller.UpdateQueue();
|
||||||
|
Controller.UpdateCharacterPositionsOnMap();
|
||||||
|
|
||||||
|
if (roundMsg != "")
|
||||||
|
{
|
||||||
|
if (isWeb)
|
||||||
|
{
|
||||||
|
roundMsg += "\r\n" + Msg;
|
||||||
|
}
|
||||||
|
result.Add(roundMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextDropItemTime <= 0)
|
||||||
|
{
|
||||||
|
// 空投
|
||||||
|
Msg = "";
|
||||||
|
WriteLine($"社区送温暖了,现在随机发放空投!!");
|
||||||
|
DropItems(_gamingQueue, qMagicCardPack, qWeapon, qArmor, qShoes, qAccessory);
|
||||||
|
WriteLine("");
|
||||||
|
if (isWeb) result.Add("=== 空投 ===\r\n" + Msg);
|
||||||
|
nextDropItemTime = 40;
|
||||||
|
if (qMagicCardPack < 5) qMagicCardPack++;
|
||||||
|
if (qWeapon < 5) qWeapon++;
|
||||||
|
if (qArmor < 5) qArmor++;
|
||||||
|
if (qShoes < 5) qShoes++;
|
||||||
|
if (qAccessory < 5) qAccessory++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.WriteLine("--- 游戏结束 ---");
|
||||||
|
Controller.WriteLine($"总游戏时长:{totalTime:0.##} {_gamingQueue.GameplayEquilibriumConstant.InGameTime}");
|
||||||
|
|
||||||
|
// 赛后统计
|
||||||
|
FunGameService.GetCharacterRating(_gamingQueue.CharacterStatistics, false, []);
|
||||||
|
|
||||||
|
// 统计技术得分,评选 MVP
|
||||||
|
Character? mvp = _gamingQueue.CharacterStatistics.OrderByDescending(d => d.Value.Rating).Select(d => d.Key).FirstOrDefault();
|
||||||
|
StringBuilder mvpBuilder = new();
|
||||||
|
if (mvp != null)
|
||||||
|
{
|
||||||
|
CharacterStatistics stats = _gamingQueue.CharacterStatistics[mvp];
|
||||||
|
stats.MVPs++;
|
||||||
|
mvpBuilder.AppendLine($"[ {mvp.ToStringWithLevel()} ]");
|
||||||
|
mvpBuilder.AppendLine($"技术得分:{stats.Rating:0.0#} / 击杀数:{stats.Kills} / 助攻数:{stats.Assists}{(_gamingQueue.MaxRespawnTimes != 0 ? " / 死亡数:" + stats.Deaths : "")}");
|
||||||
|
mvpBuilder.AppendLine($"存活时长:{stats.LiveTime:0.##} / 存活回合数:{stats.LiveRound} / 行动回合数:{stats.ActionTurn}");
|
||||||
|
mvpBuilder.AppendLine($"控制时长:{stats.ControlTime:0.##} / 总计治疗:{stats.TotalHeal:0.##} / 护盾抵消:{stats.TotalShield:0.##}");
|
||||||
|
mvpBuilder.AppendLine($"总计伤害:{stats.TotalDamage:0.##} / 总计物理伤害:{stats.TotalPhysicalDamage:0.##} / 总计魔法伤害:{stats.TotalMagicDamage:0.##}");
|
||||||
|
mvpBuilder.AppendLine($"总承受伤害:{stats.TotalTakenDamage:0.##} / 总承受物理伤害:{stats.TotalTakenPhysicalDamage:0.##} / 总承受魔法伤害:{stats.TotalTakenMagicDamage:0.##}");
|
||||||
|
if (stats.TotalTrueDamage > 0 || stats.TotalTakenTrueDamage > 0) mvpBuilder.AppendLine($"总计真实伤害:{stats.TotalTrueDamage:0.##} / 总承受真实伤害:{stats.TotalTakenTrueDamage:0.##}");
|
||||||
|
mvpBuilder.Append($"每秒伤害:{stats.DamagePerSecond:0.##} / 每回合伤害:{stats.DamagePerTurn:0.##}");
|
||||||
|
}
|
||||||
|
|
||||||
|
int top = isWeb ? _gamingQueue.CharacterStatistics.Count : 0;
|
||||||
|
int count = 1;
|
||||||
|
if (isWeb)
|
||||||
|
{
|
||||||
|
WriteLine("=== 技术得分排行榜 ===");
|
||||||
|
Msg = $"=== 技术得分排行榜 TOP{top} ===\r\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StringBuilder ratingBuilder = new();
|
||||||
|
WriteLine("=== 本场比赛最佳角色 ===");
|
||||||
|
Msg = $"=== 本场比赛最佳角色 ===\r\n";
|
||||||
|
WriteLine(mvpBuilder.ToString() + "\r\n\r\n" + ratingBuilder.ToString());
|
||||||
|
|
||||||
|
Controller.WriteLine();
|
||||||
|
Controller.WriteLine("=== 技术得分排行榜 ===");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Character character in _gamingQueue.CharacterStatistics.OrderByDescending(d => d.Value.Rating).Select(d => d.Key))
|
||||||
|
{
|
||||||
|
StringBuilder builder = new();
|
||||||
|
CharacterStatistics stats = _gamingQueue.CharacterStatistics[character];
|
||||||
|
builder.AppendLine($"{(isWeb ? count + ". " : "")}[ {character.ToStringWithLevel()} ]");
|
||||||
|
builder.AppendLine($"技术得分:{stats.Rating:0.0#} / 击杀数:{stats.Kills} / 助攻数:{stats.Assists}{(_gamingQueue.MaxRespawnTimes != 0 ? " / 死亡数:" + stats.Deaths : "")}");
|
||||||
|
builder.AppendLine($"存活时长:{stats.LiveTime:0.##} / 存活回合数:{stats.LiveRound} / 行动回合数:{stats.ActionTurn}");
|
||||||
|
builder.AppendLine($"控制时长:{stats.ControlTime:0.##} / 总计治疗:{stats.TotalHeal:0.##} / 护盾抵消:{stats.TotalShield:0.##}");
|
||||||
|
builder.AppendLine($"总计伤害:{stats.TotalDamage:0.##} / 总计物理伤害:{stats.TotalPhysicalDamage:0.##} / 总计魔法伤害:{stats.TotalMagicDamage:0.##}");
|
||||||
|
builder.AppendLine($"总承受伤害:{stats.TotalTakenDamage:0.##} / 总承受物理伤害:{stats.TotalTakenPhysicalDamage:0.##} / 总承受魔法伤害:{stats.TotalTakenMagicDamage:0.##}");
|
||||||
|
if (stats.TotalTrueDamage > 0 || stats.TotalTakenTrueDamage > 0) builder.AppendLine($"总计真实伤害:{stats.TotalTrueDamage:0.##} / 总承受真实伤害:{stats.TotalTakenTrueDamage:0.##}");
|
||||||
|
builder.Append($"每秒伤害:{stats.DamagePerSecond:0.##} / 每回合伤害:{stats.DamagePerTurn:0.##}");
|
||||||
|
if (count++ <= top)
|
||||||
|
{
|
||||||
|
WriteLine(builder.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Controller.WriteLine(builder.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
CharacterStatistics? totalStats = CharacterStatistics.Where(kv => kv.Key.GetName() == character.GetName()).Select(kv => kv.Value).FirstOrDefault();
|
||||||
|
if (totalStats != null)
|
||||||
|
{
|
||||||
|
UpdateStatistics(totalStats, stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.Add(Msg);
|
||||||
|
|
||||||
|
if (isWeb)
|
||||||
|
{
|
||||||
|
for (i = _gamingQueue.Eliminated.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
Character character = _gamingQueue.Eliminated[i];
|
||||||
|
result.Add($"=== 角色 [ {character} ] ===\r\n{character.GetInfo()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (StatsConfig)
|
||||||
|
{
|
||||||
|
foreach (Character c in CharacterStatistics.Keys)
|
||||||
|
{
|
||||||
|
StatsConfig.Add(c.ToStringWithOutUser(), CharacterStatistics[c]);
|
||||||
|
}
|
||||||
|
StatsConfig.SaveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Controller.WriteLine(ex.ToString());
|
||||||
|
return [ex.ToString()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Grid> GamingQueue_SelectTargetGrid(GamingQueue queue, Character character, List<Character> enemys, List<Character> teammates, GameMap map)
|
||||||
|
{
|
||||||
|
// 目前,格子选择未直接绑定到UI按钮。
|
||||||
|
// 如果“移动”动作被完全实现,这里需要一个UI提示来选择目标格子。
|
||||||
|
// 为简化,目前返回一个空Grid。
|
||||||
|
await Task.CompletedTask; // 模拟异步操作
|
||||||
|
return Grid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GamingQueue_CharacterMove(GamingQueue queue, Character actor, Grid grid)
|
||||||
|
{
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GamingQueue_QueueUpdated(GamingQueue queue, List<Character> characters, Character character, double hardnessTime, QueueUpdatedReason reason, string msg)
|
||||||
|
{
|
||||||
|
if (IsPlayer_OnlyTest(queue, character))
|
||||||
|
{
|
||||||
|
if (reason == QueueUpdatedReason.Action)
|
||||||
|
{
|
||||||
|
queue.SetCharactersToAIControl(false, character);
|
||||||
|
}
|
||||||
|
if (reason == QueueUpdatedReason.PreCastSuperSkill)
|
||||||
|
{
|
||||||
|
// 玩家释放爆发技后,需要等待玩家确认
|
||||||
|
await Controller.RequestContinuePrompt("你的下一回合需要选择爆发技目标,知晓请点击继续. . .");
|
||||||
|
Controller.ResolveContinuePrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Controller.UpdateQueue();
|
||||||
|
Controller.UpdateCharacterPositionsOnMap();
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> GamingQueue_TurnStart(GamingQueue queue, Character character, List<Character> enemys, List<Character> teammates, List<Skill> skills, List<Item> items)
|
||||||
|
{
|
||||||
|
Controller.UpdateBottomInfoPanel();
|
||||||
|
if (IsPlayer_OnlyTest(queue, character))
|
||||||
|
{
|
||||||
|
// 确保玩家角色在回合开始时取消AI托管,以便玩家可以控制
|
||||||
|
queue.SetCharactersToAIControl(cancel: true, character);
|
||||||
|
}
|
||||||
|
await Task.CompletedTask;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<Character>> GamingQueue_SelectNormalAttackTargets(GamingQueue queue, Character character, NormalAttack attack, List<Character> enemys, List<Character> teammates)
|
||||||
|
{
|
||||||
|
if (!IsPlayer_OnlyTest(queue, character)) return [];
|
||||||
|
|
||||||
|
List<Character> potentialTargets = [];
|
||||||
|
if (attack.CanSelectEnemy) potentialTargets.AddRange(enemys);
|
||||||
|
if (attack.CanSelectTeammate) potentialTargets.AddRange(teammates);
|
||||||
|
if (attack.CanSelectSelf) potentialTargets.Add(character);
|
||||||
|
|
||||||
|
// 通过UI请求目标选择
|
||||||
|
List<Character> selectedTargets = await Controller.RequestTargetSelection(
|
||||||
|
character,
|
||||||
|
potentialTargets,
|
||||||
|
attack.CanSelectTargetCount,
|
||||||
|
attack.CanSelectSelf,
|
||||||
|
attack.CanSelectEnemy,
|
||||||
|
attack.CanSelectTeammate
|
||||||
|
);
|
||||||
|
Controller.ResolveTargetSelection(selectedTargets);
|
||||||
|
|
||||||
|
return selectedTargets ?? []; // 如果取消,返回空列表
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Item?> GamingQueue_SelectItem(GamingQueue queue, Character character, List<Item> items)
|
||||||
|
{
|
||||||
|
if (!IsPlayer_OnlyTest(queue, character)) return null;
|
||||||
|
|
||||||
|
// 通过UI请求物品选择
|
||||||
|
Item? selectedItem = await Controller.RequestItemSelection(character, items);
|
||||||
|
Controller.ResolveItemSelection(selectedItem?.Id ?? 0);
|
||||||
|
return selectedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<Character>> GamingQueue_SelectSkillTargets(GamingQueue queue, Character caster, Skill skill, List<Character> enemys, List<Character> teammates)
|
||||||
|
{
|
||||||
|
if (!IsPlayer_OnlyTest(queue, caster)) return [];
|
||||||
|
|
||||||
|
List<Character> potentialTargets = [];
|
||||||
|
if (skill.CanSelectEnemy) potentialTargets.AddRange(enemys);
|
||||||
|
if (skill.CanSelectTeammate) potentialTargets.AddRange(teammates);
|
||||||
|
if (skill.CanSelectSelf) potentialTargets.Add(caster);
|
||||||
|
|
||||||
|
// 通过UI请求目标选择
|
||||||
|
List<Character>? selectedTargets = await Controller.RequestTargetSelection(
|
||||||
|
caster,
|
||||||
|
potentialTargets,
|
||||||
|
skill.CanSelectTargetCount,
|
||||||
|
skill.CanSelectSelf,
|
||||||
|
skill.CanSelectEnemy,
|
||||||
|
skill.CanSelectTeammate
|
||||||
|
);
|
||||||
|
Controller.ResolveTargetSelection(selectedTargets);
|
||||||
|
|
||||||
|
return selectedTargets ?? []; // 如果取消,返回空列表
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Skill?> GamingQueue_SelectSkill(GamingQueue queue, Character character, List<Skill> skills)
|
||||||
|
{
|
||||||
|
if (!IsPlayer_OnlyTest(queue, character)) return null;
|
||||||
|
|
||||||
|
// 通过UI请求技能选择
|
||||||
|
Skill? selectedSkill = await Controller.RequestSkillSelection(character, skills);
|
||||||
|
Controller.ResolveSkillSelection(selectedSkill?.Id ?? 0);
|
||||||
|
return selectedSkill;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GamingQueue_TurnEnd(GamingQueue queue, Character character)
|
||||||
|
{
|
||||||
|
Controller.UpdateBottomInfoPanel();
|
||||||
|
if (IsRoundHasPlayer_OnlyTest(queue, character))
|
||||||
|
{
|
||||||
|
// 玩家回合结束,等待玩家确认
|
||||||
|
await Controller.RequestContinuePrompt("你的回合(或与你相关的回合)已结束,请查看本回合日志,然后点击继续. . .");
|
||||||
|
Controller.ResolveContinuePrompt();
|
||||||
|
}
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<CharacterActionType> GamingQueue_DecideAction(GamingQueue queue, Character character, List<Character> enemys, List<Character> teammates, List<Skill> skills, List<Item> items)
|
||||||
|
{
|
||||||
|
if (IsPlayer_OnlyTest(queue, character))
|
||||||
|
{
|
||||||
|
// 通过UI按钮请求行动类型
|
||||||
|
CharacterActionType actionType = await Controller.RequestActionType(character, skills, items);
|
||||||
|
Controller.ResolveActionType(actionType);
|
||||||
|
return actionType;
|
||||||
|
}
|
||||||
|
return CharacterActionType.None; // 非玩家角色,由AI处理,或默认None
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsPlayer_OnlyTest(GamingQueue queue, Character current)
|
||||||
|
{
|
||||||
|
return queue.CustomData.TryGetValue("player", out object? value) && value is Character player && player == current;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsRoundHasPlayer_OnlyTest(GamingQueue queue, Character current)
|
||||||
|
{
|
||||||
|
return queue.CustomData.TryGetValue("player", out object? value) && value is Character player && (player == current || (current.CharacterState != CharacterState.Casting && queue.LastRound.Targets.Any(c => c == player)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteLine(string str)
|
||||||
|
{
|
||||||
|
Msg += str + "\r\n";
|
||||||
|
Controller.WriteLine(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DropItems(GamingQueue queue, int mQuality, int wQuality, int aQuality, int sQuality, int acQuality)
|
||||||
|
{
|
||||||
|
Item[] weapons = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("11") && (int)i.QualityType == wQuality)];
|
||||||
|
Item[] armors = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("12") && (int)i.QualityType == aQuality)];
|
||||||
|
Item[] shoes = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("13") && (int)i.QualityType == sQuality)];
|
||||||
|
Item[] accessorys = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("14") && (int)i.QualityType == acQuality)];
|
||||||
|
Item[] consumables = [.. FunGameConstant.AllItems.Where(i => i.ItemType == ItemType.Consumable && i.IsInGameItem)];
|
||||||
|
foreach (Character character in queue.AllCharacters)
|
||||||
|
{
|
||||||
|
Item? a = null, b = null, c = null, d = null;
|
||||||
|
if (weapons.Length > 0) a = weapons[Random.Shared.Next(weapons.Length)];
|
||||||
|
if (armors.Length > 0) b = armors[Random.Shared.Next(armors.Length)];
|
||||||
|
if (shoes.Length > 0) c = shoes[Random.Shared.Next(shoes.Length)];
|
||||||
|
if (accessorys.Length > 0) d = accessorys[Random.Shared.Next(accessorys.Length)];
|
||||||
|
List<Item> drops = [];
|
||||||
|
if (a != null) drops.Add(a);
|
||||||
|
if (b != null) drops.Add(b);
|
||||||
|
if (c != null) drops.Add(c);
|
||||||
|
if (d != null) drops.Add(d);
|
||||||
|
Item? magicCardPack = FunGameService.GenerateMagicCardPack(3, (QualityType)mQuality);
|
||||||
|
if (magicCardPack != null)
|
||||||
|
{
|
||||||
|
foreach (Skill magic in magicCardPack.Skills.Magics)
|
||||||
|
{
|
||||||
|
magic.Level = 8;
|
||||||
|
}
|
||||||
|
magicCardPack.SetGamingQueue(queue);
|
||||||
|
queue.Equip(character, magicCardPack);
|
||||||
|
}
|
||||||
|
foreach (Item item in drops)
|
||||||
|
{
|
||||||
|
Item realItem = item.Copy();
|
||||||
|
realItem.SetGamingQueue(queue);
|
||||||
|
queue.Equip(character, realItem);
|
||||||
|
}
|
||||||
|
if (consumables.Length > 0 && character.Items.Count < 5)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
Item consumable = consumables[Random.Shared.Next(consumables.Length)].Copy();
|
||||||
|
character.Items.Add(consumable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitCharacter()
|
||||||
|
{
|
||||||
|
foreach (Character c in FunGameConstant.Characters)
|
||||||
|
{
|
||||||
|
CharacterStatistics.Add(c, new());
|
||||||
|
}
|
||||||
|
|
||||||
|
StatsConfig.LoadConfig();
|
||||||
|
foreach (Character character in CharacterStatistics.Keys)
|
||||||
|
{
|
||||||
|
if (StatsConfig.ContainsKey(character.ToStringWithOutUser()))
|
||||||
|
{
|
||||||
|
CharacterStatistics[character] = StatsConfig.Get<CharacterStatistics>(character.ToStringWithOutUser()) ?? CharacterStatistics[character];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateStatistics(CharacterStatistics totalStats, CharacterStatistics stats)
|
||||||
|
{
|
||||||
|
// 统计此角色的所有数据
|
||||||
|
totalStats.TotalDamage = Calculation.Round2Digits(totalStats.TotalDamage + stats.TotalDamage);
|
||||||
|
totalStats.TotalPhysicalDamage = Calculation.Round2Digits(totalStats.TotalPhysicalDamage + stats.TotalPhysicalDamage);
|
||||||
|
totalStats.TotalMagicDamage = Calculation.Round2Digits(totalStats.TotalMagicDamage + stats.TotalMagicDamage);
|
||||||
|
totalStats.TotalTrueDamage = Calculation.Round2Digits(totalStats.TotalTrueDamage + stats.TotalTrueDamage);
|
||||||
|
totalStats.TotalTakenDamage = Calculation.Round2Digits(totalStats.TotalTakenDamage + stats.TotalTakenDamage);
|
||||||
|
totalStats.TotalTakenPhysicalDamage = Calculation.Round2Digits(totalStats.TotalTakenPhysicalDamage + stats.TotalTakenPhysicalDamage);
|
||||||
|
totalStats.TotalTakenMagicDamage = Calculation.Round2Digits(totalStats.TotalTakenMagicDamage + stats.TotalTakenMagicDamage);
|
||||||
|
totalStats.TotalTakenTrueDamage = Calculation.Round2Digits(totalStats.TotalTakenTrueDamage + stats.TotalTakenTrueDamage);
|
||||||
|
totalStats.TotalHeal = Calculation.Round2Digits(totalStats.TotalHeal + stats.TotalHeal);
|
||||||
|
totalStats.LiveRound += stats.LiveRound;
|
||||||
|
totalStats.ActionTurn += stats.ActionTurn;
|
||||||
|
totalStats.LiveTime = Calculation.Round2Digits(totalStats.LiveTime + stats.LiveTime);
|
||||||
|
totalStats.ControlTime = Calculation.Round2Digits(totalStats.ControlTime + stats.ControlTime);
|
||||||
|
totalStats.TotalShield = Calculation.Round2Digits(totalStats.TotalShield + stats.TotalShield);
|
||||||
|
totalStats.TotalEarnedMoney += stats.TotalEarnedMoney;
|
||||||
|
totalStats.Kills += stats.Kills;
|
||||||
|
totalStats.Deaths += stats.Deaths;
|
||||||
|
totalStats.Assists += stats.Assists;
|
||||||
|
totalStats.FirstKills += stats.FirstKills;
|
||||||
|
totalStats.FirstDeaths += stats.FirstDeaths;
|
||||||
|
totalStats.LastRank = stats.LastRank;
|
||||||
|
double totalRank = totalStats.AvgRank * totalStats.Plays + totalStats.LastRank;
|
||||||
|
double totalRating = totalStats.Rating * totalStats.Plays + stats.Rating;
|
||||||
|
totalStats.Plays += stats.Plays;
|
||||||
|
if (totalStats.Plays != 0) totalStats.AvgRank = Calculation.Round2Digits(totalRank / totalStats.Plays);
|
||||||
|
else totalStats.AvgRank = stats.LastRank;
|
||||||
|
if (totalStats.Plays != 0) totalStats.Rating = Calculation.Round4Digits(totalRating / totalStats.Plays);
|
||||||
|
else totalStats.Rating = stats.Rating;
|
||||||
|
totalStats.Wins += stats.Wins;
|
||||||
|
totalStats.Top3s += stats.Top3s;
|
||||||
|
totalStats.Loses += stats.Loses;
|
||||||
|
totalStats.MVPs += stats.MVPs;
|
||||||
|
if (totalStats.Plays != 0)
|
||||||
|
{
|
||||||
|
totalStats.AvgDamage = Calculation.Round2Digits(totalStats.TotalDamage / totalStats.Plays);
|
||||||
|
totalStats.AvgPhysicalDamage = Calculation.Round2Digits(totalStats.TotalPhysicalDamage / totalStats.Plays);
|
||||||
|
totalStats.AvgMagicDamage = Calculation.Round2Digits(totalStats.TotalMagicDamage / totalStats.Plays);
|
||||||
|
totalStats.AvgTrueDamage = Calculation.Round2Digits(totalStats.TotalTrueDamage / totalStats.Plays);
|
||||||
|
totalStats.AvgTakenDamage = Calculation.Round2Digits(totalStats.TotalTakenDamage / totalStats.Plays);
|
||||||
|
totalStats.AvgTakenPhysicalDamage = Calculation.Round2Digits(totalStats.TotalTakenPhysicalDamage / totalStats.Plays);
|
||||||
|
totalStats.AvgTakenMagicDamage = Calculation.Round2Digits(totalStats.TotalTakenMagicDamage / totalStats.Plays);
|
||||||
|
totalStats.AvgTakenTrueDamage = Calculation.Round2Digits(totalStats.TotalTakenTrueDamage / totalStats.Plays);
|
||||||
|
totalStats.AvgHeal = Calculation.Round2Digits(totalStats.TotalHeal / totalStats.Plays);
|
||||||
|
totalStats.AvgLiveRound = totalStats.LiveRound / totalStats.Plays;
|
||||||
|
totalStats.AvgActionTurn = totalStats.ActionTurn / totalStats.Plays;
|
||||||
|
totalStats.AvgLiveTime = Calculation.Round2Digits(totalStats.LiveTime / totalStats.Plays);
|
||||||
|
totalStats.AvgControlTime = Calculation.Round2Digits(totalStats.ControlTime / totalStats.Plays);
|
||||||
|
totalStats.AvgShield = Calculation.Round2Digits(totalStats.TotalShield / totalStats.Plays);
|
||||||
|
totalStats.AvgEarnedMoney = totalStats.TotalEarnedMoney / totalStats.Plays;
|
||||||
|
totalStats.Winrates = Calculation.Round4Digits(Convert.ToDouble(totalStats.Wins) / Convert.ToDouble(totalStats.Plays));
|
||||||
|
totalStats.Top3rates = Calculation.Round4Digits(Convert.ToDouble(totalStats.Top3s) / Convert.ToDouble(totalStats.Plays));
|
||||||
|
}
|
||||||
|
if (totalStats.LiveRound != 0) totalStats.DamagePerRound = Calculation.Round2Digits(totalStats.TotalDamage / totalStats.LiveRound);
|
||||||
|
if (totalStats.ActionTurn != 0) totalStats.DamagePerTurn = Calculation.Round2Digits(totalStats.TotalDamage / totalStats.ActionTurn);
|
||||||
|
if (totalStats.LiveTime != 0) totalStats.DamagePerSecond = Calculation.Round2Digits(totalStats.TotalDamage / totalStats.LiveTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
588
Desktop/GameMapTesting/GameMapViewer.xaml
Normal file
588
Desktop/GameMapTesting/GameMapViewer.xaml
Normal file
@ -0,0 +1,588 @@
|
|||||||
|
<UserControl x:Class="Milimoe.FunGame.Testing.Desktop.GameMapTesting.GameMapViewer"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:model="clr-namespace:Milimoe.FunGame.Core.Model;assembly=FunGame.Core"
|
||||||
|
xmlns:local="clr-namespace:Milimoe.FunGame.Testing.Desktop.GameMapTesting"
|
||||||
|
xmlns:constant="clr-namespace:Milimoe.FunGame.Core.Library.Constant;assembly=FunGame.Core"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="600" d:DesignWidth="800">
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<!-- ... 现有资源样式 ... -->
|
||||||
|
<!-- 装备槽位的样式 -->
|
||||||
|
<Style x:Key="EquipSlotStyle" TargetType="Border">
|
||||||
|
<Setter Property="Width" Value="50"/>
|
||||||
|
<Setter Property="Height" Value="50"/>
|
||||||
|
<Setter Property="BorderBrush" Value="DarkGray"/>
|
||||||
|
<Setter Property="BorderThickness" Value="1"/>
|
||||||
|
<Setter Property="CornerRadius" Value="3"/>
|
||||||
|
<Setter Property="Margin" Value="3"/>
|
||||||
|
<Setter Property="Background" Value="LightGray"/>
|
||||||
|
<!-- 默认背景色 -->
|
||||||
|
<Setter Property="ToolTipService.ShowOnDisabled" Value="True"/>
|
||||||
|
</Style>
|
||||||
|
<!-- 装备槽位中文本的样式 -->
|
||||||
|
<Style x:Key="EquipSlotTextStyle" TargetType="TextBlock">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||||
|
<Setter Property="FontSize" Value="18"/>
|
||||||
|
<Setter Property="FontWeight" Value="Bold"/>
|
||||||
|
<Setter Property="Foreground" Value="DimGray"/>
|
||||||
|
<!-- 默认文本颜色 -->
|
||||||
|
</Style>
|
||||||
|
<!-- 状态图标的样式 -->
|
||||||
|
<Style x:Key="StatusIconStyle" TargetType="Border">
|
||||||
|
<Setter Property="Width" Value="30"/>
|
||||||
|
<Setter Property="Height" Value="30"/>
|
||||||
|
<Setter Property="BorderBrush" Value="Gray"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0.5"/>
|
||||||
|
<Setter Property="CornerRadius" Value="2"/>
|
||||||
|
<Setter Property="Margin" Value="2"/>
|
||||||
|
<Setter Property="Background" Value="LightBlue"/>
|
||||||
|
<!-- 默认背景色 -->
|
||||||
|
<Setter Property="ToolTipService.ShowOnDisabled" Value="True"/>
|
||||||
|
</Style>
|
||||||
|
<!-- 状态图标中文本的样式 -->
|
||||||
|
<Style x:Key="StatusIconTextStyle" TargetType="TextBlock">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||||
|
<Setter Property="FontSize" Value="14"/>
|
||||||
|
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||||
|
<Setter Property="Foreground" Value="Navy"/>
|
||||||
|
<!-- 默认文本颜色 -->
|
||||||
|
</Style>
|
||||||
|
<!-- 角色属性文本的样式 -->
|
||||||
|
<Style x:Key="CharacterAttributeTextStyle" TargetType="TextBlock">
|
||||||
|
<Setter Property="Margin" Value="0,1"/>
|
||||||
|
<Setter Property="FontSize" Value="11"/>
|
||||||
|
<Setter Property="Foreground" Value="#FF333333"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- 新增:队列项中角色头像文本的转换器 -->
|
||||||
|
<local:FirstCharConverter x:Key="FirstCharConverter"/>
|
||||||
|
<!-- 新增:队列项中角色名称和等级文本的转换器 -->
|
||||||
|
<local:CharacterToStringWithLevelConverter x:Key="CharacterToStringWithLevelConverter"/>
|
||||||
|
|
||||||
|
<!-- 新增:角色图标的样式 (圆形) -->
|
||||||
|
<Style x:Key="CharacterIconStyle" TargetType="Border">
|
||||||
|
<Setter Property="Width" Value="28"/>
|
||||||
|
<Setter Property="Height" Value="28"/>
|
||||||
|
<Setter Property="CornerRadius" Value="14"/>
|
||||||
|
<Setter Property="BorderBrush" Value="DarkBlue"/>
|
||||||
|
<Setter Property="BorderThickness" Value="1.5"/>
|
||||||
|
<Setter Property="Background" Value="#FF6A5ACD"/>
|
||||||
|
<!-- 默认背景色,可根据角色动态改变 -->
|
||||||
|
<Setter Property="ToolTipService.ShowOnDisabled" Value="True"/>
|
||||||
|
</Style>
|
||||||
|
<!-- 新增:角色图标中文本的样式 -->
|
||||||
|
<Style x:Key="CharacterIconTextStyle" TargetType="TextBlock">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||||
|
<Setter Property="FontSize" Value="12"/>
|
||||||
|
<Setter Property="FontWeight" Value="Bold"/>
|
||||||
|
<Setter Property="Foreground" Value="White"/>
|
||||||
|
</Style>
|
||||||
|
<!-- 新增:选择列表项的样式 -->
|
||||||
|
<Style x:Key="SelectionItemStyle" TargetType="Border">
|
||||||
|
<Setter Property="Background" Value="LightCyan"/>
|
||||||
|
<Setter Property="BorderBrush" Value="DarkCyan"/>
|
||||||
|
<Setter Property="BorderThickness" Value="1"/>
|
||||||
|
<Setter Property="CornerRadius" Value="3"/>
|
||||||
|
<Setter Property="Padding" Value="5"/>
|
||||||
|
<Setter Property="Margin" Value="3"/>
|
||||||
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background" Value="Cyan"/>
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<!-- 左侧动态队列 -->
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<!-- 地图区域 -->
|
||||||
|
<ColumnDefinition Width="250"/>
|
||||||
|
<!-- 新增:右侧调试日志 -->
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<!-- 地图、左侧队列、右侧日志占据的行 -->
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<!-- 底部信息界面占据的行 -->
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- 左侧动态更新队列面板 -->
|
||||||
|
<Border Grid.Column="0" Grid.Row="0" BorderBrush="LightGray" BorderThickness="1" Margin="5" Padding="5">
|
||||||
|
<StackPanel x:Name="LeftQueuePanel" MinWidth="180" Background="#FFF0F8FF">
|
||||||
|
<!-- AliceBlue -->
|
||||||
|
<TextBlock Text="行动顺序表" Margin="0,0,0,10" FontWeight="Bold" FontSize="14"/>
|
||||||
|
|
||||||
|
<!-- 动态内容将在此处添加 -->
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Height="Auto">
|
||||||
|
<ItemsControl x:Name="CharacterQueueItemsControl" ItemsSource="{Binding CharacterQueueItems, RelativeSource={RelativeSource AncestorType=UserControl}}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border BorderBrush="LightGray" BorderThickness="0,0,0,1" Margin="0,2,0,2" Padding="2">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<!-- 图标列 -->
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<!-- 文本信息列 -->
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- 角色图标 (用大字代替) -->
|
||||||
|
<Border Grid.Column="0" Grid.RowSpan="2" Width="25" Height="25" BorderBrush="DarkGray" BorderThickness="1" CornerRadius="3" Margin="0,0,5,0"
|
||||||
|
Background="#FF6A5ACD">
|
||||||
|
<!-- 默认背景色,可根据角色动态改变 -->
|
||||||
|
<TextBlock Text="{Binding Character.NickName, Converter={StaticResource FirstCharConverter}}"
|
||||||
|
Foreground="White"
|
||||||
|
FontSize="10"
|
||||||
|
FontWeight="Bold"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 角色名称和等级 -->
|
||||||
|
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding Character, Converter={StaticResource CharacterToStringWithLevelConverter}}"
|
||||||
|
FontWeight="SemiBold" FontSize="10" Margin="0,0,0,2"/>
|
||||||
|
|
||||||
|
<!-- ATDelay -->
|
||||||
|
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding ATDelay, StringFormat=AT Delay: {0:0.##}}"
|
||||||
|
FontSize="11" Foreground="DimGray"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</ScrollViewer>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 地图区域 (使用ScrollViewer支持大地图滚动) -->
|
||||||
|
<ScrollViewer Grid.Column="1" Grid.Row="0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"
|
||||||
|
Background="#FFE0FFFF">
|
||||||
|
<Border BorderBrush="DarkGray" BorderThickness="1" Margin="5">
|
||||||
|
<!-- 新增一个Grid来容纳Canvas和调试文本框,实现叠加效果 -->
|
||||||
|
<Grid>
|
||||||
|
<!-- 地图Canvas,占据Grid的全部空间 -->
|
||||||
|
<!-- 添加 MouseLeftButtonDown 事件处理器 -->
|
||||||
|
<Canvas x:Name="GameMapCanvas" Background="White" MouseLeftButtonDown="GameMapCanvas_MouseLeftButtonDown">
|
||||||
|
<!-- 地图格子和角色图标将在此处动态绘制 -->
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
<!-- 格子信息面板,叠加在Canvas之上,位于左侧 -->
|
||||||
|
<Border x:Name="GridInfoPanel"
|
||||||
|
Panel.ZIndex="100"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Margin="10"
|
||||||
|
Width="250"
|
||||||
|
MaxHeight="300"
|
||||||
|
Background="#CCFFFFFF"
|
||||||
|
BorderBrush="DarkGray"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="5"
|
||||||
|
Padding="10"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<!-- 初始状态为隐藏 -->
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="格子信息" FontWeight="Bold" FontSize="14" Margin="0,0,0,5"/>
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="250">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock x:Name="GridIdTextBlock" Text="ID: " Margin="0,2"/>
|
||||||
|
<TextBlock x:Name="GridCoordTextBlock" Text="坐标: " Margin="0,2"/>
|
||||||
|
<TextBlock x:Name="GridColorTextBlock" Text="颜色: " Margin="0,2"/>
|
||||||
|
<!-- 新增:格子上的角色列表 -->
|
||||||
|
<TextBlock Text="格子上的角色:" FontWeight="SemiBold" Margin="0,5,0,2"/>
|
||||||
|
<ItemsControl x:Name="GridCharactersInfoItemsControl">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border BorderBrush="LightGray" BorderThickness="0,0,0,1" Padding="2" Margin="0,2">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Text="{Binding NickName}" FontWeight="SemiBold" Margin="0,0,5,0"/>
|
||||||
|
<TextBlock Text="{Binding HP, StringFormat=HP:{0:0.##}}"/>
|
||||||
|
<TextBlock Text="{Binding MaxHP, StringFormat=/{0:0.##}}" Margin="0,0,5,0"/>
|
||||||
|
<TextBlock Text="{Binding MP, StringFormat=MP:{0:0.##}}"/>
|
||||||
|
<TextBlock Text="{Binding MaxMP, StringFormat=/{0:0.##}}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
<!-- 原有的 GridCharactersTextBlock 已移除 -->
|
||||||
|
<TextBlock x:Name="GridEffectsTextBlock" Text="效果: " Margin="0,2" TextWrapping="Wrap"/>
|
||||||
|
<!-- 可以根据需要添加更多信息 -->
|
||||||
|
<Button x:Name="CloseGridInfoButton" Content="关闭" Margin="0,10,0,0" HorizontalAlignment="Right" Click="CloseGridInfoButton_Click"/>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 新增:角色选择面板 (Overlay) -->
|
||||||
|
<Border x:Name="CharacterSelectionOverlay"
|
||||||
|
Panel.ZIndex="200"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Width="400"
|
||||||
|
MaxHeight="400"
|
||||||
|
Background="#DDFFFFFF"
|
||||||
|
BorderBrush="DarkBlue"
|
||||||
|
BorderThickness="2"
|
||||||
|
CornerRadius="10"
|
||||||
|
Padding="20"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="请选择你的角色" FontWeight="Bold" FontSize="16" Margin="0,0,0,10" HorizontalAlignment="Center"/>
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
|
<ItemsControl x:Name="CharacterSelectionItemsControl">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border Style="{StaticResource SelectionItemStyle}"
|
||||||
|
Tag="{Binding Id}"
|
||||||
|
MouseLeftButtonDown="CharacterSelectionItem_MouseLeftButtonDown">
|
||||||
|
<TextBlock Text="{Binding NickName}" FontSize="14" FontWeight="SemiBold"/>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</ScrollViewer>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 新增:技能/物品选择面板 (Overlay) -->
|
||||||
|
<Border x:Name="SkillItemSelectionOverlay"
|
||||||
|
Panel.ZIndex="200"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Width="400"
|
||||||
|
MaxHeight="400"
|
||||||
|
Background="#DDFFFFFF"
|
||||||
|
BorderBrush="DarkGreen"
|
||||||
|
BorderThickness="2"
|
||||||
|
CornerRadius="10"
|
||||||
|
Padding="20"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock x:Name="SkillItemSelectionTitle" Text="请选择技能/物品" FontWeight="Bold" FontSize="16" Margin="0,0,0,10" HorizontalAlignment="Center"/>
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
|
<ItemsControl x:Name="SkillItemSelectionItemsControl">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border Style="{StaticResource SelectionItemStyle}"
|
||||||
|
Tag="{Binding Id}"
|
||||||
|
MouseLeftButtonDown="SkillItemSelectionItem_MouseLeftButtonDown">
|
||||||
|
<TextBlock Text="{Binding Name}" FontSize="14" FontWeight="SemiBold"/>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</ScrollViewer>
|
||||||
|
<Button Content="取消" Margin="0,10,0,0" HorizontalAlignment="Right" Click="CancelSkillItemSelection_Click"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 新增:目标选择确认面板 (Overlay) -->
|
||||||
|
<Border x:Name="TargetSelectionOverlay"
|
||||||
|
Panel.ZIndex="200"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Margin="10"
|
||||||
|
Width="250"
|
||||||
|
MaxHeight="300"
|
||||||
|
Background="#CCFFFFFF"
|
||||||
|
BorderBrush="DarkRed"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="5"
|
||||||
|
Padding="10"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock x:Name="TargetSelectionTitle" Text="选择目标" FontWeight="Bold" FontSize="14" Margin="0,0,0,5"/>
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="200">
|
||||||
|
<ItemsControl x:Name="SelectedTargetsItemsControl" ItemsSource="{Binding SelectedTargets, RelativeSource={RelativeSource AncestorType=UserControl}}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border BorderBrush="LightGray" BorderThickness="0,0,0,1" Padding="2" Margin="0,2">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Text="{Binding NickName}" FontWeight="SemiBold" Margin="0,0,5,0"/>
|
||||||
|
<Button Content="X" Margin="5,0,0,0" Tag="{Binding Id}" Click="RemoveTarget_Click"
|
||||||
|
Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</ScrollViewer>
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0">
|
||||||
|
<Button Content="确认" Margin="0,0,5,0" Click="ConfirmTargets_Click"/>
|
||||||
|
<Button Content="取消" Click="CancelTargetSelection_Click"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 新增:继续提示面板 (Overlay) -->
|
||||||
|
<Border x:Name="ContinuePromptOverlay"
|
||||||
|
Panel.ZIndex="200"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Width="300"
|
||||||
|
Height="150"
|
||||||
|
Background="#DDFFFFFF"
|
||||||
|
BorderBrush="DarkOrange"
|
||||||
|
BorderThickness="2"
|
||||||
|
CornerRadius="10"
|
||||||
|
Padding="20"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||||
|
<TextBlock x:Name="ContinuePromptTextBlock" Text="请点击继续..." TextWrapping="Wrap" HorizontalAlignment="Center" FontSize="14" Margin="0,0,0,15"/>
|
||||||
|
<Button Content="继续" Width="80" Click="ContinuePromptButton_Click"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</ScrollViewer>
|
||||||
|
|
||||||
|
<!-- 新增:右侧调试日志面板 -->
|
||||||
|
<Border Grid.Column="2" Grid.Row="0" BorderBrush="LightGray" BorderThickness="1" Margin="5" Padding="5">
|
||||||
|
<StackPanel Background="#FFF0F8FF">
|
||||||
|
<!-- AliceBlue -->
|
||||||
|
<TextBlock Text="调试日志" Margin="0,0,0,10" FontWeight="Bold" FontSize="14"/>
|
||||||
|
<ScrollViewer x:Name="DebugLogScrollViewer"
|
||||||
|
VerticalScrollBarVisibility="Auto"
|
||||||
|
HorizontalScrollBarVisibility="Auto"
|
||||||
|
Height="Auto">
|
||||||
|
<!-- 移除MaxHeight,让它填充可用空间 -->
|
||||||
|
<TextBlock x:Name="DebugLogTextBlock"
|
||||||
|
ScrollViewer.CanContentScroll="True"
|
||||||
|
Background="Transparent"
|
||||||
|
Foreground="DimGray"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Text="调试日志:" />
|
||||||
|
</ScrollViewer>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 底部信息界面面板 (横向填充) -->
|
||||||
|
<Border Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="3" BorderBrush="LightGray" BorderThickness="1" Margin="5" Padding="5">
|
||||||
|
<!-- 将StackPanel替换为Grid,实现左右两部分的布局 -->
|
||||||
|
<Grid x:Name="BottomInfoPanelGrid" Background="#FFF0FFFF">
|
||||||
|
<!-- Azure -->
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="2*"/>
|
||||||
|
<!-- 左半部分:角色信息 -->
|
||||||
|
<ColumnDefinition Width="2*"/>
|
||||||
|
<!-- 中间部分:装备和状态 (新增) -->
|
||||||
|
<ColumnDefinition Width="3*"/>
|
||||||
|
<!-- 右半部分:操作按钮 -->
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- 左半部分:角色信息 -->
|
||||||
|
<Border Grid.Column="0" BorderBrush="LightGray" BorderThickness="0,0,1,0" Margin="0,0,5,0" Padding="5">
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<TextBlock Text="当前角色信息" FontWeight="Bold" FontSize="14" Margin="0,0,0,10"/>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<!-- 头像 -->
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<!-- 名称和进度条 -->
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- 头像框 - 显示字符 -->
|
||||||
|
<Border x:Name="CharacterAvatarBorder" Grid.RowSpan="4" Grid.Column="0" Width="60" Height="60" BorderBrush="DarkGray" BorderThickness="1" CornerRadius="5" Margin="0,0,10,0"
|
||||||
|
Background="#FF6A5ACD">
|
||||||
|
<!-- 默认背景色,可以根据角色动态改变 -->
|
||||||
|
<Grid>
|
||||||
|
<TextBlock x:Name="CharacterAvatarTextBlock"
|
||||||
|
Text="?"
|
||||||
|
Foreground="White"
|
||||||
|
FontSize="28"
|
||||||
|
FontWeight="Bold"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 角色名称 -->
|
||||||
|
<TextBlock x:Name="CharacterNameTextBlock" Grid.Row="0" Grid.Column="1" Text="角色名称: [未选择]" FontWeight="SemiBold" FontSize="13" Margin="0,0,0,5"/>
|
||||||
|
|
||||||
|
<!-- HP条 (包含护盾) -->
|
||||||
|
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,2">
|
||||||
|
<TextBlock Text="HP:" VerticalAlignment="Center" Width="30"/>
|
||||||
|
<!-- 内部Grid用于叠加HP和护盾Rectangle -->
|
||||||
|
<Grid Height="10" Width="120" HorizontalAlignment="Left">
|
||||||
|
<!-- 背景条 -->
|
||||||
|
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.5" CornerRadius="2"/>
|
||||||
|
<!-- 实际HP进度 -->
|
||||||
|
<Rectangle x:Name="HpFillRectangle" HorizontalAlignment="Left" Fill="Green" Height="10" RadiusX="2" RadiusY="2"/>
|
||||||
|
<!-- 护盾进度,叠加在HP之上 -->
|
||||||
|
<Rectangle x:Name="ShieldFillRectangle" HorizontalAlignment="Left" Fill="Transparent" Height="10" RadiusX="2" RadiusY="2"
|
||||||
|
Visibility="Collapsed" Panel.ZIndex="1"/>
|
||||||
|
</Grid>
|
||||||
|
<TextBlock x:Name="HpValueTextBlock" Text="0/0" Margin="5,0,0,0" VerticalAlignment="Center" FontSize="10"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- MP条 -->
|
||||||
|
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,2">
|
||||||
|
<TextBlock Text="MP:" Width="30" VerticalAlignment="Center"/>
|
||||||
|
<ProgressBar x:Name="MpProgressBar" Value="0" Maximum="100" Height="10" Width="120" Background="LightGray" BorderBrush="Gray" BorderThickness="0.5" Foreground="Blue"/>
|
||||||
|
<TextBlock x:Name="MpValueTextBlock" Text="0/0" Margin="5,0,0,0" VerticalAlignment="Center" FontSize="10"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- EP条 -->
|
||||||
|
<StackPanel Grid.Row="3" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,2">
|
||||||
|
<TextBlock Text="EP:" Width="30" VerticalAlignment="Center"/>
|
||||||
|
<ProgressBar x:Name="EpProgressBar" Value="0" Maximum="100" Height="10" Width="120" Background="LightGray" BorderBrush="Gray" BorderThickness="0.5" Foreground="Orange"/>
|
||||||
|
<TextBlock x:Name="EpValueTextBlock" Text="0/0" Margin="5,0,0,0" VerticalAlignment="Center" FontSize="10"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- 新增:其他角色属性 -->
|
||||||
|
<Border BorderBrush="LightGray" BorderThickness="0,1,0,0" Margin="0,10,0,0" Padding="0,10,0,0">
|
||||||
|
<!-- 将StackPanel替换为Grid,实现横向两列排布 -->
|
||||||
|
<Grid x:Name="CharacterAttributesGrid">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*"/>
|
||||||
|
<ColumnDefinition Width="1.4*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="0" x:Name="AttackTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="攻击力:"/>
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="1" x:Name="PhysicalDefTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="物理护甲:"/>
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="0" x:Name="MagicResTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="魔法抗性:"/>
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="1" x:Name="SpeedTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="行动速度:"/>
|
||||||
|
<TextBlock Grid.Row="2" Grid.Column="0" x:Name="PrimaryAttrTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="核心属性:"/>
|
||||||
|
<TextBlock Grid.Row="2" Grid.Column="1" x:Name="StrengthTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="力量:"/>
|
||||||
|
<TextBlock Grid.Row="3" Grid.Column="0" x:Name="AgilityTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="敏捷:"/>
|
||||||
|
<TextBlock Grid.Row="3" Grid.Column="1" x:Name="IntellectTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="智力:"/>
|
||||||
|
<TextBlock Grid.Row="4" Grid.Column="0" x:Name="HpRegenTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="生命回复:"/>
|
||||||
|
<TextBlock Grid.Row="4" Grid.Column="1" x:Name="MpRegenTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="魔法回复:"/>
|
||||||
|
<TextBlock Grid.Row="5" Grid.Column="0" x:Name="CritRateTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="暴击率:"/>
|
||||||
|
<TextBlock Grid.Row="5" Grid.Column="1" x:Name="CritDmgTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="暴击伤害:"/>
|
||||||
|
<TextBlock Grid.Row="6" Grid.Column="0" x:Name="EvadeRateTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="闪避率:"/>
|
||||||
|
<TextBlock Grid.Row="6" Grid.Column="1" x:Name="LifestealTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="生命偷取:"/>
|
||||||
|
<TextBlock Grid.Row="7" Grid.Column="0" x:Name="CdrTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="冷却缩减:"/>
|
||||||
|
<TextBlock Grid.Row="7" Grid.Column="1" x:Name="AccelCoeffTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="加速系数:"/>
|
||||||
|
<TextBlock Grid.Row="8" Grid.Column="0" x:Name="PhysPenTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="物理穿透:"/>
|
||||||
|
<TextBlock Grid.Row="8" Grid.Column="1" x:Name="MagicPenTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Text="魔法穿透:"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 新增中间部分:装备和状态 -->
|
||||||
|
<Border Grid.Column="1" BorderBrush="LightGray" BorderThickness="0,0,1,0" Margin="0,0,5,0" Padding="5">
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<!-- 装备栏 -->
|
||||||
|
<TextBlock Text="装备" FontWeight="Bold" FontSize="14" Margin="0,0,0,5"/>
|
||||||
|
<WrapPanel x:Name="EquipSlotsPanel" HorizontalAlignment="Center" Margin="0,0,0,10">
|
||||||
|
<!-- 魔法卡包 -->
|
||||||
|
<Border x:Name="MagicCardPackBorder" Style="{StaticResource EquipSlotStyle}" MouseLeftButtonDown="EquipSlot_MouseLeftButtonDown">
|
||||||
|
<TextBlock x:Name="MagicCardPackSlotText" Text="魔" Style="{StaticResource EquipSlotTextStyle}"/>
|
||||||
|
</Border>
|
||||||
|
<!-- 武器 -->
|
||||||
|
<Border x:Name="WeaponBorder" Style="{StaticResource EquipSlotStyle}" MouseLeftButtonDown="EquipSlot_MouseLeftButtonDown">
|
||||||
|
<TextBlock x:Name="WeaponSlotText" Text="武" Style="{StaticResource EquipSlotTextStyle}"/>
|
||||||
|
</Border>
|
||||||
|
<!-- 防具 -->
|
||||||
|
<Border x:Name="ArmorBorder" Style="{StaticResource EquipSlotStyle}" MouseLeftButtonDown="EquipSlot_MouseLeftButtonDown">
|
||||||
|
<TextBlock x:Name="ArmorSlotText" Text="防" Style="{StaticResource EquipSlotTextStyle}"/>
|
||||||
|
</Border>
|
||||||
|
<!-- 鞋子 -->
|
||||||
|
<Border x:Name="ShoesBorder" Style="{StaticResource EquipSlotStyle}" MouseLeftButtonDown="EquipSlot_MouseLeftButtonDown">
|
||||||
|
<TextBlock x:Name="ShoesSlotText" Text="鞋" Style="{StaticResource EquipSlotTextStyle}"/>
|
||||||
|
</Border>
|
||||||
|
<!-- 饰品1 -->
|
||||||
|
<Border x:Name="Accessory1Border" Style="{StaticResource EquipSlotStyle}" MouseLeftButtonDown="EquipSlot_MouseLeftButtonDown">
|
||||||
|
<TextBlock x:Name="Accessory1SlotText" Text="饰1" Style="{StaticResource EquipSlotTextStyle}"/>
|
||||||
|
</Border>
|
||||||
|
<!-- 饰品2 -->
|
||||||
|
<Border x:Name="Accessory2Border" Style="{StaticResource EquipSlotStyle}" MouseLeftButtonDown="EquipSlot_MouseLeftButtonDown">
|
||||||
|
<TextBlock x:Name="Accessory2SlotText" Text="饰2" Style="{StaticResource EquipSlotTextStyle}"/>
|
||||||
|
</Border>
|
||||||
|
</WrapPanel>
|
||||||
|
|
||||||
|
<!-- 状态条 -->
|
||||||
|
<TextBlock Text="状态" FontWeight="Bold" FontSize="14" Margin="0,0,0,5"/>
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" MaxHeight="80">
|
||||||
|
<WrapPanel x:Name="CharacterEffectsPanel" HorizontalAlignment="Left">
|
||||||
|
<!-- 状态图标将在此处动态添加 -->
|
||||||
|
</WrapPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
|
||||||
|
<!-- 新增:装备和状态描述 -->
|
||||||
|
<Border BorderBrush="LightGray" BorderThickness="0,1,0,0" Margin="0,10,0,0" Padding="0,10,0,0">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="详情描述" FontWeight="Bold" FontSize="14" Margin="0,0,0,5"/>
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="80">
|
||||||
|
<TextBlock x:Name="DescriptionTextBlock" Text="点击装备或状态图标查看详情。" TextWrapping="Wrap" FontSize="11" Foreground="DimGray"/>
|
||||||
|
</ScrollViewer>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 右半部分:操作按钮 -->
|
||||||
|
<Border Grid.Column="2" Padding="5">
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<TextBlock Text="操作" FontWeight="Bold" FontSize="14" Margin="0,0,0,10"/>
|
||||||
|
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
|
<!-- IsEnabled 默认设置为 False,由代码控制 -->
|
||||||
|
<!-- Tag 属性用于在 Click 事件中识别是哪个动作 -->
|
||||||
|
<Button x:Name="MoveButton" Content="移动" Width="100" Height="30" Margin="5" Click="ActionButton_Click" Tag="{x:Static constant:CharacterActionType.Move}" IsEnabled="False"/>
|
||||||
|
<Button x:Name="AttackButton" Content="普通攻击" Width="100" Height="30" Margin="5" Click="ActionButton_Click" Tag="{x:Static constant:CharacterActionType.NormalAttack}" IsEnabled="False"/>
|
||||||
|
<Button x:Name="SkillButton" Content="释放战技" Width="100" Height="30" Margin="5" Click="ActionButton_Click" Tag="{x:Static constant:CharacterActionType.PreCastSkill}" IsEnabled="False"/>
|
||||||
|
<Button x:Name="CastButton" Content="吟唱魔法" Width="100" Height="30" Margin="5" Click="ActionButton_Click" Tag="{x:Static constant:CharacterActionType.PreCastSkill}" IsEnabled="False"/>
|
||||||
|
<Button x:Name="UseItemButton" Content="使用物品" Width="100" Height="30" Margin="5" Click="ActionButton_Click" Tag="{x:Static constant:CharacterActionType.UseItem}" IsEnabled="False"/>
|
||||||
|
<Button x:Name="EndTurnButton" Content="结束回合" Width="100" Height="30" Margin="5" Click="ActionButton_Click" Tag="{x:Static constant:CharacterActionType.EndTurn}" IsEnabled="False"/>
|
||||||
|
</WrapPanel>
|
||||||
|
|
||||||
|
<!-- 新增:数据统计 -->
|
||||||
|
<Border BorderBrush="LightGray" BorderThickness="0,1,0,0" Margin="0,10,0,0" Padding="0,10,0,0">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="数据统计" FontWeight="Bold" FontSize="14" Margin="0,0,0,5"/>
|
||||||
|
<TextBlock x:Name="StatsRatingKillsAssistsDeathsTextBlock" Style="{StaticResource CharacterAttributeTextStyle}"/>
|
||||||
|
<TextBlock x:Name="StatsLiveTimeRoundTurnTextBlock" Style="{StaticResource CharacterAttributeTextStyle}"/>
|
||||||
|
<TextBlock x:Name="StatsControlHealShieldTextBlock" Style="{StaticResource CharacterAttributeTextStyle}"/>
|
||||||
|
<TextBlock x:Name="StatsTotalDamageTextBlock" Style="{StaticResource CharacterAttributeTextStyle}"/>
|
||||||
|
<TextBlock x:Name="StatsTotalTakenDamageTextBlock" Style="{StaticResource CharacterAttributeTextStyle}"/>
|
||||||
|
<TextBlock x:Name="StatsTrueDamageTextBlock" Style="{StaticResource CharacterAttributeTextStyle}" Visibility="Collapsed"/>
|
||||||
|
<!-- 初始隐藏,有真实伤害时显示 -->
|
||||||
|
<TextBlock x:Name="StatsDamagePerSecondTurnTextBlock" Style="{StaticResource CharacterAttributeTextStyle}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
1346
Desktop/GameMapTesting/GameMapViewer.xaml.cs
Normal file
1346
Desktop/GameMapTesting/GameMapViewer.xaml.cs
Normal file
File diff suppressed because it is too large
Load Diff
43
Desktop/GameMapTesting/TestMap.cs
Normal file
43
Desktop/GameMapTesting/TestMap.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
using Milimoe.FunGame.Core.Interface.Base;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
||||||
|
using Milimoe.FunGame.Core.Model;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
|
||||||
|
{
|
||||||
|
public class TestMap : GameMap
|
||||||
|
{
|
||||||
|
public override string Name => "TestMap";
|
||||||
|
|
||||||
|
public override string Description => "TestMap";
|
||||||
|
|
||||||
|
public override string Version => "1.0.0";
|
||||||
|
|
||||||
|
public override string Author => "TestUser";
|
||||||
|
|
||||||
|
public override int Length => 12;
|
||||||
|
|
||||||
|
public override int Width => 12;
|
||||||
|
|
||||||
|
public override int Height => 1;
|
||||||
|
|
||||||
|
public override float Size => 32;
|
||||||
|
|
||||||
|
public override GameMap InitGamingQueue(IGamingQueue queue)
|
||||||
|
{
|
||||||
|
GameMap map = new TestMap();
|
||||||
|
map.Load();
|
||||||
|
|
||||||
|
if (queue is GamingQueue gq)
|
||||||
|
{
|
||||||
|
gq.WriteLine($"地图 {map.Name} 已加载。");
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AfterTimeElapsed(ref double timeToReduce)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
Desktop/InputDialog/InputDialog.xaml
Normal file
32
Desktop/InputDialog/InputDialog.xaml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<Window x:Class="Milimoe.FunGame.Testing.Desktop.InputDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="输入" Height="180" Width="350"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
|
ResizeMode="NoResize"
|
||||||
|
ShowInTaskbar="False">
|
||||||
|
<Grid Margin="10">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- 提示文本 -->
|
||||||
|
<TextBlock x:Name="PromptTextBlock" Grid.Row="0" Margin="0,0,0,10" TextWrapping="Wrap"
|
||||||
|
Text="请输入文本:"/>
|
||||||
|
|
||||||
|
<!-- 输入框 -->
|
||||||
|
<TextBox x:Name="InputTextBox" Grid.Row="1" Height="30" VerticalContentAlignment="Center"
|
||||||
|
AcceptsReturn="False" TextWrapping="NoWrap" />
|
||||||
|
|
||||||
|
<!-- 按钮区域 -->
|
||||||
|
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,15,0,0">
|
||||||
|
<Button Content="确定" Width="75" Margin="0,0,10,0" Click="OkButton_Click" IsDefault="True"/>
|
||||||
|
<Button Content="取消" Width="75" Click="CancelButton_Click" IsCancel="True"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
75
Desktop/InputDialog/InputDialog.xaml.cs
Normal file
75
Desktop/InputDialog/InputDialog.xaml.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Testing.Desktop
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// InputDialog.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class InputDialog : Window
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置用户输入的文本。
|
||||||
|
/// </summary>
|
||||||
|
public string InputText
|
||||||
|
{
|
||||||
|
get { return InputTextBox.Text; }
|
||||||
|
set { InputTextBox.Text = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数,允许设置提示文本和初始值。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="prompt">显示给用户的提示信息。</param>
|
||||||
|
/// <param name="initialValue">输入框的初始值。</param>
|
||||||
|
public InputDialog(string prompt, string initialValue = "")
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
PromptTextBlock.Text = prompt;
|
||||||
|
InputTextBox.Text = initialValue;
|
||||||
|
InputTextBox.Focus(); // 自动聚焦到输入框
|
||||||
|
InputTextBox.SelectAll(); // 选中所有文本,方便用户直接输入覆盖
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "确定" 按钮点击事件。
|
||||||
|
/// </summary>
|
||||||
|
private void OkButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DialogResult = true; // 设置对话框结果为 true,表示用户点击了确定
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "取消" 按钮点击事件。
|
||||||
|
/// </summary>
|
||||||
|
private void CancelButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DialogResult = false; // 设置对话框结果为 false,表示用户点击了取消
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 静态方法,方便外部调用显示输入弹窗。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="prompt">显示给用户的提示信息。</param>
|
||||||
|
/// <param name="initialValue">输入框的初始值。</param>
|
||||||
|
/// <param name="owner">弹窗的拥有者窗口,用于居中显示。</param>
|
||||||
|
/// <returns>如果用户点击确定,返回输入的字符串;否则返回 null。</returns>
|
||||||
|
public static string? Show(string prompt, string initialValue = "", Window? owner = null)
|
||||||
|
{
|
||||||
|
InputDialog dialog = new(prompt, initialValue);
|
||||||
|
if (owner != null)
|
||||||
|
{
|
||||||
|
dialog.Owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool? result = dialog.ShowDialog();
|
||||||
|
|
||||||
|
if (result == true)
|
||||||
|
{
|
||||||
|
return dialog.InputText;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user