feat: Implement difficulty scaling for enemy damage and enhance enemy behaviors
- Added `scaleIncomingEnemyDamage` method to `Difficulty` enum for handling damage scaling based on difficulty level. - Introduced `lives` attribute to `Player` class with methods to manage lives. - Updated enemy classes (`Dog`, `Guard`, `Mutant`, `Officer`, `SS`, `HansGrosse`) to utilize difficulty settings for health and damage calculations. - Modified enemy drop logic to reflect new collectible types and behaviors. - Created tests for verifying enemy drop parity, collectible values, and difficulty damage scaling. - Adjusted enemy spawn logic to ensure standing enemies remain idle until alerted. - Enhanced scoring system to reflect updated score values for different enemy types. Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -15,6 +15,7 @@ class Player {
|
||||
int health = 100;
|
||||
int ammo = 8;
|
||||
int score = 0;
|
||||
int lives = 3;
|
||||
|
||||
// Damage flash
|
||||
double damageFlash = 0.0; // 0.0 is none, 1.0 is maximum red
|
||||
@@ -135,6 +136,10 @@ class Player {
|
||||
ammo = newAmmo;
|
||||
}
|
||||
|
||||
void addLives(int amount) {
|
||||
lives = math.min(9, lives + amount);
|
||||
}
|
||||
|
||||
/// Attempts to collect [item] and returns the SFX to play.
|
||||
///
|
||||
/// Returns `null` when the item was not collected (for example: full health).
|
||||
@@ -164,6 +169,10 @@ class Player {
|
||||
score += effect.scoreToAdd;
|
||||
}
|
||||
|
||||
if (effect.extraLivesToAdd > 0) {
|
||||
addLives(effect.extraLivesToAdd);
|
||||
}
|
||||
|
||||
if (effect.grantGoldKey) {
|
||||
hasGoldKey = true;
|
||||
}
|
||||
|
||||
@@ -125,6 +125,8 @@ class WolfEngine {
|
||||
List<Entity> entities = [];
|
||||
|
||||
int _currentEpisodeIndex = 0;
|
||||
|
||||
bool _isPlayerMovingFast = false;
|
||||
int _currentLevelIndex = 0;
|
||||
|
||||
/// Stores the previous level index when entering a secret floor,
|
||||
@@ -213,6 +215,10 @@ class WolfEngine {
|
||||
inputResult.movement,
|
||||
);
|
||||
|
||||
// RUN key does not exist yet in current input model. Keep canonical hit
|
||||
// chance in "walking" mode until true run-state input is implemented.
|
||||
_isPlayerMovingFast = false;
|
||||
|
||||
player.x = validatedPos.x;
|
||||
player.y = validatedPos.y;
|
||||
|
||||
@@ -533,9 +539,14 @@ class WolfEngine {
|
||||
elapsedMs: _timeAliveMs,
|
||||
elapsedDeltaMs: elapsed.inMilliseconds,
|
||||
playerPosition: player.position,
|
||||
playerAngle: player.angle,
|
||||
isPlayerRunning: _isPlayerMovingFast,
|
||||
isWalkable: isWalkable,
|
||||
tryOpenDoor: doorManager.tryOpenDoor,
|
||||
onDamagePlayer: (int damage) => player.takeDamage(damage),
|
||||
onDamagePlayer: (int damage) {
|
||||
final difficultyMode = difficulty ?? Difficulty.medium;
|
||||
player.takeDamage(difficultyMode.scaleIncomingEnemyDamage(damage));
|
||||
},
|
||||
onPlaySound: audio.playSoundEffect,
|
||||
);
|
||||
|
||||
@@ -561,14 +572,25 @@ class WolfEngine {
|
||||
entity.isDying &&
|
||||
!entity.hasDroppedItem) {
|
||||
entity.hasDroppedItem = true;
|
||||
Entity? droppedAmmo = EntityRegistry.spawn(
|
||||
MapObject.ammoClip,
|
||||
entity.x,
|
||||
entity.y,
|
||||
difficulty!,
|
||||
data.sprites.length,
|
||||
);
|
||||
if (droppedAmmo != null) itemsToAdd.add(droppedAmmo);
|
||||
|
||||
Entity? droppedItem;
|
||||
if (entity is Dog) {
|
||||
droppedItem = null;
|
||||
} else if (entity is SS) {
|
||||
droppedItem = !player.hasMachineGun
|
||||
? WeaponCollectible(
|
||||
x: entity.x,
|
||||
y: entity.y,
|
||||
mapId: MapObject.machineGun,
|
||||
)
|
||||
: SmallAmmoCollectible(x: entity.x, y: entity.y);
|
||||
} else if (entity is Guard || entity is Officer || entity is Mutant) {
|
||||
droppedItem = SmallAmmoCollectible(x: entity.x, y: entity.y);
|
||||
}
|
||||
|
||||
if (droppedItem != null) {
|
||||
itemsToAdd.add(droppedItem);
|
||||
}
|
||||
}
|
||||
} else if (entity is Collectible) {
|
||||
if (player.position.distanceTo(entity.position) < 0.5) {
|
||||
|
||||
Reference in New Issue
Block a user