单位/召唤物技能实现和测试

This commit is contained in:
milimoe 2026-01-13 23:44:37 +08:00
parent 75ce024999
commit 06018b423a
Signed by: milimoe
GPG Key ID: 9554D37E4B8991D0
5 changed files with 160 additions and 7 deletions

View File

@ -15,6 +15,7 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
// 输入请求器实例
private readonly UserInputRequester<Character> _characterSelectionRequester = new();
private readonly UserInputRequester<InquiryResponse> _inquiryResponseSelectionRequester = new();
private readonly UserInputRequester<Grid> _targetGridSelectionRequester = new();
private readonly UserInputRequester<CharacterActionType> _actionTypeRequester = new();
private readonly UserInputRequester<List<Character>> _targetSelectionRequester = new();
@ -84,6 +85,14 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
);
}
public async Task<InquiryResponse?> RequestInquiryResponseSelection(InquiryOptions options)
{
await WriteLine("请选择你的反应。");
return await _inquiryResponseSelectionRequester.RequestInput(
async (callback) => await UI.InvokeAsync(() => UI.ShowInquiryResponseSelectionPrompt(options, callback))
);
}
public async Task<CharacterActionType> RequestActionType(Character character, List<Item> availableItems)
{
await WriteLine($"现在是 {character.NickName} 的回合,请选择行动。");
@ -161,6 +170,12 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
await UI.InvokeAsync(() => UI.HideCharacterSelectionPrompt());
}
public async Task ResolveInquiryResponseSelection(InquiryResponse? response)
{
_inquiryResponseSelectionRequester.ResolveInput(response);
await UI.InvokeAsync(() => UI.HideInquiryResponseSelectionPrompt());
}
public async Task ResolveActionType(CharacterActionType actionType)
{
_actionTypeRequester.ResolveInput(actionType);

View File

@ -246,6 +246,7 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
_gamingQueue.QueueUpdatedEvent += GamingQueue_QueueUpdated;
_gamingQueue.TurnEndEvent += GamingQueue_TurnEnd;
_gamingQueue.CharacterInquiryEvent += GamingQueue_CharacterInquiryEvent;
_gamingQueue.CharacterActionTakenEvent += GamingQueue_CharacterActionTakenEvent;
// 总游戏时长
double totalTime = 0;
@ -538,6 +539,11 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
}
}
private void GamingQueue_CharacterActionTakenEvent(GamingQueue queue, Character actor, DecisionPoints dp, CharacterActionType type, RoundRecord record)
{
SyncAwaiter.Wait(Controller.UpdateCharacterPositionsOnMap());
}
private Grid GamingQueue_SelectTargetGrid(GamingQueue queue, Character character, List<Character> enemys, List<Character> teammates, GameMap map, List<Grid> moveRange)
{
if (!IsPlayer_OnlyTest(queue, character) || _gamingQueue is null || _gamingQueue.Map is null) return Grid.Empty;
@ -709,8 +715,16 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
return CharacterActionType.None; // 非玩家角色由AI处理或默认None
}
private InquiryResponse GamingQueue_CharacterInquiryEvent(GamingQueue character, Character actor, DecisionPoints dp, InquiryOptions options)
private InquiryResponse GamingQueue_CharacterInquiryEvent(GamingQueue queue, Character character, DecisionPoints dp, InquiryOptions options)
{
if (IsPlayer_OnlyTest(queue, character))
{
// 通过UI按钮请求行动类型
SyncAwaiter.Wait(Controller.UpdateCharacterPositionsOnMap());
InquiryResponse? response = SyncAwaiter.WaitResult(Controller.RequestInquiryResponseSelection(options));
SyncAwaiter.Wait(Controller.ResolveInquiryResponseSelection(response));
return response ?? new(options);
}
return new(options);
}
@ -731,12 +745,12 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
private static bool IsPlayer_OnlyTest(GamingQueue queue, Character current)
{
return queue.CustomData.TryGetValue("player", out object? value) && value is Character player && player == current && !queue.IsCharacterInAIControlling(current);
return queue.CustomData.TryGetValue("player", out object? value) && value is Character player && (player == current || current.Master == player) && !queue.IsCharacterInAIControlling(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.Values.SelectMany(c => c).Any(c => c == player)));
return queue.CustomData.TryGetValue("player", out object? value) && value is Character player && (player == current || current.Master == player || (current.CharacterState != CharacterState.Casting && queue.LastRound.Targets.Values.SelectMany(c => c).Any(c => c == player)));
}
public void SetPreCastSuperSkill(Character character, Skill skill)

