feat: spawn enemies from reusable definitions

This commit is contained in:
Rijad Zuzo
2026-08-12 20:34:55 +02:00
parent 41b37a4962
commit 809e7c008d
12 changed files with 332 additions and 57 deletions
+30 -35
View File
@@ -34,8 +34,7 @@ var factions: Dictionary = {}
var economy: RefCounted
var npcs: Array[SimNPC] = []
var _npcs_by_id: Dictionary = {}
var next_combatant_id := 0
var next_wolf_id := 0
var combatant_factory := CombatantFactory.new()
var current_tick := 0
var village_center := Vector3.ZERO
var last_war_resolved_tick := -1
@@ -222,24 +221,18 @@ func player_attack(combatant_id: StringName) -> float:
func spawn_wolf(position: Vector3) -> StringName:
var definition := SimulationEnemies.get_enemy(&"enemy_wolf")
var wolf_id := StringName("wolf_%d" % next_wolf_id)
next_wolf_id += 1
var wolf := CombatantStateRecord.create(
wolf_id,
SimulationIds.COMBATANT_KIND_WOLF,
SimulationIds.FACTION_TRIBE,
definition.display_name if definition != null else "Wolf",
position,
definition.health if definition != null else 40.0,
definition.weapon_id if definition != null else SimulationIds.ITEM_CLAW,
CombatantStateRecord.NO_NPC_ID,
true
)
combatants[wolf_id] = wolf
return spawn_enemy(&"enemy_wolf", position)
func spawn_enemy(enemy_definition_id: StringName, position: Vector3) -> StringName:
var enemy := combatant_factory.create_enemy(enemy_definition_id, position)
if enemy == null:
return &""
var combatant_id := enemy.get_combatant_id()
combatants[combatant_id] = enemy
_combatant_ids_dirty = true
combatant_spawned.emit(wolf_id)
return wolf_id
combatant_spawned.emit(combatant_id)
return combatant_id
func _apply_damage(target: CombatantStateRecord, damage: float, actor_id: int) -> float:
@@ -291,7 +284,11 @@ func _advance_wolves() -> void:
var combatant := combatants[combatant_id] as CombatantStateRecord
if combatant == null or not combatant.is_alive():
continue
if combatant.get_kind() != SimulationIds.COMBATANT_KIND_WOLF:
var definition := _enemy_definition_for(combatant)
if (
definition == null
or definition.behavior_profile_id != EnemyDefinition.BEHAVIOR_PROFILE_WOLF_HUNT
):
continue
var target := _find_nearest_defender(combatant.get_position(), WOLF_HUNT_RADIUS)
if target == null:
@@ -302,8 +299,7 @@ func _advance_wolves() -> void:
var to_target := target.get_position() - combatant.get_position()
to_target.y = 0.0
if to_target.length() > reach:
var definition := SimulationEnemies.get_enemy(&"enemy_wolf")
var speed := definition.move_speed if definition != null else 3.2
var speed := definition.move_speed
var step_distance := minf(speed * tick_interval, to_target.length() - reach)
combatant.set_position(
combatant.get_position() + to_target.normalized() * maxf(step_distance, 0.0)
@@ -422,25 +418,17 @@ func village_defender_count() -> int:
func _start_raid(tribe: FactionStateRecord, simulation_tick: int) -> void:
var definition := SimulationEnemies.get_enemy(&"enemy_raider")
tribe.set_war_plan(SimulationIds.WAR_PLAN_RAIDING, simulation_tick)
tribe.set_stance(SimulationIds.STANCE_HOSTILE)
var raider_ids: Array[StringName] = []
for index in range(tribe.get_warriors()):
var raider_id := StringName("raider_%d" % next_combatant_id)
next_combatant_id += 1
var offset := Vector3(float(index * 2 - tribe.get_warriors()), 0.0, 0.0)
var raider := CombatantStateRecord.create(
raider_id,
SimulationIds.COMBATANT_KIND_RAIDER,
SimulationIds.FACTION_TRIBE,
definition.display_name if definition != null else "Raider",
village_center + RAID_SPAWN_OFFSET + offset,
definition.health if definition != null else 60.0,
definition.weapon_id if definition != null else SimulationIds.ITEM_SWORD,
CombatantStateRecord.NO_NPC_ID,
true
var raider := combatant_factory.create_enemy(
&"enemy_raider", village_center + RAID_SPAWN_OFFSET + offset
)
if raider == null:
continue
var raider_id := raider.get_combatant_id()
combatants[raider_id] = raider
_combatant_ids_dirty = true
raider_ids.append(raider_id)
@@ -695,6 +683,12 @@ func _get_faction(faction_id: StringName) -> FactionStateRecord:
return factions.get(faction_id) as FactionStateRecord
func _enemy_definition_for(combatant: CombatantStateRecord) -> EnemyDefinition:
if combatant == null or combatant.get_enemy_definition_id().is_empty():
return null
return SimulationEnemies.get_enemy(combatant.get_enemy_definition_id())
func _narrative_event_requested(
event_type: StringName,
actor_id: int,
@@ -738,6 +732,7 @@ func restore_state_records(
combatants.clear()
for combatant in combatant_records:
combatants[combatant.get_combatant_id()] = combatant
combatant_factory.restore_allocator(combatant_records)
_combatant_ids_dirty = true
factions.clear()
for faction in faction_records: