Re-added the sprite screen. Made some adjustments to enemy AI.
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:wolf_3d_data_types/wolf_3d_data_types.dart';
|
import 'package:wolf_3d_data_types/wolf_3d_data_types.dart';
|
||||||
import 'package:wolf_3d_flutter/wolf_3d.dart';
|
import 'package:wolf_3d_flutter/wolf_3d.dart';
|
||||||
import 'package:wolf_dart/screens/difficulty_screen.dart';
|
import 'package:wolf_dart/screens/difficulty_screen.dart';
|
||||||
|
import 'package:wolf_dart/screens/sprite_gallery.dart';
|
||||||
|
|
||||||
class EpisodeScreen extends StatefulWidget {
|
class EpisodeScreen extends StatefulWidget {
|
||||||
const EpisodeScreen({super.key});
|
const EpisodeScreen({super.key});
|
||||||
@@ -31,7 +32,19 @@ class _EpisodeScreenState extends State<EpisodeScreen> {
|
|||||||
final List<Episode> episodes = Wolf3d.I.activeGame.episodes;
|
final List<Episode> episodes = Wolf3d.I.activeGame.episodes;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.teal,
|
||||||
|
floatingActionButton: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) {
|
||||||
|
return SpriteGallery(sprites: Wolf3d.I.sprites);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.bug_report),
|
||||||
|
),
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
|||||||
@@ -18,16 +18,24 @@ class SpriteGallery extends StatelessWidget {
|
|||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
body: GridView.builder(
|
body: GridView.builder(
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 8, // 8 sprites per row
|
crossAxisCount: 8,
|
||||||
),
|
),
|
||||||
itemCount: sprites.length,
|
itemCount: sprites.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
// --- Check which enemy owns this sprite ---
|
// --- Check which enemy owns this sprite ---
|
||||||
String label = "Idx: $index";
|
String label = "Sprite Index: $index";
|
||||||
for (final enemy in EnemyType.values) {
|
for (final enemy in EnemyType.values) {
|
||||||
if (enemy.claimsSpriteIndex(index)) {
|
if (enemy.claimsSpriteIndex(index)) {
|
||||||
|
final EnemyAnimation? animation = enemy.getAnimationFromSprite(
|
||||||
|
index,
|
||||||
|
);
|
||||||
// Appends the enum name (e.g., "guard", "dog")
|
// Appends the enum name (e.g., "guard", "dog")
|
||||||
label += "\n${enemy.name}";
|
label += "\n${enemy.name}";
|
||||||
|
|
||||||
|
// Appends the animation name
|
||||||
|
if (animation != null) {
|
||||||
|
label += "\n${animation.name}";
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
enum Difficulty {
|
enum Difficulty {
|
||||||
canIPlayDaddy(0, "Can I play, Daddy?"),
|
canIPlayDaddy(0, "Can I play, Daddy?"),
|
||||||
dontHurtMe(1, "Don't hurt me."),
|
dontHurtMe(0, "Don't hurt me."),
|
||||||
bringEmOn(2, "Bring em' on!"),
|
bringEmOn(1, "Bring em' on!"),
|
||||||
iAmDeathIncarnate(3, "I am Death incarnate!"),
|
iAmDeathIncarnate(2, "I am Death incarnate!");
|
||||||
;
|
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
final int level;
|
final int level;
|
||||||
|
|||||||
@@ -94,27 +94,6 @@ abstract class MapObject {
|
|||||||
static const int deadGuard = 124; // Decorative only in WL1
|
static const int deadGuard = 124; // Decorative only in WL1
|
||||||
static const int deadAardwolf = 125; // Decorative only in WL1
|
static const int deadAardwolf = 125; // Decorative only in WL1
|
||||||
|
|
||||||
/// Returns true if the object ID exists in the Shareware version.
|
|
||||||
/// Returns true if the object ID exists in the Shareware version.
|
|
||||||
static bool isSharewareCompatible(int id) {
|
|
||||||
// Standard Decorations & Collectibles
|
|
||||||
if (id <= vines) return true;
|
|
||||||
|
|
||||||
// Logic Triggers (Exits/Pushwalls)
|
|
||||||
if (id >= pushwallTrigger && id <= normalExitTrigger) return true;
|
|
||||||
|
|
||||||
// Guards (108-143 includes dead bodies at 124/125)
|
|
||||||
if (id >= guardStart && id < officerStart) return true;
|
|
||||||
|
|
||||||
// Dogs (216-251) - These ARE in Shareware!
|
|
||||||
if (id >= dogStart && id < mutantStart) return true;
|
|
||||||
|
|
||||||
// Episode 1 Boss
|
|
||||||
if (id == bossHansGrosse) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double getAngle(int id) {
|
static double getAngle(int id) {
|
||||||
// Player spawn
|
// Player spawn
|
||||||
switch (id) {
|
switch (id) {
|
||||||
@@ -140,23 +119,34 @@ abstract class MapObject {
|
|||||||
return CardinalDirection.fromEnemyIndex(directionIndex).radians;
|
return CardinalDirection.fromEnemyIndex(directionIndex).radians;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool shouldSpawn(int id, Difficulty selectedDifficulty) {
|
/// Only handles the "Is this ID allowed on this difficulty?" math.
|
||||||
EnemyType? type = EnemyType.fromMapId(id);
|
/// Does NOT decide IF an object is an enemy or decoration.
|
||||||
|
static bool isDifficultyAllowed(int objId, Difficulty difficulty) {
|
||||||
|
if (objId == 124) return true;
|
||||||
|
|
||||||
// If it's not a standard enemy (it's a decoration, boss, or player), spawn it
|
int? requiredTier;
|
||||||
if (type == null) return true;
|
|
||||||
|
|
||||||
bool isStaticId = id >= (type.staticId - 2) && id <= type.staticId;
|
// Static Tier Math (IDs 23-54)
|
||||||
int offset = isStaticId ? (id - type.staticId) : (id - type.patrolId);
|
if (objId >= 23 && objId <= 54) {
|
||||||
int normalizedOffset = offset >= 18 ? offset - 18 : offset;
|
requiredTier = (objId - 23) % 3;
|
||||||
|
}
|
||||||
|
// Patrol Tier Math (IDs 108-197)
|
||||||
|
else if (objId >= 108 && objId <= 197) {
|
||||||
|
int offsetInType = (objId - 108) % 18;
|
||||||
|
requiredTier = offsetInType ~/ 4;
|
||||||
|
}
|
||||||
|
|
||||||
return switch (normalizedOffset) {
|
if (requiredTier == null) {
|
||||||
< 4 => true, // Spawns on all difficulties
|
// Default to allowed if no tier logic exists
|
||||||
< 8 => selectedDifficulty.level >= Difficulty.bringEmOn.level, // Normal
|
return true;
|
||||||
< 16 =>
|
}
|
||||||
selectedDifficulty.level >=
|
|
||||||
Difficulty.iAmDeathIncarnate.level, // Hard & Ambush
|
int currentTier = switch (difficulty) {
|
||||||
_ => true, // Dead bodies (decorations)
|
Difficulty.canIPlayDaddy || Difficulty.dontHurtMe => 0,
|
||||||
|
Difficulty.bringEmOn => 1,
|
||||||
|
Difficulty.iAmDeathIncarnate => 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return requiredTier == currentTier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,8 +102,6 @@ class WolfEngine {
|
|||||||
for (int x = 0; x < 64; x++) {
|
for (int x = 0; x < 64; x++) {
|
||||||
int objId = objectLevel[y][x];
|
int objId = objectLevel[y][x];
|
||||||
|
|
||||||
if (!MapObject.shouldSpawn(objId, difficulty)) continue;
|
|
||||||
|
|
||||||
if (objId >= MapObject.playerNorth && objId <= MapObject.playerWest) {
|
if (objId >= MapObject.playerNorth && objId <= MapObject.playerWest) {
|
||||||
double spawnAngle = 0.0;
|
double spawnAngle = 0.0;
|
||||||
if (objId == MapObject.playerNorth) {
|
if (objId == MapObject.playerNorth) {
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import 'package:wolf_3d_data_types/wolf_3d_data_types.dart';
|
||||||
|
import 'package:wolf_3d_entities/wolf_3d_entities.dart';
|
||||||
|
|
||||||
|
class DeadAardwolf extends Decorative {
|
||||||
|
static const int sprite = 96;
|
||||||
|
|
||||||
|
DeadAardwolf({required super.x, required super.y})
|
||||||
|
: super(spriteIndex: sprite, state: EntityState.staticObj, mapId: 125);
|
||||||
|
|
||||||
|
/// This is the self-spawning logic we discussed.
|
||||||
|
/// It only claims the ID 124.
|
||||||
|
static DeadAardwolf? trySpawn(
|
||||||
|
int objId,
|
||||||
|
double x,
|
||||||
|
double y,
|
||||||
|
Difficulty difficulty, {
|
||||||
|
bool isSharewareMode = false,
|
||||||
|
}) {
|
||||||
|
if (objId == 125) {
|
||||||
|
return DeadAardwolf(x: x, y: y);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import 'package:wolf_3d_data_types/wolf_3d_data_types.dart';
|
||||||
|
import 'package:wolf_3d_entities/wolf_3d_entities.dart';
|
||||||
|
|
||||||
|
class DeadGuard extends Decorative {
|
||||||
|
/// The sprite index in VSWAP for the final "dead" frame of a Guard.
|
||||||
|
static const int deadGuardSprite = 95;
|
||||||
|
|
||||||
|
DeadGuard({required super.x, required super.y})
|
||||||
|
: super(
|
||||||
|
spriteIndex: deadGuardSprite,
|
||||||
|
state: EntityState.staticObj,
|
||||||
|
// We set mapId to 124 so we can identify it if needed
|
||||||
|
mapId: 124,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// This is the self-spawning logic we discussed.
|
||||||
|
/// It only claims the ID 124.
|
||||||
|
static DeadGuard? trySpawn(
|
||||||
|
int objId,
|
||||||
|
double x,
|
||||||
|
double y,
|
||||||
|
Difficulty difficulty, {
|
||||||
|
bool isSharewareMode = false,
|
||||||
|
}) {
|
||||||
|
if (objId == 124) {
|
||||||
|
return DeadGuard(x: x, y: y);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,6 +42,9 @@ class Decorative extends Entity {
|
|||||||
Difficulty difficulty, {
|
Difficulty difficulty, {
|
||||||
bool isSharewareMode = false,
|
bool isSharewareMode = false,
|
||||||
}) {
|
}) {
|
||||||
|
// 2. Standard props (Table, Lamp, etc) use the tiered check
|
||||||
|
if (!MapObject.isDifficultyAllowed(objId, difficulty)) return null;
|
||||||
|
|
||||||
if (isDecoration(objId)) {
|
if (isDecoration(objId)) {
|
||||||
return Decorative(
|
return Decorative(
|
||||||
x: x,
|
x: x,
|
||||||
|
|||||||
@@ -11,31 +11,11 @@ import 'package:wolf_3d_entities/src/entity.dart';
|
|||||||
enum EnemyAnimation { idle, walking, attacking, pain, dying, dead }
|
enum EnemyAnimation { idle, walking, attacking, pain, dying, dead }
|
||||||
|
|
||||||
enum EnemyType {
|
enum EnemyType {
|
||||||
guard(
|
guard(staticId: 23, patrolId: 108, spriteBaseIdx: 50),
|
||||||
staticId: 108,
|
officer(staticId: 26, patrolId: 126, spriteBaseIdx: 238),
|
||||||
patrolId: 124,
|
ss(staticId: 29, patrolId: 144, spriteBaseIdx: 138),
|
||||||
spriteBaseIdx: 50,
|
dog(staticId: 32, patrolId: 162, spriteBaseIdx: 99),
|
||||||
), // Update spriteBaseIdx to your actual value
|
mutant(staticId: 35, patrolId: 180, spriteBaseIdx: 187);
|
||||||
dog(
|
|
||||||
staticId: 144,
|
|
||||||
patrolId: 160,
|
|
||||||
spriteBaseIdx: 99,
|
|
||||||
), // Update spriteBaseIdx to your actual value
|
|
||||||
ss(
|
|
||||||
staticId: 176,
|
|
||||||
patrolId: 192,
|
|
||||||
spriteBaseIdx: 138,
|
|
||||||
), // Retained from your snippet
|
|
||||||
mutant(
|
|
||||||
staticId: 238,
|
|
||||||
patrolId: 254,
|
|
||||||
spriteBaseIdx: 185,
|
|
||||||
), // Update spriteBaseIdx to your actual value
|
|
||||||
officer(
|
|
||||||
staticId: 270,
|
|
||||||
patrolId: 286,
|
|
||||||
spriteBaseIdx: 226,
|
|
||||||
); // Update spriteBaseIdx to your actual value
|
|
||||||
|
|
||||||
final int staticId;
|
final int staticId;
|
||||||
final int patrolId;
|
final int patrolId;
|
||||||
@@ -47,19 +27,18 @@ enum EnemyType {
|
|||||||
required this.spriteBaseIdx,
|
required this.spriteBaseIdx,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Wolfenstein 3D allocates blocks of 16 IDs per enemy type for standing and patrolling
|
/// Checks if the ID belongs to this enemy type range
|
||||||
/// (4 directions x 4 difficulty levels = 16 IDs)
|
|
||||||
bool claimsMapId(int id) {
|
bool claimsMapId(int id) {
|
||||||
bool isStatic = id >= staticId && id < staticId + 16;
|
// Static enemies span 3 IDs (Easy, Medium, Hard)
|
||||||
bool isPatrol = id >= patrolId && id < patrolId + 16;
|
bool isStatic = id >= staticId && id < staticId + 3;
|
||||||
|
// Patrolling enemies span 18 IDs per type
|
||||||
|
bool isPatrol = id >= patrolId && id < patrolId + 18;
|
||||||
return isStatic || isPatrol;
|
return isStatic || isPatrol;
|
||||||
}
|
}
|
||||||
|
|
||||||
static EnemyType? fromMapId(int id) {
|
static EnemyType? fromMapId(int id) {
|
||||||
for (final type in EnemyType.values) {
|
for (final type in EnemyType.values) {
|
||||||
if (type.claimsMapId(id)) {
|
if (type.claimsMapId(id)) return type;
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -200,6 +179,7 @@ abstract class Enemy extends Entity {
|
|||||||
int damage = 10;
|
int damage = 10;
|
||||||
bool isDying = false;
|
bool isDying = false;
|
||||||
bool hasDroppedItem = false;
|
bool hasDroppedItem = false;
|
||||||
|
bool isAlerted = false;
|
||||||
|
|
||||||
// Replaces ob->temp2 for reaction delays
|
// Replaces ob->temp2 for reaction delays
|
||||||
int reactionTimeMs = 0;
|
int reactionTimeMs = 0;
|
||||||
@@ -210,6 +190,8 @@ abstract class Enemy extends Entity {
|
|||||||
health -= amount;
|
health -= amount;
|
||||||
lastActionTime = currentTime;
|
lastActionTime = currentTime;
|
||||||
|
|
||||||
|
isAlerted = true;
|
||||||
|
|
||||||
if (health <= 0) {
|
if (health <= 0) {
|
||||||
state = EntityState.dead;
|
state = EntityState.dead;
|
||||||
isDying = true;
|
isDying = true;
|
||||||
@@ -227,15 +209,19 @@ abstract class Enemy extends Entity {
|
|||||||
int baseReactionMs = 200,
|
int baseReactionMs = 200,
|
||||||
int reactionVarianceMs = 600,
|
int reactionVarianceMs = 600,
|
||||||
}) {
|
}) {
|
||||||
if (state == EntityState.idle &&
|
if (!isAlerted && hasLineOfSight(playerPosition, isWalkable)) {
|
||||||
hasLineOfSight(playerPosition, isWalkable)) {
|
|
||||||
if (reactionTimeMs == 0) {
|
if (reactionTimeMs == 0) {
|
||||||
reactionTimeMs =
|
reactionTimeMs =
|
||||||
elapsedMs +
|
elapsedMs +
|
||||||
baseReactionMs +
|
baseReactionMs +
|
||||||
math.Random().nextInt(reactionVarianceMs);
|
math.Random().nextInt(reactionVarianceMs);
|
||||||
} else if (elapsedMs >= reactionTimeMs) {
|
} else if (elapsedMs >= reactionTimeMs) {
|
||||||
|
isAlerted = true;
|
||||||
|
|
||||||
|
if (state == EntityState.idle) {
|
||||||
state = EntityState.patrolling;
|
state = EntityState.patrolling;
|
||||||
|
}
|
||||||
|
|
||||||
lastActionTime = elapsedMs;
|
lastActionTime = elapsedMs;
|
||||||
reactionTimeMs = 0;
|
reactionTimeMs = 0;
|
||||||
}
|
}
|
||||||
@@ -363,16 +349,20 @@ abstract class Enemy extends Entity {
|
|||||||
Difficulty difficulty, {
|
Difficulty difficulty, {
|
||||||
bool isSharewareMode = false,
|
bool isSharewareMode = false,
|
||||||
}) {
|
}) {
|
||||||
// 1. Check Difficulty & Compatibility
|
// ID 124 (dead guard) and 125 (dead aardwolf) fall inside Guard's patrol
|
||||||
if (!MapObject.shouldSpawn(objId, difficulty)) return null;
|
// range (108–125) but are decorative bodies, not live actors.
|
||||||
|
if (objId == MapObject.deadGuard || objId == MapObject.deadAardwolf) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Explicitly ignore "Dead Guard" Map ID so Decorative.trySpawn can handle it
|
if (objId >= MapObject.playerNorth && objId <= MapObject.playerWest) {
|
||||||
// In Wolf3D, 124 is the dead guard.
|
return null;
|
||||||
if (objId == 124) return null;
|
}
|
||||||
|
|
||||||
// If the checkbox is checked, block non-Shareware enemies
|
// 2. I use the utility to check if this enemy is allowed on this difficulty
|
||||||
if (isSharewareMode && !MapObject.isSharewareCompatible(objId)) return null;
|
if (!MapObject.isDifficultyAllowed(objId, difficulty)) return null;
|
||||||
|
|
||||||
|
// 3. I check if I even know what this enemy is
|
||||||
final type = EnemyType.fromMapId(objId);
|
final type = EnemyType.fromMapId(objId);
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ class Guard extends Enemy {
|
|||||||
double distance = position.distanceTo(playerPosition);
|
double distance = position.distanceTo(playerPosition);
|
||||||
double angleToPlayer = position.angleTo(playerPosition);
|
double angleToPlayer = position.angleTo(playerPosition);
|
||||||
|
|
||||||
|
if (isAlerted && state != EntityState.dead) {
|
||||||
|
newAngle = angleToPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
if (state != EntityState.idle && state != EntityState.dead) {
|
if (state != EntityState.idle && state != EntityState.dead) {
|
||||||
newAngle = angleToPlayer;
|
newAngle = angleToPlayer;
|
||||||
}
|
}
|
||||||
@@ -67,9 +71,11 @@ class Guard extends Enemy {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (state == EntityState.patrolling) {
|
if (state == EntityState.patrolling) {
|
||||||
if (distance > 0.8) {
|
if (!isAlerted || distance > 0.8) {
|
||||||
double moveX = math.cos(angleToPlayer) * speed;
|
double currentMoveAngle = isAlerted ? angleToPlayer : angle;
|
||||||
double moveY = math.sin(angleToPlayer) * speed;
|
double moveX = math.cos(currentMoveAngle) * speed;
|
||||||
|
double moveY = math.sin(currentMoveAngle) * speed;
|
||||||
|
|
||||||
movement = getValidMovement(
|
movement = getValidMovement(
|
||||||
Coordinate2D(moveX, moveY),
|
Coordinate2D(moveX, moveY),
|
||||||
isWalkable,
|
isWalkable,
|
||||||
@@ -77,7 +83,7 @@ class Guard extends Enemy {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distance < 6.0 && elapsedMs - lastActionTime > 1500) {
|
if (isAlerted && distance < 6.0 && elapsedMs - lastActionTime > 1500) {
|
||||||
if (hasLineOfSight(playerPosition, isWalkable)) {
|
if (hasLineOfSight(playerPosition, isWalkable)) {
|
||||||
state = EntityState.attacking;
|
state = EntityState.attacking;
|
||||||
lastActionTime = elapsedMs;
|
lastActionTime = elapsedMs;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import 'package:wolf_3d_data_types/wolf_3d_data_types.dart';
|
import 'package:wolf_3d_data_types/wolf_3d_data_types.dart';
|
||||||
import 'package:wolf_3d_entities/src/entities/collectible.dart';
|
import 'package:wolf_3d_entities/src/entities/collectible.dart';
|
||||||
|
import 'package:wolf_3d_entities/src/entities/decorations/dead_aardwolf.dart';
|
||||||
|
import 'package:wolf_3d_entities/src/entities/decorations/dead_guard.dart';
|
||||||
import 'package:wolf_3d_entities/src/entities/decorative.dart';
|
import 'package:wolf_3d_entities/src/entities/decorative.dart';
|
||||||
import 'package:wolf_3d_entities/src/entities/enemies/bosses/hans_grosse.dart';
|
import 'package:wolf_3d_entities/src/entities/enemies/bosses/hans_grosse.dart';
|
||||||
import 'package:wolf_3d_entities/src/entities/enemies/enemy.dart';
|
import 'package:wolf_3d_entities/src/entities/enemies/enemy.dart';
|
||||||
@@ -16,15 +18,21 @@ typedef EntitySpawner =
|
|||||||
|
|
||||||
abstract class EntityRegistry {
|
abstract class EntityRegistry {
|
||||||
static final List<EntitySpawner> _spawners = [
|
static final List<EntitySpawner> _spawners = [
|
||||||
|
// Special
|
||||||
|
DeadGuard.trySpawn,
|
||||||
|
DeadAardwolf.trySpawn,
|
||||||
|
|
||||||
// Bosses
|
// Bosses
|
||||||
HansGrosse.trySpawn,
|
HansGrosse.trySpawn,
|
||||||
|
|
||||||
|
// Decorations
|
||||||
|
Decorative.trySpawn,
|
||||||
|
|
||||||
// Enemies need to try to spawn first
|
// Enemies need to try to spawn first
|
||||||
Enemy.spawn,
|
Enemy.spawn,
|
||||||
|
|
||||||
// Everything else
|
// Collectables
|
||||||
Collectible.trySpawn,
|
Collectible.trySpawn,
|
||||||
Decorative.trySpawn,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
static Entity? spawn(
|
static Entity? spawn(
|
||||||
@@ -35,12 +43,6 @@ abstract class EntityRegistry {
|
|||||||
int maxSprites, {
|
int maxSprites, {
|
||||||
bool isSharewareMode = false,
|
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;
|
if (objId == 0) return null;
|
||||||
|
|
||||||
for (final spawner in _spawners) {
|
for (final spawner in _spawners) {
|
||||||
@@ -51,23 +53,8 @@ abstract class EntityRegistry {
|
|||||||
difficulty,
|
difficulty,
|
||||||
isSharewareMode: isSharewareMode,
|
isSharewareMode: isSharewareMode,
|
||||||
);
|
);
|
||||||
|
if (entity != null) return entity;
|
||||||
final EnemyType? type = EnemyType.fromMapId(objId);
|
|
||||||
if (type != null) {
|
|
||||||
print("Spawning ${type.name} enemy");
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
if (entity != null) {
|
|
||||||
// Safety bounds check for the VSWAP array
|
|
||||||
if (entity.spriteIndex >= 0 && entity.spriteIndex < maxSprites) {
|
|
||||||
print("Spawned entity with objId $objId");
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
print("VSWAP doesn't have this sprite! objId $objId");
|
|
||||||
return null; // VSWAP doesn't have this sprite!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print("No class claimed this Map ID > objId $objId");
|
|
||||||
return null; // No class claimed this Map ID
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,8 +96,6 @@ class _WolfRendererState extends State<WolfRenderer>
|
|||||||
for (int x = 0; x < 64; x++) {
|
for (int x = 0; x < 64; x++) {
|
||||||
int objId = objectLevel[y][x];
|
int objId = objectLevel[y][x];
|
||||||
|
|
||||||
if (!MapObject.shouldSpawn(objId, widget.difficulty)) continue;
|
|
||||||
|
|
||||||
if (objId >= MapObject.playerNorth && objId <= MapObject.playerWest) {
|
if (objId >= MapObject.playerNorth && objId <= MapObject.playerWest) {
|
||||||
double spawnAngle = 0.0;
|
double spawnAngle = 0.0;
|
||||||
if (objId == MapObject.playerNorth) {
|
if (objId == MapObject.playerNorth) {
|
||||||
|
|||||||
Reference in New Issue
Block a user