diff --git a/lib/features/player/player.dart b/lib/features/player/player.dart index 47797eb..890dac1 100644 --- a/lib/features/player/player.dart +++ b/lib/features/player/player.dart @@ -2,6 +2,10 @@ import 'dart:math' as math; import 'package:wolf_dart/classes/linear_coordinates.dart'; import 'package:wolf_dart/features/entities/collectible.dart'; +import 'package:wolf_dart/features/player/weapon.dart'; +import 'package:wolf_dart/features/player/weapons/knife.dart'; +import 'package:wolf_dart/features/player/weapons/machine_gun.dart'; +import 'package:wolf_dart/features/player/weapons/pistol.dart'; class Player { // Spatial @@ -20,11 +24,20 @@ class Player { bool hasMachineGun = false; bool hasChainGun = false; + // Weapon + late Weapon currentWeapon; + final List availableWeapons = []; + Player({ required this.x, required this.y, required this.angle, - }); + }) { + // Start with Knife and Pistol + availableWeapons.add(Knife()); + availableWeapons.add(Pistol()); + currentWeapon = availableWeapons[1]; + } // Helper getter to interface with the RaycasterPainter LinearCoordinates get position => (x: x, y: y); @@ -105,4 +118,28 @@ class Player { } return pickedUp; } + + void fire(int currentTime) { + bool shotFired = currentWeapon.fire(currentTime, currentAmmo: ammo); + + // If it was a gun (not a knife) and it fired, consume ammo + if (shotFired && currentWeapon is! Knife) { + ammo--; + } + + // TODO: We'll add Raycast hit detection here next! + } + + void updateWeapon(int currentTime) { + currentWeapon.update(currentTime); + } + + // Logic to switch weapons (e.g., picking up the Machine Gun) + void equipBestWeapon() { + if (hasChainGun) { + /* set chain gun */ + } else if (hasMachineGun) { + currentWeapon = MachineGun(); + } + } } diff --git a/lib/features/player/weapon.dart b/lib/features/player/weapon.dart new file mode 100644 index 0000000..61f0e7b --- /dev/null +++ b/lib/features/player/weapon.dart @@ -0,0 +1,51 @@ +enum WeaponState { idle, firing } + +abstract class Weapon { + final String name; + final int idleSprite; + final List fireFrames; + final int damage; + final int msPerFrame; + + WeaponState state = WeaponState.idle; + int frameIndex = 0; + int lastFrameTime = 0; + + Weapon({ + required this.name, + required this.idleSprite, + required this.fireFrames, + required this.damage, + this.msPerFrame = 100, // Speed of animation + }); + + int get currentSprite => + state == WeaponState.idle ? idleSprite : fireFrames[frameIndex]; + + bool get isFiring => state == WeaponState.firing; + + /// The main entry point for the player to use the gun. + /// Returns true if a bullet was actually spent. + bool fire(int currentTime, {required int currentAmmo}) { + if (state == WeaponState.idle && currentAmmo > 0) { + state = WeaponState.firing; + frameIndex = 0; + lastFrameTime = currentTime; + return true; + } + return false; + } + + void update(int currentTime) { + if (state == WeaponState.firing) { + if (currentTime - lastFrameTime > msPerFrame) { + frameIndex++; + lastFrameTime = currentTime; + if (frameIndex >= fireFrames.length) { + state = WeaponState.idle; + frameIndex = 0; + } + } + } + } +} diff --git a/lib/features/player/weapons/knife.dart b/lib/features/player/weapons/knife.dart new file mode 100644 index 0000000..bb85f76 --- /dev/null +++ b/lib/features/player/weapons/knife.dart @@ -0,0 +1,24 @@ +import 'package:wolf_dart/features/player/weapon.dart'; + +class Knife extends Weapon { + Knife() + : super( + name: "Knife", + idleSprite: 416, + fireFrames: [417, 418, 419], + damage: 15, + msPerFrame: 120, + ); + + @override + bool fire(int currentTime, {required int currentAmmo}) { + // Knife doesn't need ammo! + if (state == WeaponState.idle) { + state = WeaponState.firing; + frameIndex = 0; + lastFrameTime = currentTime; + return true; + } + return false; + } +} diff --git a/lib/features/player/weapons/machine_gun.dart b/lib/features/player/weapons/machine_gun.dart new file mode 100644 index 0000000..aad9f50 --- /dev/null +++ b/lib/features/player/weapons/machine_gun.dart @@ -0,0 +1,12 @@ +import 'package:wolf_dart/features/player/weapon.dart'; + +class MachineGun extends Weapon { + MachineGun() + : super( + name: "Machine Gun", + idleSprite: 413, + fireFrames: [414, 415], // Faster 2-frame loop + damage: 20, + msPerFrame: 80, + ); +} diff --git a/lib/features/player/weapons/pistol.dart b/lib/features/player/weapons/pistol.dart new file mode 100644 index 0000000..03ab6bc --- /dev/null +++ b/lib/features/player/weapons/pistol.dart @@ -0,0 +1,11 @@ +import 'package:wolf_dart/features/player/weapon.dart'; + +class Pistol extends Weapon { + Pistol() + : super( + name: "Pistol", + idleSprite: 408, + fireFrames: [409, 410, 411, 412], + damage: 20, + ); +} diff --git a/lib/features/renderer/renderer.dart b/lib/features/renderer/renderer.dart index f40e9a4..4453181 100644 --- a/lib/features/renderer/renderer.dart +++ b/lib/features/renderer/renderer.dart @@ -300,6 +300,13 @@ class _WolfRendererState extends State }); } + // 5. Fire weapon + bool isCtrlPressed = pressedKeys.contains(LogicalKeyboardKey.controlLeft); + if (isCtrlPressed) { + player.fire(elapsed.inMilliseconds); + } + player.updateWeapon(elapsed.inMilliseconds); + // Fade out the damage flash smoothly if (damageFlashOpacity > 0) { damageFlashOpacity = math.max(0.0, damageFlashOpacity - 0.05);