feat: shared creature root, enemy definitions, defend duty, and player downing
This commit is contained in:
@@ -15,6 +15,8 @@ signal combatant_died(combatant_id: StringName)
|
||||
signal raid_started(raider_ids: Array[StringName])
|
||||
signal war_resolved(outcome: StringName)
|
||||
signal war_aborted
|
||||
signal player_damaged(amount: float)
|
||||
signal player_downed
|
||||
|
||||
const NPC_MAX_HEALTH := 100.0
|
||||
const STRONG_STRENGTH := 5.0
|
||||
@@ -24,9 +26,7 @@ const WOLF_HUNT_RADIUS := 18.0
|
||||
const RAID_SPAWN_OFFSET := Vector3(42.0, 0.0, 42.0)
|
||||
const RAID_SPEED := 1.2
|
||||
const RAID_SIZE := 4
|
||||
const RAIDER_HEALTH := 60.0
|
||||
const WOLF_HEALTH := 40.0
|
||||
const RAIDER_REACH_FACTOR := 1.6
|
||||
const PLAYER_COMBATANT_ID := &"player_combatant"
|
||||
|
||||
var combatants: Dictionary = {}
|
||||
var factions: Dictionary = {}
|
||||
@@ -52,6 +52,53 @@ func initialize_factions() -> void:
|
||||
factions[SimulationIds.FACTION_TRIBE] = FactionStateRecord.create(
|
||||
SimulationIds.FACTION_TRIBE, "Hill Tribe", 4.0, RAID_SIZE, 0.7, 0.7
|
||||
)
|
||||
_ensure_player_combatant()
|
||||
|
||||
|
||||
func _ensure_player_combatant() -> void:
|
||||
if combatants.has(PLAYER_COMBATANT_ID):
|
||||
return
|
||||
var sword := SimulationItems.get_weapon(SimulationIds.ITEM_SWORD)
|
||||
combatants[PLAYER_COMBATANT_ID] = CombatantStateRecord.create(
|
||||
PLAYER_COMBATANT_ID,
|
||||
SimulationIds.COMBATANT_KIND_PLAYER,
|
||||
SimulationIds.FACTION_VILLAGE,
|
||||
"Player",
|
||||
village_center,
|
||||
100.0,
|
||||
sword.item_id if sword != null else SimulationIds.ITEM_SWORD,
|
||||
CombatantStateRecord.NO_NPC_ID
|
||||
)
|
||||
|
||||
|
||||
func set_player_combatant_position(position: Vector3) -> void:
|
||||
var player_combatant := get_combatant(PLAYER_COMBATANT_ID)
|
||||
if player_combatant == null:
|
||||
_ensure_player_combatant()
|
||||
player_combatant = get_combatant(PLAYER_COMBATANT_ID)
|
||||
if player_combatant != null:
|
||||
player_combatant.set_position(position)
|
||||
|
||||
|
||||
func set_player_health(health: float, downed: bool) -> void:
|
||||
var player_combatant := get_combatant(PLAYER_COMBATANT_ID)
|
||||
if player_combatant == null:
|
||||
_ensure_player_combatant()
|
||||
player_combatant = get_combatant(PLAYER_COMBATANT_ID)
|
||||
if player_combatant == null:
|
||||
return
|
||||
if not downed and player_combatant.is_alive():
|
||||
var target := clampf(health, 0.0, player_combatant.get_max_health())
|
||||
var current := player_combatant.get_health()
|
||||
if target < current:
|
||||
player_combatant.take_damage(current - target)
|
||||
elif target > current:
|
||||
player_combatant.data["health"] = target
|
||||
|
||||
|
||||
func is_player_downed() -> bool:
|
||||
var player_combatant := get_combatant(PLAYER_COMBATANT_ID)
|
||||
return player_combatant != null and not player_combatant.is_alive()
|
||||
|
||||
|
||||
func register_npc_combatants(npc_list: Array[SimNPC]) -> void:
|
||||
@@ -100,7 +147,7 @@ func advance(simulation_tick: int) -> void:
|
||||
|
||||
|
||||
func _advance_raider_positions() -> void:
|
||||
if not _is_raiding():
|
||||
if not is_raiding():
|
||||
return
|
||||
for combatant_id in _sorted_combatant_ids():
|
||||
var combatant := combatants[combatant_id] as CombatantStateRecord
|
||||
@@ -132,16 +179,17 @@ 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,
|
||||
"Wolf",
|
||||
definition.display_name if definition != null else "Wolf",
|
||||
position,
|
||||
WOLF_HEALTH,
|
||||
SimulationIds.ITEM_CLAW,
|
||||
definition.health if definition != null else 40.0,
|
||||
definition.weapon_id if definition != null else SimulationIds.ITEM_CLAW,
|
||||
CombatantStateRecord.NO_NPC_ID,
|
||||
true
|
||||
)
|
||||
@@ -165,6 +213,11 @@ func _apply_damage(target: CombatantStateRecord, damage: float, actor_id: int) -
|
||||
target.get_weapon_id(),
|
||||
applied
|
||||
)
|
||||
if target.get_kind() == SimulationIds.COMBATANT_KIND_PLAYER:
|
||||
player_damaged.emit(applied)
|
||||
if not target.is_alive():
|
||||
player_downed.emit()
|
||||
return applied
|
||||
if not target.is_alive():
|
||||
_kill_combatant(target, actor_id)
|
||||
return applied
|
||||
@@ -313,6 +366,7 @@ 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] = []
|
||||
@@ -324,10 +378,10 @@ func _start_raid(tribe: FactionStateRecord, simulation_tick: int) -> void:
|
||||
raider_id,
|
||||
SimulationIds.COMBATANT_KIND_RAIDER,
|
||||
SimulationIds.FACTION_TRIBE,
|
||||
"Raider",
|
||||
definition.display_name if definition != null else "Raider",
|
||||
village_center + RAID_SPAWN_OFFSET + offset,
|
||||
RAIDER_HEALTH,
|
||||
SimulationIds.ITEM_SWORD,
|
||||
definition.health if definition != null else 60.0,
|
||||
definition.weapon_id if definition != null else SimulationIds.ITEM_SWORD,
|
||||
CombatantStateRecord.NO_NPC_ID,
|
||||
true
|
||||
)
|
||||
@@ -347,7 +401,7 @@ func _start_raid(tribe: FactionStateRecord, simulation_tick: int) -> void:
|
||||
|
||||
|
||||
func _run_battle() -> void:
|
||||
var raid_active := _is_raiding()
|
||||
var raid_active := is_raiding()
|
||||
var living_hostiles: Array[CombatantStateRecord] = []
|
||||
for combatant_id in _sorted_combatant_ids():
|
||||
var combatant := combatants[combatant_id] as CombatantStateRecord
|
||||
@@ -483,11 +537,7 @@ func _reach(combatant: CombatantStateRecord) -> float:
|
||||
var weapon := SimulationItems.get_weapon(combatant.get_weapon_id())
|
||||
if weapon == null:
|
||||
return 1.5
|
||||
return (
|
||||
weapon.reach * RAIDER_REACH_FACTOR
|
||||
if combatant.get_kind() == SimulationIds.COMBATANT_KIND_WOLF
|
||||
else weapon.reach
|
||||
)
|
||||
return weapon.reach
|
||||
|
||||
|
||||
func _actor_id_for(combatant: CombatantStateRecord) -> int:
|
||||
@@ -506,7 +556,7 @@ func _living_village_npc_count() -> int:
|
||||
return count
|
||||
|
||||
|
||||
func _is_raiding() -> bool:
|
||||
func is_raiding() -> bool:
|
||||
var tribe := _get_faction(SimulationIds.FACTION_TRIBE)
|
||||
return tribe != null and tribe.get_war_plan() == SimulationIds.WAR_PLAN_RAIDING
|
||||
|
||||
@@ -596,6 +646,8 @@ func _narrative_event_requested(
|
||||
func append_state_records(record: SimulationStateRecord) -> void:
|
||||
var combatant_keys: Array[String] = []
|
||||
for combatant_id in combatants.keys():
|
||||
if String(combatant_id) == String(PLAYER_COMBATANT_ID):
|
||||
continue
|
||||
combatant_keys.append(String(combatant_id))
|
||||
combatant_keys.sort()
|
||||
for combatant_key in combatant_keys:
|
||||
|
||||
Reference in New Issue
Block a user