shitman/lib/game/levels/operation_shitstorm.dart
zeyus 67aaa9589f
All checks were successful
/ build-web (push) Successful in 4m5s
updated level...player can now "complete" (no ui)
2025-07-27 17:41:51 +02:00

226 lines
No EOL
6.8 KiB
Dart

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<List<LevelComponent?>> levelGrid = [];
List<HouseComponent> houses = [];
TargetHouseComponent? currentTarget;
OperationShitstorm() : super(levelName: "Operation: Shitstorm", difficulty: 1);
@override
Future<void> 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<void> 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<void> 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<void> onLevelStart() async {
appLog.info('Starting Operation: Shitstorm');
// Level-specific start logic can be added here
}
@override
Future<void> onLevelEnd() async {
appLog.info('Operation: Shitstorm completed');
// Level-specific end logic can be added here
}
@override
Future<void> 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;
}
}