expense handling from gamelogic:
Problem: HandleRecordThrow ignorierte throwResult.Triggers aus ProcessThrow - speziell die ExpensePoint-Trigger vom Scheißspiel für Verlierer.
Lösung:
1. HandleRecordThrow (Zeile 358, 370, 427-436):
- Neue Variable gameLogicTriggers
- Zuweisung aus throwResult.Triggers
- Aufruf von FireGameLogicTriggersAsync
2. HandleExecuteGameAction (Zeile 457, 497-506):
- Auf async geändert
- Verarbeitet result.Triggers für Game-Actions wie "Passen"
3. Neue Methode FireGameLogicTriggersAsync (Zeile 985-1058):
- Parst TriggerType als ExpenseTriggerType
- Ruft IGameEventService.RegisterExpensePointsAsync für ExpensePoint-Trigger (mit Multiplier)
- Ruft IGameEventService.RegisterEliminatedAsync für Eliminated-Trigger
- Dispatcht TriggerExpensesCreatedAction für UI-Update
This commit is contained in:
parent
b8bd1b0939
commit
83b0e6a91b
|
|
@ -355,6 +355,7 @@ public class GameEffects
|
||||||
bool isGameOver = false;
|
bool isGameOver = false;
|
||||||
Guid? winnerId = null;
|
Guid? winnerId = null;
|
||||||
object? updatedGameModel = state.GameModel;
|
object? updatedGameModel = state.GameModel;
|
||||||
|
IReadOnlyList<TriggerEvent> gameLogicTriggers = [];
|
||||||
|
|
||||||
// Call ProcessThrow if game logic service is available
|
// Call ProcessThrow if game logic service is available
|
||||||
if (gameLogicService != null && state.GameModel != null)
|
if (gameLogicService != null && state.GameModel != null)
|
||||||
|
|
@ -366,6 +367,7 @@ public class GameEffects
|
||||||
shouldRotatePlayer = throwResult.ShouldRotatePlayer;
|
shouldRotatePlayer = throwResult.ShouldRotatePlayer;
|
||||||
isGameOver = throwResult.IsGameOver;
|
isGameOver = throwResult.IsGameOver;
|
||||||
winnerId = throwResult.WinnerId;
|
winnerId = throwResult.WinnerId;
|
||||||
|
gameLogicTriggers = throwResult.Triggers;
|
||||||
|
|
||||||
// Check for overrides from game logic
|
// Check for overrides from game logic
|
||||||
if (throwResult.Overrides != null)
|
if (throwResult.Overrides != null)
|
||||||
|
|
@ -422,6 +424,17 @@ public class GameEffects
|
||||||
// Fire expense triggers for special throw events
|
// Fire expense triggers for special throw events
|
||||||
await FireThrowTriggersAsync(state, currentPlayerId.Value, action, afterThrowState, dispatcher);
|
await FireThrowTriggersAsync(state, currentPlayerId.Value, action, afterThrowState, dispatcher);
|
||||||
|
|
||||||
|
// Fire game-specific triggers (e.g., ExpensePoint from Scheiss-Spiel)
|
||||||
|
if (gameLogicTriggers.Count > 0 && state.DayId.HasValue && state.ActiveGameId.HasValue)
|
||||||
|
{
|
||||||
|
await FireGameLogicTriggersAsync(
|
||||||
|
state.DayId.Value,
|
||||||
|
state.ActiveGameId.Value,
|
||||||
|
state.Participants.PlayerIds.ToList(),
|
||||||
|
gameLogicTriggers,
|
||||||
|
dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
// If game is over, skip save (user must confirm end via UI)
|
// If game is over, skip save (user must confirm end via UI)
|
||||||
if (isGameOver)
|
if (isGameOver)
|
||||||
{
|
{
|
||||||
|
|
@ -441,7 +454,7 @@ public class GameEffects
|
||||||
/// Handles ExecuteGameActionAction - executes game-specific action via IGameLogicService.
|
/// Handles ExecuteGameActionAction - executes game-specific action via IGameLogicService.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EffectMethod]
|
[EffectMethod]
|
||||||
public Task HandleExecuteGameAction(ExecuteGameActionAction action, IDispatcher dispatcher)
|
public async Task HandleExecuteGameAction(ExecuteGameActionAction action, IDispatcher dispatcher)
|
||||||
{
|
{
|
||||||
var state = _gameState.Value;
|
var state = _gameState.Value;
|
||||||
var gameTypeName = state.GameTypeName;
|
var gameTypeName = state.GameTypeName;
|
||||||
|
|
@ -451,13 +464,13 @@ public class GameEffects
|
||||||
if (state.IsGameOver)
|
if (state.IsGameOver)
|
||||||
{
|
{
|
||||||
dispatcher.Dispatch(new ExecuteGameActionFailureAction("Cannot execute action: game is already over"));
|
dispatcher.Dispatch(new ExecuteGameActionFailureAction("Cannot execute action: game is already over"));
|
||||||
return Task.CompletedTask;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(gameTypeName) || !currentPlayerId.HasValue || state.GameModel == null)
|
if (string.IsNullOrEmpty(gameTypeName) || !currentPlayerId.HasValue || state.GameModel == null)
|
||||||
{
|
{
|
||||||
dispatcher.Dispatch(new ExecuteGameActionFailureAction("Cannot execute action: missing game state"));
|
dispatcher.Dispatch(new ExecuteGameActionFailureAction("Cannot execute action: missing game state"));
|
||||||
return Task.CompletedTask;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -481,10 +494,21 @@ public class GameEffects
|
||||||
"Game action executed: {ActionId}, rotate={Rotate}, gameOver={GameOver}",
|
"Game action executed: {ActionId}, rotate={Rotate}, gameOver={GameOver}",
|
||||||
action.ActionId, result.ShouldRotatePlayer, result.IsGameOver);
|
action.ActionId, result.ShouldRotatePlayer, result.IsGameOver);
|
||||||
|
|
||||||
|
// Fire game-specific triggers from action result
|
||||||
|
if (result.Triggers.Count > 0 && state.DayId.HasValue && state.ActiveGameId.HasValue)
|
||||||
|
{
|
||||||
|
await FireGameLogicTriggersAsync(
|
||||||
|
state.DayId.Value,
|
||||||
|
state.ActiveGameId.Value,
|
||||||
|
state.Participants.PlayerIds.ToList(),
|
||||||
|
result.Triggers,
|
||||||
|
dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
// If game is over, skip save (user must confirm end via UI)
|
// If game is over, skip save (user must confirm end via UI)
|
||||||
if (result.IsGameOver)
|
if (result.IsGameOver)
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debounce save operations
|
// Debounce save operations
|
||||||
|
|
@ -505,8 +529,6 @@ public class GameEffects
|
||||||
_logger.LogError(ex, "Error executing game action: {ActionId}", action.ActionId);
|
_logger.LogError(ex, "Error executing game action: {ActionId}", action.ActionId);
|
||||||
dispatcher.Dispatch(new ExecuteGameActionFailureAction($"Error: {ex.Message}"));
|
dispatcher.Dispatch(new ExecuteGameActionFailureAction($"Error: {ex.Message}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ThrowPanelSnapshot CreateThrowPanelSnapshot(ThrowPanelState state)
|
private static ThrowPanelSnapshot CreateThrowPanelSnapshot(ThrowPanelState state)
|
||||||
|
|
@ -968,4 +990,79 @@ public class GameEffects
|
||||||
// Don't fail the throw recording if trigger fails
|
// Don't fail the throw recording if trigger fails
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fires game-specific triggers returned by IGameLogicService.ProcessThrow.
|
||||||
|
/// These are separate from standard throw triggers (Gutter, Strike, etc.).
|
||||||
|
/// </summary>
|
||||||
|
private async Task FireGameLogicTriggersAsync(
|
||||||
|
Guid dayId,
|
||||||
|
Guid gameId,
|
||||||
|
List<Guid> allParticipantIds,
|
||||||
|
IReadOnlyList<TriggerEvent> triggers,
|
||||||
|
IDispatcher dispatcher)
|
||||||
|
{
|
||||||
|
var allCreatedExpenses = new List<PersonExpenseDto>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var trigger in triggers)
|
||||||
|
{
|
||||||
|
// Parse trigger type
|
||||||
|
if (!Enum.TryParse<ExpenseTriggerType>(trigger.TriggerType, out var triggerType))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Unknown trigger type: {TriggerType}", trigger.TriggerType);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PersonExpenseDto> expenses = [];
|
||||||
|
|
||||||
|
switch (triggerType)
|
||||||
|
{
|
||||||
|
case ExpenseTriggerType.ExpensePoint:
|
||||||
|
expenses = await _gameEventService.RegisterExpensePointsAsync(
|
||||||
|
trigger.PersonId,
|
||||||
|
dayId,
|
||||||
|
gameId,
|
||||||
|
allParticipantIds,
|
||||||
|
trigger.Multiplier);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ExpenseTriggerType.Eliminated:
|
||||||
|
expenses = await _gameEventService.RegisterEliminatedAsync(
|
||||||
|
trigger.PersonId,
|
||||||
|
dayId,
|
||||||
|
gameId,
|
||||||
|
allParticipantIds);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_logger.LogDebug(
|
||||||
|
"Trigger type {TriggerType} not handled in game logic triggers",
|
||||||
|
triggerType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
allCreatedExpenses.AddRange(expenses);
|
||||||
|
|
||||||
|
if (expenses.Count > 0)
|
||||||
|
{
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Game logic trigger fired: Type={TriggerType}, Person={PersonId}, Multiplier={Multiplier}, Expenses={Count}",
|
||||||
|
triggerType, trigger.PersonId, trigger.Multiplier, expenses.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatch action to update UI with all created expenses
|
||||||
|
if (allCreatedExpenses.Count > 0)
|
||||||
|
{
|
||||||
|
dispatcher.Dispatch(new DayState.TriggerExpensesCreatedAction(allCreatedExpenses));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error firing game logic triggers");
|
||||||
|
// Don't fail the throw recording if trigger fails
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue