t_p2_bomb: Bomb/defuse objective system for search & destroy rounds

Adds:
- bomb_objective.gd: server-authoritative bomb state machine (IDLE→PLANTED→EXPLODED/DEFUSED)
  - plant_bomb(player_id, pos) - T-side only, LIVE phase, inside bombsite
  - defuse_bomb(player_id) - CT-side only, near bomb, 5s timer
  - cancel_defuse(player_id) - if defuser moves or is killed
  - bomb_explode() - configurable radius damage (10m lethal, 15m half)
  - 40s bomb timer (configurable)
  - Full query API: is_bomb_planted(), get_bomb_position(), get_bomb_timer()
  - Signals: bomb_planted, bomb_defused, bomb_exploded, defuse_started, defuse_cancelled
  - Connected to RoundManager via GameServer for round-end outcomes

- bomb_carrier.gd: client-side bomb carrier UI
  - Bomb status/defuse progress UI updates
  - Direction indicator to planted bomb
  - "Hold E to defuse" prompt for CT near bomb
  - "Hold E to plant" prompt for T with bomb in bombsite

- test_range.tscn: BombsiteA (south-west, -20,0,-5) and BombsiteB (north-east, 15,0,20)
  - 8x4m Area3D zones with BoxShape3D collision
  - PlantPosition Marker3D children
  - Group 'bomb_sites' for server discovery

- game_server.gd: BombObjective integration in _ready()
  - Creates and wires BombObjective to RoundManager, TeamManager, DamageProcessor
  - Registers bomb sites from scene tree
  - Connects bomb_exploded/bomb_defused → RoundManager.end_round()
  - Connects round_ended → bomb.reset()
This commit is contained in:
2026-07-01 20:39:17 -04:00
parent 222dcaebb3
commit 194aad8f83
4 changed files with 908 additions and 1 deletions
+44 -1
View File
@@ -1,4 +1,4 @@
[gd_scene load_steps=8 format=3]
[gd_scene load_steps=10 format=3]
; =============================================================================
; test_range.tscn — Greybox Test Map
@@ -103,6 +103,49 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 30, 0.5, 20)
groups = ["spawn_points_t"]
; =============================================================================
; Bomb Sites
; =============================================================================
; BombsiteA — south-west area, 8×4m zone
; BombsiteB — north-east area, 8×4m zone
; Each has a CollisionShape3D (BoxShape3D) for overlap detection
; and a Marker3D child named "PlantPosition" marking the plant location.
; --- Bombsite A ---
[sub_resource type="BoxShape3D" id="8"]
size = Vector3(8, 4, 4)
[node name="BombsiteA" type="Area3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -20, 1.0, -5)
collision_layer = 0
collision_mask = 0
groups = ["bomb_sites"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="BombsiteA"]
shape = SubResource("8")
[node name="PlantPosition" type="Marker3D" parent="BombsiteA"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0, -1)
; --- Bombsite B ---
[sub_resource type="BoxShape3D" id="9"]
size = Vector3(8, 4, 4)
[node name="BombsiteB" type="Area3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 15, 1.0, 20)
collision_layer = 0
collision_mask = 0
groups = ["bomb_sites"]
[node name="PlantPosition" type="Marker3D" parent="BombsiteB"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2)
[node name="CollisionShape3D" type="CollisionShape3D" parent="BombsiteB"]
shape = SubResource("9")
; === Open Area Floor (80×80) ===
[node name="Floor" type="CSGBox3D" parent="."]