feat: Implement Change View and Renderer Options menus
- Added functionality to display and navigate the Change View menu in SixelRenderer and SoftwareRenderer. - Introduced methods to draw the Change View and Renderer Options menus, including handling cursor and selection states. - Updated WolfClassicMenuArt to include a customize label for the new menu. - Enhanced WolfMenuScreen to support new menu states. - Created tests for Change View menu interactions, ensuring proper transitions and renderer settings toggling. - Implemented persistence for renderer settings in Flutter, allowing settings to be saved and loaded from a local file. Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -54,6 +54,7 @@ void main() {
|
||||
final engine = _buildMultiGameEngine(input: input, difficulty: null);
|
||||
|
||||
engine.init();
|
||||
_dismissIntroSplash(engine, input);
|
||||
|
||||
expect(engine.isMenuOpen, isTrue);
|
||||
expect(engine.menuManager.activeMenu, WolfMenuScreen.gameSelect);
|
||||
@@ -62,6 +63,7 @@ void main() {
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isInteracting = false;
|
||||
engine.tick(const Duration(milliseconds: 300));
|
||||
_dismissIntroSplash(engine, input);
|
||||
|
||||
expect(engine.menuManager.activeMenu, WolfMenuScreen.mainMenu);
|
||||
expect(
|
||||
@@ -85,7 +87,7 @@ void main() {
|
||||
engine.menuManager.mainMenuEntries
|
||||
.map((entry) => entry.isEnabled)
|
||||
.toList(),
|
||||
[true, false, false, false, false, false, false, false, true, true],
|
||||
[true, false, false, false, false, true, false, false, true, true],
|
||||
);
|
||||
|
||||
input.isInteracting = true;
|
||||
@@ -102,6 +104,7 @@ void main() {
|
||||
final engine = _buildEngine(input: input, difficulty: null);
|
||||
|
||||
engine.init();
|
||||
_advanceToMainMenu(engine, input);
|
||||
|
||||
expect(engine.isMenuOpen, isTrue);
|
||||
expect(engine.menuManager.activeMenu, WolfMenuScreen.mainMenu);
|
||||
@@ -124,7 +127,7 @@ void main() {
|
||||
engine.menuManager.mainMenuEntries
|
||||
.map((entry) => entry.isEnabled)
|
||||
.toList(),
|
||||
[true, false, false, false, false, false, false, false, true, true],
|
||||
[true, false, false, false, false, true, false, false, true, true],
|
||||
);
|
||||
|
||||
input.isInteracting = true;
|
||||
@@ -172,7 +175,7 @@ void main() {
|
||||
engine.menuManager.mainMenuEntries
|
||||
.map((entry) => entry.isEnabled)
|
||||
.toList(),
|
||||
[true, false, false, false, false, false, false, true, true, true],
|
||||
[true, false, false, false, false, true, false, true, true, true],
|
||||
);
|
||||
|
||||
input.isMovingForward = true;
|
||||
@@ -203,6 +206,10 @@ void main() {
|
||||
|
||||
expect(manager.selectedMainIndex, 0);
|
||||
|
||||
manager.updateMainMenu(const EngineInput(isMovingBackward: true));
|
||||
manager.updateMainMenu(const EngineInput());
|
||||
expect(manager.selectedMainIndex, 5);
|
||||
|
||||
manager.updateMainMenu(const EngineInput(isMovingBackward: true));
|
||||
manager.updateMainMenu(const EngineInput());
|
||||
expect(manager.selectedMainIndex, 8);
|
||||
@@ -232,6 +239,12 @@ void main() {
|
||||
);
|
||||
|
||||
engine.init();
|
||||
_advanceToMainMenu(engine, input);
|
||||
|
||||
input.isMovingBackward = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isMovingBackward = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
|
||||
input.isMovingBackward = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
@@ -269,6 +282,7 @@ void main() {
|
||||
);
|
||||
|
||||
engine.init();
|
||||
_advanceToMainMenu(engine, input);
|
||||
|
||||
input.isBack = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
@@ -417,6 +431,28 @@ class _SilentAudio implements EngineAudio {
|
||||
void dispose() {}
|
||||
}
|
||||
|
||||
void _dismissIntroSplash(WolfEngine engine, _TestInput input) {
|
||||
int safety = 0;
|
||||
while (engine.menuManager.activeMenu == WolfMenuScreen.introSplash &&
|
||||
safety < 160) {
|
||||
input.isInteracting = safety.isEven;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
safety++;
|
||||
}
|
||||
input.isInteracting = false;
|
||||
}
|
||||
|
||||
void _advanceToMainMenu(WolfEngine engine, _TestInput input) {
|
||||
_dismissIntroSplash(engine, input);
|
||||
if (engine.menuManager.activeMenu == WolfMenuScreen.gameSelect) {
|
||||
input.isInteracting = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isInteracting = false;
|
||||
engine.tick(const Duration(milliseconds: 300));
|
||||
}
|
||||
expect(engine.menuManager.activeMenu, WolfMenuScreen.mainMenu);
|
||||
}
|
||||
|
||||
SpriteMap _buildGrid() => List.generate(64, (_) => List.filled(64, 0));
|
||||
|
||||
void _fillBoundaries(SpriteMap grid, int wallId) {
|
||||
|
||||
@@ -0,0 +1,546 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:wolf_3d_dart/src/menu/menu_manager.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_input.dart';
|
||||
|
||||
void main() {
|
||||
group('Change View menu wiring', () {
|
||||
test('CHANGE VIEW is wired and enabled in main menu', () {
|
||||
final engine = _buildEngine(difficulty: null);
|
||||
engine.init();
|
||||
final entries = engine.menuManager.mainMenuEntries;
|
||||
final changeViewEntry = entries.firstWhere(
|
||||
(e) => e.action == WolfMenuMainAction.changeView,
|
||||
);
|
||||
expect(changeViewEntry.isEnabled, isTrue);
|
||||
});
|
||||
|
||||
test('selecting CHANGE VIEW transitions to changeView screen', () {
|
||||
final input = _TestInput();
|
||||
final engine = _buildEngine(difficulty: null, input: input);
|
||||
engine.init();
|
||||
|
||||
// Navigate to CHANGE VIEW (index 5 in the default menu)
|
||||
engine.menuManager.showMainMenu(hasResumableGame: false);
|
||||
final int cvIndex = engine.menuManager.mainMenuEntries.indexWhere(
|
||||
(e) => e.action == WolfMenuMainAction.changeView,
|
||||
);
|
||||
// Move cursor down to CHANGE VIEW
|
||||
for (int i = 0; i < cvIndex; i++) {
|
||||
input.isMovingBackward = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isMovingBackward = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
}
|
||||
expect(engine.menuManager.selectedMainIndex, cvIndex);
|
||||
|
||||
// Confirm
|
||||
input.isInteracting = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isInteracting = false;
|
||||
|
||||
expect(
|
||||
engine.menuManager.activeMenu,
|
||||
WolfMenuScreen.changeView,
|
||||
);
|
||||
});
|
||||
|
||||
test('back from changeView returns to main menu', () {
|
||||
final input = _TestInput();
|
||||
final engine = _buildEngine(difficulty: null, input: input);
|
||||
engine.init();
|
||||
|
||||
engine.menuManager.showChangeViewMenu();
|
||||
|
||||
input.isBack = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isBack = false;
|
||||
|
||||
expect(engine.menuManager.activeMenu, WolfMenuScreen.mainMenu);
|
||||
});
|
||||
|
||||
test('renderer selection toggles mode and stays on changeView', () {
|
||||
final input = _TestInput();
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
input: input,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.software, WolfRendererMode.ascii},
|
||||
supportsAsciiThemes: true,
|
||||
supportsFpsCounter: false,
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
mode: WolfRendererMode.software,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
engine.menuManager.showChangeViewMenu();
|
||||
|
||||
// Move from SOFTWARE to ASCII.
|
||||
input.isMovingBackward = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isMovingBackward = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
|
||||
input.isInteracting = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isInteracting = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
|
||||
expect(engine.rendererSettings.mode, WolfRendererMode.ascii);
|
||||
expect(engine.menuManager.activeMenu, WolfMenuScreen.changeView);
|
||||
});
|
||||
|
||||
test('renderer option toggles are available inline in changeView', () {
|
||||
final input = _TestInput();
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
input: input,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.software, WolfRendererMode.ascii},
|
||||
supportsAsciiThemes: true,
|
||||
supportsFpsCounter: false,
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
mode: WolfRendererMode.software,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
engine.menuManager.showChangeViewMenu();
|
||||
|
||||
// Select ASCII so mode-specific settings become available.
|
||||
input.isMovingBackward = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isMovingBackward = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isInteracting = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isInteracting = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
|
||||
// Move to first inline option row and toggle it.
|
||||
input.isMovingBackward = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isMovingBackward = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isInteracting = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isInteracting = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
|
||||
expect(engine.menuManager.activeMenu, WolfMenuScreen.changeView);
|
||||
expect(
|
||||
engine.rendererSettings.asciiThemeId,
|
||||
WolfRendererSettings.asciiThemeQuadrant,
|
||||
);
|
||||
});
|
||||
|
||||
test('toggling renderer option keeps cursor on selected option', () {
|
||||
final input = _TestInput();
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
input: input,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.ascii},
|
||||
supportsAsciiThemes: true,
|
||||
supportsFpsCounter: true,
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
mode: WolfRendererMode.ascii,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
engine.menuManager.showChangeViewMenu();
|
||||
|
||||
// Move from renderer row to first option row, then to second option row.
|
||||
input.isMovingBackward = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isMovingBackward = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
|
||||
input.isMovingBackward = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isMovingBackward = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
final int modeCount = engine.menuManager.changeViewEntries.length;
|
||||
expect(engine.menuManager.selectedChangeViewIndex, modeCount + 1);
|
||||
|
||||
input.isInteracting = true;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
input.isInteracting = false;
|
||||
engine.tick(const Duration(milliseconds: 16));
|
||||
|
||||
expect(engine.menuManager.selectedChangeViewIndex, modeCount + 1);
|
||||
expect(engine.rendererSettings.fpsCounterEnabled, isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
group('Renderer settings model', () {
|
||||
test('default capabilities include software mode', () {
|
||||
final engine = _buildEngine(difficulty: null);
|
||||
engine.init();
|
||||
expect(
|
||||
engine.rendererCapabilities.supportsMode(WolfRendererMode.software),
|
||||
isTrue,
|
||||
);
|
||||
});
|
||||
|
||||
test('updateRendererSettings mutates mode and notifies callback', () {
|
||||
WolfRendererSettings? notified;
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
onRendererSettingsChanged: (s) => notified = s,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.software, WolfRendererMode.ascii},
|
||||
supportsAsciiThemes: true,
|
||||
supportsFpsCounter: true,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
|
||||
engine.updateRendererSettings(
|
||||
const WolfRendererSettings(mode: WolfRendererMode.ascii),
|
||||
);
|
||||
|
||||
expect(engine.rendererSettings.mode, WolfRendererMode.ascii);
|
||||
expect(notified?.mode, WolfRendererMode.ascii);
|
||||
});
|
||||
|
||||
test('cycleRendererMode cycles through supported modes', () {
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.software, WolfRendererMode.ascii},
|
||||
supportsAsciiThemes: true,
|
||||
supportsFpsCounter: true,
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
mode: WolfRendererMode.software,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
|
||||
engine.cycleRendererMode();
|
||||
expect(engine.rendererSettings.mode, WolfRendererMode.ascii);
|
||||
|
||||
engine.cycleRendererMode();
|
||||
expect(engine.rendererSettings.mode, WolfRendererMode.software);
|
||||
});
|
||||
|
||||
test('cycleAsciiTheme cycles to next theme', () {
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.ascii},
|
||||
supportsAsciiThemes: true,
|
||||
supportsFpsCounter: false,
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
asciiThemeId: WolfRendererSettings.asciiThemeBlocks,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
|
||||
engine.cycleAsciiTheme();
|
||||
expect(
|
||||
engine.rendererSettings.asciiThemeId,
|
||||
WolfRendererSettings.asciiThemeQuadrant,
|
||||
);
|
||||
|
||||
engine.cycleAsciiTheme();
|
||||
expect(
|
||||
engine.rendererSettings.asciiThemeId,
|
||||
WolfRendererSettings.asciiThemeBlocks,
|
||||
);
|
||||
});
|
||||
|
||||
test('toggleFpsCounter toggles and syncs showFpsCounter', () {
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.software},
|
||||
supportsFpsCounter: true,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
expect(engine.showFpsCounter, isFalse);
|
||||
|
||||
engine.toggleFpsCounter();
|
||||
expect(engine.rendererSettings.fpsCounterEnabled, isTrue);
|
||||
expect(engine.showFpsCounter, isTrue);
|
||||
|
||||
engine.toggleFpsCounter();
|
||||
expect(engine.rendererSettings.fpsCounterEnabled, isFalse);
|
||||
expect(engine.showFpsCounter, isFalse);
|
||||
});
|
||||
|
||||
test('toggleHardwareEffects no-ops when capability is absent', () {
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.software},
|
||||
supportsHardwareEffects: false,
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
hardwareEffectsEnabled: false,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
|
||||
engine.toggleHardwareEffects();
|
||||
expect(engine.rendererSettings.hardwareEffectsEnabled, isFalse);
|
||||
});
|
||||
});
|
||||
|
||||
group('Renderer menu visibility', () {
|
||||
test('changeViewEntries only contain supported modes', () {
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.ascii, WolfRendererMode.software},
|
||||
supportsAsciiThemes: true,
|
||||
supportsFpsCounter: false,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
|
||||
final modes = engine.menuManager.changeViewEntries
|
||||
.map((e) => e.mode)
|
||||
.toSet();
|
||||
expect(
|
||||
modes,
|
||||
equals({WolfRendererMode.ascii, WolfRendererMode.software}),
|
||||
);
|
||||
});
|
||||
|
||||
test('checked renderer entry matches active mode', () {
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.ascii, WolfRendererMode.software},
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
mode: WolfRendererMode.ascii,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
|
||||
final checked = engine.menuManager.changeViewEntries
|
||||
.where((e) => e.isChecked)
|
||||
.toList();
|
||||
expect(checked.length, 1);
|
||||
expect(checked.first.mode, WolfRendererMode.ascii);
|
||||
});
|
||||
|
||||
test('ASCII theme option is shown when mode is ascii', () {
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.ascii},
|
||||
supportsAsciiThemes: true,
|
||||
supportsFpsCounter: false,
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
mode: WolfRendererMode.ascii,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
|
||||
final optionIds = engine.menuManager.rendererOptionEntries
|
||||
.map((e) => e.id)
|
||||
.toSet();
|
||||
expect(optionIds.contains(WolfRendererOptionId.asciiTheme), isTrue);
|
||||
});
|
||||
|
||||
test('ASCII theme option is hidden when mode is not ascii', () {
|
||||
final engine = _buildEngine(
|
||||
difficulty: null,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.software},
|
||||
supportsAsciiThemes: false,
|
||||
supportsFpsCounter: false,
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
mode: WolfRendererMode.software,
|
||||
),
|
||||
);
|
||||
engine.init();
|
||||
|
||||
final optionIds = engine.menuManager.rendererOptionEntries
|
||||
.map((e) => e.id)
|
||||
.toSet();
|
||||
expect(optionIds.contains(WolfRendererOptionId.asciiTheme), isFalse);
|
||||
});
|
||||
|
||||
test('hardware effects option only shown when hardware mode is active', () {
|
||||
final engineHardware = _buildEngine(
|
||||
difficulty: null,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.hardware},
|
||||
supportsHardwareEffects: true,
|
||||
supportsFpsCounter: false,
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
mode: WolfRendererMode.hardware,
|
||||
),
|
||||
);
|
||||
engineHardware.init();
|
||||
final hardwareOptIds = engineHardware.menuManager.rendererOptionEntries
|
||||
.map((e) => e.id)
|
||||
.toSet();
|
||||
expect(
|
||||
hardwareOptIds.contains(WolfRendererOptionId.hardwareEffects),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
final engineSoftware = _buildEngine(
|
||||
difficulty: null,
|
||||
rendererCapabilities: const WolfRendererCapabilities(
|
||||
supportedModes: {WolfRendererMode.software},
|
||||
supportsHardwareEffects: false,
|
||||
supportsFpsCounter: false,
|
||||
),
|
||||
rendererSettings: const WolfRendererSettings(
|
||||
mode: WolfRendererMode.software,
|
||||
),
|
||||
);
|
||||
engineSoftware.init();
|
||||
final softwareOptIds = engineSoftware.menuManager.rendererOptionEntries
|
||||
.map((e) => e.id)
|
||||
.toSet();
|
||||
expect(
|
||||
softwareOptIds.contains(WolfRendererOptionId.hardwareEffects),
|
||||
isFalse,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('WolfRendererSettings serialization', () {
|
||||
test('round-trip through JSON is lossless', () {
|
||||
const WolfRendererSettings original = WolfRendererSettings(
|
||||
mode: WolfRendererMode.ascii,
|
||||
asciiThemeId: WolfRendererSettings.asciiThemeQuadrant,
|
||||
hardwareEffectsEnabled: true,
|
||||
fpsCounterEnabled: true,
|
||||
);
|
||||
final json = original.toJson();
|
||||
final restored = WolfRendererSettings.fromJson(json);
|
||||
|
||||
expect(restored.mode, original.mode);
|
||||
expect(restored.asciiThemeId, original.asciiThemeId);
|
||||
expect(restored.hardwareEffectsEnabled, original.hardwareEffectsEnabled);
|
||||
expect(restored.fpsCounterEnabled, original.fpsCounterEnabled);
|
||||
});
|
||||
|
||||
test('fromJson tolerates unknown mode with safe default', () {
|
||||
final settings = WolfRendererSettings.fromJson(<String, Object?>{
|
||||
'mode': 'unknown_mode_xyz',
|
||||
});
|
||||
expect(settings.mode, WolfRendererMode.software);
|
||||
});
|
||||
|
||||
test('fromJson tolerates missing fields', () {
|
||||
final settings = WolfRendererSettings.fromJson(<String, Object?>{});
|
||||
expect(settings.mode, WolfRendererMode.software);
|
||||
expect(settings.asciiThemeId, WolfRendererSettings.asciiThemeBlocks);
|
||||
expect(settings.hardwareEffectsEnabled, isFalse);
|
||||
expect(settings.fpsCounterEnabled, isFalse);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
WolfEngine _buildEngine({
|
||||
required Difficulty? difficulty,
|
||||
_TestInput? input,
|
||||
WolfRendererCapabilities? rendererCapabilities,
|
||||
WolfRendererSettings? rendererSettings,
|
||||
void Function(WolfRendererSettings)? onRendererSettingsChanged,
|
||||
}) {
|
||||
return WolfEngine(
|
||||
data: _buildTestData(),
|
||||
difficulty: difficulty,
|
||||
startingEpisode: 0,
|
||||
frameBuffer: FrameBuffer(64, 64),
|
||||
input: input ?? _TestInput(),
|
||||
engineAudio: _SilentAudio(),
|
||||
onGameWon: () {},
|
||||
rendererCapabilities: rendererCapabilities,
|
||||
rendererSettings: rendererSettings,
|
||||
onRendererSettingsChanged: onRendererSettingsChanged,
|
||||
);
|
||||
}
|
||||
|
||||
WolfensteinData _buildTestData() {
|
||||
final wallGrid = List.generate(64, (_) => List.filled(64, 0));
|
||||
final objGrid = List.generate(64, (_) => List.filled(64, 0));
|
||||
_fillBoundaries(wallGrid, 2);
|
||||
objGrid[2][2] = MapObject.playerEast;
|
||||
|
||||
return WolfensteinData(
|
||||
version: GameVersion.retail,
|
||||
dataVersion: DataVersion.unknown,
|
||||
registry: RetailAssetRegistry(),
|
||||
walls: [_sprite(1), _sprite(1), _sprite(2), _sprite(2)],
|
||||
sprites: List.generate(436, (_) => _sprite(255)),
|
||||
sounds: List.generate(200, (_) => PcmSound(Uint8List(1))),
|
||||
adLibSounds: const [],
|
||||
music: const [],
|
||||
vgaImages: const [],
|
||||
episodes: [
|
||||
Episode(
|
||||
name: 'Test Episode',
|
||||
levels: [
|
||||
WolfLevel(
|
||||
name: 'Test Level',
|
||||
wallGrid: wallGrid,
|
||||
areaGrid: List.generate(64, (_) => List.filled(64, -1)),
|
||||
objectGrid: objGrid,
|
||||
music: Music.level01,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _fillBoundaries(List<List<int>> grid, int wallId) {
|
||||
for (int i = 0; i < 64; i++) {
|
||||
grid[0][i] = wallId;
|
||||
grid[63][i] = wallId;
|
||||
grid[i][0] = wallId;
|
||||
grid[i][63] = wallId;
|
||||
}
|
||||
}
|
||||
|
||||
Sprite _sprite(int c) => Sprite(Uint8List.fromList(List.filled(64 * 64, c)));
|
||||
|
||||
class _TestInput extends Wolf3dInput {
|
||||
@override
|
||||
void update() {}
|
||||
}
|
||||
|
||||
class _SilentAudio implements EngineAudio {
|
||||
@override
|
||||
WolfensteinData? activeGame;
|
||||
@override
|
||||
Future<void> debugSoundTest() async {}
|
||||
@override
|
||||
Future<void> init() async {}
|
||||
@override
|
||||
void playLevelMusic(Music music) {}
|
||||
@override
|
||||
void playMenuMusic() {}
|
||||
@override
|
||||
void playSoundEffect(SoundEffect effect) {}
|
||||
@override
|
||||
void playSoundEffectId(int sfxId) {}
|
||||
@override
|
||||
void stopMusic() {}
|
||||
@override
|
||||
Future<void> stopAllAudio() async {}
|
||||
@override
|
||||
void dispose() {}
|
||||
}
|
||||
Reference in New Issue
Block a user