Trying to figure out issue with sprites loading improperly. Broken, still.

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-14 23:20:03 +01:00
parent 1ec891d9a0
commit 8ea7642c8b
12 changed files with 242 additions and 320 deletions

View File

@@ -32,8 +32,9 @@ class Collectible extends Entity {
int objId,
double x,
double y,
Difficulty _,
) {
Difficulty difficulty, {
bool isSharewareMode = false,
}) {
if (isCollectible(objId)) {
return Collectible(
x: x,

View File

@@ -39,8 +39,9 @@ class Decorative extends Entity {
int objId,
double x,
double y,
Difficulty _,
) {
Difficulty difficulty, {
bool isSharewareMode = false,
}) {
if (isDecoration(objId)) {
return Decorative(
x: x,

View File

@@ -35,8 +35,9 @@ class HansGrosse extends Enemy {
int objId,
double x,
double y,
Difficulty difficulty,
) {
Difficulty difficulty, {
bool isSharewareMode = false,
}) {
if (objId == MapObject.bossHansGrosse) {
return HansGrosse(
x: x,

View File

@@ -1,37 +1,26 @@
import 'dart:math' as math;
import 'package:wolf_dart/classes/coordinate_2d.dart';
import 'package:wolf_dart/features/difficulty/difficulty.dart';
import 'package:wolf_dart/features/entities/enemies/enemy.dart';
import 'package:wolf_dart/features/entities/entity.dart';
import 'package:wolf_dart/features/entities/map_objects.dart'; // NEW
class Dog extends Enemy {
static const double speed = 0.05;
bool _hasBittenThisCycle = false;
static EnemyType get type => EnemyType.dog;
Dog({
required super.x,
required super.y,
required super.angle,
required super.mapId,
}) : super(
spriteIndex: EnemyType.dog.spriteBaseIdx,
spriteIndex: type.spriteBaseIdx,
state: EntityState.idle,
);
static Dog? trySpawn(int objId, double x, double y, Difficulty _) {
if (EnemyType.dog.claimsMapId(objId)) {
bool isPatrolling = objId >= EnemyType.dog.mapBaseId + 18;
return Dog(
x: x,
y: y,
angle: MapObject.getAngle(objId),
mapId: objId,
)..state = isPatrolling ? EntityState.patrolling : EntityState.idle;
}
return null;
) {
health = 1;
damage = 5;
}
@override
@@ -39,8 +28,8 @@ class Dog extends Enemy {
required int elapsedMs,
required Coordinate2D playerPosition,
required bool Function(int x, int y) isWalkable,
required void Function(int x, int y) tryOpenDoor,
required void Function(int damage) onDamagePlayer,
required void Function(int x, int y) tryOpenDoor,
}) {
Coordinate2D movement = const Coordinate2D(0, 0);
double newAngle = angle;
@@ -49,8 +38,6 @@ class Dog extends Enemy {
elapsedMs: elapsedMs,
playerPosition: playerPosition,
isWalkable: isWalkable,
baseReactionMs: 100,
reactionVarianceMs: 200,
);
double distance = position.distanceTo(playerPosition);
@@ -61,7 +48,6 @@ class Dog extends Enemy {
}
double diff = angleToPlayer - newAngle;
while (diff <= -math.pi) {
diff += 2 * math.pi;
}
@@ -69,72 +55,35 @@ class Dog extends Enemy {
diff -= 2 * math.pi;
}
int octant = ((diff + (math.pi / 8)) / (math.pi / 4)).floor() % 8;
if (octant < 0) octant += 8;
EnemyAnimation currentAnim = switch (state) {
EntityState.patrolling => EnemyAnimation.walking,
EntityState.attacking => EnemyAnimation.attacking,
EntityState.dead => isDying ? EnemyAnimation.dying : EnemyAnimation.dead,
_ => EnemyAnimation.idle,
};
// 3. Clean State Machine
switch (state) {
case EntityState.idle:
spriteIndex = 99 + octant;
break;
case EntityState.patrolling:
if (distance > 0.8) {
// UPGRADED: Smooth vector movement instead of grid-snapping
double moveX = math.cos(angleToPlayer) * speed;
double moveY = math.sin(angleToPlayer) * speed;
Coordinate2D intendedMovement = Coordinate2D(moveX, moveY);
movement = getValidMovement(
intendedMovement,
isWalkable,
tryOpenDoor,
spriteIndex = type.getSpriteFromAnimation(
animation: currentAnim,
elapsedMs: elapsedMs,
lastActionTime: lastActionTime,
angleDiff: diff,
);
}
int walkFrame = (elapsedMs ~/ 100) % 4;
spriteIndex = 107 + (walkFrame * 8) + octant;
if (distance < 1.0 && elapsedMs - lastActionTime > 1000) {
if (state == EntityState.patrolling && distance < 1.0) {
state = EntityState.attacking;
lastActionTime = elapsedMs;
_hasBittenThisCycle = false;
}
break;
case EntityState.attacking:
int timeAttacking = elapsedMs - lastActionTime;
if (timeAttacking < 200) {
spriteIndex = 139;
if (!_hasBittenThisCycle) {
onDamagePlayer(5);
if (state == EntityState.attacking) {
int time = elapsedMs - lastActionTime;
if (time >= 200 && !_hasBittenThisCycle) {
onDamagePlayer(damage);
_hasBittenThisCycle = true;
}
} else {
} else if (time >= 400) {
state = EntityState.patrolling;
lastActionTime = elapsedMs;
}
break;
// Make sure dogs have a death state so they don't stay standing!
case EntityState.dead:
if (isDying) {
int deathFrame = (elapsedMs - lastActionTime) ~/ 100;
if (deathFrame < 4) {
spriteIndex =
140 + deathFrame; // Dog death frames usually start here
} else {
spriteIndex = 143; // Dead dog on floor
isDying = false;
}
} else {
spriteIndex = 143;
}
break;
default:
break;
}
return (movement: movement, newAngle: newAngle);

View File

@@ -1,7 +1,23 @@
import 'dart:math' as math;
import 'package:wolf_dart/classes/coordinate_2d.dart';
import 'package:wolf_dart/features/difficulty/difficulty.dart';
import 'package:wolf_dart/features/entities/enemies/dog.dart';
import 'package:wolf_dart/features/entities/enemies/guard.dart';
import 'package:wolf_dart/features/entities/enemies/mutant.dart';
import 'package:wolf_dart/features/entities/enemies/officer.dart';
import 'package:wolf_dart/features/entities/enemies/ss.dart';
import 'package:wolf_dart/features/entities/entity.dart';
import 'package:wolf_dart/features/entities/map_objects.dart';
enum EnemyAnimation {
idle,
walking,
attacking,
pain,
dying,
dead,
}
enum EnemyType {
guard(mapBaseId: 108, spriteBaseIdx: 50),
@@ -44,6 +60,93 @@ enum EnemyType {
EnemyType.officer => index >= 238 && index <= 287,
};
}
/// Returns the current animation state for a given sprite index.
/// Returns null if the sprite index does not belong to this enemy.
EnemyAnimation? getAnimationFromSprite(int spriteIndex) {
if (!claimsSpriteIndex(spriteIndex)) return null;
// By working with offsets, we don't have to hardcode the 100+ sprite indices!
int offset = spriteIndex - spriteBaseIdx;
// All standard enemies use offsets 0-7 for their 8 directional Idle frames
if (offset >= 0 && offset <= 7) return EnemyAnimation.idle;
// The action frames vary slightly depending on the enemy type
return switch (this) {
EnemyType.guard || EnemyType.ss => switch (offset) {
>= 8 && <= 39 => EnemyAnimation.walking, // 4 frames * 8 directions
>= 40 && <= 42 => EnemyAnimation.attacking, // Aim, Fire, Recoil
43 => EnemyAnimation.pain,
>= 44 && <= 46 => EnemyAnimation.dying,
_ => EnemyAnimation.dead, // Catch-all for final frames
},
EnemyType.officer || EnemyType.mutant => switch (offset) {
>= 8 && <= 39 => EnemyAnimation.walking,
>= 40 && <= 41 => EnemyAnimation.attacking, // Only 2 attack frames!
42 => EnemyAnimation.pain,
>= 43 && <= 45 => EnemyAnimation.dying,
_ => EnemyAnimation.dead,
},
EnemyType.dog => switch (offset) {
// Dogs are special: 3 walk frames (24 total) and NO pain frame!
>= 8 && <= 31 => EnemyAnimation.walking,
>= 32 && <= 34 => EnemyAnimation.attacking, // Leap and bite
>= 35 && <= 37 => EnemyAnimation.dying,
_ => EnemyAnimation.dead,
},
};
}
int getSpriteFromAnimation({
required EnemyAnimation animation,
required int elapsedMs,
required int lastActionTime,
double angleDiff = 0,
int? walkFrameOverride, // Optional for custom timing
}) {
// 1. Calculate Octant for directional sprites (Idle/Walk)
int octant = ((angleDiff + (math.pi / 8)) / (math.pi / 4)).floor() % 8;
if (octant < 0) octant += 8;
return switch (animation) {
EnemyAnimation.idle => spriteBaseIdx + octant,
EnemyAnimation.walking => () {
int frameCount = this == EnemyType.dog ? 3 : 4;
int frame = walkFrameOverride ?? (elapsedMs ~/ 150) % frameCount;
return (spriteBaseIdx + 8) + (frame * 8) + octant;
}(),
EnemyAnimation.attacking => () {
int time = elapsedMs - lastActionTime;
return switch (this) {
EnemyType.guard || EnemyType.ss || EnemyType.dog =>
spriteBaseIdx +
(time < 150
? 40
: time < 300
? 41
: 40),
EnemyType.officer ||
EnemyType.mutant => spriteBaseIdx + (time < 200 ? 40 : 41),
};
}(),
EnemyAnimation.pain => spriteBaseIdx + (this == EnemyType.dog ? 32 : 42),
EnemyAnimation.dying => () {
int frame = (elapsedMs - lastActionTime) ~/ 150;
int maxFrames = this == EnemyType.dog ? 2 : 3;
int offset = this == EnemyType.dog ? 35 : 43;
return spriteBaseIdx + offset + (frame.clamp(0, maxFrames));
}(),
EnemyAnimation.dead => spriteBaseIdx + (this == EnemyType.dog ? 37 : 45),
};
}
}
abstract class Enemy extends Entity {
@@ -216,4 +319,34 @@ abstract class Enemy extends Entity {
required void Function(int x, int y) tryOpenDoor,
required void Function(int damage) onDamagePlayer,
});
/// Centralized factory to handle all enemy spawning logic
static Enemy? spawn(
int objId,
double x,
double y,
Difficulty difficulty, {
bool isSharewareMode = false,
}) {
// 1. Check Difficulty & Compatibility
if (!MapObject.shouldSpawn(objId, difficulty)) return null;
// If the checkbox is checked, block non-Shareware enemies
if (isSharewareMode && !MapObject.isSharewareCompatible(objId)) return null;
final type = EnemyType.fromMapId(objId);
if (type == null) return null;
bool isPatrolling = objId >= type.mapBaseId + 18;
double spawnAngle = MapObject.getAngle(objId);
// 2. Return the specific instance
return switch (type) {
EnemyType.guard => Guard(x: x, y: y, angle: spawnAngle, mapId: objId),
EnemyType.dog => Dog(x: x, y: y, angle: spawnAngle, mapId: objId),
EnemyType.ss => SS(x: x, y: y, angle: spawnAngle, mapId: objId),
EnemyType.mutant => Mutant(x: x, y: y, angle: spawnAngle, mapId: objId),
EnemyType.officer => Officer(x: x, y: y, angle: spawnAngle, mapId: objId),
}..state = isPatrolling ? EntityState.patrolling : EntityState.idle;
}
}

View File

@@ -1,39 +1,25 @@
import 'dart:math' as math;
import 'package:wolf_dart/classes/coordinate_2d.dart';
import 'package:wolf_dart/features/difficulty/difficulty.dart';
import 'package:wolf_dart/features/entities/enemies/enemy.dart';
import 'package:wolf_dart/features/entities/entity.dart';
import 'package:wolf_dart/features/entities/map_objects.dart';
class Guard extends Enemy {
static const double speed = 0.03;
bool _hasFiredThisCycle = false;
static EnemyType get type => EnemyType.guard;
Guard({
required super.x,
required super.y,
required super.angle,
required super.mapId,
}) : super(
spriteIndex: EnemyType.guard.spriteBaseIdx,
spriteIndex: type.spriteBaseIdx,
state: EntityState.idle,
);
static Guard? trySpawn(int objId, double x, double y, Difficulty _) {
if (EnemyType.guard.claimsMapId(objId) && objId != 124 && objId != 125) {
bool isPatrolling = objId >= EnemyType.guard.mapBaseId + 18;
return Guard(
x: x,
y: y,
angle: MapObject.getAngle(objId),
mapId: objId,
)..state = isPatrolling ? EntityState.patrolling : EntityState.idle;
}
return null;
}
@override
({Coordinate2D movement, double newAngle}) update({
required int elapsedMs,
@@ -58,9 +44,8 @@ class Guard extends Enemy {
newAngle = angleToPlayer;
}
// Octant logic (Directional sprites)
// Calculate angle diff for the octant logic
double diff = angleToPlayer - newAngle;
while (diff <= -math.pi) {
diff += 2 * math.pi;
}
@@ -68,82 +53,32 @@ class Guard extends Enemy {
diff -= 2 * math.pi;
}
int octant = ((diff + (math.pi / 8)) / (math.pi / 4)).floor() % 8;
if (octant < 0) octant += 8;
// Helper to get sprite based on current state
EnemyAnimation currentAnim = switch (state) {
EntityState.patrolling => EnemyAnimation.walking,
EntityState.attacking => EnemyAnimation.attacking,
EntityState.pain => EnemyAnimation.pain,
EntityState.dead => isDying ? EnemyAnimation.dying : EnemyAnimation.dead,
_ => EnemyAnimation.idle,
};
// 3. State Machine
switch (state) {
case EntityState.idle:
spriteIndex = 50 + octant;
break;
case EntityState.patrolling:
if (distance > 0.8) {
double moveX = math.cos(angleToPlayer) * speed;
double moveY = math.sin(angleToPlayer) * speed;
Coordinate2D intendedMovement = Coordinate2D(moveX, moveY);
movement = getValidMovement(
intendedMovement,
isWalkable,
tryOpenDoor,
spriteIndex = type.getSpriteFromAnimation(
animation: currentAnim,
elapsedMs: elapsedMs,
lastActionTime: lastActionTime,
angleDiff: diff,
);
}
int walkFrame = (elapsedMs ~/ 150) % 4;
spriteIndex = 58 + (walkFrame * 8) + octant;
if (distance < 6.0 && elapsedMs - lastActionTime > 1500) {
if (hasLineOfSight(playerPosition, isWalkable)) {
state = EntityState.attacking;
lastActionTime = elapsedMs;
_hasFiredThisCycle = false;
}
}
break;
case EntityState.attacking:
int timeShooting = elapsedMs - lastActionTime;
if (timeShooting < 150) {
spriteIndex = 90; // Aiming
} else if (timeShooting < 300) {
spriteIndex = 91; // Firing
if (!_hasFiredThisCycle) {
// Logic triggers (Damage, State transitions)
if (state == EntityState.attacking) {
int time = elapsedMs - lastActionTime;
if (time >= 150 && time < 300 && !_hasFiredThisCycle) {
onDamagePlayer(10);
_hasFiredThisCycle = true;
}
} else if (timeShooting < 450) {
spriteIndex = 90; // Recoil (back to aim pose)
} else {
} else if (time >= 450) {
state = EntityState.patrolling;
lastActionTime = elapsedMs;
}
break;
case EntityState.pain:
spriteIndex = 92; // Ouch frame
if (elapsedMs - lastActionTime > 250) {
state = EntityState.patrolling;
lastActionTime = elapsedMs;
}
break;
case EntityState.dead:
if (isDying) {
int deathFrame = (elapsedMs - lastActionTime) ~/ 150;
if (deathFrame < 3) {
spriteIndex = 93 + deathFrame; // Cycles 93, 94, 95
} else {
spriteIndex = 95; // Final dead frame
isDying = false;
}
} else {
spriteIndex = 95; // Final dead frame
}
break;
default:
break;
}
return (movement: movement, newAngle: newAngle);

View File

@@ -1,42 +1,28 @@
import 'dart:math' as math;
import 'package:wolf_dart/classes/coordinate_2d.dart';
import 'package:wolf_dart/features/difficulty/difficulty.dart';
import 'package:wolf_dart/features/entities/enemies/enemy.dart';
import 'package:wolf_dart/features/entities/entity.dart';
import 'package:wolf_dart/features/entities/map_objects.dart';
class Mutant extends Enemy {
static const double speed = 0.045;
static const double speed = 0.04;
bool _hasFiredThisCycle = false;
static EnemyType get type => EnemyType.mutant;
Mutant({
required super.x,
required super.y,
required super.angle,
required super.mapId,
}) : super(
spriteIndex: EnemyType.mutant.spriteBaseIdx,
spriteIndex: type.spriteBaseIdx,
state: EntityState.idle,
) {
health = 45;
damage = 10;
}
static Mutant? trySpawn(int objId, double x, double y, Difficulty _) {
if (EnemyType.mutant.claimsMapId(objId)) {
bool isPatrolling = objId >= EnemyType.mutant.mapBaseId + 18;
return Mutant(
x: x,
y: y,
angle: MapObject.getAngle(objId),
mapId: objId,
)..state = isPatrolling ? EntityState.patrolling : EntityState.idle;
}
return null;
}
@override
({Coordinate2D movement, double newAngle}) update({
required int elapsedMs,
@@ -48,7 +34,6 @@ class Mutant extends Enemy {
Coordinate2D movement = const Coordinate2D(0, 0);
double newAngle = angle;
// Mutants don't make wake-up noises in the original game!
checkWakeUp(
elapsedMs: elapsedMs,
playerPosition: playerPosition,
@@ -62,6 +47,7 @@ class Mutant extends Enemy {
newAngle = angleToPlayer;
}
// Calculate angle diff for the octant logic
double diff = angleToPlayer - newAngle;
while (diff <= -math.pi) {
diff += 2 * math.pi;
@@ -69,80 +55,31 @@ class Mutant extends Enemy {
while (diff > math.pi) {
diff -= 2 * math.pi;
}
int octant = ((diff + (math.pi / 8)) / (math.pi / 4)).floor() % 8;
if (octant < 0) octant += 8;
switch (state) {
case EntityState.idle:
spriteIndex = EnemyType.mutant.spriteBaseIdx + octant;
break;
EnemyAnimation currentAnim = switch (state) {
EntityState.patrolling => EnemyAnimation.walking,
EntityState.attacking => EnemyAnimation.attacking,
EntityState.pain => EnemyAnimation.pain,
EntityState.dead => isDying ? EnemyAnimation.dying : EnemyAnimation.dead,
_ => EnemyAnimation.idle,
};
case EntityState.patrolling:
if (distance > 0.8) {
double moveX = math.cos(angleToPlayer) * speed;
double moveY = math.sin(angleToPlayer) * speed;
movement = getValidMovement(
Coordinate2D(moveX, moveY),
isWalkable,
tryOpenDoor,
spriteIndex = type.getSpriteFromAnimation(
animation: currentAnim,
elapsedMs: elapsedMs,
lastActionTime: lastActionTime,
angleDiff: diff,
);
}
int walkFrame = (elapsedMs ~/ 150) % 4;
spriteIndex =
(EnemyType.mutant.spriteBaseIdx + 8) + (walkFrame * 8) + octant;
if (distance < 6.0 && elapsedMs - lastActionTime > 1000) {
if (hasLineOfSight(playerPosition, isWalkable)) {
state = EntityState.attacking;
lastActionTime = elapsedMs;
_hasFiredThisCycle = false;
}
}
break;
case EntityState.attacking:
int timeShooting = elapsedMs - lastActionTime;
if (timeShooting < 150) {
spriteIndex = EnemyType.mutant.spriteBaseIdx + 46; // Aiming
} else if (timeShooting < 300) {
spriteIndex = EnemyType.mutant.spriteBaseIdx + 47; // Firing
if (!_hasFiredThisCycle) {
if (state == EntityState.attacking) {
int time = elapsedMs - lastActionTime;
if (time >= 150 && !_hasFiredThisCycle) {
onDamagePlayer(damage);
_hasFiredThisCycle = true;
}
} else if (timeShooting < 450) {
spriteIndex = EnemyType.mutant.spriteBaseIdx + 48; // Recoil
} else {
} else if (time >= 300) {
state = EntityState.patrolling;
lastActionTime = elapsedMs;
}
break;
case EntityState.pain:
spriteIndex = EnemyType.mutant.spriteBaseIdx + 44;
if (elapsedMs - lastActionTime > 250) {
state = EntityState.patrolling;
lastActionTime = elapsedMs;
}
break;
case EntityState.dead:
if (isDying) {
int deathFrame = (elapsedMs - lastActionTime) ~/ 150;
if (deathFrame < 4) {
spriteIndex = (EnemyType.mutant.spriteBaseIdx + 40) + deathFrame;
} else {
spriteIndex = EnemyType.mutant.spriteBaseIdx + 45;
isDying = false;
}
} else {
spriteIndex = EnemyType.mutant.spriteBaseIdx + 45;
}
break;
default:
break;
}
return (movement: movement, newAngle: newAngle);

View File

@@ -1,10 +1,8 @@
import 'dart:math' as math;
import 'package:wolf_dart/classes/coordinate_2d.dart';
import 'package:wolf_dart/features/difficulty/difficulty.dart';
import 'package:wolf_dart/features/entities/enemies/enemy.dart';
import 'package:wolf_dart/features/entities/entity.dart';
import 'package:wolf_dart/features/entities/map_objects.dart';
class Officer extends Enemy {
static const double speed = 0.055;
@@ -23,20 +21,6 @@ class Officer extends Enemy {
damage = 15;
}
static Officer? trySpawn(int objId, double x, double y, Difficulty _) {
if (EnemyType.officer.claimsMapId(objId)) {
bool isPatrolling = objId >= EnemyType.officer.mapBaseId + 18;
return Officer(
x: x,
y: y,
angle: MapObject.getAngle(objId),
mapId: objId,
)..state = isPatrolling ? EntityState.patrolling : EntityState.idle;
}
return null;
}
@override
({Coordinate2D movement, double newAngle}) update({
required int elapsedMs,

View File

@@ -1,10 +1,8 @@
import 'dart:math' as math;
import 'package:wolf_dart/classes/coordinate_2d.dart';
import 'package:wolf_dart/features/difficulty/difficulty.dart';
import 'package:wolf_dart/features/entities/enemies/enemy.dart';
import 'package:wolf_dart/features/entities/entity.dart';
import 'package:wolf_dart/features/entities/map_objects.dart';
class SS extends Enemy {
static const double speed = 0.04;
@@ -23,20 +21,6 @@ class SS extends Enemy {
damage = 20;
}
static SS? trySpawn(int objId, double x, double y, Difficulty _) {
if (EnemyType.ss.claimsMapId(objId)) {
bool isPatrolling = objId >= EnemyType.ss.mapBaseId + 18;
return SS(
x: x,
y: y,
angle: MapObject.getAngle(objId),
mapId: objId,
)..state = isPatrolling ? EntityState.patrolling : EntityState.idle;
}
return null;
}
@override
({Coordinate2D movement, double newAngle}) update({
required int elapsedMs,

View File

@@ -2,12 +2,7 @@ import 'package:wolf_dart/features/difficulty/difficulty.dart';
import 'package:wolf_dart/features/entities/collectible.dart';
import 'package:wolf_dart/features/entities/decorative.dart';
import 'package:wolf_dart/features/entities/enemies/bosses/hans_grosse.dart';
import 'package:wolf_dart/features/entities/enemies/dog.dart';
import 'package:wolf_dart/features/entities/enemies/enemy.dart';
import 'package:wolf_dart/features/entities/enemies/guard.dart';
import 'package:wolf_dart/features/entities/enemies/mutant.dart';
import 'package:wolf_dart/features/entities/enemies/officer.dart';
import 'package:wolf_dart/features/entities/enemies/ss.dart';
import 'package:wolf_dart/features/entities/entity.dart';
import 'package:wolf_dart/features/entities/map_objects.dart';
@@ -16,17 +11,14 @@ typedef EntitySpawner =
int objId,
double x,
double y,
Difficulty difficulty,
);
Difficulty difficulty, {
bool isSharewareMode,
});
abstract class EntityRegistry {
static final List<EntitySpawner> _spawners = [
// Enemies need to try to spawn first
Guard.trySpawn,
Officer.trySpawn,
SS.trySpawn,
Mutant.trySpawn,
Dog.trySpawn,
Enemy.spawn,
// Bosses
HansGrosse.trySpawn,
@@ -41,11 +33,15 @@ abstract class EntityRegistry {
double x,
double y,
Difficulty difficulty,
int maxSprites,
) {
int maxSprites, {
bool isSharewareMode = false,
}) {
// 1. Difficulty check before even looking for a spawner
if (!MapObject.shouldSpawn(objId, difficulty)) return null;
// If the checkbox is checked, block non-Shareware enemies
if (isSharewareMode && !MapObject.isSharewareCompatible(objId)) return null;
if (objId == 0) return null;
for (final spawner in _spawners) {

View File

@@ -9,7 +9,7 @@ abstract class WolfMapParser {
static List<WolfLevel> parseMaps(
ByteData mapHead,
ByteData gameMaps, {
bool isShareware = false,
bool isShareware = true,
}) {
List<WolfLevel> levels = [];

View File

@@ -109,6 +109,7 @@ class _WolfRendererState extends State<WolfRenderer>
y + 0.5,
widget.difficulty,
gameMap.sprites.length,
isSharewareMode: isShareware,
);
if (newEntity != null) {