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
+40
View File
@@ -61,6 +61,9 @@ var economy_manager: EconomyManager = null
## BuyMenuHandler — server-side buy request validation and processing.
var buy_menu_handler: BuyMenuHandler = null
## BombObjective — server-authoritative bomb plant/defuse logic.
var bomb_objective: BombObjective = null
## Current server tick counter, incremented each time tick() is called.
var _current_tick: int = 0
@@ -163,6 +166,43 @@ func _ready() -> void:
# Register as singleton so FPSCharacterController can find us
Engine.register_singleton("SimulationServer", simulation_server)
# --- Bomb / Defuse Objective ---
bomb_objective = BombObjective.new()
add_child(bomb_objective)
bomb_objective.round_manager = round_manager
bomb_objective.team_manager = team_manager
bomb_objective.damage_processor = damage_processor
bomb_objective.entity_to_peer = entity_to_peer
bomb_objective.peer_to_entity = peer_to_entity
# Register bomb sites from the scene tree
if is_inside_tree():
var bomb_sites: Array[Area3D] = get_tree().get_nodes_in_group("bomb_sites")
if bomb_sites.size() > 0:
bomb_objective.register_bomb_sites(bomb_sites)
print("[GameServer] Registered %d bomb sites with BombObjective" % bomb_sites.size())
else:
print("[GameServer] No bomb sites found in scene — bomb can't be planted")
else:
print("[GameServer] Not in scene tree yet — bomb sites will be registered later")
# Wire: bomb explosion/defuse → round end
bomb_objective.bomb_exploded.connect(func(_pos):
if round_manager:
round_manager.end_round(TeamData.Team.TERRORIST, "bomb_exploded")
)
bomb_objective.bomb_defused.connect(func(_player_id):
if round_manager:
round_manager.end_round(TeamData.Team.COUNTER_TERRORIST, "bomb_defused")
)
# Wire: round end → reset bomb
round_manager.round_ended.connect(func(_winning_team, _reason):
bomb_objective.reset()
)
print("[GameServer] BombObjective integrated — bomb/defuse ready")
print("[GameServer] SimulationServer created. Tick rate: %d Hz" % simulation_server.get_tick_rate())
func _exit_tree() -> void: