import 'package:flame/components.dart'; import 'package:shitman/game/levels/shit_level.dart'; import 'package:shitman/game/components/level_components.dart'; import 'package:shitman/game/components/road_components.dart'; import 'package:shitman/game/components/house_components.dart'; import 'package:shitman/game/components/security_components.dart'; import 'dart:math'; /// Level 1: Operation Shitstorm /// A grid-based neighborhood with various house types and security systems class OperationShitstorm extends ShitLevel { static const double cellSize = 100.0; static const int gridWidth = 5; static const int gridHeight = 5; List> levelGrid = []; List houses = []; TargetHouseComponent? currentTarget; OperationShitstorm() : super(levelName: "Operation: Shitstorm", difficulty: 1); @override Future initializeLevelComponents() async { appLog.fine('Initializing Operation Shitstorm level layout'); // Initialize the grid levelGrid = List.generate( gridHeight, (row) => List.generate(gridWidth, (col) => null), ); // Create the level layout await createLevelLayout(); // Add all components to the level await addComponentsToLevel(); // Initialize core components (player, etc.) await super.initializeLevelComponents(); // Select a random target house selectRandomTarget(); appLog.fine('Operation Shitstorm level initialized'); } Future createLevelLayout() async { // Create a simple grid layout: // H = House, R = Road (various types), I = Intersection // Layout pattern: // H R H R H // R I R I R // H R H R H // R I R I R // H R H R H for (int row = 0; row < gridHeight; row++) { for (int col = 0; col < gridWidth; col++) { final gridPos = Vector2(col.toDouble(), row.toDouble()); if (row % 2 == 0) { // Even rows: Houses and vertical roads if (col % 2 == 0) { // House position levelGrid[row][col] = createRandomHouse(gridPos); } else { // Vertical road levelGrid[row][col] = VerticalRoad(gridPosition: gridPos); } } else { // Odd rows: Horizontal roads and intersections if (col % 2 == 0) { // Horizontal road levelGrid[row][col] = HorizontalRoad(gridPosition: gridPos); } else { // Intersection levelGrid[row][col] = IntersectionRoad(gridPosition: gridPos); } } } } } HouseComponent createRandomHouse(Vector2 gridPos) { final random = Random(); final houseTypes = HouseType.values; final selectedType = houseTypes[random.nextInt(houseTypes.length)]; final house = HouseComponent( gridPosition: gridPos, houseType: selectedType, ); // Randomly add security systems to some houses if (random.nextDouble() < 0.4) { // 40% chance of security addRandomSecurityToHouse(house, random); } houses.add(house); return house; } void addRandomSecurityToHouse(HouseComponent house, Random random) { final securityTypes = random.nextInt(3); // 0-2 different security types switch (securityTypes) { case 0: // PIR sensor final pirSensor = PIRSensorComponent( position: Vector2(house.size.x * 0.9, house.size.y * 0.1), ); house.addSecuritySystem(pirSensor); break; case 1: // Security camera final camera = SecurityCameraComponent( position: Vector2(house.size.x * 0.9, house.size.y * 0.1), direction: _getOptimalCameraDirection(house), ); house.addSecuritySystem(camera); break; case 2: // Guard dog final dog = GuardDogComponent( position: Vector2(-20, house.size.y + 10), patrolCenter: Vector2(-20, house.size.y + 10), ); house.addSecuritySystem(dog); break; } } double _getOptimalCameraDirection(HouseComponent house) { // Point camera towards center of level final levelCenter = Vector2(gridWidth * cellSize / 2, gridHeight * cellSize / 2); final houseCenter = house.getWorldPosition(cellSize) + house.size / 2; final toCenter = levelCenter - houseCenter; return atan2(toCenter.y, toCenter.x); } Future addComponentsToLevel() async { for (int row = 0; row < gridHeight; row++) { for (int col = 0; col < gridWidth; col++) { final component = levelGrid[row][col]; if (component != null) { // Set world position based on grid position component.position = component.getWorldPosition(cellSize); add(component); } } } } void selectRandomTarget() { if (houses.isEmpty) return; // Clear previous target currentTarget?.setAsTarget(false); // Convert a random house to a target house final random = Random(); final randomHouse = houses[random.nextInt(houses.length)]; // Remove the old house and create a new target house at the same position remove(randomHouse); houses.remove(randomHouse); currentTarget = TargetHouseComponent( gridPosition: randomHouse.gridPosition, houseType: randomHouse.houseType, ); currentTarget!.position = randomHouse.position; currentTarget!.setAsTarget(true); // Copy security systems for (final security in randomHouse.securitySystems) { currentTarget!.addSecuritySystem(security); } add(currentTarget!); houses.add(currentTarget!); appLog.info('Target selected at grid position ${currentTarget!.gridPosition}'); } @override Future onLevelStart() async { appLog.info('Starting Operation: Shitstorm'); // Level-specific start logic can be added here } @override Future onLevelEnd() async { appLog.info('Operation: Shitstorm completed'); // Level-specific end logic can be added here } @override Future reset() async { await super.reset(); // Clear level-specific data levelGrid.clear(); houses.clear(); currentTarget = null; // Recreate the level await createLevelLayout(); await addComponentsToLevel(); selectRandomTarget(); appLog.fine('Operation Shitstorm level reset'); } /// Get the current target house position Vector2? getTargetPosition() { return currentTarget?.doorPosition; } /// Check if player is near the target bool isPlayerNearTarget(Vector2 playerPosition, {double threshold = 50.0}) { final targetPos = getTargetPosition(); if (targetPos == null) return false; final distance = (playerPosition - targetPos).length; return distance < threshold; } }