feat: make pantry crises visible in the world
This commit is contained in:
+200
-7
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=36 format=3]
|
||||
[gd_scene load_steps=50 format=3]
|
||||
|
||||
[ext_resource type="Terrain3DAssets" path="res://terrain/jajce/assets.tres" id="1_assets"]
|
||||
[ext_resource type="PackedScene" path="res://world/resource_nodes/ResourceNode.tscn" id="2_resource"]
|
||||
@@ -17,6 +17,7 @@
|
||||
[ext_resource type="Script" path="res://world/activity/ActivitySite.gd" id="15_activity"]
|
||||
[ext_resource type="NavigationMesh" path="res://world/jajce/JajceNavigationMesh.tres" id="16_nav"]
|
||||
[ext_resource type="PackedScene" path="res://world/jajce/vfx/WindGustField.tscn" id="17_wind_gust"]
|
||||
[ext_resource type="Script" path="res://world/storage/PantryStockVisual.gd" id="18_pantry_visual"]
|
||||
|
||||
[sub_resource type="Terrain3DMaterial" id="Terrain3DMaterial_jajce"]
|
||||
_shader_parameters = {
|
||||
@@ -74,6 +75,83 @@ size = Vector3(1.0, 0.08, 0.5)
|
||||
material = SubResource("Material_site_canvas")
|
||||
size = Vector3(0.5, 0.62, 0.42)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_pantry_berry"]
|
||||
albedo_color = Color(0.56, 0.16, 0.19, 1)
|
||||
roughness = 0.82
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_pantry_leaf"]
|
||||
albedo_color = Color(0.35, 0.52, 0.25, 1)
|
||||
roughness = 0.86
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_pantry_empty"]
|
||||
albedo_color = Color(0.48, 0.22, 0.09, 1)
|
||||
roughness = 0.94
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_pantry_glow"]
|
||||
transparency = 1
|
||||
shading_mode = 0
|
||||
albedo_color = Color(0.96, 0.72, 0.3, 0.7)
|
||||
emission_enabled = true
|
||||
emission = Color(0.92, 0.5, 0.15, 1)
|
||||
emission_energy_multiplier = 0.45
|
||||
|
||||
[sub_resource type="CylinderMesh" id="Mesh_pantry_basket"]
|
||||
material = SubResource("Material_site_dark_wood")
|
||||
top_radius = 0.46
|
||||
bottom_radius = 0.38
|
||||
height = 0.3
|
||||
radial_segments = 12
|
||||
|
||||
[sub_resource type="SphereMesh" id="Mesh_pantry_berry"]
|
||||
material = SubResource("Material_pantry_berry")
|
||||
radius = 0.15
|
||||
height = 0.26
|
||||
radial_segments = 10
|
||||
rings = 5
|
||||
|
||||
[sub_resource type="SphereMesh" id="Mesh_pantry_leaf"]
|
||||
material = SubResource("Material_pantry_leaf")
|
||||
radius = 0.12
|
||||
height = 0.24
|
||||
radial_segments = 8
|
||||
rings = 4
|
||||
|
||||
[sub_resource type="TorusMesh" id="Mesh_pantry_bowl_rim"]
|
||||
material = SubResource("Material_pantry_empty")
|
||||
inner_radius = 0.3
|
||||
outer_radius = 0.39
|
||||
rings = 14
|
||||
ring_segments = 8
|
||||
|
||||
[sub_resource type="CylinderMesh" id="Mesh_pantry_bowl_base"]
|
||||
material = SubResource("Material_pantry_empty")
|
||||
top_radius = 0.3
|
||||
bottom_radius = 0.24
|
||||
height = 0.08
|
||||
radial_segments = 12
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_pantry_shelf"]
|
||||
material = SubResource("Material_site_dark_wood")
|
||||
size = Vector3(1.5, 0.12, 0.5)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_pantry_backcloth"]
|
||||
material = SubResource("Material_site_canvas")
|
||||
size = Vector3(1.45, 1.05, 0.08)
|
||||
|
||||
[sub_resource type="TorusMesh" id="Mesh_pantry_refill_ring"]
|
||||
material = SubResource("Material_pantry_glow")
|
||||
inner_radius = 0.55
|
||||
outer_radius = 0.66
|
||||
rings = 18
|
||||
ring_segments = 8
|
||||
|
||||
[sub_resource type="SphereMesh" id="Mesh_pantry_refill_mote"]
|
||||
material = SubResource("Material_pantry_glow")
|
||||
radius = 0.09
|
||||
height = 0.17
|
||||
radial_segments = 8
|
||||
rings = 4
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_study_book"]
|
||||
material = SubResource("Material_site_book")
|
||||
size = Vector3(0.42, 0.08, 0.3)
|
||||
@@ -458,6 +536,9 @@ discovery_priority = 0.45
|
||||
[node name="VillagePantry" parent="WorldObjects/StorageSites" instance=ExtResource("14_storage")]
|
||||
position = Vector3(0, 0, -8)
|
||||
|
||||
[node name="Visual" parent="WorldObjects/StorageSites/VillagePantry"]
|
||||
visible = false
|
||||
|
||||
[node name="VillageWoodpile" parent="WorldObjects/StorageSites" instance=ExtResource("14_storage")]
|
||||
position = Vector3(8, 0, -12)
|
||||
storage_id = &"village_woodpile"
|
||||
@@ -471,16 +552,128 @@ position = Vector3(-1.05, 1.85, 1.25)
|
||||
rotation_degrees = Vector3(0, 90, 0)
|
||||
mesh = SubResource("Mesh_site_sign")
|
||||
|
||||
[node name="PantrySack_A" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry"]
|
||||
position = Vector3(-0.95, 0.3, -0.65)
|
||||
scale = Vector3(0.65, 1.0, 0.65)
|
||||
[node name="PantryPresentation" type="Node3D" parent="WorldObjects/StorageSites/VillagePantry"]
|
||||
position = Vector3(0, 0, -0.48)
|
||||
scale = Vector3(1.12, 1.12, 1.12)
|
||||
script = ExtResource("18_pantry_visual")
|
||||
|
||||
[node name="Backcloth" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation"]
|
||||
position = Vector3(0, 0.68, 0.22)
|
||||
mesh = SubResource("Mesh_pantry_backcloth")
|
||||
|
||||
[node name="ShelfLower" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation"]
|
||||
position = Vector3(0, 0.18, 0)
|
||||
mesh = SubResource("Mesh_pantry_shelf")
|
||||
|
||||
[node name="ShelfUpper" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation"]
|
||||
position = Vector3(0, 1.15, 0)
|
||||
mesh = SubResource("Mesh_pantry_shelf")
|
||||
|
||||
[node name="PostLeft" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation"]
|
||||
position = Vector3(-0.65, 0.66, 0.18)
|
||||
scale = Vector3(0.08, 8, 0.12)
|
||||
mesh = SubResource("Mesh_pantry_shelf")
|
||||
|
||||
[node name="PostRight" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation"]
|
||||
position = Vector3(0.65, 0.66, 0.18)
|
||||
scale = Vector3(0.08, 8, 0.12)
|
||||
mesh = SubResource("Mesh_pantry_shelf")
|
||||
|
||||
[node name="EmptyStock" type="Node3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation"]
|
||||
position = Vector3(0, 0, -0.38)
|
||||
|
||||
[node name="BowlBase" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/EmptyStock"]
|
||||
position = Vector3(0, 0.27, -0.04)
|
||||
mesh = SubResource("Mesh_pantry_bowl_base")
|
||||
|
||||
[node name="BowlRim" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/EmptyStock"]
|
||||
position = Vector3(0, 0.34, -0.04)
|
||||
mesh = SubResource("Mesh_pantry_bowl_rim")
|
||||
|
||||
[node name="LowStock" type="Node3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation"]
|
||||
visible = false
|
||||
position = Vector3(0, 0, -0.38)
|
||||
|
||||
[node name="Sack" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/LowStock"]
|
||||
position = Vector3(-0.42, 0.49, 0)
|
||||
scale = Vector3(0.72, 0.9, 0.72)
|
||||
mesh = SubResource("Mesh_site_sack")
|
||||
|
||||
[node name="PantrySack_B" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry"]
|
||||
position = Vector3(-1.35, 0.22, -0.25)
|
||||
scale = Vector3(0.5, 0.75, 0.5)
|
||||
[node name="Basket" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/LowStock"]
|
||||
position = Vector3(0.36, 0.32, -0.02)
|
||||
mesh = SubResource("Mesh_pantry_basket")
|
||||
|
||||
[node name="BerryLeft" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/LowStock"]
|
||||
position = Vector3(0.18, 0.52, -0.02)
|
||||
mesh = SubResource("Mesh_pantry_berry")
|
||||
|
||||
[node name="BerryCenter" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/LowStock"]
|
||||
position = Vector3(0.38, 0.57, 0.02)
|
||||
mesh = SubResource("Mesh_pantry_berry")
|
||||
|
||||
[node name="BerryRight" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/LowStock"]
|
||||
position = Vector3(0.55, 0.5, -0.03)
|
||||
mesh = SubResource("Mesh_pantry_berry")
|
||||
|
||||
[node name="Leaf" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/LowStock"]
|
||||
position = Vector3(0.36, 0.67, 0)
|
||||
rotation_degrees = Vector3(20, 0, 58)
|
||||
scale = Vector3(0.45, 1, 0.3)
|
||||
mesh = SubResource("Mesh_pantry_leaf")
|
||||
|
||||
[node name="FullStock" type="Node3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation"]
|
||||
visible = false
|
||||
position = Vector3(0, 0, -0.38)
|
||||
|
||||
[node name="SackLeft" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/FullStock"]
|
||||
position = Vector3(-0.48, 0.77, 0)
|
||||
scale = Vector3(0.55, 0.72, 0.55)
|
||||
mesh = SubResource("Mesh_site_sack")
|
||||
|
||||
[node name="SackRight" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/FullStock"]
|
||||
position = Vector3(0.48, 0.78, 0)
|
||||
scale = Vector3(0.5, 0.68, 0.5)
|
||||
mesh = SubResource("Mesh_site_sack")
|
||||
|
||||
[node name="UpperBasket" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/FullStock"]
|
||||
position = Vector3(0, 1.31, -0.02)
|
||||
scale = Vector3(0.82, 0.82, 0.82)
|
||||
mesh = SubResource("Mesh_pantry_basket")
|
||||
|
||||
[node name="UpperBerryLeft" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/FullStock"]
|
||||
position = Vector3(-0.18, 1.48, -0.03)
|
||||
mesh = SubResource("Mesh_pantry_berry")
|
||||
|
||||
[node name="UpperBerryCenter" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/FullStock"]
|
||||
position = Vector3(0, 1.52, 0.02)
|
||||
mesh = SubResource("Mesh_pantry_berry")
|
||||
|
||||
[node name="UpperBerryRight" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/FullStock"]
|
||||
position = Vector3(0.18, 1.46, -0.02)
|
||||
mesh = SubResource("Mesh_pantry_berry")
|
||||
|
||||
[node name="RefillResponse" type="Node3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation"]
|
||||
visible = false
|
||||
position = Vector3(0, 0.08, -0.5)
|
||||
scale = Vector3(0.45, 0.45, 0.45)
|
||||
|
||||
[node name="Ring" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/RefillResponse"]
|
||||
position = Vector3(0, 0.78, 0)
|
||||
mesh = SubResource("Mesh_pantry_refill_ring")
|
||||
|
||||
[node name="MoteLeft" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/RefillResponse"]
|
||||
position = Vector3(-0.48, 1.02, 0)
|
||||
mesh = SubResource("Mesh_pantry_refill_mote")
|
||||
|
||||
[node name="MoteCenter" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/RefillResponse"]
|
||||
position = Vector3(0, 1.18, 0)
|
||||
scale = Vector3(0.8, 1.3, 0.8)
|
||||
mesh = SubResource("Mesh_pantry_refill_mote")
|
||||
|
||||
[node name="MoteRight" type="MeshInstance3D" parent="WorldObjects/StorageSites/VillagePantry/PantryPresentation/RefillResponse"]
|
||||
position = Vector3(0.48, 1.02, 0)
|
||||
mesh = SubResource("Mesh_pantry_refill_mote")
|
||||
|
||||
[node name="ActivitySites" type="Node3D" parent="WorldObjects"]
|
||||
|
||||
[node name="GuardPost" type="Node3D" parent="WorldObjects/ActivitySites"]
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
class_name PantryStockVisual
|
||||
extends Node3D
|
||||
|
||||
enum StockLevel { EMPTY, LOW, STOCKED }
|
||||
|
||||
const LOW_STOCK_THRESHOLD := 4.0
|
||||
const REFILL_RESPONSE_START := Vector3(0.0, 0.08, -0.5)
|
||||
const REFILL_RESPONSE_END := Vector3(0.0, 0.36, -0.5)
|
||||
|
||||
@onready var empty_root: Node3D = $EmptyStock
|
||||
@onready var low_stock_root: Node3D = $LowStock
|
||||
@onready var full_stock_root: Node3D = $FullStock
|
||||
@onready var refill_response_root: Node3D = $RefillResponse
|
||||
@onready var refill_response_visuals: Array[MeshInstance3D] = [
|
||||
$RefillResponse/Ring,
|
||||
$RefillResponse/MoteLeft,
|
||||
$RefillResponse/MoteCenter,
|
||||
$RefillResponse/MoteRight,
|
||||
]
|
||||
|
||||
var displayed_amount := -1.0
|
||||
var stock_level := StockLevel.EMPTY
|
||||
var transition_tween: Tween
|
||||
var refill_tween: Tween
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
refill_response_root.visible = false
|
||||
|
||||
|
||||
func set_food_amount(amount: float, animate: bool = true) -> void:
|
||||
var normalized_amount := maxf(amount, 0.0)
|
||||
var next_level := _get_stock_level(normalized_amount)
|
||||
if next_level == StockLevel.EMPTY:
|
||||
_stop_refill_response()
|
||||
var was_initialized := displayed_amount >= 0.0
|
||||
var was_empty := was_initialized and displayed_amount <= 0.001
|
||||
if was_initialized and next_level == stock_level:
|
||||
displayed_amount = normalized_amount
|
||||
return
|
||||
var should_animate := animate and was_initialized
|
||||
displayed_amount = normalized_amount
|
||||
stock_level = next_level
|
||||
if should_animate:
|
||||
_transition_to_level(next_level)
|
||||
else:
|
||||
_apply_level_immediately(next_level)
|
||||
if was_empty and normalized_amount > 0.001 and animate:
|
||||
_play_refill_response()
|
||||
|
||||
|
||||
func get_stock_level() -> StockLevel:
|
||||
return stock_level
|
||||
|
||||
|
||||
func _get_stock_level(amount: float) -> StockLevel:
|
||||
if amount <= 0.001:
|
||||
return StockLevel.EMPTY
|
||||
if amount < LOW_STOCK_THRESHOLD:
|
||||
return StockLevel.LOW
|
||||
return StockLevel.STOCKED
|
||||
|
||||
|
||||
func _apply_level_immediately(level: StockLevel) -> void:
|
||||
_stop_transition()
|
||||
_set_root_visible(empty_root, level == StockLevel.EMPTY)
|
||||
_set_root_visible(low_stock_root, level in [StockLevel.LOW, StockLevel.STOCKED])
|
||||
_set_root_visible(full_stock_root, level == StockLevel.STOCKED)
|
||||
|
||||
|
||||
func _transition_to_level(level: StockLevel) -> void:
|
||||
_stop_transition()
|
||||
transition_tween = create_tween().set_parallel(true)
|
||||
_transition_root(empty_root, level == StockLevel.EMPTY)
|
||||
_transition_root(low_stock_root, level in [StockLevel.LOW, StockLevel.STOCKED])
|
||||
_transition_root(full_stock_root, level == StockLevel.STOCKED)
|
||||
transition_tween.chain().tween_callback(_finish_transition.bind(level))
|
||||
|
||||
|
||||
func _transition_root(root: Node3D, should_show: bool) -> void:
|
||||
if should_show:
|
||||
if not root.visible:
|
||||
root.visible = true
|
||||
root.scale = Vector3.ONE * 0.62
|
||||
(
|
||||
transition_tween
|
||||
. tween_property(root, "scale", Vector3.ONE, 0.28)
|
||||
. set_trans(Tween.TRANS_BACK)
|
||||
. set_ease(Tween.EASE_OUT)
|
||||
)
|
||||
return
|
||||
if not root.visible:
|
||||
return
|
||||
(
|
||||
transition_tween
|
||||
. tween_property(root, "scale", Vector3.ONE * 0.18, 0.16)
|
||||
. set_trans(Tween.TRANS_SINE)
|
||||
. set_ease(Tween.EASE_IN)
|
||||
)
|
||||
|
||||
|
||||
func _finish_transition(level: StockLevel) -> void:
|
||||
transition_tween = null
|
||||
_set_root_visible(empty_root, level == StockLevel.EMPTY)
|
||||
_set_root_visible(low_stock_root, level in [StockLevel.LOW, StockLevel.STOCKED])
|
||||
_set_root_visible(full_stock_root, level == StockLevel.STOCKED)
|
||||
|
||||
|
||||
func _set_root_visible(root: Node3D, is_visible: bool) -> void:
|
||||
root.visible = is_visible
|
||||
root.scale = Vector3.ONE
|
||||
|
||||
|
||||
func _stop_transition() -> void:
|
||||
if transition_tween != null:
|
||||
transition_tween.kill()
|
||||
transition_tween = null
|
||||
|
||||
|
||||
func _play_refill_response() -> void:
|
||||
_stop_refill_response()
|
||||
refill_response_root.visible = true
|
||||
refill_response_root.position = REFILL_RESPONSE_START
|
||||
refill_response_root.scale = Vector3.ONE * 0.45
|
||||
_set_refill_transparency(0.0)
|
||||
refill_tween = create_tween()
|
||||
refill_tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
|
||||
refill_tween.tween_property(refill_response_root, "scale", Vector3.ONE, 0.24)
|
||||
refill_tween.parallel().tween_method(_set_refill_transparency, 0.0, 1.0, 0.18)
|
||||
refill_tween.tween_property(refill_response_root, "position", REFILL_RESPONSE_END, 0.5)
|
||||
refill_tween.parallel().tween_method(_set_refill_transparency, 1.0, 0.0, 0.5)
|
||||
refill_tween.tween_callback(_stop_refill_response)
|
||||
|
||||
|
||||
func _set_refill_transparency(value: float) -> void:
|
||||
for visual in refill_response_visuals:
|
||||
visual.transparency = clampf(1.0 - value, 0.0, 1.0)
|
||||
|
||||
|
||||
func _stop_refill_response() -> void:
|
||||
if refill_tween != null:
|
||||
refill_tween.kill()
|
||||
refill_tween = null
|
||||
if refill_response_root == null:
|
||||
return
|
||||
refill_response_root.visible = false
|
||||
refill_response_root.position = REFILL_RESPONSE_START
|
||||
refill_response_root.scale = Vector3.ONE * 0.45
|
||||
_set_refill_transparency(0.0)
|
||||
@@ -0,0 +1 @@
|
||||
uid://bj2aigpu1nug6
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=7 format=3]
|
||||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/storage/StorageNode.gd" id="1_storage"]
|
||||
|
||||
@@ -18,10 +18,6 @@ size = Vector3(1.6, 1.1, 1.6)
|
||||
material = SubResource("Material_cloth")
|
||||
size = Vector3(1.75, 0.12, 1.75)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_sack"]
|
||||
material = SubResource("Material_cloth")
|
||||
size = Vector3(0.45, 0.65, 0.45)
|
||||
|
||||
[node name="StorageNode" type="Node3D"]
|
||||
script = ExtResource("1_storage")
|
||||
|
||||
@@ -35,10 +31,6 @@ mesh = SubResource("Mesh_crate")
|
||||
transform = Transform3D(1, 0, 0, 0, 0.7, 0.7173561, 0, -0.7173561, 0.7, 0, 1.15, -0.06)
|
||||
mesh = SubResource("Mesh_lid")
|
||||
|
||||
[node name="FoodSack" type="MeshInstance3D" parent="Visual"]
|
||||
transform = Transform3D(0.85, 0, 0, 0, 1, 0, 0, 0, 0.85, 0.8, 0.325, 0.55)
|
||||
mesh = SubResource("Mesh_sack")
|
||||
|
||||
[node name="InteractionPoint" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2.0)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ extends Node
|
||||
@export var npc_visual_scene: PackedScene
|
||||
@export var simulation_manager: Node
|
||||
@export var active_npcs_parent: Node3D
|
||||
@export var pantry_visual: Node3D
|
||||
|
||||
var active_npc_visuals := {}
|
||||
|
||||
@@ -44,11 +45,24 @@ func initialize_world_view() -> void:
|
||||
simulation_manager.relationship_changed.connect(_on_relationship_changed)
|
||||
else:
|
||||
push_error("WorldViewManager: SimulationManager has no relationship_changed signal")
|
||||
if simulation_manager.has_signal("economic_event_recorded"):
|
||||
simulation_manager.economic_event_recorded.connect(_on_economic_event_recorded)
|
||||
else:
|
||||
push_error("WorldViewManager: SimulationManager has no economic_event_recorded signal")
|
||||
if simulation_manager.has_signal("opportunity_opened"):
|
||||
simulation_manager.opportunity_opened.connect(_on_opportunity_changed)
|
||||
else:
|
||||
push_error("WorldViewManager: SimulationManager has no opportunity_opened signal")
|
||||
if simulation_manager.has_signal("opportunity_resolved"):
|
||||
simulation_manager.opportunity_resolved.connect(_on_opportunity_resolved)
|
||||
else:
|
||||
push_error("WorldViewManager: SimulationManager has no opportunity_resolved signal")
|
||||
if simulation_manager.has_signal("state_restored"):
|
||||
simulation_manager.state_restored.connect(_on_simulation_state_restored)
|
||||
else:
|
||||
push_error("WorldViewManager: SimulationManager has no state_restored signal")
|
||||
spawn_initial_npcs()
|
||||
_refresh_world_state_presentation(false)
|
||||
|
||||
|
||||
func spawn_initial_npcs() -> void:
|
||||
@@ -86,6 +100,7 @@ func spawn_npc_visual(npc: SimNPC) -> void:
|
||||
else:
|
||||
push_error("WorldViewManager: NPCVisual has no position_changed signal")
|
||||
active_npc_visuals[npc.id] = visual
|
||||
_sync_npc_opportunity_concern(npc.id, visual)
|
||||
debug_log("Spawned visual for %s at %s" % [npc.npc_name, npc.position])
|
||||
if npc.is_dead:
|
||||
visual.apply_dead_visual_state()
|
||||
@@ -200,8 +215,62 @@ func _on_relationship_changed(
|
||||
push_error("WorldViewManager: NPCVisual has no play_trust_gain_reaction method")
|
||||
|
||||
|
||||
func _on_economic_event_recorded(_event: EconomicEventRecord) -> void:
|
||||
_refresh_pantry_stock(true)
|
||||
|
||||
|
||||
func _on_opportunity_changed(_opportunity: OpportunityStateRecord) -> void:
|
||||
_refresh_world_state_presentation(true)
|
||||
|
||||
|
||||
func _on_opportunity_resolved(
|
||||
_opportunity: OpportunityStateRecord, _cause_event: EconomicEventRecord
|
||||
) -> void:
|
||||
_refresh_world_state_presentation(true)
|
||||
|
||||
|
||||
func _on_simulation_state_restored() -> void:
|
||||
for visual in active_npc_visuals.values():
|
||||
visual.queue_free()
|
||||
active_npc_visuals.clear()
|
||||
spawn_initial_npcs()
|
||||
_refresh_world_state_presentation(false)
|
||||
|
||||
|
||||
func _refresh_world_state_presentation(animate: bool) -> void:
|
||||
_refresh_pantry_stock(animate)
|
||||
_refresh_opportunity_concern()
|
||||
|
||||
|
||||
func _refresh_pantry_stock(animate: bool) -> void:
|
||||
if pantry_visual == null or not pantry_visual.has_method("set_food_amount"):
|
||||
return
|
||||
var pantry: StorageStateRecord = simulation_manager.get_pantry()
|
||||
var amount := 0.0
|
||||
if pantry != null:
|
||||
amount = pantry.get_amount(SimulationIds.RESOURCE_FOOD)
|
||||
pantry_visual.set_food_amount(amount, animate)
|
||||
|
||||
|
||||
func _refresh_opportunity_concern() -> void:
|
||||
for visual in active_npc_visuals.values():
|
||||
if visual.has_method("set_opportunity_concern_visible"):
|
||||
visual.set_opportunity_concern_visible(false)
|
||||
var opportunity: OpportunityStateRecord = simulation_manager.get_active_opportunity()
|
||||
if opportunity == null:
|
||||
return
|
||||
var interested_visual = active_npc_visuals.get(opportunity.get_interested_npc_id())
|
||||
if (
|
||||
interested_visual != null
|
||||
and interested_visual.has_method("set_opportunity_concern_visible")
|
||||
):
|
||||
interested_visual.set_opportunity_concern_visible(true)
|
||||
|
||||
|
||||
func _sync_npc_opportunity_concern(npc_id: int, visual: Node3D) -> void:
|
||||
if not visual.has_method("set_opportunity_concern_visible"):
|
||||
return
|
||||
var opportunity: OpportunityStateRecord = simulation_manager.get_active_opportunity()
|
||||
visual.set_opportunity_concern_visible(
|
||||
opportunity != null and opportunity.get_interested_npc_id() == npc_id
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user