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/weapon/weapon.dart'; import 'package:wolf_dart/features/weapon/weapons/chain_gun.dart'; import 'package:wolf_dart/features/weapon/weapons/knife.dart'; import 'package:wolf_dart/features/weapon/weapons/machine_gun.dart'; import 'package:wolf_dart/features/weapon/weapons/pistol.dart'; enum WeaponSwitchState { idle, lowering, raising } class Player { // Spatial double x; double y; double angle; // Stats int health = 100; int ammo = 8; int score = 0; // Inventory bool hasGoldKey = false; bool hasSilverKey = false; bool hasMachineGun = false; bool hasChainGun = false; // Weapon System late Weapon currentWeapon; final Map weapons = { WeaponType.knife: Knife(), WeaponType.pistol: Pistol(), WeaponType.machineGun: null, WeaponType.chainGun: null, }; WeaponSwitchState switchState = WeaponSwitchState.idle; WeaponType? pendingWeaponType; // 0.0 is resting, 500.0 is fully off-screen double weaponAnimOffset = 0.0; // How fast the weapon drops/raises per tick final double switchSpeed = 30.0; Player({ required this.x, required this.y, required this.angle, }) { currentWeapon = weapons[WeaponType.pistol]!; } // Helper getter to interface with the RaycasterPainter LinearCoordinates get position => (x: x, y: y); // --- Weapon Switching & Animation Logic --- void updateWeaponSwitch() { if (switchState == WeaponSwitchState.lowering) { weaponAnimOffset += switchSpeed; if (weaponAnimOffset >= 500.0) { weaponAnimOffset = 500.0; // Grab the pending weapon from inventory, default to pistol if something goes wrong currentWeapon = weapons[pendingWeaponType ?? WeaponType.pistol]!; switchState = WeaponSwitchState.raising; } } else if (switchState == WeaponSwitchState.raising) { weaponAnimOffset -= switchSpeed; if (weaponAnimOffset <= 0) { weaponAnimOffset = 0.0; switchState = WeaponSwitchState.idle; } } } void requestWeaponSwitch(WeaponType weaponType) { if (switchState != WeaponSwitchState.idle) return; if (currentWeapon.state != WeaponState.idle) return; if (weaponType == currentWeapon.type) return; if (!weapons.containsKey(weaponType)) return; if (weaponType == WeaponType.knife && ammo <= 0) return; pendingWeaponType = weaponType; switchState = WeaponSwitchState.lowering; } // --- Health & Damage --- void takeDamage(int damage) { health = math.max(0, health - damage); if (health <= 0) { print("YOU DIED!"); } else { print("Ouch! ($health)"); } } void heal(int amount) { final int newHealth = math.min(100, health + amount); if (health < 100) { print("Feelin' better. ($newHealth)"); } health = newHealth; } void addAmmo(int amount) { final int newAmmo = math.min(99, ammo + amount); if (ammo < 99) { print("Hell yeah. ($newAmmo)"); } ammo = newAmmo; } // --- Interaction & Firing --- bool tryPickup(Collectible item) { bool pickedUp = false; switch (item.type) { case CollectibleType.health: if (health >= 100) return false; // Map IDs 47 (Dog Food) and 48 (Medkit) heal(item.mapId == 47 ? 4 : 25); pickedUp = true; break; case CollectibleType.ammo: if (ammo >= 99) return false; int previousAmmo = ammo; addAmmo(8); // Auto-switch back to Pistol if holding Knife and just got ammo if (currentWeapon is Knife && previousAmmo <= 0) { requestWeaponSwitch(WeaponType.pistol); } pickedUp = true; break; case CollectibleType.treasure: if (item.mapId == 52) score += 100; if (item.mapId == 53) score += 500; if (item.mapId == 54) score += 1000; if (item.mapId == 55) score += 5000; if (item.mapId == 56) { heal(100); addAmmo(25); } pickedUp = true; break; case CollectibleType.weapon: if (item.mapId == 50) { if (!weapons.containsKey(WeaponType.machineGun)) { weapons[WeaponType.machineGun] = MachineGun(); } requestWeaponSwitch(WeaponType.machineGun); pickedUp = true; } if (item.mapId == 51) { if (!weapons.containsKey(WeaponType.chainGun)) { weapons[WeaponType.chainGun] = ChainGun(); } requestWeaponSwitch(WeaponType.chainGun); pickedUp = true; } break; case CollectibleType.key: if (item.mapId == 43) hasGoldKey = true; if (item.mapId == 44) hasSilverKey = true; pickedUp = true; break; } return pickedUp; } void fire(int currentTime) { if (switchState != WeaponSwitchState.idle) return; bool shotFired = currentWeapon.fire(currentTime, currentAmmo: ammo); // Check currentWeapon.type if (shotFired && currentWeapon.type != WeaponType.knife) { ammo--; if (ammo <= 0) { requestWeaponSwitch(WeaponType.knife); } } } /// Returns true only on the specific frame where the hit should be calculated bool updateWeapon(int currentTime) { int oldFrame = currentWeapon.frameIndex; currentWeapon.update(currentTime); if (currentWeapon.state == WeaponState.firing && oldFrame == 0 && currentWeapon.frameIndex == 1) { return true; } return false; } }