shitman/lib/game/components/security_components.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

297 lines
No EOL
7.9 KiB
Dart

import 'package:flame/components.dart';
import 'package:flutter/material.dart';
import 'package:shitman/game/components/level_components.dart';
import 'package:shitman/game/components/vision_cone.dart';
import 'package:shitman/settings/app_settings.dart';
import 'dart:math';
/// PIR sensor triggered light
class PIRSensorComponent extends SecurityComponent with AppSettings {
bool isTriggered = false;
bool lightsOn = false;
bool _showDetectionRadius = true;
PIRSensorComponent({
required super.position,
super.detectionRange = 40.0,
}) {
size = Vector2(8, 8);
}
@override
Future<void> onLoad() async {
await super.onLoad();
await initSettings();
// Initialize detection radius visibility from settings
try {
_showDetectionRadius = appSettings.getBool('game.show_detection_radius');
} catch (e) {
_showDetectionRadius = true; // Default to visible
}
}
@override
bool detectsPlayer(Vector2 playerPosition, double playerStealthLevel) {
final distance = (playerPosition - position).length;
final effectiveRange = getEffectiveDetectionRange(playerStealthLevel);
bool detected = distance < effectiveRange;
if (detected && !isTriggered) {
isTriggered = true;
lightsOn = true;
appLog.fine('PIR sensor triggered at $position');
} else if (!detected && isTriggered) {
// Cool down period before turning off
Future.delayed(const Duration(seconds: 5), () {
isTriggered = false;
lightsOn = false;
});
}
return detected;
}
@override
void render(Canvas canvas) {
// Draw detection radius if enabled
if (_showDetectionRadius) {
final radiusPaint = Paint()
..color = const Color(0xFFFF9800).withValues(alpha: 0.2)
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
canvas.drawCircle(
Offset(size.x / 2, size.y / 2),
detectionRange,
radiusPaint,
);
}
// Draw PIR sensor as small circle
final sensorPaint = Paint()
..color = isTriggered ? const Color(0xFFFF0000) : const Color(0xFF000000);
canvas.drawCircle(Offset(size.x / 2, size.y / 2), 4, sensorPaint);
// Draw light effect if triggered
if (lightsOn) {
final lightPaint = Paint()
..color = const Color(0xFFFFFF00).withValues(alpha: 0.3);
canvas.drawCircle(
Offset(size.x / 2, size.y / 2),
detectionRange,
lightPaint,
);
}
}
/// Update detection radius visibility (call when settings change)
void updateDetectionRadiusVisibility(bool visible) {
_showDetectionRadius = visible;
}
/// Refresh visibility from current settings
void refreshVisibilityFromSettings() {
try {
final newVisibility = appSettings.getBool('game.show_detection_radius');
updateDetectionRadiusVisibility(newVisibility);
} catch (e) {
// Settings not ready, keep current state
}
}
@override
Future<void> reset() async {
isTriggered = false;
lightsOn = false;
}
}
/// Security camera with vision cone
class SecurityCameraComponent extends SecurityComponent with AppSettings {
late VisionCone visionCone;
double direction;
bool _currentVisionConeVisibility = true;
SecurityCameraComponent({
required super.position,
required this.direction,
super.detectionRange = 120.0,
}) {
size = Vector2(8, 8);
}
@override
Future<void> onLoad() async {
await super.onLoad();
await initSettings();
// Create vision cone with initial visibility based on settings
try {
_currentVisionConeVisibility = appSettings.getBool('game.show_vision_cones');
} catch (e) {
_currentVisionConeVisibility = true; // Default to visible
}
visionCone = VisionCone(
origin: Vector2.zero(),
direction: direction,
range: detectionRange,
fov: pi / 2, // 90 degrees
color: Colors.red,
opacity: _currentVisionConeVisibility ? 0.3 : 0.0,
);
add(visionCone);
}
@override
bool detectsPlayer(Vector2 playerPosition, double playerStealthLevel) {
return visionCone.canSee(playerPosition) &&
visionCone.hasLineOfSight(playerPosition, []);
}
@override
void render(Canvas canvas) {
// Draw camera as black circle
final cameraPaint = Paint()..color = const Color(0xFF000000);
canvas.drawCircle(Offset(size.x / 2, size.y / 2), 4, cameraPaint);
}
/// Call this method when settings change to update vision cone visibility
void updateVisionConeVisibility(bool visible) {
if (_currentVisionConeVisibility != visible) {
_currentVisionConeVisibility = visible;
visionCone.updateOpacity(visible ? 0.3 : 0.0);
}
}
/// Refresh visibility from current settings (call when settings might have changed)
void refreshVisibilityFromSettings() {
try {
final newVisibility = appSettings.getBool('game.show_vision_cones');
updateVisionConeVisibility(newVisibility);
} catch (e) {
// Settings not ready, keep current state
}
}
@override
Future<void> reset() async {
await visionCone.reset();
}
}
/// Guard dog with patrol area
class GuardDogComponent extends SecurityComponent with AppSettings {
Vector2 patrolCenter;
double patrolRadius;
double currentAngle = 0;
bool isPatrolling = true;
bool _showDetectionRadius = true;
GuardDogComponent({
required super.position,
required this.patrolCenter,
this.patrolRadius = 30.0,
super.detectionRange = 50.0,
}) {
size = Vector2(12, 12);
}
@override
Future<void> onLoad() async {
await super.onLoad();
await initSettings();
// Initialize detection radius visibility from settings
try {
_showDetectionRadius = appSettings.getBool('game.show_detection_radius');
} catch (e) {
_showDetectionRadius = true; // Default to visible
}
}
@override
bool detectsPlayer(Vector2 playerPosition, double playerStealthLevel) {
final distance = (playerPosition - position).length;
final effectiveRange = getEffectiveDetectionRange(playerStealthLevel);
return distance < effectiveRange;
}
@override
void update(double dt) {
super.update(dt);
if (isPatrolling) {
// Simple circular patrol
currentAngle += dt * 0.5; // Rotation speed
final offset = Vector2(
cos(currentAngle) * patrolRadius,
sin(currentAngle) * patrolRadius,
);
position = patrolCenter + offset;
}
}
@override
void render(Canvas canvas) {
// Draw detection radius if enabled
if (_showDetectionRadius) {
final radiusPaint = Paint()
..color = const Color(0xFFFF9800).withValues(alpha: 0.2)
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
canvas.drawCircle(
Offset(size.x / 2, size.y / 2),
detectionRange,
radiusPaint,
);
}
// Draw dog house
final dogHousePaint = Paint()..color = const Color(0xFF8B4513);
canvas.drawRect(
Rect.fromLTWH(0, 0, size.x, size.y),
dogHousePaint,
);
// Draw dog (simple circle)
final dogPaint = Paint()..color = const Color(0xFF654321);
canvas.drawCircle(
Offset(size.x / 2, size.y / 2),
4,
dogPaint,
);
}
void stopPatrol() {
isPatrolling = false;
}
void startPatrol() {
isPatrolling = true;
}
/// Update detection radius visibility (call when settings change)
void updateDetectionRadiusVisibility(bool visible) {
_showDetectionRadius = visible;
}
/// Refresh visibility from current settings
void refreshVisibilityFromSettings() {
try {
final newVisibility = appSettings.getBool('game.show_detection_radius');
updateDetectionRadiusVisibility(newVisibility);
} catch (e) {
// Settings not ready, keep current state
}
}
@override
Future<void> reset() async {
currentAngle = 0;
isPatrolling = true;
position = patrolCenter;
}
}