feat(state): coordinate booster use with inventory in the session

This commit is contained in:
2026-06-18 12:17:30 +09:00
parent 638a177fbb
commit ba4d4a662b
3 changed files with 103 additions and 1 deletions
+38
View File
@@ -2,12 +2,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../game/engine/game_engine.dart';
import '../game/engine/piece_generator.dart';
import '../game/models/booster.dart';
import '../game/models/grid.dart';
import '../game/models/objective.dart';
import '../game/models/piece.dart';
import '../game/models/stage.dart';
import 'providers.dart';
enum BoosterUseResult { success, noBooster, invalidTarget }
/// Immutable snapshot of one engine moment; the only game state the UI sees.
class GameViewState {
const GameViewState({
@@ -117,6 +120,41 @@ class GameSessionNotifier extends Notifier<GameViewState?> {
_publish(lastPlacement: null);
}
Future<BoosterUseResult> useHammer(int x, int y) =>
_useBooster(BoosterType.hammer, () {
final engine = _engine;
if (engine == null) return false;
return engine.useHammer(x, y);
});
Future<BoosterUseResult> useShuffle() =>
_useBooster(BoosterType.shuffle, () {
final engine = _engine;
if (engine == null) return false;
return engine.useShuffle();
});
Future<BoosterUseResult> useLineBomb({int? row, int? col}) =>
_useBooster(BoosterType.lineBomb, () {
final engine = _engine;
if (engine == null) return false;
return engine.useLineBomb(row: row, col: col);
});
Future<BoosterUseResult> _useBooster(
BoosterType type, bool Function() apply) async {
final engine = _engine;
if (engine == null) return BoosterUseResult.noBooster;
final inv = ref.read(boosterInventoryProvider.notifier);
if ((ref.read(boosterInventoryProvider)[type] ?? 0) <= 0) {
return BoosterUseResult.noBooster;
}
if (!apply()) return BoosterUseResult.invalidTarget;
await inv.consume(type);
_publish(lastPlacement: null);
return BoosterUseResult.success;
}
void _publish({required PlacementResult? lastPlacement}) {
final engine = _engine!;
state = GameViewState(