View File

@ -412,6 +412,57 @@
</StackPanel>
</Border>
<!-- 新增:询问反应选择面板 (Overlay) -->
<Border x:Name="InquiryResponseSelectionOverlay"
Panel.ZIndex="200"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="400"
MaxHeight="600"
Background="#DDFFFFFF"
BorderBrush="DarkBlue"
BorderThickness="2"
CornerRadius="10"
Padding="20"
Visibility="Collapsed">
<StackPanel>
<TextBlock x:Name="InquiryResponseSelectionTitle" Text="请选择你的反应" FontWeight="Bold" FontSize="16" Margin="0,0,0,10" HorizontalAlignment="Center"/>
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="300">
<ItemsControl x:Name="InquiryResponseSelectionItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Style="{StaticResource SelectionItemStyle}"
Tag="{Binding}"
MouseLeftButtonDown="InquiryResponseSelectionItem_MouseLeftButtonDown"
MouseEnter="InquiryResponseSelectionItem_MouseEnter">
<TextBlock Text="{Binding Choices[0]}" FontSize="14" FontWeight="SemiBold"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<!-- 新增:详情显示区域 -->
<TextBlock Text="详情" FontWeight="Bold" FontSize="14" Margin="0,10,0,5" HorizontalAlignment="Center"/>
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="200">
<!-- 限制详情区域高度 -->
<RichTextBox x:Name="InquiryResponseDetailsRichTextBox"
IsReadOnly="True"
BorderThickness="0"
Background="Transparent"
Foreground="DimGray"
FontSize="11"
AcceptsReturn="True"
VerticalScrollBarVisibility="Disabled"
HorizontalScrollBarVisibility="Disabled">
<FlowDocument>
<Paragraph Margin="0">将鼠标悬停在选项上以查看详情。</Paragraph>
</FlowDocument>
</RichTextBox>
</ScrollViewer>
<Button x:Name="InquiryResponseCancel" Content="取消" Margin="0,10,0,0" HorizontalAlignment="Right" Click="CancelInquiryResponseSelection_Click"/>
</StackPanel>
</Border>
<!-- 新增:技能/物品选择面板 (Overlay) -->
<Border x:Name="SkillItemSelectionOverlay"
Panel.ZIndex="200"

View File

