From 173339af82f587e6c185ac68d57088d03a7d3158 Mon Sep 17 00:00:00 2001 From: Hans Kokx Date: Sun, 15 Mar 2026 20:12:59 +0100 Subject: [PATCH] Fixed shareware sprites Signed-off-by: Hans Kokx --- lib/screens/sprite_gallery.dart | 12 +++--- .../lib/src/entities/enemies/enemy.dart | 3 ++ .../lib/src/entities/enemies/enemy_type.dart | 40 ++++++++++++------- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/lib/screens/sprite_gallery.dart b/lib/screens/sprite_gallery.dart index 7bc2b92..1ef87bf 100644 --- a/lib/screens/sprite_gallery.dart +++ b/lib/screens/sprite_gallery.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:wolf_3d_data_types/wolf_3d_data_types.dart'; import 'package:wolf_3d_entities/wolf_3d_entities.dart'; +import 'package:wolf_3d_flutter/wolf_3d.dart'; import 'package:wolf_3d_renderer/color_palette.dart'; class SpriteGallery extends StatelessWidget { @@ -8,6 +9,8 @@ class SpriteGallery extends StatelessWidget { const SpriteGallery({super.key, required this.sprites}); + bool get isShareware => Wolf3d.I.activeGame.version == GameVersion.shareware; + @override Widget build(BuildContext context) { return Scaffold( @@ -25,10 +28,12 @@ class SpriteGallery extends StatelessWidget { // --- Check which enemy owns this sprite --- String label = "Sprite Index: $index"; for (final enemy in EnemyType.values) { - if (enemy.claimsSpriteIndex(index)) { + if (enemy.claimsSpriteIndex(index, isShareware: isShareware)) { final EnemyAnimation? animation = enemy.getAnimationFromSprite( index, + isShareware: isShareware, ); + // Appends the enum name (e.g., "guard", "dog") label += "\n${enemy.name}"; @@ -37,11 +42,6 @@ class SpriteGallery extends StatelessWidget { label += "\n${animation.name}"; } - // Append the Map IDs for level editing reference - int staticBase = enemy.mapData.baseId; - - label += - "\nStat: $staticBase (E), ${staticBase + 1} (M), ${staticBase + 2} (H)"; break; } } diff --git a/packages/wolf_3d_entities/lib/src/entities/enemies/enemy.dart b/packages/wolf_3d_entities/lib/src/entities/enemies/enemy.dart index 17836c2..c8f00cc 100644 --- a/packages/wolf_3d_entities/lib/src/entities/enemies/enemy.dart +++ b/packages/wolf_3d_entities/lib/src/entities/enemies/enemy.dart @@ -210,6 +210,9 @@ abstract class Enemy extends Entity { final type = EnemyType.fromMapId(objId); if (type == null) return null; + // Reject enemies that don't exist in the shareware data! + if (isSharewareMode && !type.existsInShareware) return null; + final mapData = type.mapData; // ALL enemies have explicit directional angles! diff --git a/packages/wolf_3d_entities/lib/src/entities/enemies/enemy_type.dart b/packages/wolf_3d_entities/lib/src/entities/enemies/enemy_type.dart index 69078fe..8da24a2 100644 --- a/packages/wolf_3d_entities/lib/src/entities/enemies/enemy_type.dart +++ b/packages/wolf_3d_entities/lib/src/entities/enemies/enemy_type.dart @@ -3,7 +3,6 @@ import 'dart:math' as math; import 'package:wolf_3d_data_types/wolf_3d_data_types.dart'; import 'package:wolf_3d_entities/src/entities/enemies/enemy_animation.dart'; -/// Maps all possible animation states to their specific frame ranges. class EnemyAnimationMap { final SpriteFrameRange idle; final SpriteFrameRange walking; @@ -87,6 +86,7 @@ enum EnemyType { dying: SpriteFrameRange(227, 230), dead: SpriteFrameRange(232, 232), ), + existsInShareware: false, ), officer( mapData: EnemyMapData(MapObject.officerStart), @@ -98,12 +98,18 @@ enum EnemyType { dying: SpriteFrameRange(278, 281), dead: SpriteFrameRange(283, 283), ), + existsInShareware: false, ); final EnemyMapData mapData; final EnemyAnimationMap animations; + final bool existsInShareware; - const EnemyType({required this.mapData, required this.animations}); + const EnemyType({ + required this.mapData, + required this.animations, + this.existsInShareware = true, + }); static EnemyType? fromMapId(int id) { for (final type in EnemyType.values) { @@ -112,10 +118,21 @@ enum EnemyType { return null; } - bool claimsSpriteIndex(int index) => animations.getAnimation(index) != null; + /// Returns the animations only if the enemy actually exists in the current version. + EnemyAnimationMap? getAnimations(bool isShareware) { + if (isShareware && !existsInShareware) return null; + return animations; + } - EnemyAnimation? getAnimationFromSprite(int spriteIndex) { - return animations.getAnimation(spriteIndex); + bool claimsSpriteIndex(int index, {bool isShareware = false}) { + return getAnimations(isShareware)?.getAnimation(index) != null; + } + + EnemyAnimation? getAnimationFromSprite( + int spriteIndex, { + bool isShareware = false, + }) { + return getAnimations(isShareware)?.getAnimation(spriteIndex); } int getSpriteFromAnimation({ @@ -125,40 +142,33 @@ enum EnemyType { double angleDiff = 0, int? walkFrameOverride, }) { + // We don't need to check isShareware here, because if the entity exists + // in the game world, it implicitly passed the version check during spawn. final range = animations.getRange(animation); - // Calculates which of the 8 directions the enemy is facing relative to player int octant = ((angleDiff + (math.pi / 8)) / (math.pi / 4)).floor() % 8; if (octant < 0) octant += 8; return switch (animation) { EnemyAnimation.idle => range.start + octant, - EnemyAnimation.walking => () { - // Automatically calculates frames per angle (e.g. 32 frames / 8 angles = 4 frames) int framesPerAngle = range.length ~/ 8; - if (framesPerAngle < 1) framesPerAngle = 1; // Failsafe + if (framesPerAngle < 1) framesPerAngle = 1; int frame = walkFrameOverride ?? (elapsedMs ~/ 150) % framesPerAngle; return range.start + (frame * 8) + octant; }(), - EnemyAnimation.attacking => () { int time = elapsedMs - lastActionTime; - // Progresses through attack frames based on time, clamping at the last frame int mappedFrame = (time ~/ 150).clamp(0, range.length - 1); return range.start + mappedFrame; }(), - EnemyAnimation.pain => range.start, - EnemyAnimation.dying => () { int time = elapsedMs - lastActionTime; - // Progresses through death frames, staying on the final frame int mappedFrame = (time ~/ 150).clamp(0, range.length - 1); return range.start + mappedFrame; }(), - EnemyAnimation.dead => range.start, }; }