Fixed shareware sprites
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -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!
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user