@ -60,6 +60,7 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
// 回调Action用于将UI选择结果传递给Controller
private Action<Character?>? _resolveCharacterSelection;
private Action<InquiryResponse?>? _resolveInquiryResponseSelection;
private Action<Grid?>? _resolveTargetGridSelection;
private Action<List<Grid>>? _resolveTargetGridsSelection;
private Action<CharacterActionType>? _resolveActionType;
@ -1459,6 +1460,36 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
CharacterSelectionOverlay.Visibility = Visibility.Visible;
}
/// <summary>
/// 显示反应选择面板。
/// </summary>
/// <param name="options">询问内容。</param>
/// <param name="callback">选择完成后调用的回调函数。</param>
public void ShowInquiryResponseSelectionPrompt(InquiryOptions options, Action<InquiryResponse?> callback)
{
switch (options.InquiryType)
{
case InquiryType.Choice:
case InquiryType.BinaryChoice:
_resolveInquiryResponseSelection = callback;
InquiryResponseSelectionTitle.Text = options.Description;
List<InquiryResponse> responses = [];
foreach (string key in options.Choices.Keys)
{
responses.Add(new(options.InquiryType, options.Topic)
{
Choices = [key],
TextResult = options.Choices[key]
});
}
InquiryResponseSelectionItemsControl.ItemsSource = responses;
SetRichTextBoxText(InquiryResponseDetailsRichTextBox, "将鼠标悬停在选项上以查看详情。");
InquiryResponseSelectionOverlay.Visibility = Visibility.Visible;
InquiryResponseCancel.Visibility = Visibility.Hidden;
break;
}
}
/// <summary>
/// 角色选择项的点击事件。
/// </summary>
@ -1470,6 +1501,17 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
}
}
/// <summary>
/// 反应选择项的点击事件。
/// </summary>
private void InquiryResponseSelectionItem_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (sender is Border border && border.Tag is InquiryResponse response)
{
_resolveInquiryResponseSelection?.Invoke(response);
}
}
/// <summary>
/// 角色选择项的鼠标进入事件。
/// </summary>
@ -1483,6 +1525,18 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
}
}
/// <summary>
/// 反应选择项的鼠标进入事件。
/// </summary>
private void InquiryResponseSelectionItem_MouseEnter(object sender, MouseEventArgs e)
{
if (sender is Border border && border.Tag is InquiryResponse response)
{
string details = response.TextResult;
SetRichTextBoxText(InquiryResponseDetailsRichTextBox, details);
}
}
/// <summary>
/// 隐藏角色选择提示面板。
/// </summary>
@ -1494,6 +1548,25 @@ namespace Milimoe.FunGame.Testing.Desktop.GameMapTesting
SetRichTextBoxText(CharacterDetailsRichTextBox, "");
}
/// <summary>
/// 隐藏反应选择提示面板。
/// </summary>
public void HideInquiryResponseSelectionPrompt()
{
InquiryResponseSelectionOverlay.Visibility = Visibility.Collapsed;
InquiryResponseSelectionItemsControl.ItemsSource = null;
_resolveInquiryResponseSelection = null;
SetRichTextBoxText(InquiryResponseDetailsRichTextBox, "");
}
/// <summary>
/// 取消反应选择的点击事件。
/// </summary>
private void CancelInquiryResponseSelection_Click(object sender, RoutedEventArgs e)
{
_resolveInquiryResponseSelection?.Invoke(null);
}
/// <summary>
/// 显示行动按钮,并根据可用技能和物品启用/禁用相关按钮。
/// </summary>

View File

@ -104,7 +104,7 @@ Console.ReadKey();
while (true)
{
//DateTime start = DateTime.Now;
//await FunGameSimulation.StartSimulationGame(true, false, true, false, useStore: false, hasMap: true);
//await FunGameSimulation.StartSimulationGame(true, false, true, false, useStore: false, hasMap: false);
//DateTime end = DateTime.Now;
//Console.WriteLine("模拟时长" + (end - start).TotalSeconds + "秒");
//ConsoleKeyInfo key = Console.ReadKey();
@ -114,14 +114,14 @@ while (true)
//}
//await Task.Delay(1);
//start = DateTime.Now;
//await FunGameSimulation.StartSimulationGame(true, false, false, false, hasMap: true);
//await FunGameSimulation.StartSimulationGame(true, false, false, false, hasMap: false);
//end = DateTime.Now;
//Console.WriteLine("模拟时长" + (end - start).TotalSeconds + "秒");
//key = Console.ReadKey();
//if (key.Key == ConsoleKey.Escape)
//{
// break;
//}
//end = DateTime.Now;
//Console.WriteLine("模拟时长" + (end - start).TotalSeconds + "秒");
await FunGameSimulation.StartSimulationGame(false, false, true, false, useStore: false, hasMap: false);
await FunGameSimulation.StartSimulationGame(false, false, false, false, hasMap: false);
}