class_name HostileCombatant extends CreatureVisual var combatant: CombatantStateRecord var simulation_manager: Node var _flash_tween: Tween var _spawn_tween: Tween func _ready() -> void: add_to_group("grass_interactors") scale = Vector3.ONE * 0.001 _spawn_tween = create_tween() _spawn_tween.set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT) _spawn_tween.tween_property(self, "scale", Vector3.ONE, 0.28) func bind(combatant_id_value: StringName, manager: Node) -> void: creature_id = combatant_id_value simulation_manager = manager combatant = manager.get_combatant(creature_id) as CombatantStateRecord if combatant == null: return global_position = combatant.get_position() sim_position = combatant.get_position() _build_from_definition() combatant.changed.connect(_on_combatant_changed) func _process(_delta: float) -> void: if is_dead_visual or combatant == null or not is_instance_valid(combatant): return if not combatant.is_alive(): play_death() return set_sim_position(combatant.get_position()) func _on_combatant_changed(_state: CombatantStateRecord) -> void: if combatant == null or combatant.get_health() >= combatant.get_max_health(): return _flash_hit() func _flash_hit() -> void: if _flash_tween != null and _flash_tween.is_valid(): _flash_tween.kill() _flash_tween = create_tween() _flash_tween.tween_property(self, "scale", _definition_scale() * 0.85, 0.06) _flash_tween.tween_property(self, "scale", _definition_scale(), 0.12) func play_death() -> void: is_dead_visual = true super.play_death() func _definition_scale() -> Vector3: var definition := _enemy_definition() return definition.visual_scale if definition != null else Vector3.ONE func _build_from_definition() -> void: var definition := _enemy_definition() if definition != null: move_speed = definition.move_speed scale = definition.visual_scale if definition.kind == SimulationIds.COMBATANT_KIND_WOLF: _build_wolf(definition) else: _build_raider(definition) func _enemy_definition() -> EnemyDefinition: if combatant == null: return null var enemy_id: StringName = ( &"enemy_wolf" if combatant.get_kind() == SimulationIds.COMBATANT_KIND_WOLF else &"enemy_raider" ) return SimulationEnemies.get_enemy(enemy_id) func _build_raider(definition: EnemyDefinition) -> void: var tunic := StandardMaterial3D.new() tunic.albedo_color = definition.body_color tunic.roughness = 0.85 var skin := StandardMaterial3D.new() skin.albedo_color = Color(0.8, 0.58, 0.36, 1.0) skin.roughness = 0.9 var metal := StandardMaterial3D.new() metal.albedo_color = definition.accent_color metal.roughness = 0.35 _add_mesh("Body", CylinderMesh.new(), Vector3(0.0, 1.1, 0.0), tunic) _add_mesh("Head", SphereMesh.new(), Vector3(0.0, 1.7, 0.0), skin) var blade := BoxMesh.new() blade.size = Vector3(0.06, 0.72, 0.14) _add_mesh("Sword", blade, Vector3(0.42, 1.25, 0.0), metal, Vector3(0.0, 0.0, -0.2)) var shield := CylinderMesh.new() shield.top_radius = 0.3 shield.bottom_radius = 0.3 shield.height = 0.12 _add_mesh( "Shield", shield, Vector3(-0.42, 1.15, 0.0), metal, Vector3.ZERO, Vector3(1.57, 0.0, 0.0) ) func _build_wolf(definition: EnemyDefinition) -> void: var fur := StandardMaterial3D.new() fur.albedo_color = definition.body_color fur.roughness = 0.95 var eye := StandardMaterial3D.new() eye.albedo_color = definition.accent_color eye.roughness = 0.3 var body := SphereMesh.new() body.radius = 0.34 body.height = 0.68 _add_mesh("Body", body, Vector3(0.0, 0.55, 0.0), fur, Vector3.ZERO, Vector3(1.57, 0.0, 0.0)) var head := SphereMesh.new() head.radius = 0.2 head.height = 0.4 _add_mesh("Head", head, Vector3(0.0, 0.62, -0.42), fur, Vector3.ZERO, Vector3(1.57, 0.0, 0.0)) var tail := BoxMesh.new() tail.size = Vector3(0.1, 0.1, 0.5) _add_mesh("Tail", tail, Vector3(0.0, 0.72, 0.42), fur, Vector3(0.6, 0.0, 0.0)) var leg_mesh := CylinderMesh.new() leg_mesh.top_radius = 0.06 leg_mesh.bottom_radius = 0.06 leg_mesh.height = 0.42 for leg_x in [-0.18, 0.18]: for leg_z in [-0.2, 0.2]: _add_mesh("Leg", leg_mesh, Vector3(leg_x, 0.21, leg_z), fur) func _add_mesh( node_name: String, mesh: PrimitiveMesh, local_position: Vector3, material: Material, rotation_offset: Vector3 = Vector3.ZERO, mesh_rotation: Vector3 = Vector3.ZERO ) -> void: var mesh_instance := MeshInstance3D.new() mesh_instance.name = node_name mesh_instance.mesh = mesh mesh_instance.material_override = material mesh_instance.position = local_position if not rotation_offset.is_zero_approx(): mesh_instance.rotation = rotation_offset if not mesh_rotation.is_zero_approx(): mesh_instance.rotation += mesh_rotation add_child(mesh_instance)