diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4afa3d5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "godotTools.editorPath.godot4": "c:\\Users\\jason\\Downloads\\Godot_v4.4.1-stable_mono_win64\\Godot_v4.4.1-stable_mono_win64\\Godot_v4.4.1-stable_mono_win64.exe" +} \ No newline at end of file diff --git a/configs/example_mission_config.tres b/configs/example_mission_config.tres new file mode 100644 index 0000000..827fa00 --- /dev/null +++ b/configs/example_mission_config.tres @@ -0,0 +1,62 @@ +[gd_resource type="Resource" script_class="MissionConfig" load_steps=2 format=3] + +[ext_resource type="Script" path="res://scripts/mission/mission_config.gd" id="1_config"] + +[resource] +script = ExtResource("1_config") +starting_structures = ["res://structures/road-straight.tres", "res://structures/building-small-a.tres"] +initial_structures = [ + { + "structure_path": "res://structures/road-straight.tres", + "position": Vector3(0, 0, 0), + "rotation": 0 + }, + { + "structure_path": "res://structures/road-straight.tres", + "position": Vector3(1, 0, 0), + "rotation": 90 + } +] +missions = [ + { + "id": "custom_mission_1", + "title": "Road Network", + "description": "Build a basic road network for your city", + "objectives": [ + { + "type": 1, + "target_count": 4, + "structure_path": "res://structures/road-straight.tres", + "description": "Build 4 straight roads" + } + ], + "rewards": { + "cash": 200, + "experience": 25 + }, + "unlocked_items": [ + "res://structures/road-corner.tres" + ] + }, + { + "id": "custom_mission_2", + "title": "First Houses", + "description": "Start building houses along your roads", + "objectives": [ + { + "type": 1, + "target_count": 2, + "structure_path": "res://structures/building-small-a.tres", + "description": "Build 2 Type A houses" + } + ], + "rewards": { + "cash": 300, + "experience": 50 + }, + "unlocked_items": [ + "res://structures/building-small-b.tres", + "res://structures/building-small-c.tres" + ] + } +] \ No newline at end of file diff --git a/fonts/lilita_one_regular.ttf.import b/fonts/lilita_one_regular.ttf.import index c0d7278..2cf3216 100644 --- a/fonts/lilita_one_regular.ttf.import +++ b/fonts/lilita_one_regular.ttf.import @@ -23,7 +23,6 @@ allow_system_fallback=true force_autohinter=false hinting=1 subpixel_positioning=1 -keep_rounding_remainders=true oversampling=0.0 Fallbacks=null fallbacks=[] diff --git a/mission/unit_1.02/census_planning_1.tres b/mission/unit_1.02/census_planning_1.tres index 9a6e4ab..d733a88 100644 --- a/mission/unit_1.02/census_planning_1.tres +++ b/mission/unit_1.02/census_planning_1.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://x5h4xutbldq3"] [ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="1_nv6c6"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_yfbrc"] +[ext_resource type="Script" uid="uid://be2nkvjhpebhi" path="res://scripts/mission/mission_objective.gd" id="1_yfbrc"] [ext_resource type="Resource" uid="uid://dv14kkhb6umkv" path="res://structures/road-straight.tres" id="2_d0ffl"] [sub_resource type="Resource" id="Resource_ywws1"] diff --git a/mission/unit_1.02/census_planning_2.tres b/mission/unit_1.02/census_planning_2.tres index e6a81e8..0b34ca8 100644 --- a/mission/unit_1.02/census_planning_2.tres +++ b/mission/unit_1.02/census_planning_2.tres @@ -1,12 +1,12 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://cjr36hqnmyn0x"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_dhx01"] +[ext_resource type="Script" uid="uid://be2nkvjhpebhi" path="res://scripts/mission/mission_objective.gd" id="1_dhx01"] [ext_resource type="Resource" uid="uid://cntgl86ianngh" path="res://structures/building-small-a.tres" id="2_em5vq"] [ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="2_mum3p"] [sub_resource type="Resource" id="Resource_7c02e"] script = ExtResource("1_dhx01") -type = 0 +type = 1 target_count = 3 current_count = 0 description = "Build 3 residential buildings" diff --git a/mission/unit_1.02/census_planning_3.tres b/mission/unit_1.02/census_planning_3.tres index b1eaa08..4c3169a 100644 --- a/mission/unit_1.02/census_planning_3.tres +++ b/mission/unit_1.02/census_planning_3.tres @@ -1,14 +1,14 @@ -[gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://dykbopx8n3c3v"] +[gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://cjr36hqnmyn0x"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_l3spi"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="2_b4llw"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_dhx01"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="2_b4llw"] [sub_resource type="Resource" id="Resource_c06be"] -script = ExtResource("1_l3spi") -type = 3 -target_count = 50 +script = ExtResource("1_dhx01") +type = 4 +target_count = 1 current_count = 0 -description = "Reach a population of 50 citizens" +description = "Study the construction company data and determine which company is more efficient" completed = false [resource] @@ -16,7 +16,7 @@ script = ExtResource("2_b4llw") id = "3" title = "Census Planning" description = "As your city grows, you need to interpret your two-way frequency tables. Increase your population to see relative frequencies and possible associations between resident demographics and infrastructure usage." -objectives = Array[ExtResource("1_l3spi")]([SubResource("Resource_c06be")]) +objectives = Array[ExtResource("1_dhx01")]([SubResource("Resource_c06be")]) rewards = { "cash": 500 } diff --git a/mission/unit_1.02/construction_efficiency.tres b/mission/unit_1.02/construction_efficiency.tres new file mode 100644 index 0000000..8df6537 --- /dev/null +++ b/mission/unit_1.02/construction_efficiency.tres @@ -0,0 +1,85 @@ +[gd_resource type="Resource" script_class="MissionData" load_steps=9 format=3 uid="uid://bh148683scgge"] + +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_objective"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="2_mission"] +[ext_resource type="Resource" uid="uid://dykbopx8n3c3v" path="res://resources/patterns/road_square.tres" id="3_pattern"] +[ext_resource type="Resource" uid="uid://cntgl86ianngh" path="res://structures/building-small-a.tres" id="4_building_a"] +[ext_resource type="Resource" uid="uid://bh65eqgid4kxy" path="res://structures/building-small-c.tres" id="5_building_c"] + +[sub_resource type="Resource" id="Resource_objective1"] +script = ExtResource("1_objective") +type = 3 +target_count = 1 +current_count = 0 +description = "Build a 2x2 road square using corner and straight roads" +completed = false +pattern_rules = ExtResource("3_pattern") + +[sub_resource type="Resource" id="Resource_objective2"] +script = ExtResource("1_objective") +type = 0 +target_count = 2 +current_count = 0 +description = "Build 2 Type A houses inside the road square" +completed = false +structure = ExtResource("4_building_a") + +[sub_resource type="Resource" id="Resource_objective3"] +script = ExtResource("1_objective") +type = 0 +target_count = 2 +current_count = 0 +description = "Build 2 Type C houses outside the road square" +completed = false +structure = ExtResource("5_building_c") + +[resource] +script = ExtResource("2_mission") +id = "road_square_neighborhood" +title = "Square Neighborhood" +description = "Create a well-organized neighborhood by building a square road pattern and placing different types of houses strategically. Complete this mission to unlock all building types!" +objectives = Array[ExtResource("1_objective")]([SubResource("Resource_objective1"), SubResource("Resource_objective2"), SubResource("Resource_objective3")]) +rewards = { +"cash": 500, +"experience": 100 +} +next_mission_id = "" +graph_path = "" +full_screen_path = "" +intro_text = "Let's create an organized neighborhood! First, we'll build a square road pattern using corner and straight roads. Then, we'll place Type A houses inside the square and Type C houses outside to create a diverse residential area. Complete this mission to unlock all building types!" +question_text = "" +correct_answer = "" +feedback_text = "" +incorrect_feedback = "" +company_data = "" +power_math_content = "" +num_of_user_inputs = 1 +input_labels = Array[String]([]) +companion_dialog = { +"mission_completed": { +"animation": "excited", +"duration": 6000, +"text": "Excellent work! You've created a well-organized neighborhood with a good mix of house types. You've unlocked all building types!" +}, +"mission_started": { +"animation": "excited", +"duration": 6000, +"text": ["Time to build a well-organized neighborhood!", "Let's start by creating a square road pattern."] +}, +"objective_completed_1": { +"animation": "happy", +"duration": 5000, +"text": ["Perfect square! The roads are perfectly aligned.", "Now we can start placing houses inside."] +}, +"objective_completed_2": { +"animation": "happy", +"duration": 5000, +"text": ["The Type A houses fit perfectly inside the road square!", "Now let's add some Type C houses outside."] +}, +"objective_completed_3": { +"animation": "happy", +"duration": 5000, +"text": ["Great placement of the Type C houses outside the square!", "This creates a nice variety in our neighborhood."] +} +} +unlocked_items = Array[String](["res://structures/building-small-a.tres", "res://structures/building-small-b.tres", "res://structures/building-small-c.tres", "res://structures/building-garage.tres"]) diff --git a/mission/unit_1.02/market_research_1.tres b/mission/unit_1.02/market_research_1.tres index b30ae1c..15b890e 100644 --- a/mission/unit_1.02/market_research_1.tres +++ b/mission/unit_1.02/market_research_1.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://442cwthak2pa"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_tcpuf"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_tcpuf"] [ext_resource type="Resource" uid="uid://dtal0tl2ee336" path="res://structures/store.tres" id="2_d7dn8"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_viy3t"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_viy3t"] [sub_resource type="Resource" id="Resource_1rxby"] script = ExtResource("1_tcpuf") diff --git a/mission/unit_1.02/market_research_2.tres b/mission/unit_1.02/market_research_2.tres index 718d688..bd7cc2a 100644 --- a/mission/unit_1.02/market_research_2.tres +++ b/mission/unit_1.02/market_research_2.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://bom5bu47dy5kp"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_pfd6v"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_pfd6v"] [ext_resource type="Resource" uid="uid://dv14kkhb6umkv" path="res://structures/road-straight.tres" id="2_ktjdq"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_w1cq1"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_w1cq1"] [sub_resource type="Resource" id="Resource_a42kn"] script = ExtResource("1_pfd6v") diff --git a/mission/unit_1.02/market_research_3.tres b/mission/unit_1.02/market_research_3.tres index 67d5c55..2a19103 100644 --- a/mission/unit_1.02/market_research_3.tres +++ b/mission/unit_1.02/market_research_3.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://csrqvfwp63ygr"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_a8iy6"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="2_5q4dp"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_a8iy6"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="2_5q4dp"] [sub_resource type="Resource" id="Resource_m1jev"] script = ExtResource("1_a8iy6") diff --git a/mission/unit_1.02/market_research_4.tres b/mission/unit_1.02/market_research_4.tres index b393a4a..6d04cfc 100644 --- a/mission/unit_1.02/market_research_4.tres +++ b/mission/unit_1.02/market_research_4.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://qwiwim2pg88f"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_lsd8i"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_lsd8i"] [ext_resource type="Resource" uid="uid://mxrnqinnsqnt" path="res://structures/road-straight-lightposts.tres" id="2_v2q1j"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_gtu3s"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_gtu3s"] [sub_resource type="Resource" id="Resource_mhw3l"] script = ExtResource("1_lsd8i") diff --git a/mission/unit_1.02/unlock_buildings.tres b/mission/unit_1.02/unlock_buildings.tres new file mode 100644 index 0000000..c858e24 --- /dev/null +++ b/mission/unit_1.02/unlock_buildings.tres @@ -0,0 +1,56 @@ +[gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://cua0khnbyusip"] + +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_objective"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="2_mission"] +[ext_resource type="Resource" uid="uid://cntgl86ianngh" path="res://structures/building-small-a.tres" id="3_building_a"] + +[sub_resource type="Resource" id="Resource_objective1"] +script = ExtResource("1_objective") +type = 1 +target_count = 3 +current_count = 0 +description = "Build 3 Type A houses to unlock all building types" +completed = false +structure = ExtResource("3_building_a") + +[resource] +script = ExtResource("2_mission") +id = "unlock_buildings" +title = "Building Variety" +description = "Demonstrate your basic building skills to unlock access to all residential building types!" +objectives = Array[ExtResource("1_objective")]([SubResource("Resource_objective1")]) +rewards = { +"cash": 300, +"experience": 50 +} +next_mission_id = "construction_efficiency" +graph_path = "" +full_screen_path = "" +intro_text = "The city council is impressed with your development plans! Show them you can handle basic construction by building a few houses, and they'll grant you access to build all residential building types." +question_text = "" +correct_answer = "" +feedback_text = "" +incorrect_feedback = "" +company_data = "" +power_math_content = "" +num_of_user_inputs = 0 +input_labels = Array[String]([]) +companion_dialog = { +"mission_completed": { +"animation": "excited", +"duration": 6000, +"text": "Great job! You now have access to all residential building types!" +}, +"mission_started": { +"animation": "excited", +"duration": 6000, +"text": ["Let's start building some houses!", "Show the city council what you can do!"] +}, +"objective_completed_1": { +"animation": "happy", +"duration": 5000, +"text": ["Nice work with those houses!", "The city council is impressed with your building skills!"] +} +} +unlocked_items = Array[String](["res://structures/building-small-a.tres", "res://structures/building-small-b.tres", "res://structures/building-small-c.tres", "res://structures/building-garage.tres", "res://structures/road-straight.tres"]) +starting_structures = Array[String](["res://structures/building-small-a.tres", "res://structures/building-small-b.tres"]) diff --git a/mission/unit_1.03_1.05/grid_growth_1.tres b/mission/unit_1.03_1.05/grid_growth_1.tres index 2f8d7c1..147ba7f 100644 --- a/mission/unit_1.03_1.05/grid_growth_1.tres +++ b/mission/unit_1.03_1.05/grid_growth_1.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://cfgw8dblm55c5"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_fvshb"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_fvshb"] [ext_resource type="Resource" uid="uid://dv14kkhb6umkv" path="res://structures/road-straight.tres" id="2_evy85"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_mtrpd"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_mtrpd"] [sub_resource type="Resource" id="Resource_pj2vg"] script = ExtResource("1_fvshb") diff --git a/mission/unit_1.03_1.05/grid_growth_2.tres b/mission/unit_1.03_1.05/grid_growth_2.tres index f095a64..38aa9c0 100644 --- a/mission/unit_1.03_1.05/grid_growth_2.tres +++ b/mission/unit_1.03_1.05/grid_growth_2.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://ba3ndftq7dht7"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_miqck"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_miqck"] [ext_resource type="Resource" uid="uid://cntgl86ianngh" path="res://structures/building-small-a.tres" id="2_r3vpw"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_mdu3m"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_mdu3m"] [sub_resource type="Resource" id="Resource_utswr"] script = ExtResource("1_miqck") diff --git a/mission/unit_1.03_1.05/grid_growth_3.tres b/mission/unit_1.03_1.05/grid_growth_3.tres index 02482d2..f437fea 100644 --- a/mission/unit_1.03_1.05/grid_growth_3.tres +++ b/mission/unit_1.03_1.05/grid_growth_3.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://dgimr2v12rjqu"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_8rvyb"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_8rvyb"] [ext_resource type="Resource" uid="uid://c4qbn3d85prxx" path="res://structures/power-plant.tres" id="2_0kbkj"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_8cjg3"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_8cjg3"] [sub_resource type="Resource" id="Resource_fmshv"] script = ExtResource("1_8rvyb") diff --git a/mission/unit_1.03_1.05/grid_growth_4.tres b/mission/unit_1.03_1.05/grid_growth_4.tres index cd65f54..923cfbb 100644 --- a/mission/unit_1.03_1.05/grid_growth_4.tres +++ b/mission/unit_1.03_1.05/grid_growth_4.tres @@ -1,9 +1,9 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=7 format=3 uid="uid://dm2o4dq2oml53"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_x4c68"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_x4c68"] [ext_resource type="Resource" uid="uid://tm532uesguhk" path="res://structures/grass.tres" id="2_ckbw6"] [ext_resource type="Resource" uid="uid://y6jafhfnhbrp" path="res://structures/grass-trees-tall.tres" id="3_i0070"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_mjpfs"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_mjpfs"] [sub_resource type="Resource" id="Resource_mldwf"] script = ExtResource("1_x4c68") diff --git a/mission/unit_1.03_1.05/traffic_flow_1.tres b/mission/unit_1.03_1.05/traffic_flow_1.tres index 81c128f..39117ac 100644 --- a/mission/unit_1.03_1.05/traffic_flow_1.tres +++ b/mission/unit_1.03_1.05/traffic_flow_1.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://btwrfq37q8vey"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_ajvs5"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_ajvs5"] [ext_resource type="Resource" uid="uid://d2jplegnkl6u2" path="res://structures/road-corner.tres" id="2_exdai"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_kexcf"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_kexcf"] [sub_resource type="Resource" id="Resource_qykcx"] script = ExtResource("1_ajvs5") diff --git a/mission/unit_1.03_1.05/traffic_flow_2.tres b/mission/unit_1.03_1.05/traffic_flow_2.tres index f96efde..c8f9860 100644 --- a/mission/unit_1.03_1.05/traffic_flow_2.tres +++ b/mission/unit_1.03_1.05/traffic_flow_2.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://cf7gpb4j7gq1g"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_8k2sf"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_8k2sf"] [ext_resource type="Resource" uid="uid://cntgl86ianngh" path="res://structures/building-small-a.tres" id="2_4a8uo"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_aihyv"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_aihyv"] [sub_resource type="Resource" id="Resource_fmsjh"] script = ExtResource("1_8k2sf") diff --git a/mission/unit_1.03_1.05/traffic_flow_3.tres b/mission/unit_1.03_1.05/traffic_flow_3.tres index 6a613fa..5f423bf 100644 --- a/mission/unit_1.03_1.05/traffic_flow_3.tres +++ b/mission/unit_1.03_1.05/traffic_flow_3.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://ddmxjjyxgxyxo"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_1hl01"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_1hl01"] [ext_resource type="Resource" uid="uid://dv14kkhb6umkv" path="res://structures/road-straight.tres" id="2_i3hgc"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_6fq1p"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_6fq1p"] [sub_resource type="Resource" id="Resource_h6f0e"] script = ExtResource("1_1hl01") diff --git a/mission/unit_1.03_1.05/traffic_flow_4.tres b/mission/unit_1.03_1.05/traffic_flow_4.tres index 653646d..d337013 100644 --- a/mission/unit_1.03_1.05/traffic_flow_4.tres +++ b/mission/unit_1.03_1.05/traffic_flow_4.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://doxd30r8qbgdq"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_kdkdo"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_kdkdo"] [ext_resource type="Resource" uid="uid://mxrnqinnsqnt" path="res://structures/road-straight-lightposts.tres" id="2_0dtbf"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_uodr7"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_uodr7"] [sub_resource type="Resource" id="Resource_uq2hw"] script = ExtResource("1_kdkdo") diff --git a/mission/unit_1.06/sustainable_dev_1.tres b/mission/unit_1.06/sustainable_dev_1.tres index 1230d92..7848393 100644 --- a/mission/unit_1.06/sustainable_dev_1.tres +++ b/mission/unit_1.06/sustainable_dev_1.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://duaxn13myfx22"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_40kcw"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="2_x8j3r"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_40kcw"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="2_x8j3r"] [sub_resource type="Resource" id="Resource_qlixo"] script = ExtResource("1_40kcw") diff --git a/mission/unit_1.06/sustainable_dev_2.tres b/mission/unit_1.06/sustainable_dev_2.tres index fb95e7c..653394d 100644 --- a/mission/unit_1.06/sustainable_dev_2.tres +++ b/mission/unit_1.06/sustainable_dev_2.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://fuxb3pfbbwjm"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_75i2t"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_75i2t"] [ext_resource type="Resource" uid="uid://cntgl86ianngh" path="res://structures/building-small-a.tres" id="2_lh8y5"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="4_30pdy"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="4_30pdy"] [sub_resource type="Resource" id="Resource_qb5w1"] script = ExtResource("1_75i2t") diff --git a/mission/unit_1.06/sustainable_dev_2b.tres b/mission/unit_1.06/sustainable_dev_2b.tres index 59a3283..ce4e9b0 100644 --- a/mission/unit_1.06/sustainable_dev_2b.tres +++ b/mission/unit_1.06/sustainable_dev_2b.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://bsic030rpgh08"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_75i2t"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_75i2t"] [ext_resource type="Resource" uid="uid://dtal0tl2ee336" path="res://structures/store.tres" id="2_3t66o"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_30pdy"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_30pdy"] [sub_resource type="Resource" id="Resource_vcbou"] script = ExtResource("1_75i2t") diff --git a/mission/unit_1.06/sustainable_dev_3.tres b/mission/unit_1.06/sustainable_dev_3.tres index 5a5c87a..0c9df68 100644 --- a/mission/unit_1.06/sustainable_dev_3.tres +++ b/mission/unit_1.06/sustainable_dev_3.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://byd5jxiutxpky"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_3s3sm"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_3s3sm"] [ext_resource type="Resource" uid="uid://c4qbn3d85prxx" path="res://structures/power-plant.tres" id="2_5l1dw"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_w8jc7"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_w8jc7"] [sub_resource type="Resource" id="Resource_d7jw4"] script = ExtResource("1_3s3sm") diff --git a/mission/unit_1.06/sustainable_dev_4.tres b/mission/unit_1.06/sustainable_dev_4.tres index fefc82d..26e50c6 100644 --- a/mission/unit_1.06/sustainable_dev_4.tres +++ b/mission/unit_1.06/sustainable_dev_4.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://daug1o7kppqit"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_oa16m"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_oa16m"] [ext_resource type="Resource" uid="uid://y6jafhfnhbrp" path="res://structures/grass-trees-tall.tres" id="2_x4xh6"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_3tpnw"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_3tpnw"] [sub_resource type="Resource" id="Resource_8dxyl"] script = ExtResource("1_oa16m") diff --git a/mission/unit_1.06/urban_planning_1.tres b/mission/unit_1.06/urban_planning_1.tres index b0b7c3c..873c71a 100644 --- a/mission/unit_1.06/urban_planning_1.tres +++ b/mission/unit_1.06/urban_planning_1.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://cp7tcpktwlrkt"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_fywct"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_fywct"] [ext_resource type="Resource" uid="uid://dtal0tl2ee336" path="res://structures/store.tres" id="2_a71iq"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_38y5t"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_38y5t"] [sub_resource type="Resource" id="Resource_wq8mf"] script = ExtResource("1_fywct") diff --git a/mission/unit_1.06/urban_planning_2.tres b/mission/unit_1.06/urban_planning_2.tres index 9326d0b..f964be8 100644 --- a/mission/unit_1.06/urban_planning_2.tres +++ b/mission/unit_1.06/urban_planning_2.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://c3q1afcvwi4rk"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_0s0wv"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_0s0wv"] [ext_resource type="Resource" uid="uid://cntgl86ianngh" path="res://structures/building-small-a.tres" id="2_6f04c"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_7jlc0"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_7jlc0"] [sub_resource type="Resource" id="Resource_3fy3g"] script = ExtResource("1_0s0wv") diff --git a/mission/unit_1.06/urban_planning_3.tres b/mission/unit_1.06/urban_planning_3.tres index 2a51031..8666eb0 100644 --- a/mission/unit_1.06/urban_planning_3.tres +++ b/mission/unit_1.06/urban_planning_3.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://ct1k7n2oopwdu"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_40klq"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_40klq"] [ext_resource type="Resource" uid="uid://mxrnqinnsqnt" path="res://structures/road-straight-lightposts.tres" id="2_u46hd"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_j3mtn"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_j3mtn"] [sub_resource type="Resource" id="Resource_fai8r"] script = ExtResource("1_40klq") diff --git a/mission/unit_1.06/urban_planning_4.tres b/mission/unit_1.06/urban_planning_4.tres index e18efa5..dc7d446 100644 --- a/mission/unit_1.06/urban_planning_4.tres +++ b/mission/unit_1.06/urban_planning_4.tres @@ -1,9 +1,9 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=7 format=3 uid="uid://d1fykuxfmh2q1"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_wnlf0"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_wnlf0"] [ext_resource type="Resource" uid="uid://dqqe3iofnleup" path="res://structures/pavement-fountain.tres" id="2_bmmdj"] [ext_resource type="Resource" uid="uid://y6jafhfnhbrp" path="res://structures/grass-trees-tall.tres" id="3_fegi2"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="4_8gmvv"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="4_8gmvv"] [sub_resource type="Resource" id="Resource_1ht3m"] script = ExtResource("1_wnlf0") diff --git a/mission/unit_1.07/economic_forecast_1.tres b/mission/unit_1.07/economic_forecast_1.tres index 4dae6c9..c6bfb42 100644 --- a/mission/unit_1.07/economic_forecast_1.tres +++ b/mission/unit_1.07/economic_forecast_1.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://detwnqsq87r30"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_cjqfg"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="2_pv8r1"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_cjqfg"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="2_pv8r1"] [sub_resource type="Resource" id="Resource_e2jx7"] script = ExtResource("1_cjqfg") diff --git a/mission/unit_1.07/economic_forecast_2.tres b/mission/unit_1.07/economic_forecast_2.tres index d0c7bee..b2c374b 100644 --- a/mission/unit_1.07/economic_forecast_2.tres +++ b/mission/unit_1.07/economic_forecast_2.tres @@ -1,9 +1,9 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=7 format=3 uid="uid://bj7tjuknfaeyg"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_t87pd"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_t87pd"] [ext_resource type="Resource" uid="uid://cntgl86ianngh" path="res://structures/building-small-a.tres" id="2_ys3mw"] [ext_resource type="Resource" uid="uid://bh65eqgid4kxy" path="res://structures/building-small-c.tres" id="3_jl18p"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="4_2h1ol"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="4_2h1ol"] [sub_resource type="Resource" id="Resource_mht7j"] script = ExtResource("1_t87pd") diff --git a/mission/unit_1.07/economic_forecast_3.tres b/mission/unit_1.07/economic_forecast_3.tres index bcb5d8e..afcc471 100644 --- a/mission/unit_1.07/economic_forecast_3.tres +++ b/mission/unit_1.07/economic_forecast_3.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://ctyrlnq5cxuiu"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_r0j2r"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_r0j2r"] [ext_resource type="Resource" uid="uid://dtal0tl2ee336" path="res://structures/store.tres" id="2_oqy42"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_r78ev"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_r78ev"] [sub_resource type="Resource" id="Resource_c21kt"] script = ExtResource("1_r0j2r") diff --git a/mission/unit_1.07/resource_alloc_1.tres b/mission/unit_1.07/resource_alloc_1.tres index e757054..88f7ec4 100644 --- a/mission/unit_1.07/resource_alloc_1.tres +++ b/mission/unit_1.07/resource_alloc_1.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://bwrkqv42wk8f"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_1k37f"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_1k37f"] [ext_resource type="Resource" uid="uid://cntgl86ianngh" path="res://structures/building-small-a.tres" id="2_qlnvj"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_4udbq"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_4udbq"] [sub_resource type="Resource" id="Resource_0fxto"] script = ExtResource("1_1k37f") diff --git a/mission/unit_1.07/resource_alloc_2.tres b/mission/unit_1.07/resource_alloc_2.tres index 2ba5059..ee9ea43 100644 --- a/mission/unit_1.07/resource_alloc_2.tres +++ b/mission/unit_1.07/resource_alloc_2.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://d0nblitd4ixir"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_vdhxy"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_vdhxy"] [ext_resource type="Resource" uid="uid://dtal0tl2ee336" path="res://structures/store.tres" id="2_hh0xb"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_k5ivn"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_k5ivn"] [sub_resource type="Resource" id="Resource_21csl"] script = ExtResource("1_vdhxy") diff --git a/mission/unit_1.07/resource_alloc_3.tres b/mission/unit_1.07/resource_alloc_3.tres index 98d499b..6e7d54a 100644 --- a/mission/unit_1.07/resource_alloc_3.tres +++ b/mission/unit_1.07/resource_alloc_3.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://cxh8dgf54oimx"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_c76o5"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_c76o5"] [ext_resource type="Resource" uid="uid://dv14kkhb6umkv" path="res://structures/road-straight.tres" id="2_4rkoa"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_iqaae"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_iqaae"] [sub_resource type="Resource" id="Resource_r01e3"] script = ExtResource("1_c76o5") diff --git a/mission/unit_1.07/resource_alloc_4.tres b/mission/unit_1.07/resource_alloc_4.tres index f9863db..f02fdf7 100644 --- a/mission/unit_1.07/resource_alloc_4.tres +++ b/mission/unit_1.07/resource_alloc_4.tres @@ -1,8 +1,8 @@ [gd_resource type="Resource" script_class="MissionData" load_steps=5 format=3 uid="uid://cpfr2xnjtpcog"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="1_4b0uw"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_4b0uw"] [ext_resource type="Resource" uid="uid://ccb475jeg7ym5" path="res://structures/grass-trees.tres" id="2_y8alv"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="3_p34yh"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="3_p34yh"] [sub_resource type="Resource" id="Resource_grdmr"] script = ExtResource("1_4b0uw") diff --git a/models/building-arcology.glb.import b/models/building-arcology.glb.import index e8cbf88..c2f09d0 100644 --- a/models/building-arcology.glb.import +++ b/models/building-arcology.glb.import @@ -18,7 +18,6 @@ nodes/root_name="" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/building-garage.glb.import b/models/building-garage.glb.import index 90489b8..bc34f24 100644 --- a/models/building-garage.glb.import +++ b/models/building-garage.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/building-small-a.glb.import b/models/building-small-a.glb.import index 57a8598..45016a3 100644 --- a/models/building-small-a.glb.import +++ b/models/building-small-a.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/building-small-b.glb.import b/models/building-small-b.glb.import index 31bebe0..a7fb7d8 100644 --- a/models/building-small-b.glb.import +++ b/models/building-small-b.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/building-small-c.glb.import b/models/building-small-c.glb.import index 73068f3..2279e06 100644 --- a/models/building-small-c.glb.import +++ b/models/building-small-c.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/grass-trees-tall.glb.import b/models/grass-trees-tall.glb.import index 81ab2a8..436ec44 100644 --- a/models/grass-trees-tall.glb.import +++ b/models/grass-trees-tall.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/grass-trees.glb.import b/models/grass-trees.glb.import index 109f75c..9e87226 100644 --- a/models/grass-trees.glb.import +++ b/models/grass-trees.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/grass.glb.import b/models/grass.glb.import index d7463d4..9517802 100644 --- a/models/grass.glb.import +++ b/models/grass.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/orb.glb.import b/models/orb.glb.import index 78b9c38..543da10 100644 --- a/models/orb.glb.import +++ b/models/orb.glb.import @@ -18,7 +18,6 @@ nodes/root_name="" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/pavement-fountain.glb.import b/models/pavement-fountain.glb.import index 4244037..baff4cd 100644 --- a/models/pavement-fountain.glb.import +++ b/models/pavement-fountain.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/pavement.glb.import b/models/pavement.glb.import index 85f9eed..2a906e7 100644 --- a/models/pavement.glb.import +++ b/models/pavement.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/power_plant.glb.import b/models/power_plant.glb.import index 09c9374..9057ff1 100644 --- a/models/power_plant.glb.import +++ b/models/power_plant.glb.import @@ -18,7 +18,6 @@ nodes/root_name="" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/road-corner.glb.import b/models/road-corner.glb.import index 4ca15d3..2749d65 100644 --- a/models/road-corner.glb.import +++ b/models/road-corner.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/road-intersection.glb.import b/models/road-intersection.glb.import index 6f60e3a..7bf6a46 100644 --- a/models/road-intersection.glb.import +++ b/models/road-intersection.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/road-split.glb.import b/models/road-split.glb.import index 5f68323..49d7cb1 100644 --- a/models/road-split.glb.import +++ b/models/road-split.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/road-straight-lightposts.glb.import b/models/road-straight-lightposts.glb.import index eb75c53..f8bbe28 100644 --- a/models/road-straight-lightposts.glb.import +++ b/models/road-straight-lightposts.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/road-straight.glb.import b/models/road-straight.glb.import index bc9e256..d11a8d2 100644 --- a/models/road-straight.glb.import +++ b/models/road-straight.glb.import @@ -18,7 +18,6 @@ nodes/root_name="" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/models/store.glb.import b/models/store.glb.import index d4078db..8420836 100644 --- a/models/store.glb.import +++ b/models/store.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/people/character-female-a.glb.import b/people/character-female-a.glb.import index 6cfbf0f..07579bb 100644 --- a/people/character-female-a.glb.import +++ b/people/character-female-a.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/people/character-female-d.glb.import b/people/character-female-d.glb.import index 51e5035..c3dc70f 100644 --- a/people/character-female-d.glb.import +++ b/people/character-female-d.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/people/character-male-a.glb.import b/people/character-male-a.glb.import index b30a2bd..d2e6620 100644 --- a/people/character-male-a.glb.import +++ b/people/character-male-a.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/people/character-male-b.glb.import b/people/character-male-b.glb.import index 8e0692d..e238e0b 100644 --- a/people/character-male-b.glb.import +++ b/people/character-male-b.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/people/character-male-c.glb.import b/people/character-male-c.glb.import index 3362357..01d0609 100644 --- a/people/character-male-c.glb.import +++ b/people/character-male-c.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/people/character-male-d.glb.import b/people/character-male-d.glb.import index d55f076..5b12b97 100644 --- a/people/character-male-d.glb.import +++ b/people/character-male-d.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/people/character-male-e.glb.import b/people/character-male-e.glb.import index 74b3747..a3e394d 100644 --- a/people/character-male-e.glb.import +++ b/people/character-male-e.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/people/character-male-f.glb.import b/people/character-male-f.glb.import index 9bdc45c..b2fe348 100644 --- a/people/character-male-f.glb.import +++ b/people/character-male-f.glb.import @@ -18,7 +18,6 @@ nodes/root_name="Scene Root" nodes/apply_root_scale=true nodes/root_scale=1.0 nodes/import_as_skeleton_bones=false -nodes/use_node_type_suffixes=true meshes/ensure_tangents=true meshes/generate_lods=true meshes/create_shadow_meshes=true diff --git a/project.godot b/project.godot index 50bb50b..2972f98 100644 --- a/project.godot +++ b/project.godot @@ -13,7 +13,7 @@ config_version=5 config/name="Starter Kit City Builder" config/tags=PackedStringArray("starterkit") run/main_scene="res://scenes/main.tscn" -config/features=PackedStringArray("4.4", "Forward Plus") +config/features=PackedStringArray("4.3", "Forward Plus") boot_splash/bg_color=Color(0.92549, 0.92549, 0.960784, 1) boot_splash/image="res://splash-screen.png" config/icon="res://icon.png" @@ -28,6 +28,7 @@ SoundManager="*res://scripts/sound_manager.gd" EventBus="*res://global/event_bus.gd" Globals="*res://global/globals.gd" WebSaveManager="*res://scripts/web_save_manager.gd" +JSBridge="*res://scripts/javascript_bridge.gd" [display] @@ -94,12 +95,12 @@ camera_rotate={ } structure_next={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null) ] } structure_previous={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":81,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":true,"keycode":0,"physical_keycode":81,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null) ] } save={ diff --git a/resources/building_selector.tres b/resources/building_selector.tres new file mode 100644 index 0000000..943ee53 --- /dev/null +++ b/resources/building_selector.tres @@ -0,0 +1,10 @@ +[gd_resource type="Resource" script_class="GenericText" load_steps=2 format=3] + +[ext_resource type="Script" path="res://resources/generic_text_panel.resource.gd" id="1_resource"] + +[resource] +script = ExtResource("1_resource") +panel_type = 0 +title = "Building Selector" +body_text = "Select structures to build in your city." +button_text = "Close" \ No newline at end of file diff --git a/resources/patterns/road_square.tres b/resources/patterns/road_square.tres new file mode 100644 index 0000000..f65bf72 --- /dev/null +++ b/resources/patterns/road_square.tres @@ -0,0 +1,39 @@ +[gd_resource type="Resource" script_class="PatternRules" load_steps=9 format=3 uid="uid://dykbopx8n3c3v"] + +[ext_resource type="Script" path="res://scripts/mission/pattern_rules.gd" id="1_rules"] +[ext_resource type="Script" path="res://scripts/mission/pattern_rule.gd" id="2_rule"] +[ext_resource type="Resource" uid="uid://d2jplegnkl6u2" path="res://structures/road-corner.tres" id="3_corner"] +[ext_resource type="Resource" uid="uid://dv14kkhb6umkv" path="res://structures/road-straight.tres" id="4_straight"] + +[sub_resource type="Resource" id="Resource_corner1"] +script = ExtResource("2_rule") +type = 0 +offset = Vector2i(0, 0) +structure = ExtResource("3_corner") +rotation = 0 + +[sub_resource type="Resource" id="Resource_straight1"] +script = ExtResource("2_rule") +type = 0 +offset = Vector2i(1, 0) +structure = ExtResource("4_straight") +rotation = 0 + +[sub_resource type="Resource" id="Resource_straight2"] +script = ExtResource("2_rule") +type = 0 +offset = Vector2i(0, 1) +structure = ExtResource("4_straight") +rotation = 90 + +[sub_resource type="Resource" id="Resource_corner2"] +script = ExtResource("2_rule") +type = 0 +offset = Vector2i(1, 1) +structure = ExtResource("3_corner") +rotation = 180 + +[resource] +script = ExtResource("1_rules") +pattern_size = Vector2i(2, 2) +rules = Array[ExtResource("2_rule")]([SubResource("Resource_corner1"), SubResource("Resource_straight1"), SubResource("Resource_straight2"), SubResource("Resource_corner2")]) diff --git a/scenes/building_selector.tscn b/scenes/building_selector.tscn index 807c296..89ab1b5 100644 --- a/scenes/building_selector.tscn +++ b/scenes/building_selector.tscn @@ -1,42 +1,7 @@ -[gd_scene load_steps=6 format=3 uid="uid://b4k3xfm8pd8qw"] - -[ext_resource type="Script" uid="uid://bsjmj0qu3xfrr" path="res://scripts/building_selector.gd" id="1_yvr4p"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_button_hover"] -bg_color = Color(0.3, 0.3, 0.3, 0.9) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(0.5, 0.5, 0.5, 1) -corner_radius_top_left = 4 -corner_radius_top_right = 4 -corner_radius_bottom_right = 4 -corner_radius_bottom_left = 4 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_button_pressed"] -bg_color = Color(0.4, 0.4, 0.4, 1) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(0.6, 0.6, 0.6, 1) -corner_radius_top_left = 4 -corner_radius_top_right = 4 -corner_radius_bottom_right = 4 -corner_radius_bottom_left = 4 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_button"] -bg_color = Color(0.2, 0.2, 0.2, 0.8) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(0.4, 0.4, 0.4, 1) -corner_radius_top_left = 4 -corner_radius_top_right = 4 -corner_radius_bottom_right = 4 -corner_radius_bottom_left = 4 +[gd_scene load_steps=4 format=3 uid="uid://b4k3xfm8pd8qw"] + +[ext_resource type="Script" path="res://scripts/building_selector.gd" id="1_jybm7"] +[ext_resource type="Resource" path="res://resources/building_selector.tres" id="2_resource"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_panel"] bg_color = Color(0.145098, 0.172549, 0.231373, 0.941176) @@ -50,184 +15,209 @@ corner_radius_top_right = 8 corner_radius_bottom_right = 8 corner_radius_bottom_left = 8 -[node name="BuildingSelector" type="Control"] -layout_mode = 3 +[node name="BuildingSelector" type="PanelContainer"] anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -mouse_filter = 1 -script = ExtResource("1_yvr4p") +size_flags_horizontal = 3 +size_flags_vertical = 3 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_panel") +script = ExtResource("1_jybm7") +resource_data = ExtResource("2_resource") + +[node name="ClickBlocker" type="ColorRect" parent="."] +visible = false +z_index = 1000 +layout_mode = 2 +mouse_filter = 2 +color = Color(0, 0, 0, 0.01) [node name="MainButton" type="Button" parent="."] -layout_mode = 0 -offset_left = 20.0 -offset_top = 20.0 -offset_right = 170.0 -offset_bottom = 60.0 -mouse_filter = 1 -theme_override_font_sizes/font_size = 16 -theme_override_styles/hover = SubResource("StyleBoxFlat_button_hover") -theme_override_styles/pressed = SubResource("StyleBoxFlat_button_pressed") -theme_override_styles/normal = SubResource("StyleBoxFlat_button") -text = "Select Building" +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +size_flags_horizontal = 8 +size_flags_vertical = 4 +mouse_filter = 2 +text = "▶" +flat = true [node name="SelectionPanel" type="Panel" parent="."] -layout_mode = 0 -offset_left = 20.0 -offset_top = 70.0 -offset_right = 380.0 -offset_bottom = 620.0 -mouse_filter = 1 +visible = false +layout_mode = 2 +mouse_filter = 2 theme_override_styles/panel = SubResource("StyleBoxFlat_panel") -[node name="SearchBar" type="LineEdit" parent="SelectionPanel"] -layout_mode = 0 -offset_left = 10.0 -offset_top = 10.0 -offset_right = 350.0 -offset_bottom = 40.0 -placeholder_text = "Search buildings..." -clear_button_enabled = true - -[node name="FilterButtons" type="HBoxContainer" parent="SelectionPanel"] -layout_mode = 0 -offset_left = 10.0 -offset_top = 50.0 -offset_right = 350.0 -offset_bottom = 90.0 +[node name="MarginContainer" type="MarginContainer" parent="SelectionPanel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="VBoxContainer" type="VBoxContainer" parent="SelectionPanel/MarginContainer"] +layout_mode = 2 +mouse_filter = 2 +theme_override_constants/separation = 10 + +[node name="HBoxContainer" type="HBoxContainer" parent="SelectionPanel/MarginContainer/VBoxContainer"] +layout_mode = 2 +mouse_filter = 2 + +[node name="TitleLabel" type="Label" parent="SelectionPanel/MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_font_sizes/font_size = 18 +text = "Building Selector" + +[node name="CloseButton" type="Button" parent="SelectionPanel/MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +mouse_filter = 2 +text = "✕" +flat = true + +[node name="SearchBar" type="LineEdit" parent="SelectionPanel/MarginContainer/VBoxContainer"] +layout_mode = 2 +mouse_filter = 2 +placeholder_text = "Search structures..." + +[node name="FilterButtons" type="HBoxContainer" parent="SelectionPanel/MarginContainer/VBoxContainer"] +layout_mode = 2 +mouse_filter = 2 theme_override_constants/separation = 5 -[node name="AllButton" type="Button" parent="SelectionPanel/FilterButtons"] +[node name="AllButton" type="Button" parent="SelectionPanel/MarginContainer/VBoxContainer/FilterButtons"] layout_mode = 2 size_flags_horizontal = 3 -theme_override_styles/hover = SubResource("StyleBoxFlat_button_hover") -theme_override_styles/pressed = SubResource("StyleBoxFlat_button_pressed") -theme_override_styles/normal = SubResource("StyleBoxFlat_button") +mouse_filter = 2 toggle_mode = true button_pressed = true text = "All" +flat = true -[node name="ResidentialButton" type="Button" parent="SelectionPanel/FilterButtons"] +[node name="GroundButton" type="Button" parent="SelectionPanel/MarginContainer/VBoxContainer/FilterButtons"] layout_mode = 2 size_flags_horizontal = 3 -theme_override_styles/hover = SubResource("StyleBoxFlat_button_hover") -theme_override_styles/pressed = SubResource("StyleBoxFlat_button_pressed") -theme_override_styles/normal = SubResource("StyleBoxFlat_button") +mouse_filter = 2 toggle_mode = true -text = "Residential" +text = "Ground" +flat = true -[node name="CommercialButton" type="Button" parent="SelectionPanel/FilterButtons"] +[node name="BuildingButton" type="Button" parent="SelectionPanel/MarginContainer/VBoxContainer/FilterButtons"] layout_mode = 2 size_flags_horizontal = 3 -theme_override_styles/hover = SubResource("StyleBoxFlat_button_hover") -theme_override_styles/pressed = SubResource("StyleBoxFlat_button_pressed") -theme_override_styles/normal = SubResource("StyleBoxFlat_button") +mouse_filter = 2 toggle_mode = true -text = "Commercial" +text = "Buildings" +flat = true -[node name="IndustrialButton" type="Button" parent="SelectionPanel/FilterButtons"] +[node name="ScrollContainer" type="ScrollContainer" parent="SelectionPanel/MarginContainer/VBoxContainer"] layout_mode = 2 -size_flags_horizontal = 3 -theme_override_styles/hover = SubResource("StyleBoxFlat_button_hover") -theme_override_styles/pressed = SubResource("StyleBoxFlat_button_pressed") -theme_override_styles/normal = SubResource("StyleBoxFlat_button") -toggle_mode = true -text = "Industrial" - -[node name="ScrollContainer" type="ScrollContainer" parent="SelectionPanel"] -layout_mode = 0 -offset_left = 10.0 -offset_top = 100.0 -offset_right = 350.0 -offset_bottom = 510.0 -horizontal_scroll_mode = 0 +size_flags_vertical = 3 +mouse_filter = 2 -[node name="VBoxContainer" type="VBoxContainer" parent="SelectionPanel/ScrollContainer"] +[node name="VBoxContainer" type="VBoxContainer" parent="SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer"] layout_mode = 2 -size_flags_horizontal = 3 size_flags_vertical = 3 -theme_override_constants/separation = 20 +mouse_filter = 2 -[node name="GroundSection" type="VBoxContainer" parent="SelectionPanel/ScrollContainer/VBoxContainer"] +[node name="GroundSection" type="VBoxContainer" parent="SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer"] layout_mode = 2 -theme_override_constants/separation = 10 +mouse_filter = 2 -[node name="Label" type="Label" parent="SelectionPanel/ScrollContainer/VBoxContainer/GroundSection"] +[node name="Label" type="Label" parent="SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/GroundSection"] layout_mode = 2 -theme_override_font_sizes/font_size = 18 -text = "Ground Types" -horizontal_alignment = 1 +theme_override_font_sizes/font_size = 16 +text = "Ground Structures" -[node name="GroundOptions" type="GridContainer" parent="SelectionPanel/ScrollContainer/VBoxContainer/GroundSection"] +[node name="GroundOptions" type="GridContainer" parent="SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/GroundSection"] layout_mode = 2 +mouse_filter = 2 theme_override_constants/h_separation = 10 theme_override_constants/v_separation = 10 -columns = 2 +columns = 4 -[node name="BuildingSection" type="VBoxContainer" parent="SelectionPanel/ScrollContainer/VBoxContainer"] +[node name="BuildingSection" type="VBoxContainer" parent="SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer"] layout_mode = 2 -theme_override_constants/separation = 10 +mouse_filter = 2 -[node name="Label" type="Label" parent="SelectionPanel/ScrollContainer/VBoxContainer/BuildingSection"] +[node name="Label" type="Label" parent="SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/BuildingSection"] layout_mode = 2 -theme_override_font_sizes/font_size = 18 -text = "Buildings" -horizontal_alignment = 1 +theme_override_font_sizes/font_size = 16 +text = "Building Structures" -[node name="BuildingOptions" type="GridContainer" parent="SelectionPanel/ScrollContainer/VBoxContainer/BuildingSection"] +[node name="BuildingOptions" type="GridContainer" parent="SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/BuildingSection"] layout_mode = 2 +mouse_filter = 2 theme_override_constants/h_separation = 10 theme_override_constants/v_separation = 10 -columns = 2 - -[node name="DescriptionPanel" type="Panel" parent="SelectionPanel"] -layout_mode = 0 -offset_left = 10.0 -offset_top = 520.0 -offset_right = 350.0 -offset_bottom = 610.0 +columns = 4 + +[node name="DescriptionPanel" type="Panel" parent="SelectionPanel/MarginContainer/VBoxContainer"] +layout_mode = 2 +mouse_filter = 2 theme_override_styles/panel = SubResource("StyleBoxFlat_panel") -[node name="VBoxContainer" type="VBoxContainer" parent="SelectionPanel/DescriptionPanel"] +[node name="MarginContainer" type="MarginContainer" parent="SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel"] layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 +mouse_filter = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="VBoxContainer" type="VBoxContainer" parent="SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer"] +layout_mode = 2 +mouse_filter = 2 theme_override_constants/separation = 10 -[node name="TitleLabel" type="Label" parent="SelectionPanel/DescriptionPanel/VBoxContainer"] +[node name="TitleLabel" type="Label" parent="SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer"] layout_mode = 2 -theme_override_font_sizes/font_size = 20 -text = "No Building Selected" -horizontal_alignment = 1 +theme_override_font_sizes/font_size = 18 +text = "Structure Name" -[node name="DescriptionLabel" type="Label" parent="SelectionPanel/DescriptionPanel/VBoxContainer"] +[node name="DescriptionLabel" type="Label" parent="SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer"] layout_mode = 2 -size_flags_vertical = 3 theme_override_font_sizes/font_size = 14 -text = "Select a building to view its details" -horizontal_alignment = 1 -vertical_alignment = 1 +text = "Structure description goes here..." +autowrap_mode = 2 -[node name="StatsContainer" type="HBoxContainer" parent="SelectionPanel/DescriptionPanel/VBoxContainer"] +[node name="StatsContainer" type="HBoxContainer" parent="SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer"] layout_mode = 2 +mouse_filter = 2 theme_override_constants/separation = 20 -[node name="PriceLabel" type="Label" parent="SelectionPanel/DescriptionPanel/VBoxContainer/StatsContainer"] +[node name="PriceLabel" type="Label" parent="SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer/StatsContainer"] layout_mode = 2 theme_override_font_sizes/font_size = 14 text = "Price: $0" -[node name="PopulationLabel" type="Label" parent="SelectionPanel/DescriptionPanel/VBoxContainer/StatsContainer"] +[node name="PopulationLabel" type="Label" parent="SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer/StatsContainer"] layout_mode = 2 theme_override_font_sizes/font_size = 14 text = "Population: 0" -[node name="PowerLabel" type="Label" parent="SelectionPanel/DescriptionPanel/VBoxContainer/StatsContainer"] +[node name="PowerLabel" type="Label" parent="SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer/StatsContainer"] layout_mode = 2 theme_override_font_sizes/font_size = 14 -text = "Power: 0 kW" +text = "Power: 0" + +[connection signal="pressed" from="MainButton" to="." method="_on_main_button_pressed"] +[connection signal="pressed" from="SelectionPanel/MarginContainer/VBoxContainer/HBoxContainer/CloseButton" to="." method="hide_panel"] +[connection signal="text_changed" from="SelectionPanel/MarginContainer/VBoxContainer/SearchBar" to="." method="_on_search_text_changed"] +[connection signal="pressed" from="SelectionPanel/MarginContainer/VBoxContainer/FilterButtons/AllButton" to="." method="_on_filter_button_pressed" binds= ["All"]] +[connection signal="pressed" from="SelectionPanel/MarginContainer/VBoxContainer/FilterButtons/GroundButton" to="." method="_on_filter_button_pressed" binds= ["Ground"]] +[connection signal="pressed" from="SelectionPanel/MarginContainer/VBoxContainer/FilterButtons/BuildingButton" to="." method="_on_filter_button_pressed" binds= ["Buildings"]] diff --git a/scenes/character.tscn b/scenes/character.tscn index 88c248a..aaebce1 100644 --- a/scenes/character.tscn +++ b/scenes/character.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=8 format=3 uid="uid://b4gkfwf4i3ydl"] -[ext_resource type="Script" uid="uid://dexknr7it5val" path="res://scripts/mission/character_controller.gd" id="1_g3a7y"] +[ext_resource type="Script" path="res://scripts/mission/character_controller.gd" id="1_g3a7y"] [ext_resource type="PackedScene" uid="uid://h2jjkvc4edsp" path="res://people/character-female-d.glb" id="2_d5jmi"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_b4w3n"] @@ -58,9 +58,9 @@ tracks/0/keys = { [sub_resource type="AnimationLibrary" id="AnimationLibrary_8ib1s"] _data = { -&"RESET": SubResource("Animation_reset"), -&"idle": SubResource("Animation_idle"), -&"walk": SubResource("Animation_walk") +"RESET": SubResource("Animation_reset"), +"idle": SubResource("Animation_idle"), +"walk": SubResource("Animation_walk") } [node name="Character" type="CharacterBody3D"] @@ -80,7 +80,7 @@ transform = Transform3D(0.6, 0, 0, 0, 0.6, 0, 0, 0, 0.6, 0, 0, 0) [node name="AnimationPlayer" type="AnimationPlayer" parent="."] libraries = { -&"": SubResource("AnimationLibrary_8ib1s") +"": SubResource("AnimationLibrary_8ib1s") } autoplay = "walk" speed_scale = 3.0 diff --git a/scenes/controls_panel.tscn b/scenes/controls_panel.tscn index 42d5b33..a303f5d 100644 --- a/scenes/controls_panel.tscn +++ b/scenes/controls_panel.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=4 format=3 uid="uid://bqjnp7uypupog"] [ext_resource type="FontFile" uid="uid://d0cxd77jybrcn" path="res://fonts/lilita_one_regular.ttf" id="1_tnlhn"] -[ext_resource type="Script" uid="uid://drdr16kowbvmd" path="res://scripts/controls_panel.gd" id="1_xyuqg"] +[ext_resource type="Script" path="res://scripts/controls_panel.gd" id="1_xyuqg"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_f2mso"] bg_color = Color(0.145098, 0.172549, 0.231373, 0.941176) diff --git a/scenes/main-environment.tres b/scenes/main-environment.tres index 9794e52..285c0c4 100644 --- a/scenes/main-environment.tres +++ b/scenes/main-environment.tres @@ -18,10 +18,10 @@ ambient_light_color = Color(0.662745, 0.694118, 0.772549, 1) ambient_light_energy = 0.75 tonemap_mode = 2 ssao_enabled = true -ssao_radius = 0.25 -ssao_intensity = 0.5 -ssao_power = 100.0 -ssao_horizon = 0.1 +ssao_detail = 1.0 +ssao_horizon = 0.25 +ssao_light_affect = 0.5 +ssao_ao_channel_affect = 0.75 sdfgi_cascades = 1 sdfgi_max_distance = 25.6 sdfgi_energy = 0.5 diff --git a/scenes/main.tscn b/scenes/main.tscn index 0c96e5a..7fb1b2a 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -1,47 +1,48 @@ -[gd_scene load_steps=72 format=3 uid="uid://b6eb1v02n61vv"] +[gd_scene load_steps=73 format=3 uid="uid://b6eb1v02n61vv"] -[ext_resource type="Script" uid="uid://c37h6na3e4twn" path="res://scripts/builder.gd" id="1_jybm7"] +[ext_resource type="Script" path="res://scripts/builder.gd" id="1_jybm7"] [ext_resource type="Environment" uid="uid://jbptgqvstei3" path="res://scenes/main-environment.tres" id="1_yndf3"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="2_54v6r"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="2_54v6r"] [ext_resource type="Resource" uid="uid://dv14kkhb6umkv" path="res://structures/road-straight.tres" id="2_bwyku"] [ext_resource type="Texture2D" uid="uid://cbk07cxgshg26" path="res://sprites/selector.png" id="4_wr1wv"] [ext_resource type="Resource" uid="uid://cntgl86ianngh" path="res://structures/building-small-a.tres" id="5_v5o2m"] [ext_resource type="Resource" uid="uid://ccb475jeg7ym5" path="res://structures/grass-trees.tres" id="6_fwsy4"] [ext_resource type="Resource" uid="uid://y6jafhfnhbrp" path="res://structures/grass-trees-tall.tres" id="7_t5ykj"] -[ext_resource type="Script" uid="uid://d3n8yylhejdoh" path="res://scripts/view.gd" id="8_yovpv"] +[ext_resource type="Script" path="res://scripts/view.gd" id="8_yovpv"] [ext_resource type="Resource" uid="uid://tm532uesguhk" path="res://structures/grass.tres" id="9_e755i"] -[ext_resource type="Script" uid="uid://otnxt4e77gmc" path="res://scripts/mission/mission_manager.gd" id="10_oe3re"] +[ext_resource type="Script" path="res://scripts/mission/mission_manager.gd" id="10_oe3re"] [ext_resource type="Resource" uid="uid://mxrnqinnsqnt" path="res://structures/road-straight-lightposts.tres" id="11_20frt"] [ext_resource type="Resource" uid="uid://ch8vtcpine1lc" path="res://structures/pavement.tres" id="11_ro3en"] [ext_resource type="Resource" uid="uid://c4qbn3d85prxx" path="res://structures/power-plant.tres" id="12_xtc7p"] [ext_resource type="PackedScene" uid="uid://dmsy06s02tcw4" path="res://scenes/generic_text_panel.tscn" id="13_7i6dj"] [ext_resource type="Resource" uid="uid://bh65eqgid4kxy" path="res://structures/building-small-c.tres" id="13_kf5aa"] -[ext_resource type="Script" uid="uid://ctqqmg4ydlbse" path="res://scripts/mission/mission_ui.gd" id="13_xvw5w"] -[ext_resource type="Script" uid="uid://n26k1k7243dd" path="res://resources/generic_text_panel.resource.gd" id="14_76jlq"] -[ext_resource type="Script" uid="uid://52tdmmosdbpa" path="res://scripts/mission/learning_panel.gd" id="14_q2ymb"] +[ext_resource type="Script" path="res://scripts/mission/mission_ui.gd" id="13_xvw5w"] +[ext_resource type="Script" path="res://resources/generic_text_panel.resource.gd" id="14_76jlq"] +[ext_resource type="Script" path="res://scripts/mission/learning_panel.gd" id="14_q2ymb"] [ext_resource type="Resource" uid="uid://dqqe3iofnleup" path="res://structures/pavement-fountain.tres" id="14_t5ykj"] -[ext_resource type="Script" uid="uid://cjaik5ku37xqx" path="res://scripts/mission/mission_data.gd" id="14_vcrh8"] +[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="14_vcrh8"] [ext_resource type="Resource" uid="uid://dveu4dnue0d54" path="res://structures/road-intersection.tres" id="15_e755i"] -[ext_resource type="Resource" uid="uid://x5h4xutbldq3" path="res://mission/unit_1.02/census_planning_1.tres" id="15_obmwc"] -[ext_resource type="Resource" uid="uid://cjr36hqnmyn0x" path="res://mission/unit_1.02/census_planning_2.tres" id="16_rl54y"] -[ext_resource type="Resource" uid="uid://dykbopx8n3c3v" path="res://mission/unit_1.02/census_planning_3.tres" id="17_rrdy6"] +[ext_resource type="Resource" uid="uid://cjr36hqnmyn0x" path="res://mission/unit_1.02/census_planning_3.tres" id="17_rrdy6"] [ext_resource type="FontFile" uid="uid://d0cxd77jybrcn" path="res://fonts/lilita_one_regular.ttf" id="17_vlub6"] [ext_resource type="PackedScene" uid="uid://b4gkfwf4i3ydl" path="res://scenes/character.tscn" id="18_8lrh8"] [ext_resource type="PackedScene" uid="uid://cgk66f6rg03mj" path="res://scenes/hud.tscn" id="18_hud"] [ext_resource type="PackedScene" uid="uid://bqjnp7uypupog" path="res://scenes/controls_panel.tscn" id="19_controls"] -[ext_resource type="Script" uid="uid://b5nubrdeseay4" path="res://scripts/game_manager.gd" id="20_game_manager"] +[ext_resource type="Script" path="res://scripts/game_manager.gd" id="20_game_manager"] [ext_resource type="Resource" uid="uid://442cwthak2pa" path="res://mission/unit_1.02/market_research_1.tres" id="20_ngu16"] [ext_resource type="PackedScene" uid="uid://b4s46k58ddpyc" path="res://scenes/sound_panel.tscn" id="21_sound_panel"] [ext_resource type="Resource" uid="uid://dtal0tl2ee336" path="res://structures/store.tres" id="21_y11qv"] [ext_resource type="PackedScene" uid="uid://btfwonjc8uj0w" path="res://scenes/mission_select_menu.tscn" id="24_ro3en"] [ext_resource type="Resource" uid="uid://bom5bu47dy5kp" path="res://mission/unit_1.02/market_research_2.tres" id="24_xud6a"] [ext_resource type="Resource" uid="uid://csrqvfwp63ygr" path="res://mission/unit_1.02/market_research_3.tres" id="25_6hx7u"] +[ext_resource type="PackedScene" uid="uid://b4k3xfm8pd8qw" path="res://scenes/building_selector.tscn" id="25_od4ux"] [ext_resource type="Resource" uid="uid://qwiwim2pg88f" path="res://mission/unit_1.02/market_research_4.tres" id="26_lvk23"] [ext_resource type="PackedScene" uid="uid://cb2rylpbex3ep" path="res://models/building-arcology.glb" id="27_m8wco"] [ext_resource type="Resource" uid="uid://cfgw8dblm55c5" path="res://mission/unit_1.03_1.05/grid_growth_1.tres" id="27_s0e58"] [ext_resource type="Resource" uid="uid://ba3ndftq7dht7" path="res://mission/unit_1.03_1.05/grid_growth_2.tres" id="28_hurxs"] +[ext_resource type="Resource" uid="uid://cua0khnbyusip" path="res://mission/unit_1.02/unlock_buildings.tres" id="28_ro3en"] [ext_resource type="Resource" uid="uid://dgimr2v12rjqu" path="res://mission/unit_1.03_1.05/grid_growth_3.tres" id="29_rhn1n"] [ext_resource type="Resource" uid="uid://dm2o4dq2oml53" path="res://mission/unit_1.03_1.05/grid_growth_4.tres" id="30_4rwkv"] +[ext_resource type="Resource" uid="uid://bh148683scgge" path="res://mission/unit_1.02/construction_efficiency.tres" id="30_od4ux"] [ext_resource type="Resource" uid="uid://btwrfq37q8vey" path="res://mission/unit_1.03_1.05/traffic_flow_1.tres" id="31_j2idb"] [ext_resource type="Resource" uid="uid://cf7gpb4j7gq1g" path="res://mission/unit_1.03_1.05/traffic_flow_2.tres" id="32_ipu0c"] [ext_resource type="Resource" uid="uid://ddmxjjyxgxyxo" path="res://mission/unit_1.03_1.05/traffic_flow_3.tres" id="33_c0l5e"] @@ -61,7 +62,7 @@ [ext_resource type="Resource" uid="uid://d0nblitd4ixir" path="res://mission/unit_1.07/resource_alloc_2.tres" id="48_ck35a"] [ext_resource type="Resource" uid="uid://cxh8dgf54oimx" path="res://mission/unit_1.07/resource_alloc_3.tres" id="49_cvgxw"] [ext_resource type="Resource" uid="uid://cpfr2xnjtpcog" path="res://mission/unit_1.07/resource_alloc_4.tres" id="50_6ke0d"] -[ext_resource type="Script" uid="uid://b8b67y260mq6g" path="res://scripts/mission/mission_objective.gd" id="51_kf5aa"] +[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="51_kf5aa"] [ext_resource type="Resource" uid="uid://bsic030rpgh08" path="res://mission/unit_1.06/sustainable_dev_2b.tres" id="57_e755i"] [sub_resource type="Resource" id="Resource_1gdbm"] @@ -139,6 +140,7 @@ companion_dialog = { } } unlocked_items = Array[String]([]) +starting_structures = Array[String]([]) [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mission"] bg_color = Color(0.145098, 0.172549, 0.231373, 0.941176) @@ -242,19 +244,26 @@ shadow_opacity = 0.75 [node name="HUD" parent="CanvasLayer" instance=ExtResource("18_hud")] [node name="ControlsPanel" parent="CanvasLayer" instance=ExtResource("19_controls")] +visible = false [node name="SoundPanel" parent="CanvasLayer" instance=ExtResource("21_sound_panel")] +visible = false anchors_preset = 8 [node name="GenericTextPanel" parent="CanvasLayer" instance=ExtResource("13_7i6dj")] +visible = false resource_data = ExtResource("14_76jlq") [node name="MissionSelectMenu" parent="CanvasLayer" instance=ExtResource("24_ro3en")] visible = false +[node name="BuildingSelector" parent="CanvasLayer" instance=ExtResource("25_od4ux")] +visible = false +offset_right = -277.0 + [node name="MissionManager" type="Node" parent="." node_paths=PackedStringArray("mission_ui", "builder")] script = ExtResource("10_oe3re") -missions = Array[ExtResource("14_vcrh8")]([ExtResource("15_obmwc"), ExtResource("16_rl54y"), ExtResource("17_rrdy6"), ExtResource("20_ngu16"), ExtResource("24_xud6a"), ExtResource("25_6hx7u"), ExtResource("26_lvk23"), ExtResource("27_s0e58"), ExtResource("28_hurxs"), ExtResource("29_rhn1n"), ExtResource("30_4rwkv"), ExtResource("31_j2idb"), ExtResource("32_ipu0c"), ExtResource("33_c0l5e"), ExtResource("34_21t20"), ExtResource("35_o0bjh"), ExtResource("36_2wodh"), ExtResource("37_psgx1"), ExtResource("38_hw762"), ExtResource("39_ymw5p"), ExtResource("40_uggp1"), ExtResource("41_f0dxf"), ExtResource("42_fv8gl"), ExtResource("43_qvne6"), ExtResource("44_haub2"), ExtResource("45_xs8xk"), SubResource("Resource_t5ykj"), ExtResource("47_6w4y8"), ExtResource("48_ck35a"), ExtResource("49_cvgxw"), ExtResource("50_6ke0d"), ExtResource("57_e755i")]) +missions = Array[ExtResource("14_vcrh8")]([ExtResource("28_ro3en"), ExtResource("30_od4ux"), ExtResource("17_rrdy6"), ExtResource("20_ngu16"), ExtResource("24_xud6a"), ExtResource("25_6hx7u"), ExtResource("26_lvk23"), ExtResource("27_s0e58"), ExtResource("28_hurxs"), ExtResource("29_rhn1n"), ExtResource("30_4rwkv"), ExtResource("31_j2idb"), ExtResource("32_ipu0c"), ExtResource("33_c0l5e"), ExtResource("34_21t20"), ExtResource("35_o0bjh"), ExtResource("36_2wodh"), ExtResource("37_psgx1"), ExtResource("38_hw762"), ExtResource("39_ymw5p"), ExtResource("40_uggp1"), ExtResource("41_f0dxf"), ExtResource("42_fv8gl"), ExtResource("43_qvne6"), ExtResource("44_haub2"), ExtResource("45_xs8xk"), SubResource("Resource_t5ykj"), ExtResource("47_6w4y8"), ExtResource("48_ck35a"), ExtResource("49_cvgxw"), ExtResource("50_6ke0d"), ExtResource("57_e755i")]) mission_ui = NodePath("MissionPanel") builder = NodePath("../Builder") character_scene = ExtResource("18_8lrh8") @@ -444,6 +453,23 @@ offset_bottom = 23.0 [node name="building-arcology2" parent="." instance=ExtResource("27_m8wco")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10, -16, -14) +[node name="Builder2" type="Node3D" parent="." node_paths=PackedStringArray("selector", "selector_container", "view_camera", "gridmap", "cash_display")] +script = ExtResource("1_jybm7") +structures = Array[ExtResource("2_54v6r")]([ExtResource("13_kf5aa"), ExtResource("5_v5o2m"), ExtResource("7_t5ykj"), ExtResource("6_fwsy4"), ExtResource("9_e755i"), ExtResource("14_t5ykj"), ExtResource("11_ro3en"), ExtResource("12_xtc7p"), ExtResource("15_e755i"), ExtResource("21_y11qv"), ExtResource("2_bwyku"), ExtResource("11_20frt")]) +selector = NodePath("Selector") +selector_container = NodePath("Selector/Container") +view_camera = NodePath("../View/Camera") +gridmap = NodePath("../GridMap") +cash_display = NodePath("../CanvasLayer/HUD/HBoxContainer/CashItem/CashLabel") + +[node name="Selector" type="Node3D" parent="Builder2"] + +[node name="Sprite" type="Sprite3D" parent="Builder2/Selector"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0.06, 0) +texture = ExtResource("4_wr1wv") + +[node name="Container" type="Node3D" parent="Builder2/Selector"] + [connection signal="all_missions_completed" from="MissionManager" to="." method="_on_mission_manager_all_missions_completed"] [connection signal="mission_started" from="MissionManager" to="." method="_on_mission_manager_mission_started"] [connection signal="pressed" from="MissionManager/LearningPanel/MarginContainer/VBoxContainer/HBoxContainer/CompleteButton" to="MissionManager/LearningPanel" method="_on_complete_button_pressed"] diff --git a/scenes/ui/learning_panel.tscn b/scenes/ui/learning_panel.tscn new file mode 100644 index 0000000..7828490 --- /dev/null +++ b/scenes/ui/learning_panel.tscn @@ -0,0 +1,56 @@ +[gd_scene load_steps=2 format=3 uid="uid://b6x8v0j6y5n3q"] + +[ext_resource type="Script" path="res://scripts/mission/learning_panel.gd" id="1_2k4m3"] + +[node name="LearningPanel" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_2k4m3") + +[node name="PanelContainer" type="PanelContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] +layout_mode = 2 +theme_override_constants/margin_left = 20 +theme_override_constants/margin_top = 20 +theme_override_constants/margin_right = 20 +theme_override_constants/margin_bottom = 20 + +[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer/MarginContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer/ScrollContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/separation = 20 + +[node name="TitleLabel" type="Label" parent="PanelContainer/MarginContainer/ScrollContainer/VBoxContainer"] +layout_mode = 2 +theme_override_font_sizes/font_size = 24 +text = "Learning Panel" +horizontal_alignment = 1 + +[node name="ContentLabel" type="Label" parent="PanelContainer/MarginContainer/ScrollContainer/VBoxContainer"] +layout_mode = 2 +text = "Welcome to the learning panel!" +autowrap_mode = 3 + +[node name="SubmitButtonContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/ScrollContainer/VBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="SubmitButton" type="Button" parent="PanelContainer/MarginContainer/ScrollContainer/VBoxContainer/SubmitButtonContainer"] +layout_mode = 2 +size_flags_horizontal = 4 +text = "Submit" \ No newline at end of file diff --git a/scripts/NavigationNPC.gd b/scripts/NavigationNPC.gd index 53e6940..afd0b5e 100644 --- a/scripts/NavigationNPC.gd +++ b/scripts/NavigationNPC.gd @@ -63,7 +63,6 @@ func _physics_process(delta:float)->void: stuck_timer += delta if stuck_timer > stuck_threshold: # Character is stuck, pick a new random target - print("Character stuck at ", global_position, ", picking new target") pick_random_target() stuck_timer = 0.0 else: diff --git a/scripts/builder.gd b/scripts/builder.gd index 8b20033..0ea1376 100644 --- a/scripts/builder.gd +++ b/scripts/builder.gd @@ -28,6 +28,69 @@ signal structure_placed(structure_index, position) # For our mission flow var invalid_placement_material: StandardMaterial3D +# Central structure management +var _structures: Array[Structure] = [] + +# Getter for structures that ensures deduplication +func get_structures() -> Array[Structure]: + return _structures + +# Setter for structures that ensures deduplication +func set_structures(new_structures: Array[Structure]) -> void: + print("\n=== Updating Structures ===") + _structures = new_structures + _deduplicate_structures() + # Update construction manager with deduplicated structures + if construction_manager: + construction_manager.structures = _structures + print("=== Structure Update Complete ===\n") + +# Function to deduplicate structures +func _deduplicate_structures() -> void: + print("\n=== Deduplicating Structures ===") + + # Create a new array to store unique structures + var unique_structures: Array[Structure] = [] + var seen_paths = {} + + # Initialize all structures, skipping duplicates + for i in range(_structures.size()): + var structure = _structures[i] + if not structure: + push_error("Null structure at index " + str(i)) + continue + + # Skip if no model + if not structure.model: + push_error("Structure at index " + str(i) + " has no model!") + continue + + var path = structure.model.resource_path + + # Skip if we've seen this path before + if path in seen_paths: + print("Skipping duplicate structure: " + path) + continue + + seen_paths[path] = true + + # Initialize unlocked property only if it doesn't exist + if not "unlocked" in structure: + structure.unlocked = false + print("Adding structure: " + path + " - Unlocked: " + str(structure.unlocked)) + unique_structures.append(structure) + + # Replace the original structures array with our deduplicated one + _structures.clear() + _structures.append_array(unique_structures) + + # Print final structure list for verification + print("\nFinal structure list:") + for i in range(_structures.size()): + var structure = _structures[i] + print(str(i) + ": " + structure.model.resource_path + " - Unlocked: " + str(structure.unlocked)) + print("=== Structure Deduplication Complete ===\n") + func _ready(): map = DataMap.new() plane = Plane(Vector3.UP, Vector3.ZERO) @@ -48,29 +111,67 @@ func _ready(): # Give the construction manager references it needs construction_manager.builder = self construction_manager.gridmap = gridmap - construction_manager.structures = structures # Set gridmap cell size to 3 units if gridmap: gridmap.cell_size = Vector3(3, 3, 3) - # Sound effects now handled in game_manager.gd + print("\n=== Initializing Structures ===") + + # Load all structures from the structures directory + var dir = DirAccess.open("res://structures") + if dir: + dir.list_dir_begin() + var file_name = dir.get_next() + while file_name != "": + if file_name.ends_with(".tres"): + var structure = load("res://structures/" + file_name) + if structure: + structures.append(structure) + file_name = dir.get_next() + else: + push_error("Failed to open structures directory!") - # Ensure we start with an unlocked structure - var found_unlocked = false - for i in range(structures.size()): - if "unlocked" in structures[i] and structures[i].unlocked: - index = i - found_unlocked = true - print("Starting with unlocked structure: " + structures[i].model.resource_path) - break + # Set initial structures through our centralized system + set_structures(structures) - if not found_unlocked: - print("WARNING: No unlocked structures found at start!") + # Connect to mission manager's structures_unlocked signal + var mission_manager = get_node_or_null("/root/Main/MissionManager") + if mission_manager: + mission_manager.structures_unlocked.connect(_on_structures_unlocked) + + # Initially hide the selector since we don't know which structure to show yet + if selector: + selector.visible = false + + print("=== Structure Initialization Complete ===\n") - update_structure() update_cash() +# Override the setter for structures to ensure deduplication +func _set_structures(new_structures: Array[Structure]) -> void: + structures = new_structures + _deduplicate_structures() + # Update construction manager with deduplicated structures + if construction_manager: + construction_manager.structures = structures + +# Function to add a structure to the array +func add_structure(structure: Structure) -> void: + structures.append(structure) + _deduplicate_structures() + # Update construction manager with deduplicated structures + if construction_manager: + construction_manager.structures = structures + +# Function to remove a structure from the array +func remove_structure(structure: Structure) -> void: + structures.erase(structure) + _deduplicate_structures() + # Update construction manager with deduplicated structures + if construction_manager: + construction_manager.structures = structures + func _process(delta): # Skip all building functionality if disabled or game is paused if disabled or get_tree().paused: @@ -115,6 +216,13 @@ func is_mouse_over_ui() -> bool: # Get mouse position var mouse_pos = get_viewport().get_mouse_position() + # Check building selector panel + var building_selector = get_node_or_null("/root/Main/CanvasLayer/BuildingSelector") + if building_selector and building_selector.selection_panel and building_selector.selection_panel.visible: + var panel_rect = building_selector.selection_panel.get_global_rect() + if panel_rect.has_point(mouse_pos): + return true + # Let's try an extremely simple approach - just check coordinates # most HUDs are at top of screen if mouse_pos.y < 100: @@ -227,7 +335,7 @@ func action_build(gridmap_position, can_place: bool): var is_terrain = structures[index].type == Structure.StructureType.TERRAIN # Check if we're in mission 3 (when we should use construction workers) - var use_worker_construction = structures[index].spawn_builder + var use_worker_construction = true var mission_manager = get_node_or_null("/root/Main/MissionManager") # Sound effects are handled via game_manager.gd through the structure_placed signal @@ -262,20 +370,10 @@ func action_build(gridmap_position, can_place: bool): # We still set the cell item for collision detection gridmap.set_cell_item(gridmap_position, index, gridmap.get_orthogonal_index_from_basis(selector.basis)) - elif is_residential or use_worker_construction: - # For residential buildings in mission 3, use construction workers - # Pass the current selector basis to preserve rotation + else: + # For all other buildings, start construction process with worker var selector_basis = selector.basis construction_manager.start_construction(gridmap_position, index, selector_basis) - - # Don't place the building immediately - it will be placed when construction completes - # We leave gridmap empty for now - - # For mission 3, don't update objectives immediately - wait for construction to finish - # See _update_mission_objective_on_completion in building_construction_manager.gd - else: - # For non-road structures or not in mission 3, add to the gridmap as usual - gridmap.set_cell_item(gridmap_position, index, gridmap.get_orthogonal_index_from_basis(selector.basis)) if previous_tile != index: map.cash -= structures[index].price @@ -435,42 +533,61 @@ func action_rotate(): # Toggle between structures to build func action_structure_toggle(): + # Original keyboard controls if Input.is_action_just_pressed("structure_next"): - # Find the next unlocked structure - var next_index = index - var tried_indices = [] + print("\nE key pressed - attempting to switch to next structure") + # First, collect all unlocked structure indices in order + var unlocked_indices = [] + for i in range(_structures.size()): + var structure = _structures[i] + if structure.model: + if structure.unlocked: + unlocked_indices.append(i) - while tried_indices.size() < structures.size(): - next_index = wrap(next_index + 1, 0, structures.size()) - if tried_indices.has(next_index): - break # We've already tried this index, avoid infinite loop - - tried_indices.append(next_index) + if unlocked_indices.is_empty(): + print("WARNING: No unlocked structures available!") + return - # Check if this structure is unlocked - if "unlocked" in structures[next_index] and structures[next_index].unlocked: - index = next_index - break + # Find the next unlocked structure + var current_pos = unlocked_indices.find(index) + if current_pos == -1: + # If current index is not in unlocked list, start from beginning + index = unlocked_indices[0] + print("Current structure not unlocked, starting from first unlocked: ", index) + else: + # Move to next structure, wrapping around to start if at end + index = unlocked_indices[(current_pos + 1) % unlocked_indices.size()] + print("Moving to next unlocked structure: ", index) + + update_structure() if Input.is_action_just_pressed("structure_previous"): - # Find the previous unlocked structure - var prev_index = index - var tried_indices = [] + print("\nQ key pressed - attempting to switch to previous structure") + # First, collect all unlocked structure indices in order + var unlocked_indices = [] + for i in range(_structures.size()): + var structure = _structures[i] + if structure.model: + if structure.unlocked: + unlocked_indices.append(i) - while tried_indices.size() < structures.size(): - prev_index = wrap(prev_index - 1, 0, structures.size()) - if tried_indices.has(prev_index): - break # We've already tried this index, avoid infinite loop - - tried_indices.append(prev_index) + if unlocked_indices.is_empty(): + print("WARNING: No unlocked structures available!") + return - # Check if this structure is unlocked - if "unlocked" in structures[prev_index] and structures[prev_index].unlocked: - index = prev_index - break - - update_structure() - + # Find the previous unlocked structure + var current_pos = unlocked_indices.find(index) + if current_pos == -1: + # If current index is not in unlocked list, start from end + index = unlocked_indices[-1] + print("Current structure not unlocked, starting from last unlocked: ", index) + else: + # Move to previous structure, wrapping around to end if at start + index = unlocked_indices[(current_pos - 1 + unlocked_indices.size()) % unlocked_indices.size()] + print("Moving to previous unlocked structure: ", index) + + update_structure() + # Update the structure visual in the 'cursor' func update_structure(): # Clear previous structure preview in selector @@ -478,14 +595,14 @@ func update_structure(): selector_container.remove_child(n) # Create new structure preview in selector - var _model = structures[index].model.instantiate() + var _model = _structures[index].model.instantiate() selector_container.add_child(_model) # Get reference to the selector sprite var selector_sprite = selector.get_node("Sprite") # Apply appropriate scaling based on structure type - if structures[index].model.resource_path.contains("power_plant"): + if _structures[index].model.resource_path.contains("power_plant"): # Scale power plant model to be much smaller (0.5x) _model.scale = Vector3(0.5, 0.5, 0.5) # Center the power plant model within the selector @@ -496,7 +613,7 @@ func update_structure(): _model.position.y += 0.0 # No need for Y adjustment with scaling # Get the selector scale from the structure resource - var scale_factor = structures[index].selector_scale + var scale_factor = _structures[index].selector_scale selector_sprite.scale = Vector3(scale_factor, scale_factor, scale_factor) # Sound effects are now handled in game_manager.gd @@ -827,25 +944,13 @@ func _on_construction_completed(position: Vector3): break if structure_index >= 0: - # Add the completed building to the gridmap with the correct rotation and structure index - gridmap.set_cell_item(position, structure_index, rotation_index) - # Check if we need to spawn a character for mission 1 var mission_manager = get_node_or_null("/root/Main/MissionManager") if mission_manager: - # We DON'T re-emit the structure_placed signal here, because we already - # emitted it when construction started in action_build() - # This prevents double-counting buildings in the HUD - # Now check if we need to manually handle mission 1 character spawning if mission_manager.current_mission and mission_manager.current_mission.id == "1" and not mission_manager.character_spawned: mission_manager.character_spawned = true mission_manager._spawn_character_on_road(position) - - # NOTE: We removed the structure_placed signal emission here to fix the population double-counting - else: - # We don't emit the signal anymore to prevent double-counting - pass else: # No residential building structure found pass @@ -855,11 +960,6 @@ func _on_construction_completed(position: Vector3): # Make sure the navigation mesh is updated rebake_navigation_mesh() - - # Note that mission objective updates are now handled in the construction manager - # to ensure they only occur after construction is complete - - # Saving/load @@ -965,6 +1065,7 @@ func check_can_place(pos: Vector3) -> bool: if construction_manager: for site_pos in construction_manager.construction_sites: var distance = Vector2(abs(site_pos.x - pos.x), abs(site_pos.z - pos.z)) + # Block the entire 3x3 grid space where construction is happening if distance.x < 3 and distance.y < 3: return false @@ -977,6 +1078,7 @@ func check_can_place(pos: Vector3) -> bool: float(child.name.split("_")[2]) ) var distance = Vector2(abs(plot_pos.x - pos.x), abs(plot_pos.z - pos.z)) + # Block the entire 3x3 grid space where construction is happening if distance.x < 3 and distance.y < 3: return false @@ -1021,3 +1123,95 @@ func _get_all_mesh_instances(node: Node) -> Array: mesh_instances.append_array(_get_all_mesh_instances(child)) return mesh_instances + +# Place a structure at a specific position and rotation +func place_structure(structure_index: int, position: Vector3, rotation: float = 0.0) -> void: + if structure_index < 0 or structure_index >= structures.size(): + push_error("Invalid structure index: " + str(structure_index)) + return + + # Store current index + var previous_index = index + + # Set the structure to place + index = structure_index + + # Create a gridmap position from the world position + var gridmap_position = Vector3( + round(position.x / 3.0) * 3.0, + 0, + round(position.z / 3.0) * 3.0 + ) + + # Check if we can place here + if not check_can_place(gridmap_position): + push_error("Cannot place structure at position: " + str(position)) + index = previous_index + return + + # Place the structure + var is_road = structures[index].type == Structure.StructureType.ROAD + var is_residential = structures[index].type == Structure.StructureType.RESIDENTIAL_BUILDING + var is_power_plant = structures[index].model.resource_path.contains("power_plant") + var is_terrain = structures[index].type == Structure.StructureType.TERRAIN + + if is_road: + # For roads, we'll need to track in our data without using the GridMap + # But for now, we won't add it to the GridMap visually, just add to NavRegion3D + var previous_tile = gridmap.get_cell_item(gridmap_position) + if previous_tile >= 0 and previous_tile < structures.size() and structures[previous_tile].type == Structure.StructureType.ROAD: + _remove_road_from_navregion(gridmap_position) + _add_road_to_navregion(gridmap_position, index) + emit_signal("structure_placed", index, gridmap_position) + elif is_residential: + # For residential buildings, we use the construction manager + construction_manager.start_construction(gridmap_position, index) + emit_signal("structure_placed", index, gridmap_position) + elif is_power_plant: + # For power plants, we just place them directly in the gridmap + gridmap.set_cell_item(gridmap_position, index) + emit_signal("structure_placed", index, gridmap_position) + elif is_terrain: + # For grass and trees (terrain), we just place them directly in the gridmap + gridmap.set_cell_item(gridmap_position, index) + emit_signal("structure_placed", index, gridmap_position) + else: + # For other structures, we use the gridmap + gridmap.set_cell_item(gridmap_position, index) + emit_signal("structure_placed", index, gridmap_position) + + # Restore previous index + index = previous_index + +# New function to handle when structures are unlocked +func _on_structures_unlocked(): + print("\n=== Structures Unlocked, Setting Initial Structure ===") + + # Find the first unlocked structure in the array + var found_unlocked = false + print("\nChecking for unlocked structures:") + for i in range(_structures.size()): + var structure = _structures[i] + print("Structure " + str(i) + ": " + structure.model.resource_path + " - Unlocked: " + str(structure.unlocked)) + if structure.unlocked: + index = i + found_unlocked = true + print("Found first unlocked structure at index " + str(i) + ": " + structure.model.resource_path) + break + + if not found_unlocked: + print("WARNING: No unlocked structures found!") + # Don't set any structure as selected if none are unlocked + index = -1 + # Hide the selector since we have no structures to place + if selector: + selector.visible = false + else: + # Show the selector since we have a structure to place + if selector: + selector.visible = true + + update_structure() + print("=== Initial Structure Set ===\n") + +# Function to deduplicate structures diff --git a/scripts/building_selector.gd b/scripts/building_selector.gd index dbef5c9..87639af 100644 --- a/scripts/building_selector.gd +++ b/scripts/building_selector.gd @@ -1,64 +1,202 @@ -extends Control +extends PanelContainer -@onready var main_button = $MainButton -@onready var selection_panel = $SelectionPanel -@onready var ground_options = $SelectionPanel/ScrollContainer/VBoxContainer/GroundSection/GroundOptions -@onready var building_options = $SelectionPanel/ScrollContainer/VBoxContainer/BuildingSection/BuildingOptions -@onready var search_bar = $SelectionPanel/SearchBar -@onready var filter_buttons = $SelectionPanel/FilterButtons -@onready var description_panel = $SelectionPanel/DescriptionPanel -@onready var title_label = $SelectionPanel/DescriptionPanel/VBoxContainer/TitleLabel -@onready var description_label = $SelectionPanel/DescriptionPanel/VBoxContainer/DescriptionLabel -@onready var price_label = $SelectionPanel/DescriptionPanel/VBoxContainer/StatsContainer/PriceLabel -@onready var population_label = $SelectionPanel/DescriptionPanel/VBoxContainer/StatsContainer/PopulationLabel -@onready var power_label = $SelectionPanel/DescriptionPanel/VBoxContainer/StatsContainer/PowerLabel +const GenericText = preload("res://resources/generic_text_panel.resource.gd") -@export var builder: Node: - set(value): - _builder = value - if is_inside_tree(): # Only create buttons if node is ready - _create_option_buttons() - get: - return _builder +signal closed -var _builder: Node +@export var resource_data: GenericText + +@onready var main_button: Button = $MainButton +@onready var selection_panel: Panel = $SelectionPanel +@onready var ground_options = $SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/GroundSection/GroundOptions +@onready var building_options = $SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/BuildingSection/BuildingOptions +@onready var search_bar: LineEdit = $SelectionPanel/MarginContainer/VBoxContainer/SearchBar +@onready var filter_buttons: HBoxContainer = $SelectionPanel/MarginContainer/VBoxContainer/FilterButtons +@onready var description_panel: Panel = $SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel +@onready var title_label: Label = $SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer/TitleLabel +@onready var description_label: Label = $SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer/DescriptionLabel +@onready var price_label: Label = $SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer/StatsContainer/PriceLabel +@onready var population_label: Label = $SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer/StatsContainer/PopulationLabel +@onready var power_label: Label = $SelectionPanel/MarginContainer/VBoxContainer/DescriptionPanel/MarginContainer/VBoxContainer/StatsContainer/PowerLabel +@onready var click_blocker: ColorRect = $ClickBlocker + +var builder: Node var current_selection: int = 0 var is_panel_visible: bool = false var current_filter: String = "All" var search_text: String = "" +var slide_tween: Tween +var tween: Tween -func _ready(): - # Connect the main button signal - main_button.pressed.connect(_on_main_button_pressed) +func _ready() -> void: + # Hide the panel initially + visible = false + + # Make sure this control blocks mouse input from passing through + mouse_filter = Control.MOUSE_FILTER_STOP + + # Initialize the panel state + if selection_panel: + selection_panel.visible = false + selection_panel.position = Vector2(0, 0) # Reset position + selection_panel.mouse_filter = Control.MOUSE_FILTER_STOP + selection_panel.size = Vector2(300, get_viewport_rect().size.y) # Set a fixed width - # Connect search bar signal - search_bar.text_changed.connect(_on_search_text_changed) + # Set up click blocker + if click_blocker: + click_blocker.visible = false + click_blocker.mouse_filter = Control.MOUSE_FILTER_STOP + click_blocker.size = get_viewport_rect().size + click_blocker.position = Vector2.ZERO + click_blocker.z_index = 1000 # Ensure it's above everything else + + # Create background panel for the main button + var button_bg = ColorRect.new() + button_bg.color = Color(0, 0, 0, 0.7) # Semi-transparent black + button_bg.size = Vector2(40, 40) # Slightly larger than the button + button_bg.position = Vector2(-5, -5) # Offset to center the button + button_bg.mouse_filter = Control.MOUSE_FILTER_STOP # Block clicks on background + add_child(button_bg) + button_bg.z_index = -1 # Place behind the button + + if main_button: + main_button.text = "▶" + main_button.mouse_filter = Control.MOUSE_FILTER_STOP + # Set initial position to stick to the right side + main_button.position.x = 0 + # Center the button vertically + main_button.position.y = get_viewport_rect().size.y / 2 - 20 + # Style the button + main_button.add_theme_color_override("font_color", Color(1, 1, 1)) # White text + main_button.add_theme_font_size_override("font_size", 24) # Larger font + + # Connect signals + if main_button and not main_button.pressed.is_connected(_on_main_button_pressed): + main_button.pressed.connect(_on_main_button_pressed) + if search_bar and not search_bar.text_changed.is_connected(_on_search_text_changed): + search_bar.text_changed.connect(_on_search_text_changed) - # Connect filter button signals for button in filter_buttons.get_children(): - if button is Button: + if button is Button and not button.pressed.is_connected(_on_filter_button_pressed.bind(button.text)): button.pressed.connect(_on_filter_button_pressed.bind(button.text)) - # Initially hide the selection panel - selection_panel.visible = false + # Set mouse filters for containers + if ground_options: + ground_options.mouse_filter = Control.MOUSE_FILTER_STOP + if building_options: + building_options.mouse_filter = Control.MOUSE_FILTER_STOP - # Make sure the panel doesn't pass through mouse events - selection_panel.mouse_filter = Control.MOUSE_FILTER_STOP - ground_options.mouse_filter = Control.MOUSE_FILTER_STOP - building_options.mouse_filter = Control.MOUSE_FILTER_STOP + # Create initial buttons if builder is set + if builder: + _create_filter_buttons() + _create_option_buttons() - # Create the building and ground option buttons - _create_option_buttons() + # Apply resource data if available + if resource_data: + apply_resource_data(resource_data) -func _create_option_buttons(): +func show_panel() -> void: + visible = true + is_panel_visible = true + selection_panel.visible = true + click_blocker.visible = true + main_button.text = "◀" + + # Create tween for smooth animation + if tween: + tween.kill() + tween = create_tween() + + # Panel is opening + selection_panel.position.x = -selection_panel.size.x + tween.tween_property(selection_panel, "position:x", 0, 0.2) + tween.parallel().tween_property(main_button, "position:x", selection_panel.size.x, 0.2) + + # Pause the game when the panel is open + get_tree().paused = true + +func hide_panel() -> void: + is_panel_visible = false + + # Create tween for smooth animation + if tween: + tween.kill() + tween = create_tween() + + # Panel is closing + tween.tween_property(selection_panel, "position:x", -selection_panel.size.x, 0.2) + tween.parallel().tween_property(main_button, "position:x", 0, 0.2) + tween.tween_callback(func(): + selection_panel.visible = false + click_blocker.visible = false + main_button.text = "▶" + visible = false + # Resume the game when the panel is closed + get_tree().paused = false + # Emit signal that panel was closed + closed.emit() + ) + +func _on_main_button_pressed() -> void: + if !selection_panel or !main_button or !click_blocker: + return + + if !is_panel_visible: + show_panel() + else: + hide_panel() + +func _create_filter_buttons(): + if not filter_buttons or not builder: + return + # Clear existing buttons - for child in ground_options.get_children(): - child.queue_free() - for child in building_options.get_children(): + for child in filter_buttons.get_children(): child.queue_free() + # Create "All" button + var all_button = Button.new() + all_button.text = "All" + all_button.toggle_mode = true + all_button.button_pressed = true + all_button.flat = true + all_button.pressed.connect(_on_filter_button_pressed.bind("All")) + filter_buttons.add_child(all_button) + + # Get unique structure types + var structure_types = {} + for structure in builder.get_structures(): + if structure.type == Structure.StructureType.TERRAIN: + structure_types["Ground"] = true + else: + structure_types["Buildings"] = true + + # Create buttons for each structure type + for type_name in structure_types.keys(): + var button = Button.new() + button.text = type_name + button.toggle_mode = true + button.flat = true + button.pressed.connect(_on_filter_button_pressed.bind(type_name)) + filter_buttons.add_child(button) + +func _create_option_buttons(): + # Clear existing buttons + if ground_options: + for child in ground_options.get_children(): + child.queue_free() + if building_options: + for child in building_options.get_children(): + child.queue_free() + # Get structures from builder - if not _builder or not _builder.structures: + if not builder: + print("ERROR: No builder reference in building selector") + return + + var structures = builder.get_structures() + if not structures or structures.size() == 0: + print("WARNING: No structures available in builder") return # Create ground options (grass, pavement, etc.) @@ -66,7 +204,10 @@ func _create_option_buttons(): var building_structures = [] # Sort structures by type and apply filters - for structure in _builder.structures: + for structure in structures: + if not structure: + continue + # Apply search filter if search_text != "" and not structure.title.to_lower().contains(search_text.to_lower()): continue @@ -74,44 +215,57 @@ func _create_option_buttons(): # Apply type filter if current_filter != "All": match current_filter: - "Residential": - if structure.type != Structure.StructureType.RESIDENTIAL_BUILDING: + "Ground": + if structure.type != Structure.StructureType.TERRAIN: continue - "Commercial": - if structure.type != Structure.StructureType.COMMERCIAL_BUILDING: - continue - "Industrial": - if structure.type != Structure.StructureType.INDUSTRIAL_BUILDING: + "Buildings": + if structure.type == Structure.StructureType.TERRAIN: continue + # Add to appropriate list if structure.type == Structure.StructureType.TERRAIN: ground_structures.append(structure) else: building_structures.append(structure) # Set up grid layout for ground options - ground_options.columns = 4 # Set number of columns - ground_options.add_theme_constant_override("h_separation", 10) # Horizontal spacing - ground_options.add_theme_constant_override("v_separation", 10) # Vertical spacing + if ground_options: + ground_options.columns = 4 + ground_options.add_theme_constant_override("h_separation", 10) + ground_options.add_theme_constant_override("v_separation", 10) # Create buttons for ground structures for i in range(ground_structures.size()): var button = _create_option_button(ground_structures[i], i) - ground_options.add_child(button) + if ground_options: + ground_options.add_child(button) # Set up grid layout for building options - building_options.columns = 4 # Set number of columns - building_options.add_theme_constant_override("h_separation", 10) # Horizontal spacing - building_options.add_theme_constant_override("v_separation", 10) # Vertical spacing + if building_options: + building_options.columns = 4 + building_options.add_theme_constant_override("h_separation", 10) + building_options.add_theme_constant_override("v_separation", 10) # Create buttons for building structures for i in range(building_structures.size()): var button = _create_option_button(building_structures[i], i + ground_structures.size()) - building_options.add_child(button) + if building_options: + building_options.add_child(button) # Hide sections if they have no options - $SelectionPanel/ScrollContainer/VBoxContainer/GroundSection.visible = ground_structures.size() > 0 - $SelectionPanel/ScrollContainer/VBoxContainer/BuildingSection.visible = building_structures.size() > 0 + var ground_section = $SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/GroundSection + var building_section = $SelectionPanel/MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/BuildingSection + + if ground_section: + ground_section.visible = ground_structures.size() > 0 + if building_section: + building_section.visible = building_structures.size() > 0 + + # Force update the layout + if ground_options: + ground_options.queue_redraw() + if building_options: + building_options.queue_redraw() func _create_option_button(structure: Structure, index: int) -> Button: var button = Button.new() @@ -199,33 +353,21 @@ func _create_option_button(structure: Structure, index: int) -> Button: button.pressed.connect(_on_option_selected.bind(index)) return button -func _on_main_button_pressed(): - is_panel_visible = !is_panel_visible - selection_panel.visible = is_panel_visible - - if is_panel_visible: - # Update button states to show current selection - _update_button_states() - -func _on_search_text_changed(new_text: String): +func _on_search_text_changed(new_text: String) -> void: search_text = new_text _create_option_buttons() -func _on_filter_button_pressed(filter_name: String): - # Update filter buttons - for button in filter_buttons.get_children(): - if button is Button: - button.button_pressed = (button.text == filter_name) - - current_filter = filter_name +func _on_filter_button_pressed(filter: String) -> void: + current_filter = filter _create_option_buttons() func _on_option_selected(index: int): - if not _builder: + if not builder: print("ERROR: No builder reference in building selector") return - if not _builder.structures or index < 0 or index >= _builder.structures.size(): + var structures = builder.get_structures() + if not structures or index < 0 or index >= structures.size(): print("ERROR: Invalid structure index: ", index) return @@ -233,8 +375,8 @@ func _on_option_selected(index: int): _update_button_states() # Update the builder's current selection - _builder.index = index - _builder.update_structure() + builder.index = index + builder.update_structure() # Update the main button text main_button.text = "Selected: " + _get_structure_name(index) @@ -244,18 +386,36 @@ func _on_option_selected(index: int): func _update_button_states(): # Update all buttons to show which one is selected - var all_buttons = ground_options.get_children() + building_options.get_children() + if not ground_options or not building_options: + return + + var all_buttons = [] + + # Add ground options buttons if they exist + for child in ground_options.get_children(): + if child is Button: + all_buttons.append(child) + + # Add building options buttons if they exist + for child in building_options.get_children(): + if child is Button: + all_buttons.append(child) + + # Update button states for i in range(all_buttons.size()): - all_buttons[i].button_pressed = (i == current_selection) + if all_buttons[i] is Button: + all_buttons[i].button_pressed = (i == current_selection) func _get_structure_name(index: int) -> String: - if _builder and _builder.structures and index >= 0 and index < _builder.structures.size(): - var structure = _builder.structures[index] + var structures = builder.get_structures() + if structures and index >= 0 and index < structures.size(): + var structure = structures[index] return structure.title return "Unknown" func _update_description_panel(index: int): - if not _builder or not _builder.structures or index < 0 or index >= _builder.structures.size(): + var structures = builder.get_structures() + if not structures or index < 0 or index >= structures.size(): title_label.text = "No Building Selected" description_label.text = "Select a building to view its details" price_label.text = "Price: $0" @@ -263,7 +423,7 @@ func _update_description_panel(index: int): power_label.text = "Power: 0 kW" return - var structure = _builder.structures[index] + var structure = structures[index] title_label.text = structure.title description_label.text = structure.description price_label.text = "Price: $" + str(structure.price) @@ -276,4 +436,48 @@ func _update_description_panel(index: int): power_text += "-" + str(structure.kW_usage) + " kW" else: power_text += "0 kW" - power_label.text = power_text + power_label.text = power_text + +func apply_resource_data(data: GenericText) -> void: + if data: + if title_label: + title_label.text = data.title + if description_label: + description_label.text = data.body_text + +# Override _gui_input to ensure we're handling all input +func _gui_input(event: InputEvent) -> void: + if is_panel_visible: + # When panel is visible, accept all input to prevent it from reaching the game + get_viewport().set_input_as_handled() + +# Override _input to catch all input events +func _input(event: InputEvent) -> void: + if is_panel_visible and (event is InputEventMouseButton or event is InputEventMouseMotion): + # When panel is visible, accept all mouse input to prevent it from reaching the game + get_viewport().set_input_as_handled() + + # If it's a mouse button press, mark it as handled + if event is InputEventMouseButton: + event.pressed = false + +# Override _unhandled_input to catch any remaining input events +func _unhandled_input(event: InputEvent) -> void: + if is_panel_visible: + get_viewport().set_input_as_handled() + if event is InputEventMouseButton: + event.pressed = false + +# Override _get_global_rect to ensure the builder's UI check detects us +func _get_global_rect() -> Rect2: + if is_panel_visible: + return Rect2(Vector2.ZERO, get_viewport_rect().size) + return Rect2(Vector2.ZERO, Vector2.ZERO) + +# Add a method to check if the mouse is over our panel +func is_mouse_over_building_selector() -> bool: + if is_panel_visible: + var mouse_pos = get_viewport().get_mouse_position() + var rect = get_global_rect() + return rect.has_point(mouse_pos) + return false diff --git a/scripts/game_manager.gd b/scripts/game_manager.gd index 08b9a39..08924ec 100644 --- a/scripts/game_manager.gd +++ b/scripts/game_manager.gd @@ -16,6 +16,11 @@ var construction_sfx: AudioStreamPlayer @export var intro_text_resource: GenericText @export var outro_text_resource: GenericText +# Node references +@onready var building_selector = get_node_or_null("CanvasLayer/BuildingSelector") +@onready var resource_display = get_node_or_null("CanvasLayer/ResourceDisplay") +@onready var game_menu = get_node_or_null("CanvasLayer/GameMenu") + func _ready(): print("GameManager: Initializing...") # Load data from a file. @@ -56,11 +61,12 @@ func _ready(): Engine.get_main_loop().set_meta("sound_manager", sound_manager) # Reference to the controls panel and HUD - var controls_panel = $CanvasLayer/ControlsPanel - var hud = $CanvasLayer/HUD + var controls_panel = get_node_or_null("CanvasLayer/ControlsPanel") + var hud = get_node_or_null("CanvasLayer/HUD") # Set up the HUD's reference to the panels - hud.controls_panel = controls_panel + if hud and controls_panel: + hud.controls_panel = controls_panel # Show intro text if available if generic_text_panel and intro_text_resource: @@ -94,6 +100,7 @@ func _ready(): var builder = get_node_or_null("/root/Main/Builder") if builder: builder.structure_placed.connect(_on_structure_placed) + print("GameManager: Connected to Builder signals") # Connect to construction signals via deferred call to make sure everything is ready call_deferred("_setup_construction_signals") @@ -102,9 +109,14 @@ func _ready(): call_deferred("_setup_sound_buses") # Connect the building selector to the builder - var building_selector = $CanvasLayer/BuildingSelector if building_selector: - building_selector.builder = $Builder + if builder: + building_selector.builder = builder + print("GameManager: Connected BuildingSelector to Builder") + else: + print("GameManager: Warning - Builder not found!") + else: + print("GameManager: Warning - BuildingSelector not found!") # Connect builder's cash display to HUD if builder and hud: @@ -122,6 +134,18 @@ func _ready(): economy_manager.population_changed.connect(hud_manager.update_population_count) economy_manager.energy_balance_changed.connect(hud_manager.update_energy_balance) + # Initialize managers + _initialize_managers() + + # Connect signals + _connect_signals() + + # Initialize game state + _initialize_game_state() + + # Start the game + start_game() + func _on_music_volume_changed(new_volume: float): print("GameManager: Music volume changed to ", new_volume) config.set_value("audio", "music_volume", new_volume) @@ -395,3 +419,23 @@ func _on_mission_manager_mission_started(mission: MissionData) -> void: generic_text_panel.apply_resource_data(mission_text) generic_text_panel.show_panel() + +func _initialize_managers(): + print("GameManager: Initializing managers") + # Initialize any required managers here + pass + +func _connect_signals(): + print("GameManager: Connecting signals") + # Connect any required signals here + pass + +func _initialize_game_state(): + print("GameManager: Initializing game state") + # Initialize game state here + pass + +func start_game(): + print("GameManager: Starting game") + # Start game logic here + pass diff --git a/scripts/hud_manager.gd b/scripts/hud_manager.gd index e27bb03..61aa4a3 100644 --- a/scripts/hud_manager.gd +++ b/scripts/hud_manager.gd @@ -46,11 +46,17 @@ func _ready(): # Setup mission select button if mission_select_button: - mission_select_button.connect("pressed", _on_mission_select_button_pressed) + if not mission_select_button.pressed.is_connected(_on_mission_select_button_pressed): + mission_select_button.pressed.connect(_on_mission_select_button_pressed) + else: + push_error("Mission select button not found in HUD") # Setup mission select menu _setup_mission_select_menu() + # Wait a frame to ensure all nodes are ready + await get_tree().process_frame + # Update mission select visibility based on export variable _update_mission_select_visibility() @@ -97,9 +103,15 @@ func _setup_mission_select_menu(): # Update mission select visibility based on export variable func _update_mission_select_visibility(): - var mission_select_item = $HBoxContainer/MissionSelectItem + if not is_inside_tree(): + # If we're not in the tree yet, wait until we are + await ready + + var mission_select_item = get_node_or_null("HBoxContainer/MissionSelectItem") if mission_select_item: mission_select_item.visible = show_mission_select + else: + push_warning("MissionSelectItem node not found in HUD") # Handle mission select button press func _on_mission_select_button_pressed(): diff --git a/scripts/javascript_bridge.gd b/scripts/javascript_bridge.gd index a40b347..98cecc0 100644 --- a/scripts/javascript_bridge.gd +++ b/scripts/javascript_bridge.gd @@ -1,540 +1,164 @@ extends Node -class_name JSBridge + +# Make this a singleton +static var instance = null + +# Signals +signal init_data_received(data) +signal init_check_received +signal mission_progress_updated(data) +signal mission_completed(data) +signal open_react_graph(data) +signal open_react_table(data) + +# Variables +var _interface = null +var _init_data = null +var _init_check_received = false +var _pending_signals = [] + +func _init(): + instance = self # This script provides a bridge to JavaScript functionality # while gracefully handling platforms that don't support it -# Check if JavaScript is available -static func has_interface() -> bool: - # Check if running in a web environment - # Use OS.has_feature("web") for consistency with sound_manager.gd +func _ready(): + # Connect signals when the node is initialized if OS.has_feature("web"): - print("Running in web environment, JavaScript should be available") - - # Double-check by evaluating a simple script - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - var test_result = js.eval("!!window && typeof window !== 'undefined'") - print("JavaScript test result: " + str(test_result)) - return test_result != null - else: - print("JavaScriptBridge singleton not available, running in editor or non-web platform") - else: - print("Not running in web environment") - - return false - -# Get the JavaScript interface -static func get_interface(): - if has_interface(): - return JavaScriptGlobal - return null - -# JavaScriptGlobal is a mock class that provides fallback implementations -# for platforms that don't support JavaScript -class JavaScriptGlobal: - # Check if a JavaScript function exists - static func has_function(function_name: String) -> bool: - if not OS.has_feature("web"): - return false - - print("Checking if function exists: " + function_name) - var script = "typeof %s === 'function'" % function_name - - # Use Engine.get_singleton for consistency with sound_manager.gd - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - var result = js.eval(script) - - # If result is null, the JavaScript eval failed - if result == null: - print("JavaScript eval failed when checking for function: " + function_name) - return false - - print("Function check result for " + function_name + ": " + str(result)) - return result - else: - print("JavaScriptBridge singleton not available") - return false - - # Evaluate JavaScript code - static func eval(script: String): - if not OS.has_feature("web"): - return null - - # Use Engine.get_singleton for consistency with sound_manager.gd - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - return js.eval(script) - else: - print("JavaScriptBridge singleton not available") - return null - - # Call a JavaScript function with arguments - static func call_js_function(function_name: String, args = []): - if not OS.has_feature("web"): - return null - - var formatted_args = [] - for arg in args: - if arg is String: - formatted_args.append("\"%s\"" % arg.replace("\"", "\\\"")) - elif arg is Dictionary or arg is Array: - formatted_args.append(JSON.stringify(arg)) - else: - formatted_args.append(str(arg)) - - var script = "%s(%s)" % [function_name, ",".join(formatted_args)] - - # Use Engine.get_singleton for consistency with sound_manager.gd - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - return js.eval(script) - else: - print("JavaScriptBridge singleton not available") - return null - - # Connect to the learning companion - legacy method with postMessage fallback - static func connectLearningCompanion(success_callback = null, error_callback = null): - print("Attempting to connect to learning companion") - - if not OS.has_feature("web"): - print("Skipping learning companion connection on non-web platform") - if error_callback != null and error_callback.is_valid(): - error_callback.call() - return - - # Always use postMessage approach regardless of function availability - connectLearningCompanionViaPostMessage(success_callback, error_callback) - - # Connect to the learning companion using only postMessage - static func connectLearningCompanionViaPostMessage(success_callback = null, error_callback = null): - print("Connecting to learning companion via postMessage") - - if not OS.has_feature("web"): - print("Skipping learning companion connection on non-web platform") - if error_callback != null and error_callback.is_valid(): - error_callback.call() - return - - # Use postMessage approach exclusively - note: no return statements allowed in the script - var script = """ - (function() { - try { - // Send a message directly to the parent window - if (window.parent) { - console.log('Sending connection message to parent window'); - window.parent.postMessage({ - type: 'stemCity_connect', - source: 'godot-game', - timestamp: Date.now() - }, '*'); - - // Set up a global event listener for responses if not already set up - if (!window._stemCityListenerInitialized) { - window._stemCityListenerInitialized = true; - window.addEventListener('message', function(event) { - console.log('Game received message:', event.data); - if (event.data && event.data.type === 'stemCity_connect_ack') { - console.log('Received connection acknowledgment from parent'); - } - }); + # Wait for the interface to be available + await get_tree().process_frame + + # Set up message listener and interface + JavaScript.JavaScriptGlobal.eval(""" + // Create the Godot interface + window.godot_interface = { + _callbacks: {}, + emit_signal: function(signal_name, data) { + console.log('Emitting signal:', signal_name, 'with data:', data); + if (window.godot_interface._callbacks[signal_name]) { + window.godot_interface._callbacks[signal_name](data); } - - // Don't use return statements here - they're not allowed in top-level eval - var result = true; - } else { - console.log('No parent window found'); - var result = false; - } - } catch (e) { - console.error('Error connecting via postMessage:', e); - var result = false; - } - })(); - """ - - # Use Engine.get_singleton for consistency with sound_manager.gd - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - js.eval(script) - - # Always consider this a success - we'll use the force connection timer as backup - print("Sent connection message via postMessage") - - # Try to ensure audio is initialized as well since we now have user interaction - JavaScriptGlobal.ensure_audio_initialized() - - if success_callback != null and success_callback.is_valid(): - success_callback.call() - else: - print("JavaScriptBridge singleton not available") - if error_callback != null and error_callback.is_valid(): - error_callback.call() - - # The following methods call the JavaScript functions for game events using postMessage - - static func onGameStarted(): - if not OS.has_feature("web"): - return - - print("Sending game started event via postMessage") - var script = """ - (function() { - try { - if (window.parent) { - console.log('Sending gameStarted message to parent window'); - window.parent.postMessage({ - type: 'stemCity_gameStarted', - source: 'godot-game', - timestamp: Date.now() - }, '*'); - } else { - console.log('No parent window found for gameStarted event'); } - } catch (e) { - console.error('Error sending gameStarted via postMessage:', e); - } - })(); - """ - - # Use Engine.get_singleton for consistency with sound_manager.gd - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - js.eval(script) - else: - print("JavaScriptBridge singleton not available") - - static func onMissionStarted(mission_data: Dictionary): - if not OS.has_feature("web"): - return - - print("Sending mission started event for mission: " + str(mission_data.get("id", "unknown"))) - var mission_json = JSON.stringify(mission_data) - var script = """ - (function() { - try { - if (window.parent) { - console.log('Sending missionStarted message to parent window'); - window.parent.postMessage({ - type: 'stemCity_missionStarted', - data: %s, - source: 'godot-game', - timestamp: Date.now() - }, '*'); - } else { - console.log('No parent window found for missionStarted event'); - } - } catch (e) { - console.error('Error sending missionStarted via postMessage:', e); - } - })(); - """ % mission_json - - # Use Engine.get_singleton for consistency with sound_manager.gd - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - js.eval(script) - else: - print("JavaScriptBridge singleton not available") - - static func onMissionCompleted(mission_data: Dictionary): - if not OS.has_feature("web"): - return - - print("Sending mission completed event for mission: " + str(mission_data.get("id", "unknown"))) - var mission_json = JSON.stringify(mission_data) - var script = """ - (function() { - try { - if (window.parent) { - console.log('Sending missionCompleted message to parent window'); - window.parent.postMessage({ - type: 'stemCity_missionCompleted', - data: %s, - source: 'godot-game', - timestamp: Date.now() - }, '*'); - } else { - console.log('No parent window found for missionCompleted event'); - } - } catch (e) { - console.error('Error sending missionCompleted via postMessage:', e); - } - })(); - """ % mission_json - - # Use Engine.get_singleton for consistency with sound_manager.gd - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - js.eval(script) - else: - print("JavaScriptBridge singleton not available") - - static func onAllMissionsCompleted(): - if not OS.has_feature("web"): - return - - print("Sending all missions completed event") - var script = """ - (function() { - try { - if (window.parent) { - console.log('Sending allMissionsCompleted message to parent window'); - window.parent.postMessage({ - type: 'stemCity_allMissionsCompleted', - source: 'godot-game', - timestamp: Date.now() - }, '*'); - } else { - console.log('No parent window found for allMissionsCompleted event'); - } - } catch (e) { - console.error('Error sending allMissionsCompleted via postMessage:', e); - } - })(); - """ - - # Use Engine.get_singleton for consistency with sound_manager.gd - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - js.eval(script) - else: - print("JavaScriptBridge singleton not available") - - static func sendCompanionDialog(key: String, dialog_data: Dictionary): - if not OS.has_feature("web"): - return - - print("Sending companion dialog for key: " + key) - var dialog_json = JSON.stringify(dialog_data) - var script = """ - (function() { - try { - if (window.parent) { - console.log('Sending companion dialog to parent window'); - window.parent.postMessage({ - type: 'stemCity_companionDialog', - key: '%s', - data: %s, - source: 'godot-game', - timestamp: Date.now() - }, '*'); - } else { - console.log('No parent window found for companion dialog'); + }; + + // Set up message listener + window.addEventListener('message', function(event) { + console.log('Received message:', event.data); + + // Handle the message + if (event.data && event.data.type) { + switch(event.data.type) { + case 'cityBuilder_init': + console.log('Received init data:', event.data.data); + window.godot_interface.emit_signal('init_data_received', event.data.data); + break; + case 'cityBuilder_init_check': + console.log('Received init check'); + window.godot_interface.emit_signal('init_check_received'); + break; + case 'mission_progress_updated': + window.godot_interface.emit_signal('mission_progress_updated', event.data.data); + break; + case 'mission_completed': + window.godot_interface.emit_signal('mission_completed', event.data.data); + break; + case 'open_react_graph': + window.godot_interface.emit_signal('open_react_graph', event.data.data); + break; + case 'open_react_table': + window.godot_interface.emit_signal('open_react_table', event.data.data); + break; + } } - } catch (e) { - console.error('Error sending companion dialog via postMessage:', e); - } - })(); - """ % [key, dialog_json] - - # Use Engine.get_singleton for consistency with sound_manager.gd - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - js.eval(script) - else: - print("JavaScriptBridge singleton not available") + }); + """) + + # Set up the interface + _interface = JavaScript.get_interface() + print("JavaScript interface initialized") + + # Set up callbacks in JavaScript + JavaScript.JavaScriptGlobal.eval(""" + window.godot_interface._callbacks.init_data_received = function(data) { + console.log('Emitting init_data_received signal with data:', data); + // Don't re-emit the signal to avoid recursion + window.godot_interface._callbacks.init_data_received = null; + }; + window.godot_interface._callbacks.init_check_received = function() { + console.log('Emitting init_check_received signal'); + // Don't re-emit the signal to avoid recursion + window.godot_interface._callbacks.init_check_received = null; + }; + window.godot_interface._callbacks.mission_progress_updated = function(data) { + window.godot_interface.emit_signal('mission_progress_updated', data); + }; + window.godot_interface._callbacks.mission_completed = function(data) { + window.godot_interface.emit_signal('mission_completed', data); + }; + window.godot_interface._callbacks.open_react_graph = function(data) { + window.godot_interface.emit_signal('open_react_graph', data); + }; + window.godot_interface._callbacks.open_react_table = function(data) { + window.godot_interface.emit_signal('open_react_table', data); + }; + """) + print("JavaScript callbacks set up") + + # Process any pending signals + _process_pending_signals() - # Handle audio actions via JavaScript - static func handle_audio_action(action: String, sound_name: String = "", volume: float = -1.0): - if not OS.has_feature("web"): - return false - - print("Handling audio action via JavaScript bridge: " + action) - - var action_data = { - "action": action, - "sound": sound_name, - } - - if volume >= 0.0: - action_data["volume"] = volume - - var action_json = JSON.stringify(action_data) - var script = """ - (function() { - try { - if (window.parent) { - console.log('Sending audio action to parent window:', %s); - window.parent.postMessage({ - type: 'stemCity_audio', - data: %s, - source: 'godot-game', - timestamp: Date.now() - }, '*'); - return true; - } else { - console.log('No parent window found for audio action'); - return false; - } - } catch (e) { - console.error('Error sending audio action via postMessage:', e); - return false; - } - })(); - """ % [action_json, action_json] - - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - return js.eval(script) - else: - print("JavaScriptBridge singleton not available") - return false - - # Helper method to ensure the sound manager's audio is initialized - # Call this method after user interaction to ensure audio works - static func ensure_audio_initialized(): - if not OS.has_feature("web"): - return true # Audio always works on non-web platforms - - print("Ensuring audio is initialized via JavaScript bridge") - - # Setup audio message listener if it's not already set up - setup_audio_message_listener() - - # Try to initialize audio through the sound manager if it exists - var sound_manager = _get_sound_manager() - - if sound_manager and sound_manager.has_method("init_web_audio_from_js"): - print("Found SoundManager, calling init_web_audio_from_js") - sound_manager.init_web_audio_from_js() - - # Follow up with direct JavaScript audio context unlocking for extra reliability - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - _run_audio_unlock_script(js) - - return true - else: - # Fallback: directly try to unlock web audio using JavaScript - if Engine.has_singleton("JavaScriptBridge"): - var js = Engine.get_singleton("JavaScriptBridge") - var result = _run_audio_unlock_script(js) - return result - else: - print("JavaScriptBridge singleton not available for audio initialization") - return false - - # Helper method to run the audio unlocking script with maximum compatibility - static func _run_audio_unlock_script(js_interface): - var script = """ - (function() { - var result = false; - try { - // Simple approach to unlock audio - console.log('Running simplified audio unlock'); - - // Create audio context if needed - if (!window._godotAudioContext) { - window._godotAudioContext = new (window.AudioContext || window.webkitAudioContext)(); - } - - var audioCtx = window._godotAudioContext; - console.log('Audio context state:', audioCtx.state); - - // Resume it (for Chrome/Safari) - if (audioCtx.state === 'suspended') { - audioCtx.resume(); - } - - // Play a short, quiet beep - var oscillator = audioCtx.createOscillator(); - var gainNode = audioCtx.createGain(); - gainNode.gain.value = 0.01; // Very quiet - oscillator.connect(gainNode); - gainNode.connect(audioCtx.destination); - oscillator.start(0); - oscillator.stop(0.1); - - // Add event listeners for future interactions - ['click', 'touchstart', 'touchend'].forEach(function(event) { - document.addEventListener(event, function() { - if (audioCtx.state === 'suspended') { - audioCtx.resume(); - } - }, {once: false}); - }); - - result = audioCtx.state === 'running'; - } catch (e) { - console.error("JavaScript bridge: Audio unlock error:", e); - result = false; - } - return result; - })() - """ - -# var result = js_interface.eval(script) -# print("JavaScript audio initialization result:", result) -# return result - - # Setup audio message listener from JavaScript - static func setup_audio_message_listener(): - if not OS.has_feature("web"): - return false - - print("Setting up audio message listener via JavaScript bridge") - - if not Engine.has_singleton("JavaScriptBridge"): - print("JavaScriptBridge singleton not available") - return false - - var js = Engine.get_singleton("JavaScriptBridge") - - # Register the callback function - js.set_callback("godot_audio_callback", Callable(_get_sound_manager(), "process_js_audio_state")) - - # Set up a listener for audio state messages - var script = """ - (function() { - // Set up message listener if not already done - if (!window.godot_audio_listener_initialized) { - window.addEventListener('message', function(event) { - if (event.data && event.data.type === 'stemCity_audio_state') { - console.log('Godot received audio state:', event.data); - // Call our Godot callback with the state data - if (typeof godot_audio_callback === 'function') { - console.log('Sending audio state to Godot'); - godot_audio_callback(event.data.data); - } else { - console.warn('godot_audio_callback is not available'); - } - } - }); - - console.log('Audio message listener initialized'); - window.godot_audio_listener_initialized = true; - - // Request initial audio state from parent - window.parent.postMessage({ - type: 'stemCity_audio', - data: { action: 'GET_STATE' }, - source: 'godot-game', - timestamp: Date.now() - }, '*'); - - return true; - } - return false; - })(); - """ - - var result = js.eval(script) - print("Audio message listener setup result: ", result) - return result - - # Helper to get the sound manager instance - static func _get_sound_manager(): - var sound_manager = null - - # Try to find using meta - if Engine.get_main_loop().has_meta("sound_manager"): - sound_manager = Engine.get_main_loop().get_meta("sound_manager") +func _process_pending_signals(): + if _pending_signals.size() > 0: + print("Processing pending signals...") + for signal_data in _pending_signals: + emit_signal(signal_data.signal_name, signal_data.data) + _pending_signals.clear() + print("All pending signals processed") + +# Static methods for interface checks +static func has_interface() -> bool: + return JavaScript.has_interface() + +static func get_interface(): + return JavaScript.get_interface() + +func send_signal(signal_name: String, data = null): + if JavaScript.has_interface(): + if _interface and _interface.has_method("emit_signal"): + _interface.emit_signal(signal_name, data) else: - # Try to find in scene tree - var scene_tree = Engine.get_main_loop() as SceneTree - if scene_tree: - sound_manager = scene_tree.root.get_node_or_null("/root/SoundManager") - - return sound_manager + _pending_signals.append({"signal_name": signal_name, "data": data}) + else: + _pending_signals.append({"signal_name": signal_name, "data": data}) + +func send_mission_progress(mission_id: String, objective_index: int, current_count: int, target_count: int): + send_signal("mission_progress_updated", { + "mission_id": mission_id, + "objective_index": objective_index, + "current_count": current_count, + "target_count": target_count + }) + +func send_mission_completed(mission_id: String): + send_signal("mission_completed", { + "mission_id": mission_id + }) + +func send_open_graph(graph_data: Dictionary): + send_signal("open_react_graph", graph_data) + +func send_open_table(table_data: Dictionary): + send_signal("open_react_table", table_data) + +func send_companion_dialog(dialog_type: String, dialog_data: Dictionary): + send_signal("companion_dialog", { + "type": dialog_type, + "data": dialog_data + }) + +func send_audio_action(action: String, data: Dictionary = {}): + send_signal("audio_action", { + "action": action, + "data": data + }) diff --git a/scripts/javascript_global.gd b/scripts/javascript_global.gd new file mode 100644 index 0000000..64ed485 --- /dev/null +++ b/scripts/javascript_global.gd @@ -0,0 +1,93 @@ +extends Node + +# JavaScript global class for handling JavaScript functionality +class_name JavaScript + +# Check if JavaScript is available +static func has_interface() -> bool: + # Check if running in a web environment + if OS.has_feature("web"): + print("Running in web environment, JavaScript should be available") + + # Double-check by evaluating a simple script + if Engine.has_singleton("JavaScriptBridge"): + var js = Engine.get_singleton("JavaScriptBridge") + var test_result = js.eval("!!window && typeof window !== 'undefined'") + print("JavaScript test result: " + str(test_result)) + return test_result != null + else: + print("JavaScriptBridge singleton not available, running in editor or non-web platform") + else: + print("Not running in web environment") + + return false + +# Get the JavaScript interface +static func get_interface(): + if has_interface(): + return JavaScriptGlobal + return null + +# JavaScriptGlobal is a mock class that provides fallback implementations +# for platforms that don't support JavaScript +class JavaScriptGlobal: + # Check if a JavaScript function exists + static func has_function(function_name: String) -> bool: + if not OS.has_feature("web"): + return false + + print("Checking if function exists: " + function_name) + var script = "typeof %s === 'function'" % function_name + + # Use Engine.get_singleton for consistency with sound_manager.gd + if Engine.has_singleton("JavaScriptBridge"): + var js = Engine.get_singleton("JavaScriptBridge") + var result = js.eval(script) + + # If result is null, the JavaScript eval failed + if result == null: + print("JavaScript eval failed when checking for function: " + function_name) + return false + + print("Function check result for " + function_name + ": " + str(result)) + return result + else: + print("JavaScriptBridge singleton not available") + return false + + # Evaluate JavaScript code + static func eval(script: String): + if not OS.has_feature("web"): + return null + + # Use Engine.get_singleton for consistency with sound_manager.gd + if Engine.has_singleton("JavaScriptBridge"): + var js = Engine.get_singleton("JavaScriptBridge") + return js.eval(script) + else: + print("JavaScriptBridge singleton not available") + return null + + # Call a JavaScript function with arguments + static func call_js_function(function_name: String, args = []): + if not OS.has_feature("web"): + return null + + var formatted_args = [] + for arg in args: + if arg is String: + formatted_args.append("\"%s\"" % arg.replace("\"", "\\\"")) + elif arg is Dictionary or arg is Array: + formatted_args.append(JSON.stringify(arg)) + else: + formatted_args.append(str(arg)) + + var script = "%s(%s)" % [function_name, ",".join(formatted_args)] + + # Use Engine.get_singleton for consistency with sound_manager.gd + if Engine.has_singleton("JavaScriptBridge"): + var js = Engine.get_singleton("JavaScriptBridge") + return js.eval(script) + else: + print("JavaScriptBridge singleton not available") + return null \ No newline at end of file diff --git a/scripts/lesson_manager.gd.uid b/scripts/lesson_manager.gd.uid new file mode 100644 index 0000000..c1390eb --- /dev/null +++ b/scripts/lesson_manager.gd.uid @@ -0,0 +1 @@ +uid://djghkkucobwfl diff --git a/scripts/lesson_test.gd.uid b/scripts/lesson_test.gd.uid new file mode 100644 index 0000000..33057b2 --- /dev/null +++ b/scripts/lesson_test.gd.uid @@ -0,0 +1 @@ +uid://s05virx2cxsi diff --git a/scripts/mission/building_construction_manager.gd b/scripts/mission/building_construction_manager.gd index 9af12b0..4dd4250 100644 --- a/scripts/mission/building_construction_manager.gd +++ b/scripts/mission/building_construction_manager.gd @@ -12,6 +12,7 @@ signal worker_construction_ended const CONSTRUCTION_TIME = 10.0 # seconds to build a building +var debug_timer = 0.0 # Add debug timer # References to necessary scenes and resources @@ -29,12 +30,23 @@ var mission_manager: MissionManager var construction_sites = {} # position (Vector3) -> construction data (dict) func _ready(): + print("\n=== Initializing Building Construction Manager ===") # Load the worker character scene - add more fallbacks to ensure we get a valid model builder = get_node_or_null('/root/Main/Builder') worker_scene = load("res://people/character-male-a.glb") hud_manager = get_node_or_null("/root/Main/CanvasLayer/HUD") mission_manager = builder.get_node_or_null("/root/Main/MissionManager") + + # Get navigation region + if builder and builder.nav_region: + nav_region = builder.nav_region + print("Found navigation region with ", nav_region.get_child_count(), " children") + for child in nav_region.get_children(): + print("Nav region child: ", child.name) + else: + print("WARNING: No navigation region found!") + if not worker_scene: worker_scene = load("res://people/character-female-a.glb") if not worker_scene: @@ -54,10 +66,17 @@ func _ready(): if not final_building_scene: # Create an empty PackedScene as a last resort final_building_scene = PackedScene.new() + + print("=== Building Construction Manager Initialized ===\n") # Call this method to start construction at a position func start_construction(position: Vector3, structure_index: int, rotation_basis = null): + print("\n=== Starting Construction ===") + print("Position: ", position) + print("Structure Index: ", structure_index) + if position in construction_sites: + print("ERROR: Construction site already exists at this position!") return # Get the current selector rotation if available @@ -70,6 +89,8 @@ func start_construction(position: Vector3, structure_index: int, rotation_basis if builder.gridmap: rotation_index = builder.gridmap.get_orthogonal_index_from_basis(rotation_basis) + print("Rotation Index: ", rotation_index) + # Create a construction site entry construction_sites[position] = { "position": position, @@ -78,10 +99,12 @@ func start_construction(position: Vector3, structure_index: int, rotation_basis "worker": null, "timer": 0.0, "completed": false, - "rotation_index": rotation_index, # Store the rotation for later use - "rotation_basis": rotation_basis # Store the rotation basis + "rotation_index": rotation_index, + "rotation_basis": rotation_basis } + print("Created construction site entry") + # Place plot marker (outline/transparent version of the building) var plot @@ -89,14 +112,17 @@ func start_construction(position: Vector3, structure_index: int, rotation_basis if structure_index >= 0 and structure_index < builder.structures.size(): var structure = builder.structures[structure_index] plot = structure.model.instantiate() + print("Created plot using structure model: ", structure.model.resource_path) else: # Fallback to default building model plot = building_plot_scene.instantiate() + print("Created plot using fallback model") plot.name = "Plot_" + str(int(position.x)) + "_" + str(int(position.z)) # Make it a transparent outline by applying transparency to all materials - _make_model_transparent(plot, 0.3) # More transparent (0.3 instead of 0.5) + _make_model_transparent(plot, 0.3) + print("Applied transparent material to plot") # Add to the scene and position it builder.add_child(plot) @@ -106,34 +132,17 @@ func start_construction(position: Vector3, structure_index: int, rotation_basis if rotation_basis: plot.basis = rotation_basis - plot.scale = Vector3(3.0, 3.0, 3.0) # Scale to match other buildings + plot.scale = Vector3(3.0, 3.0, 3.0) + print("Added plot to scene at position: ", position) # Store reference construction_sites[position]["plot"] = plot - # Check if we should spawn a worker based on structure type - var should_spawn_worker = false - - if structure_index >= 0 and structure_index < builder.structures.size(): - var structure = builder.structures[structure_index] - - # Check if this structure type should spawn a builder - if structure.spawn_builder: - should_spawn_worker = true - else: - # Default to true if we can't determine the structure type - should_spawn_worker = true - - # Find a road position to spawn the worker if needed - if should_spawn_worker: - _spawn_worker_for_construction(position) - else: - # For structures without workers, start a timer to complete construction automatically - var timer = get_tree().create_timer(CONSTRUCTION_TIME) - timer.timeout.connect(func(): _complete_construction(position)) + # Always spawn a worker for construction + _spawn_worker_for_construction(position) + print("=== Construction Started ===\n") # Send building_selected dialog to learning companion if available in the current mission - var mission_manager = builder.get_node_or_null("/root/Main/MissionManager") if mission_manager and mission_manager.current_mission and mission_manager.learning_companion_connected: var mission = mission_manager.current_mission @@ -156,6 +165,7 @@ func start_construction(position: Vector3, structure_index: int, rotation_basis # Process active construction sites func _process(delta): var sites_to_complete = [] + debug_timer += delta # Track total time # Update all construction sites for pos in construction_sites.keys(): @@ -178,48 +188,63 @@ func _process(delta): # Update the construction preview shader progress if site["plot"] != null: var progress = site["timer"] / build_time + progress = clamp(progress, 0.0, 1.0) + # Find all mesh instances and update their materials var mesh_instances = [] _find_all_mesh_instances(site["plot"], mesh_instances) for mesh_instance in mesh_instances: for i in range(mesh_instance.get_surface_override_material_count()): var material = mesh_instance.get_surface_override_material(i) - if material: + if material and material is ShaderMaterial: material.set_shader_parameter("progress", progress) - + material.set_shader_parameter("alpha", 0.3) + # Check if construction is complete if site["timer"] >= build_time: sites_to_complete.append(pos) # Complete construction for sites that are done for pos in sites_to_complete: + print("\n=== Completing Construction ===") + print("Position: ", pos) _complete_construction(pos) # Find a road and spawn a worker there func _spawn_worker_for_construction(target_position: Vector3): + print("\n=== Attempting to Spawn Worker ===") + print("Target Position: ", target_position) + # Find closest road tile var road_position = _find_nearest_road(target_position) if road_position == Vector3.ZERO: print("ERROR: No road found for worker spawn at target position: ", target_position) - # Force completion immediately without worker since we can't spawn one - var timer = get_tree().create_timer(0.5) - timer.timeout.connect(func(): _complete_construction(target_position)) + print("Checking navigation region...") + if nav_region: + print("Nav region has ", nav_region.get_child_count(), " children") + for child in nav_region.get_children(): + print("Child: ", child.name) + else: + print("Nav region is null!") + # Don't force completion - let the timer run normally return - print("DEBUG: Spawning worker at road position: ", road_position, " for target: ", target_position) + print("Found road position: ", road_position) + print("Distance to target: ", road_position.distance_to(target_position)) + # Create the worker var worker = _create_worker(road_position, target_position) if worker == null: print("ERROR: Failed to create worker for construction at: ", target_position) - # Force completion immediately without worker - var timer = get_tree().create_timer(0.5) - timer.timeout.connect(func(): _complete_construction(target_position)) + # Don't force completion - let the timer run normally return # Store in the construction site data construction_sites[target_position]["worker"] = worker + print("Worker spawned successfully") + print("=== Worker Spawn Complete ===\n") # Find nearest road (simplified version of what's in mission_manager.gd) func _find_nearest_road(position: Vector3) -> Vector3: @@ -316,6 +341,7 @@ func _on_worker_construction_started(): func _on_worker_construction_ended(): # Forward the signal for mission managers/other systems that need it worker_construction_ended.emit() + func update_population(count: int): Globals.set_population_count(count) @@ -324,21 +350,34 @@ func update_population(count: int): # Complete construction at a position func _complete_construction(position: Vector3): + print("\n=== Completing Construction Process ===") + print("Position: ", position) + if not position in construction_sites: + print("ERROR: No construction site found at position!") return var site = construction_sites[position] + print("Found construction site") + + # Verify the timer has reached the build time + var build_time = CONSTRUCTION_TIME + if site["structure_index"] >= 0 and site["structure_index"] < builder.structures.size(): + var structure = builder.structures[site["structure_index"]] + if "build_time" in structure: + build_time = structure.build_time + + if site["timer"] < build_time: + print("WARNING: Construction completing before timer is done!") + return # Mark as completed site["completed"] = true - - # Remove placeholder plot - if site["plot"] != null: - site["plot"].queue_free() - site["plot"] = null + print("Marked as completed") # Stop worker and send back to a road if site["worker"] != null: + print("Stopping worker") if site["worker"].has_method("finish_construction"): site["worker"].finish_construction() else: @@ -346,32 +385,41 @@ func _complete_construction(position: Vector3): site["worker"].queue_free() site["worker"] = null + # Remove placeholder plot + if site["plot"] != null: + print("Removing plot") + site["plot"].queue_free() + site["plot"] = null + # Place the final building + print("Placing final building") _place_final_building(position, site["structure_index"]) - # Update mission objective now that construction is complete -# _update_mission_objective_on_completion(site["structure_index"]) - # Check if we should spawn a resident (only for residential buildings) var mission_manager = builder.get_node_or_null("/root/Main/MissionManager") var should_spawn_resident = false # Only spawn residents for residential buildings - var structure = builder.structures[site["structure_index"]] if structure.type == Structure.StructureType.RESIDENTIAL_BUILDING: - should_spawn_resident = true + should_spawn_resident = true # Spawn a resident from the new residential building if appropriate if should_spawn_resident: + print("Spawning resident") _spawn_resident_from_building(position) if structure.type == Structure.StructureType.RESIDENTIAL_BUILDING and structure.population_count > 0: - update_population(structure.population_count) -# + update_population(structure.population_count) # Emit completion signal + print("Emitting completion signal") construction_completed.emit(position) + + # Remove from construction sites + print("Removing from construction sites") + construction_sites.erase(position) + print("=== Construction Process Complete ===\n") # Function to handle building demolition at a position func handle_demolition(position: Vector3): @@ -395,13 +443,19 @@ func handle_demolition(position: Vector3): # Place the final building at the construction site func _place_final_building(position: Vector3, structure_index: int): + print("\n=== Placing Final Building ===") + print("Position: ", position) + print("Structure Index: ", structure_index) + # Create the final building using the actual selected structure model var building if structure_index >= 0 and structure_index < builder.structures.size(): building = builder.structures[structure_index].model.instantiate() + print("Created building using structure model: ", builder.structures[structure_index].model.resource_path) else: - # Fallback to our default model if structure index is invalid + # Fallback to default building model building = final_building_scene.instantiate() + print("Created building using fallback model") building.name = "Building_" + str(int(position.x)) + "_" + str(int(position.z)) @@ -415,10 +469,15 @@ func _place_final_building(position: Vector3, structure_index: int): if "rotation_basis" in site and site["rotation_basis"]: building.basis = site["rotation_basis"] - building.scale = Vector3(3.0, 3.0, 3.0) # Scale to match other buildings + building.scale = Vector3(3.0, 3.0, 3.0) + print("Added building to scene") + + # Add to gridmap for collision detection and mission tracking + if builder.gridmap: + print("Adding to gridmap") + builder.gridmap.set_cell_item(position, structure_index, builder.gridmap.get_orthogonal_index_from_basis(building.basis)) # Send placement_success dialog to learning companion if available in the current mission - var mission_manager = builder.get_node_or_null("/root/Main/MissionManager") if mission_manager and mission_manager.current_mission and mission_manager.learning_companion_connected: var mission = mission_manager.current_mission diff --git a/scripts/mission/fixed_handling.gd b/scripts/mission/fixed_handling.gd index cda133a..ae9917f 100644 --- a/scripts/mission/fixed_handling.gd +++ b/scripts/mission/fixed_handling.gd @@ -1,38 +1,60 @@ extends Node # Simple function to handle structure unlocking for missions -static func process_structures(structures, mission_id): +static func process_structures(structures, mission): + print("\n=== Processing Structures for Mission: ", mission.id, " ===") + print("Starting Structures: ", mission.starting_structures) + print("Unlocked Items: ", mission.unlocked_items) + for structure in structures: + print("\n--- Processing Structure: ", structure.model.resource_path, " ---") + print("Initial status: ", structure.unlocked) + # Default is locked structure.unlocked = false + print("After default lock: ", structure.unlocked) + + # Handle starting structures (always available for this mission) + if mission.starting_structures != null: + print("Checking starting structures: ", mission.starting_structures) + for item in mission.starting_structures: + if structure.model.resource_path == item or structure.resource_path == item: + print("Found matching starting structure: ", item) + structure.unlocked = true + print("After starting structures check: ", structure.unlocked) + break - # Handle basic structures (always available) + # Handle unlocked items (unlocked from previous missions) + if mission.unlocked_items != null: + print("Checking unlocked items: ", mission.unlocked_items) + for item in mission.unlocked_items: + if structure.model.resource_path == item or structure.resource_path == item: + print("Found matching unlocked item: ", item) + structure.unlocked = true + print("After unlocked items check: ", structure.unlocked) + break + + # Check if it's a basic structure if basic_structure(structure): + print("Structure is marked as basic") structure.unlocked = true + print("After basic structure check: ", structure.unlocked) - # Handle mission-specific structures - if mission_id == "1": - # Mission 1: Unlock residential buildings - if residential_building(structure): - structure.unlocked = true - - elif mission_id == "2" or mission_id == "3": - # Missions 2-3: Unlock curved roads and decoration - if curved_road(structure) or decoration(structure): - structure.unlocked = true - - elif mission_id == "4" or mission_id == "5": - # Missions 4-5: Unlock power plants - if power_plant(structure): - structure.unlocked = true + print("Final status: ", structure.unlocked) + print("--- End Structure Processing ---\n") # Simple helper functions to categorize structures static func basic_structure(structure): var path = structure.model.resource_path - return path.contains("road-straight") or path.contains("pavement") + # Only consider the exact road-straight.tres as basic + return path == "res://structures/road-straight.tres" or path.contains("pavement") static func residential_building(structure): - return structure.model.resource_path.contains("building-small-a") + var path = structure.model.resource_path + var res_path = structure.resource_path if structure.has("resource_path") else "" + var is_residential = path.contains("building-small-a") or res_path.contains("building-small-a") + print("Checking if residential: ", path, " or ", res_path, " = ", is_residential) + return is_residential static func curved_road(structure): return structure.model.resource_path.contains("road-corner") diff --git a/scripts/mission/handle_structure_unlocking.gd b/scripts/mission/handle_structure_unlocking.gd index faa062e..ac0df77 100644 --- a/scripts/mission/handle_structure_unlocking.gd +++ b/scripts/mission/handle_structure_unlocking.gd @@ -5,17 +5,14 @@ extends Node # Unlocks basic structures and locks special ones func process_structures(structures_array): - # Start with all unlocked + # Start with all locked for structure in structures_array: - # Basic structures are always unlocked - if basic_structure(structure): - structure.unlocked = true # Special structures start locked unless mission-specific - elif special_structure(structure): + if special_structure(structure): structure.unlocked = false else: - # Default to unlocked for other structures - structure.unlocked = true + # Default to locked for other structures + structure.unlocked = false # Check if this is a mission-dependent structure type that should be unlocked func unlock_by_mission(structures_array, mission_id): @@ -35,13 +32,6 @@ func unlock_by_mission(structures_array, mission_id): if structure.model.resource_path.contains("power_plant"): structure.unlocked = true -# Check if a structure is one of the basic types (always available) -func basic_structure(structure): - return (structure.model.resource_path.contains("road-straight") or - structure.model.resource_path.contains("building-small-a") or - structure.model.resource_path.contains("pavement") or - structure.model.resource_path.contains("grass.glb")) - # Check if a structure is a special type (requires unlocking) func special_structure(structure): return (structure.model.resource_path.contains("road-corner") or @@ -59,8 +49,7 @@ func select_unlocked_structure(builder): found_unlocked = true break - # If no structures are unlocked, unlock a basic one + # If no structures are unlocked, use the first structure if not found_unlocked and builder.structures.size() > 0: - builder.structures[0].unlocked = true builder.index = 0 builder.update_structure() \ No newline at end of file diff --git a/scripts/mission/learning_panel.gd b/scripts/mission/learning_panel.gd index a6e7b9c..7d9c36e 100644 --- a/scripts/mission/learning_panel.gd +++ b/scripts/mission/learning_panel.gd @@ -32,7 +32,7 @@ func _ready(): # Only get references needed for signal connections user_input = get_node_or_null("PanelContainer/MarginContainer/ScrollContainer/VBoxContainer/MainContent/UserInputContainer/UserInput") - submit_button = get_node_or_null("PanelContainer/MarginContainer/ScrollContainer/VBoxContainer/SubmitButtonContainer/SubmitButton") + submit_button = get_node_or_null("PanelContainer/MarginContainer/ScrollContainer/VBoxContainer/MainContent/UserInputContainer/SubmitButton") # Clear the user inputs array user_inputs = [] @@ -46,69 +46,73 @@ func _ready(): push_error("Submit button not found in learning panel") func show_learning_panel(mission_data: MissionData): - # Check if the mission data is valid - if mission_data == null: - push_error("Invalid mission data provided to learning panel") - return - - mission = mission_data - - # Make panel fully visible and ensure process mode is set to handle input while paused - visible = true - process_mode = Node.PROCESS_MODE_ALWAYS - - # First, reset the panel to a clean state - _reset_panel() - - # Use traditional text and graph mode - _setup_traditional_mode() - - # Set up the correct answer from mission data - if not mission.correct_answer.is_empty(): - correct_answer = mission.correct_answer - else: - # Default answer based on mission type - correct_answer = "1" if not mission.power_math_content.is_empty() else "A" - - # Set up user input fields based on mission data - if mission.num_of_user_inputs > 1: - _setup_multiple_user_inputs() - # Set focus to the first input field after a short delay - get_tree().create_timer(0.2).timeout.connect(func(): - if user_inputs.size() > 0 and user_inputs[0]: - user_inputs[0].grab_focus() - print("Set focus to the first input field in multi-input") - ) - else: - # Traditional single input - if user_input: - user_input.placeholder_text = mission.question_text if not mission.question_text.is_empty() else "Enter your answer" - # Set focus to the single input field after a short delay - get_tree().create_timer(0.2).timeout.connect(func(): - user_input.grab_focus() - print("Set focus to the single input field") - ) - - # Hide the HUD when learning panel is shown - var hud = get_node_or_null("/root/Main/CanvasLayer/HUD") - if hud: - hud.visible = false - - # Make sure we're on top - if get_parent(): - get_parent().move_child(self, get_parent().get_child_count() - 1) - - # Make sure we're at the proper z-index - z_index = 100 - - # Disable background interaction by creating a fullscreen invisible barrier - _disable_background_interaction() - - # Emit signal to lock building controls - panel_opened.emit() - - print("Panel is now visible = ", visible) - + # Disabled learning panel + return + + # Original code commented out + ## Check if the mission data is valid + #if mission_data == null: + # push_error("Invalid mission data provided to learning panel") + # return + # + #mission = mission_data + # + ## Make panel fully visible and ensure process mode is set to handle input while paused + #visible = true + #process_mode = Node.PROCESS_MODE_ALWAYS + # + ## First, reset the panel to a clean state + #_reset_panel() + # + ## Use traditional text and graph mode + #_setup_traditional_mode() + # + ## Set up the correct answer from mission data + #if not mission.correct_answer.is_empty(): + # correct_answer = mission.correct_answer + #else: + # # Default answer based on mission type + # correct_answer = "1" if not mission.power_math_content.is_empty() else "A" + # + ## Set up user input fields based on mission data + #if mission.num_of_user_inputs > 1: + # _setup_multiple_user_inputs() + # # Set focus to the first input field after a short delay + # get_tree().create_timer(0.2).timeout.connect(func(): + # if user_inputs.size() > 0 and user_inputs[0]: + # user_inputs[0].grab_focus() + # print("Set focus to the first input field in multi-input") + # ) + #else: + # # Traditional single input + # if user_input: + # user_input.placeholder_text = mission.question_text if not mission.question_text.is_empty() else "Enter your answer" + # # Set focus to the single input field after a short delay + # get_tree().create_timer(0.2).timeout.connect(func(): + # user_input.grab_focus() + # print("Set focus to the single input field") + # ) + # + ## Hide the HUD when learning panel is shown + #var hud = get_node_or_null("/root/Main/CanvasLayer/HUD") + #if hud: + # hud.visible = false + # + ## Make sure we're on top + #if get_parent(): + # get_parent().move_child(self, get_parent().get_child_count() - 1) + # + ## Make sure we're at the proper z-index + #z_index = 100 + # + ## Disable background interaction by creating a fullscreen invisible barrier + #_disable_background_interaction() + # + ## Emit signal to lock building controls + #panel_opened.emit() + # + #print("Panel is now visible = ", visible) + # Creates an invisible fullscreen barrier to block clicks on the background func _disable_background_interaction(): # Remove any existing barrier diff --git a/scripts/mission/learning_panel_main.gd b/scripts/mission/learning_panel_main.gd index d558abc..57eecd7 100644 --- a/scripts/mission/learning_panel_main.gd +++ b/scripts/mission/learning_panel_main.gd @@ -270,4 +270,4 @@ func _on_complete_button_pressed(): hide_learning_panel() # Emit signal - completed.emit() \ No newline at end of file + completed.emit() diff --git a/scripts/mission/lesson_data.gd.uid b/scripts/mission/lesson_data.gd.uid new file mode 100644 index 0000000..95fe97e --- /dev/null +++ b/scripts/mission/lesson_data.gd.uid @@ -0,0 +1 @@ +uid://d1ndmeoogiuf4 diff --git a/scripts/mission/lesson_loader.gd.uid b/scripts/mission/lesson_loader.gd.uid new file mode 100644 index 0000000..b86b67b --- /dev/null +++ b/scripts/mission/lesson_loader.gd.uid @@ -0,0 +1 @@ +uid://nujnbtcf5kkf diff --git a/scripts/mission/mission_config.gd.uid b/scripts/mission/mission_config.gd.uid new file mode 100644 index 0000000..d3a44eb --- /dev/null +++ b/scripts/mission/mission_config.gd.uid @@ -0,0 +1 @@ +uid://cuuydsps7ubth diff --git a/scripts/mission/mission_data.gd b/scripts/mission/mission_data.gd index 1dbc078..3099c83 100644 --- a/scripts/mission/mission_data.gd +++ b/scripts/mission/mission_data.gd @@ -20,4 +20,4 @@ class_name MissionData @export var input_labels: Array[String] = [] # Labels for each input field @export var companion_dialog: Dictionary = {} # Map of event keys to dialog entries for the learning companion @export var unlocked_items: Array[String] = [] # Array of structure resource paths that get unlocked after mission completion - +@export var starting_structures: Array[String] = [] # Array of structure resource paths that are unlocked when this mission starts diff --git a/scripts/mission/mission_loader.gd b/scripts/mission/mission_loader.gd new file mode 100644 index 0000000..8dcd17e --- /dev/null +++ b/scripts/mission/mission_loader.gd @@ -0,0 +1,197 @@ +extends Node +class_name MissionLoader + +const MissionData = preload("res://scripts/mission/mission_data.gd") +const MissionObjective = preload("res://scripts/mission/mission_objective.gd") + +var mission_manager: MissionManager +var builder: Node3D + +func _init(manager: MissionManager, builder_ref: Node3D): + mission_manager = manager + builder = builder_ref + +# Load mission data from JavaScript +func load_from_js(mission_data: Dictionary) -> void: + print("\n=== Loading Mission Data from JavaScript ===") + print("Received mission data:", mission_data) + + if not mission_data: + print("WARNING: No mission data received from JavaScript") + return + + print("Converting mission data to Godot objects...") + if "missions" in mission_data: + var missions = _convert_missions(mission_data.missions) + print("Converted missions:", missions) + print("Number of missions converted: ", missions.size()) + + if missions.is_empty(): + print("WARNING: No missions were converted from the data") + return + + print("Setting up missions...") + mission_manager.missions = missions + print("Missions set in manager. Current missions array size: ", mission_manager.missions.size()) + if mission_manager.missions.size() > 0: + print("First mission details:") + print(" Title: ", mission_manager.missions[0].title) + print(" Description: ", mission_manager.missions[0].description) + print(" Number of objectives: ", mission_manager.missions[0].objectives.size()) + print("=== Mission Data Loading Complete ===\n") + else: + print("WARNING: No 'missions' key found in mission data") + +# Unlock the starting structures +func _unlock_starting_structures(structure_paths: Array) -> void: + print("\n=== Unlocking Starting Structures ===") + print("Paths to unlock: ", structure_paths) + + if not builder: + push_error("Builder not available") + return + + # Get current structures + var structures = builder.get_structures() + if not structures: + push_error("No structures available") + return + + # Print current unlock status + print("\nCurrent structure status:") + for i in range(structures.size()): + var structure = structures[i] + if structure.model: + print("Structure ", i, ": ", structure.model.resource_path, " - Unlocked: ", structure.unlocked) + + # Process each path + for path in structure_paths: + print("\nProcessing path: ", path) + + # Handle both structures/ and models/ paths + var possible_paths = [] + + # Add the original path + possible_paths.append(path) + + # Handle .tres to .glb conversion + if path.ends_with(".tres"): + # Convert structures/ path to models/ path + if "structures/" in path: + possible_paths.append(path.replace("structures/", "models/").replace(".tres", ".glb")) + + # Handle .glb to .tres conversion + if path.ends_with(".glb"): + # Convert models/ path to structures/ path + if "models/" in path: + possible_paths.append(path.replace("models/", "structures/").replace(".glb", ".tres")) + + print("Trying possible paths: ", possible_paths) + + var found_match = false + for structure in structures: + if not structure.model: + continue + + var structure_path = structure.model.resource_path + + print("Checking structure: ", structure_path) + + # Only try exact path matches + for possible_path in possible_paths: + if structure_path == possible_path: + print("Found exact path match: ", possible_path) + structure.unlocked = true + found_match = true + break + + if found_match: + break + + if not found_match: + print("WARNING: No match found for path: ", path) + print("Available structures:") + for i in range(structures.size()): + var structure = structures[i] + if structure.model: + print(" ", i, ": ", structure.model.resource_path) + + # Print final unlock status + print("\nFinal structure status:") + for i in range(structures.size()): + var structure = structures[i] + if structure.model: + print("Structure ", i, ": ", structure.model.resource_path, " - Unlocked: ", structure.unlocked) + + print("=== Structure Unlocking Complete ===\n") + +# Convert mission dictionaries to MissionData objects +func _convert_missions(mission_dicts: Array) -> Array[MissionData]: + print("Converting mission configurations...") + var converted: Array[MissionData] = [] + + for mission_dict in mission_dicts: + var mission_data = MissionData.new() + + # Set basic properties + mission_data.id = mission_dict.get("id", "") + mission_data.title = mission_dict.get("title", "") + mission_data.description = mission_dict.get("description", "") + + # Convert objectives + var objectives: Array[MissionObjective] = [] + for obj in mission_dict.get("objectives", []): + var objective = MissionObjective.new() + objective.type = obj.get("type", 0) + objective.target_count = obj.get("target_count", 0) + objective.description = obj.get("description", "") + + # Load structure resource if specified + var structure_path = obj.get("structure_path", "") + if structure_path: + objective.structure = load(structure_path) + + objectives.append(objective) + + mission_data.objectives = objectives + + # Set rewards + mission_data.rewards = mission_dict.get("rewards", {}) + + # Set unlocked items + var unlocked_items_array: Array[String] = [] + for item in mission_dict.get("unlocked_items", []): + unlocked_items_array.append(str(item)) + mission_data.unlocked_items = unlocked_items_array + + # Set starting structures + var starting_structures_array: Array[String] = [] + for item in mission_dict.get("starting_structures", []): + starting_structures_array.append(str(item)) + mission_data.starting_structures = starting_structures_array + + # Set additional properties + mission_data.next_mission_id = mission_dict.get("next_mission_id", "") + mission_data.graph_path = mission_dict.get("graph_path", "") + mission_data.full_screen_path = mission_dict.get("full_screen_path", "") + mission_data.intro_text = mission_dict.get("intro_text", "") + mission_data.question_text = mission_dict.get("question_text", "") + mission_data.correct_answer = mission_dict.get("correct_answer", "") + mission_data.feedback_text = mission_dict.get("feedback_text", "") + mission_data.incorrect_feedback = mission_dict.get("incorrect_feedback", "") + mission_data.company_data = mission_dict.get("company_data", "") + mission_data.power_math_content = mission_dict.get("power_math_content", "") + mission_data.num_of_user_inputs = mission_dict.get("num_of_user_inputs", 1) + + # Convert input labels to Array[String] + var input_labels_array: Array[String] = [] + for label in mission_dict.get("input_labels", []): + input_labels_array.append(str(label)) + mission_data.input_labels = input_labels_array + + # Set companion dialog + mission_data.companion_dialog = mission_dict.get("companion_dialog", {}) + + converted.append(mission_data) + + return converted diff --git a/scripts/mission/mission_loader.gd.uid b/scripts/mission/mission_loader.gd.uid new file mode 100644 index 0000000..795f864 --- /dev/null +++ b/scripts/mission/mission_loader.gd.uid @@ -0,0 +1 @@ +uid://c7x6l804lvsdk diff --git a/scripts/mission/mission_manager.gd b/scripts/mission/mission_manager.gd index a34a36c..d9c29f1 100644 --- a/scripts/mission/mission_manager.gd +++ b/scripts/mission/mission_manager.gd @@ -5,6 +5,10 @@ class_name MissionManager # This ensures JavaScript is available and degrades gracefully on other platforms const JSBridge = preload("res://scripts/javascript_bridge.gd") const ObjectiveType = preload("res://configs/data.config.gd").ObjectiveType +const StructureUnlocking = preload("res://scripts/mission/structure_unlocking.gd") + +# Add to the top with other preloads +const MissionLoader = preload("res://scripts/mission/mission_loader.gd") signal mission_started(mission: MissionData) signal mission_completed(mission: MissionData) @@ -12,6 +16,8 @@ signal objective_completed(objective: MissionObjective) signal objective_progress(objective: MissionObjective, new_count: int) signal game_started() signal all_missions_completed() +signal structures_unlocked() # New signal for when structures are unlocked +signal bridge_connection_completed @export var missions: Array[MissionData] = [] @export var mission_ui: Control @@ -40,26 +46,65 @@ const SKIP_KEY = KEY_TAB # The key to press for skipping missions var learning_panel var fullscreen_learning_panel -func _ready(): +# Add after other variables +var learning_panel_scene: PackedScene +var mission_loader: MissionLoader +var fullscreen_learning_panel_scene: PackedScene +func _ready() -> void: + print("\n=== Starting Mission Manager Initialization ===") + + # Set up communication with the learning companion first, before ANY other initialization + print("Attempting to establish JavaScript bridge...") + await _setup_learning_companion_communication() + print("JavaScript bridge setup completed") + + # Only proceed with other initialization after bridge is established + print("\n=== Starting Mission Loader Initialization ===") + # Initialize mission loader + mission_loader = MissionLoader.new(self, builder) + print("Mission loader initialized") + + # Connect to event bus and builder signals + print("\n=== Setting up Event Connections ===") EventBus.population_update.connect(population_updated) + print("Connected to population update event") + if builder: # Connect to builder signals builder.connect("structure_placed", _on_structure_placed) + print("Connected to structure_placed signal") + # Connect to construction manager signals + if builder.construction_manager: + builder.construction_manager.construction_completed.connect(_on_construction_completed) + print("Connected to construction_completed signal") + print("\n=== Setting up Learning Panels ===") # Find and remove existing learning panel to avoid conflicts var old_panel = get_node_or_null("LearningPanel") if old_panel: old_panel.queue_free() + print("Removed existing learning panel") - # Load the learning panel scene fresh each time - var learning_panel_scene = load("res://scenes/learning_panel.tscn") - if learning_panel_scene: - learning_panel = learning_panel_scene.instantiate() - learning_panel.name = "LearningPanelFromScene" - add_child(learning_panel) - else: - print("ERROR: Could not load learning_panel.tscn scene") + # Load the learning panel scene + learning_panel_scene = load("res://scenes/ui/learning_panel.tscn") + if not learning_panel_scene: + push_error("Failed to load learning panel scene") + return + + # Instantiate the learning panel + learning_panel = learning_panel_scene.instantiate() + learning_panel.name = "LearningPanelFromScene" + add_child(learning_panel) + + # Connect to the JavaScript bridge + if OS.has_feature("web"): + var js = Engine.get_singleton("JavaScriptBridge") + if js: + js.connect("init_data_received", Callable(self, "_on_init_data_received")) + + # Hide the panel initially + learning_panel.hide() # Load the fullscreen learning panel scene var fullscreen_panel_scene = load("res://scenes/fullscreen_learning_panel.tscn") @@ -67,40 +112,28 @@ func _ready(): fullscreen_learning_panel = fullscreen_panel_scene.instantiate() fullscreen_learning_panel.name = "FullscreenLearningPanel" add_child(fullscreen_learning_panel) - else: - print("ERROR: Could not load fullscreen_learning_panel.tscn scene") + print("Created fullscreen learning panel") # Fall back to existing panels if needed if not learning_panel: learning_panel = get_node_or_null("/root/Main/LearningPanel") + if learning_panel: + print("Using existing learning panel from Main") # Connect signals for both panel types if learning_panel: learning_panel.completed.connect(_on_learning_completed) learning_panel.panel_opened.connect(_on_learning_panel_opened) learning_panel.panel_closed.connect(_on_learning_panel_closed) - else: - print("WARNING: Regular learning panel not found!") + print("Connected learning panel signals") if fullscreen_learning_panel: fullscreen_learning_panel.completed.connect(_on_learning_completed) fullscreen_learning_panel.panel_opened.connect(_on_learning_panel_opened) fullscreen_learning_panel.panel_closed.connect(_on_learning_panel_closed) - else: - print("WARNING: Fullscreen learning panel not found!") - - # For web builds, try to proactively initialize audio on load -# if OS.has_feature("web"): -# # Try to find sound manager and init audio -# var sound_manager = get_node_or_null("/root/SoundManager") -# if sound_manager and not sound_manager.audio_initialized: -# # Connect to user input to detect interaction -# get_viewport().gui_focus_changed.connect(_on_gui_focus_for_audio) -# get_tree().get_root().connect("gui_input", _on_gui_input_for_audio) - - # Set up communication with the learning companion - _setup_learning_companion_communication() + print("Connected fullscreen learning panel signals") + print("\n=== Setting up Connection Timer ===") # Create a simple timer to force a learning companion connection in 3 seconds # This is a fallback in case the normal connection doesn't work var connection_timer = Timer.new() @@ -110,16 +143,20 @@ func _ready(): connection_timer.name = "ConnectionTimer" add_child(connection_timer) connection_timer.timeout.connect(_force_learning_companion_connection) - print("Created timer to force learning companion connection in 3 seconds") - - + print("Connection timer set up") + print("\n=== Emitting Game Started Signal ===") # Emit game_started signal before starting the first mission game_started.emit() # Start the first mission if available if missions.size() > 0: + print("Starting first mission") start_mission(missions[0]) + else: + print("No missions available to start") + + print("=== Mission Manager Initialization Complete ===\n") # Web-specific audio initialization helper methods func _on_gui_focus_for_audio(_control=null): @@ -168,7 +205,6 @@ func _try_init_audio_on_interaction(): # Find the sound manager var sound_manager = get_node_or_null("/root/SoundManager") if sound_manager and not sound_manager.audio_initialized: - print("User interaction detected in MissionManager, attempting audio init") sound_manager._initialize_web_audio() # Also use JavaScript bridge to help with audio @@ -181,81 +217,155 @@ func _try_init_audio_on_interaction(): game_manager._start_background_music() # Function to set up communication with the learning companion -func _setup_learning_companion_communication(): +func _setup_learning_companion_communication() -> void: + print("\n=== Setting up JavaScript Bridge ===") # First, check if JavaScript is available if JSBridge.has_interface(): - print("Setting up learning companion communication via postMessage") - - # Try to initialize audio first since we now have user interaction - JSBridge.get_interface().ensure_audio_initialized() - - # Connect directly using the simpler postMessage approach - JSBridge.get_interface().connectLearningCompanionViaPostMessage( - # Success callback - func(): - learning_companion_connected = true - print("Successfully connected to learning companion") - - # Connect signals to JavaScript callbacks - game_started.connect(_on_game_started_for_companion) - mission_started.connect(_on_mission_started_for_companion) - mission_completed.connect(_on_mission_completed_for_companion) - all_missions_completed.connect(_on_all_missions_completed_for_companion) - - print("Learning companion event handlers connected") - - # Try to initialize audio again to ensure it works - JSBridge.get_interface().ensure_audio_initialized(), - func(): - learning_companion_connected = false - print("Failed to connect to learning companion via postMessage") - - ) + print("JavaScript interface found") + var js_interface = JSBridge.get_interface() + if js_interface: + print("JavaScript interface initialized") + + # In web environment, we'll skip audio initialization for now + if OS.has_feature("web"): + print("Running in web environment - skipping audio initialization") + else: + # Try to initialize audio first since we now have user interaction + if js_interface.has_method("ensure_audio_initialized"): + print("Initializing audio...") + js_interface.ensure_audio_initialized() + print("Audio initialization complete") + + # Connect directly using the simpler postMessage approach + if js_interface.has_method("connectLearningCompanionViaPostMessage"): + print("Setting up learning companion connection...") + + # Create a safe callback wrapper + var success_wrapper = func(): + print("Learning companion connection successful") + learning_companion_connected = true + # Connect signals to JavaScript callbacks + game_started.connect(_on_game_started_for_companion) + mission_started.connect(_on_mission_started_for_companion) + mission_completed.connect(_on_mission_completed_for_companion) + all_missions_completed.connect(_on_all_missions_completed_for_companion) + print("Connected all JavaScript callbacks") + + # Request initial mission data if available + if js_interface.has_method("requestInitialMissionData"): + print("Requesting initial mission data...") + js_interface.requestInitialMissionData() + print("Initial mission data request sent") + + # Emit signal that connection is complete + bridge_connection_completed.emit() + + var error_wrapper = func(): + print("Learning companion connection failed") + learning_companion_connected = false + # Still emit signal even on failure + bridge_connection_completed.emit() + + # Call the connection method with our wrapped callbacks + js_interface.connectLearningCompanionViaPostMessage(success_wrapper, error_wrapper) + + print("Waiting for learning companion connection...") + # Wait for the connection to be established + await bridge_connection_completed + print("Learning companion connection process complete") + else: + print("WARNING: connectLearningCompanionViaPostMessage method not found - continuing without JavaScript bridge") + bridge_connection_completed.emit() + else: + print("WARNING: Failed to get JavaScript interface - continuing without JavaScript bridge") + bridge_connection_completed.emit() else: - print("JavaScript interface for learning companion not available") + print("WARNING: No JavaScript interface available - continuing without JavaScript bridge") + bridge_connection_completed.emit() + print("=== JavaScript Bridge Setup Complete ===\n") -func start_mission(mission: MissionData): - # Check that the mission data is valid - if mission == null: - push_error("Null mission data provided to start_mission") +# Helper function to safely find UI elements +func _find_ui_element(path: String, required: bool = true) -> Node: + var element = get_node_or_null(path) + if required and not element: + push_warning("Required UI element not found: " + path) + return element + +# Function to show learning panel with error handling +func _show_learning_panel(mission: MissionData) -> void: + if not learning_panel: + push_warning("Learning panel not found") return + + # Check for required UI elements + var submit_button = _find_ui_element("LearningPanelFromScene/PanelContainer/MarginContainer/ScrollContainer/VBoxContainer/MainContent/UserInputContainer/SubmitButton", false) + if not submit_button: + push_warning("Submit button not found in learning panel - some functionality may be limited") + # Continue anyway since this is not critical - # If the unlocked items panel is currently showing, queue this mission to start later - if is_unlocked_panel_showing: - print("Unlocked items panel is showing, queueing mission start: " + mission.id) - delayed_mission_start_queue.append(mission) + # Show the panel + learning_panel.show_learning_panel(mission) + +# Function to start mission with error handling +func start_mission(mission: MissionData): + if not mission: + push_error("Cannot start mission: mission is null") return current_mission = mission - active_missions[mission.id] = mission - mission_started.emit(current_mission) - # Set the first objective as the current objective + # Process structure unlocking + if builder: + var structures = builder.get_structures() + if structures: + # Only unlock starting structures at mission start + if mission.starting_structures.size() > 0: + for structure_path in mission.starting_structures: + if not ResourceLoader.exists(structure_path): + push_error("Structure not found: " + structure_path) + continue + mission_loader._unlock_starting_structures([structure_path]) + builder.update_structure() # Update the current structure display + + # Emit signal that structures have been unlocked + structures_unlocked.emit() + + # Set first objective as current if mission.objectives.size() > 0: current_objective = mission.objectives[0] - print("Set current objective: " + str(current_objective.type) + " - " + current_objective.description) + # Find the index of the current objective in the array + var objective_index = 0 + for i in range(mission.objectives.size()): + if mission.objectives[i] == current_objective: + objective_index = i + break - # Immediately update the mission UI with the new mission - if mission_ui: - print("Updating mission UI with new mission") - mission_ui.update_mission_display(mission) + # Update UI + if mission_ui: + mission_ui.update_mission_display(mission) + + # Show intro text if available + if mission.intro_text: + _show_learning_panel(mission) + + # Add mission to active missions + active_missions[mission.id] = mission + + # Emit signal that mission has started + mission_started.emit(mission) func complete_mission(mission_id: String): if not active_missions.has(mission_id): - print("ERROR: Mission " + mission_id + " not found in active_missions!") return var mission = active_missions[mission_id] - print("Completing mission: " + mission.id + " - " + mission.title) # Grant rewards if mission.rewards.has("cash") and builder: builder.map.cash += mission.rewards.cash builder.update_cash() - print("Granted " + str(mission.rewards.cash) + " cash reward") # Handle structure unlocking when mission is completed - print("Handling structure unlocking for mission: " + mission.id) _handle_structure_unlocking(mission) # Keep a copy of the mission for UI display during transition @@ -290,181 +400,134 @@ func complete_mission(mission_id: String): active_missions.erase(mission_id) all_missions_completed.emit() - print("No more missions available - all complete!") # Send the "end" event to the companion await get_tree().create_timer(2.0).timeout func update_objective_progress(structure:Structure = null): - print("Updating objective progress for type: " + str(current_objective.type)) - print("Current count: " + str(current_objective.current_count) + " / " + str(current_objective.target_count)) - - match current_objective.type: - ObjectiveType.BUILD_RESIDENTIAL: - current_objective.current_count += structure.population_count - if current_objective.target_count <= current_objective.current_count: - print("Residential building objective completed!") - current_objective.completed = true - objective_completed.emit(current_objective) - var dialog_key = "objective_completed_" + str(current_objective.type) - _send_companion_dialog(dialog_key, current_mission) - update_current_objective(current_mission) - ObjectiveType.BUILD_STRUCTURE: - current_objective.current_count += 1 - if current_objective.target_count <= current_objective.current_count: - print("Build structure objective completed!") - current_objective.completed = true - objective_completed.emit(current_objective) - var dialog_key = "objective_completed_" + str(current_objective.type) - _send_companion_dialog(dialog_key, current_mission) - update_current_objective(current_mission) - ObjectiveType.REACH_POPULATION: - if Globals.population >= current_objective.target_count: - print("Population objective completed!") - current_objective.completed = true - objective_completed.emit(current_objective) - var dialog_key = "objective_completed_" + str(current_objective.type) - _send_companion_dialog(dialog_key, current_mission) - update_current_objective(current_mission) + print("\n=== Updating Objective Progress ===") + print("Objective type: ", current_objective.type) + print("Current count: ", current_objective.current_count) + print("Target count: ", current_objective.target_count) + + if current_objective.type == ObjectiveType.BUILD_RESIDENTIAL: + print("Updating BUILD_RESIDENTIAL objective") + print("Structure population count: ", structure.population_count) + current_objective.current_count += structure.population_count + print("New count: ", current_objective.current_count) + if current_objective.target_count <= current_objective.current_count: + current_objective.completed = true + objective_completed.emit(current_objective) + var dialog_key = "objective_completed_" + str(current_objective.type) + _send_companion_dialog(dialog_key, current_mission) + update_current_objective() + elif current_objective.type == ObjectiveType.BUILD_STRUCTURE: + print("Updating BUILD_STRUCTURE objective") + current_objective.current_count += 1 + print("New count: ", current_objective.current_count) + if current_objective.target_count <= current_objective.current_count: + current_objective.completed = true + objective_completed.emit(current_objective) + var dialog_key = "objective_completed_" + str(current_objective.type) + _send_companion_dialog(dialog_key, current_mission) + update_current_objective() + elif current_objective.type == ObjectiveType.REACH_POPULATION: + if Globals.population >= current_objective.target_count: + current_objective.completed = true + objective_completed.emit(current_objective) + var dialog_key = "objective_completed_" + str(current_objective.type) + _send_companion_dialog(dialog_key, current_mission) + update_current_objective() - print("Emitting objective progress signal") objective_progress.emit(current_objective, current_objective.current_count) # Force UI update after objective progress if mission_ui: - print("Forcing mission UI update") - mission_ui.update_missions(active_missions) - - - + mission_ui.update_mission_display(current_mission) func is_structure_of_current_mission(structure:Structure): if not current_mission: - print("ERROR: No current mission to check structure against") return false - print("Checking structure against current objective:") - print("- Current objective type: " + str(current_objective.type)) - print("- Current objective structure type: " + str(current_objective.structure.type)) - print("- Placed structure type: " + str(structure.type)) - # Handle BUILD_STRUCTURE objective type if current_objective.type == ObjectiveType.BUILD_STRUCTURE: - # For commercial buildings, check if the placed structure is also a commercial building - if current_objective.structure.type == Structure.StructureType.COMMERCIAL_BUILDING: - if structure.type == Structure.StructureType.COMMERCIAL_BUILDING: - print("Commercial building match for store objective") - return true - # For roads, check if the placed structure is a road - elif current_objective.structure.type == Structure.StructureType.ROAD: - if structure.type == Structure.StructureType.ROAD: - print("Road match for road objective") - return true - # For other structures, do exact match - elif current_objective.structure == structure: - print("Exact structure match") - return true + # Check if the placed structure matches the objective's structure exactly + if current_objective.structure and structure.model: + return current_objective.structure.resource_path == structure.model.resource_path - print("No match found") return false func _on_structure_placed(structure_index, position): # Get the structure that was placed if structure_index < 0 or structure_index >= builder.structures.size(): - print("ERROR: Invalid structure index: " + str(structure_index)) return var structure = builder.structures[structure_index] - print("Structure placed: " + structure.model.resource_path + " at position: " + str(position)) # Check if this structure is needed for the current objective if current_mission and current_objective: - print("Current objective type: " + str(current_objective.type)) - # Handle structure-based objectives - if current_objective.type == ObjectiveType.BUILD_STRUCTURE and is_structure_of_current_mission(structure): - print("Structure matches current objective") - # For roads, check if they are placed next to each other - if structure.type == Structure.StructureType.ROAD: - # Check adjacent positions for roads - var adjacent_roads = 0 - var directions = [Vector3.RIGHT * 3, Vector3.LEFT * 3, Vector3.FORWARD * 3, Vector3.BACK * 3] - - for direction in directions: - var check_pos = position + direction - # Check if there's a road at this position in the NavRegion3D - var road_name = "Road_" + str(int(check_pos.x)) + "_" + str(int(check_pos.z)) - if builder.nav_region and builder.nav_region.has_node(road_name): - adjacent_roads += 1 - print("Found adjacent road at: " + str(check_pos)) - - print("Total adjacent roads: " + str(adjacent_roads)) - print("Current objective count: " + str(current_objective.current_count)) - - # For the first road, always count it - # For subsequent roads, only count if they're adjacent to another road - if adjacent_roads > 0 or current_objective.current_count == 0: - print("Counting road placement") - update_objective_progress(structure) - print("Updated count: " + str(current_objective.current_count)) - - # Check if objective is complete - if current_objective.current_count >= current_objective.target_count: - print("Objective complete!") - current_objective.completed = true - objective_completed.emit(current_objective) - update_current_objective(current_mission) + if current_objective.type == ObjectiveType.BUILD_STRUCTURE: + # Check if the structure matches the objective's required structure exactly + if current_objective.structure and structure.model and current_objective.structure.resource_path == structure.model.resource_path: + # For buildings, we'll update progress after construction completes + if structure.type == Structure.StructureType.RESIDENTIAL_BUILDING: + # Connect to the construction_completed signal if it exists + if builder.has_signal("construction_completed"): + if not builder.is_connected("construction_completed", _on_construction_completed): + builder.construction_completed.connect(_on_construction_completed) else: - print("Road not counted - not adjacent to another road and not first road") - else: - # For non-road structures, update progress normally - print("Updating progress for non-road structure") - update_objective_progress(structure) + # For non-building structures, update progress immediately + update_objective_progress(structure) elif current_objective.type == ObjectiveType.BUILD_RESIDENTIAL and structure.type == Structure.StructureType.RESIDENTIAL_BUILDING: # For residential buildings, update progress after construction completes - print("Residential building placed, will update after construction completes") - elif current_objective.type == ObjectiveType.REACH_POPULATION: - # Population objectives are handled by the population_updated signal - print("Population objective - will update when population changes") + if builder.has_signal("construction_completed"): + if not builder.is_connected("construction_completed", _on_construction_completed): + builder.construction_completed.connect(_on_construction_completed) + +# Handle construction completion +func _on_construction_completed(position: Vector3): + if not current_mission or not current_objective: + return + + # Find the structure at this position + var structure = null + if builder and builder.gridmap: + var cell = builder.gridmap.get_cell_item(position) + if cell >= 0 and cell < builder.structures.size(): + structure = builder.structures[cell] + + if structure: + print("\n=== Checking Structure for Objective ===") + print("Structure type: ", structure.type) + print("Structure model: ", structure.model.resource_path if structure.model else "null") + print("Current objective type: ", current_objective.type) + print("Current objective structure: ", current_objective.structure.resource_path if current_objective.structure else "null") + + # Check if this structure counts for our current objective + if current_objective.type == ObjectiveType.BUILD_STRUCTURE: + # Check if the structure matches the objective's required structure + if current_objective.structure and structure.model: + var model_name = structure.model.resource_path.get_file().get_basename() + var structure_name = current_objective.structure.resource_path.get_file().get_basename() + if model_name == structure_name: + print("Structure matches BUILD_STRUCTURE objective") + update_objective_progress(structure) + else: + print("Structure does not match BUILD_STRUCTURE objective") + elif current_objective.type == ObjectiveType.BUILD_RESIDENTIAL: + # Check both the structure type AND the specific structure required + if structure.type == Structure.StructureType.RESIDENTIAL_BUILDING and current_objective.structure and structure.model: + var model_name = structure.model.resource_path.get_file().get_basename() + var structure_name = current_objective.structure.resource_path.get_file().get_basename() + if model_name == structure_name: + print("Structure matches BUILD_RESIDENTIAL objective") + update_objective_progress(structure) + else: + print("Structure does not match BUILD_RESIDENTIAL objective") else: - print("Structure does not match current objective type") - else: - print("No current mission or objective to check against") - - if current_mission: - if structure.type == Structure.StructureType.RESIDENTIAL_BUILDING: - # Note: for mission 3, the objective update happens after construction is complete - # See builder.gd -> _on_construction_completed - - # Special check for mission 1 since we might need to manually spawn a character - if character_spawned: - # Only spawn a new character if: - # 1. This is mission 1 - # 2. We haven't spawned a character yet - # 3. All objectives except character spawning are complete - - # Check if all non-character objectives are complete - var spawn_character = true - for objective in current_mission.objectives: - spawn_character = false - break - - if spawn_character: - # This will be done after construction completes in mission_manager._on_construction_completed - print("Character will be spawned after construction completes") - - # Check for power plant unlocking in normal gameplay - if structure.type == Structure.StructureType.POWER_PLANT: - # This should increase the city's power production - var power_produced = structure.kW_production - if power_produced > 0: - # Get the HUD if available - var hud = get_node_or_null("/root/Main/CanvasLayer/HUD") - if hud: - # Update the power display - hud.total_kW_production += power_produced - hud.update_hud() - + print("Structure does not match any objective criteria") + # Only used for mission 3, to disable builder functionality during the companion dialog func _on_learning_panel_opened(): if builder: @@ -477,7 +540,6 @@ func _on_learning_panel_closed(): func _on_learning_completed(mission): if mission: - print("Learning completed for mission: " + mission.id) # If the mission has a learning objective, mark it as completed for objective in mission.objectives: if objective.type == MissionObjective.ObjectiveType.LEARNING: @@ -538,7 +600,6 @@ func _skip_current_mission(): var next_mission_id = current_mission.next_mission_id # Complete the current mission - print("Skipping mission: " + current_mission.id) # Force all objectives to be complete for objective in current_mission.objectives: @@ -547,8 +608,6 @@ func _skip_current_mission(): # Complete the mission complete_mission(current_mission.id) - else: - print("No current mission to skip") # Called when the unlocked panel is shown - used for additional state tracking func _on_unlocked_panel_shown(): @@ -561,14 +620,10 @@ func _on_unlocked_panel_shown(): if fullscreen_learning_panel and fullscreen_learning_panel.visible: fullscreen_learning_panel.hide_fullscreen_panel() - - print("Unlocked panel shown, game paused") # Helper function to process any delayed mission starts after panel closes func _process_delayed_mission_starts(): if delayed_mission_start_queue.size() > 0: - print("Processing " + str(delayed_mission_start_queue.size()) + " delayed mission starts") - # Get the first mission in the queue var next_mission = delayed_mission_start_queue.pop_front() @@ -578,7 +633,6 @@ func _process_delayed_mission_starts(): # Start the mission if next_mission: - print("Starting delayed mission: " + next_mission.id) # Use a short delay to ensure the UI is fully updated await get_tree().create_timer(0.5).timeout start_mission(next_mission) @@ -586,20 +640,15 @@ func _process_delayed_mission_starts(): # Function to spawn a character at a residential building func _spawn_character_on_road(building_position: Vector3): if not character_scene: - print("ERROR: No character scene provided for spawning") return if not builder: - print("ERROR: Builder reference missing, can't spawn character") return # Find the nearest road to the building var nearby_road = _find_nearest_road(building_position, builder.gridmap) if nearby_road == Vector3.ZERO: - print("ERROR: Could not find a road near the building to spawn character") return - - print("Spawning character on road at: " + str(nearby_road)) # Check if the road is associated with a navigation mesh var has_navigation = false @@ -609,9 +658,6 @@ func _spawn_character_on_road(building_position: Vector3): if nav_region: has_navigation = true - if not has_navigation: - print("WARNING: No navigation mesh found near spawn point") - # Create the character var character = character_scene.instantiate() character.name = "Resident_" + str(int(building_position.x)) + "_" + str(int(building_position.z)) @@ -657,7 +703,6 @@ func _spawn_character_on_road(building_position: Vector3): # Set character as spawned to prevent multiple spawns character_spawned = true - # Make sure the character has auto-patrol is enabled if the character supports it if character.get("auto_patrol") != null: character.auto_patrol = true @@ -804,137 +849,70 @@ func _get_connected_road_length(road_position: Vector3, gridmap: GridMap) -> flo # This function handles structure unlocking when a mission is completed func _handle_structure_unlocking(mission): if not builder: - print("ERROR: Builder is null, can't unlock structures") return - print("Builder has " + str(builder.structures.size()) + " structures") + var structures = builder.get_structures() var unlocked_structures = [] - # Check mission properties - print("Mission properties check:") - print("- mission is Resource: " + str(mission is Resource)) - if mission is Resource: - print("- 'unlocked_items' in mission: " + str("unlocked_items" in mission)) - if "unlocked_items" in mission: - print("- unlocked_items size: " + str(mission.unlocked_items.size())) - print("- unlocked_items content: " + str(mission.unlocked_items)) - # Check for explicitly defined unlocked items in mission if mission is Resource and "unlocked_items" in mission and mission.unlocked_items.size() > 0: - print("Found unlocked_items in mission: " + mission.id) - print("Unlocked items: " + str(mission.unlocked_items)) - var items = mission.unlocked_items for item_path in items: - print("Looking for structure with path: " + item_path) var found = false # Find the structure in builder's structures that matches this path - for structure in builder.structures: + for structure in structures: if structure.model: # Try exact match if structure.model.resource_path == item_path: found = true - print("EXACT MATCH: " + structure.model.resource_path) # Make sure structure has the unlocked property before setting it if "unlocked" in structure: structure.unlocked = true unlocked_structures.append(structure) - print("SUCCESS: Unlocked structure: " + structure.model.resource_path) - else: - print("WARNING: Structure doesn't have an 'unlocked' property") # Try matching just the filename part elif structure.model.resource_path.get_file() == item_path.get_file(): found = true - print("FILENAME MATCH: " + structure.model.resource_path + " = " + item_path.get_file()) # Make sure structure has the unlocked property before setting it if "unlocked" in structure: structure.unlocked = true unlocked_structures.append(structure) - print("SUCCESS: Unlocked structure: " + structure.model.resource_path) - else: - print("WARNING: Structure doesn't have an 'unlocked' property") # Try contains match for more flexible path matching (handles directory differences) elif item_path.get_file() in structure.model.resource_path: found = true - print("CONTAINS MATCH: " + structure.model.resource_path + " contains " + item_path.get_file()) # Make sure structure has the unlocked property before setting it if "unlocked" in structure: structure.unlocked = true unlocked_structures.append(structure) - print("SUCCESS: Unlocked structure: " + structure.model.resource_path) - else: - print("WARNING: Structure doesn't have an 'unlocked' property") - - if not found: - print("ERROR: Couldn't find any structure with path: " + item_path) - # Make sure the builder starts with a valid unlocked structure selected + # Update builder's current structure if needed var found_unlocked = false - for i in range(builder.structures.size()): - var structure = builder.structures[i] + for i in range(structures.size()): + var structure = structures[i] if "unlocked" in structure and structure.unlocked: - builder.index = i - builder.update_structure() + # Only update if the current structure is not unlocked + if not (structures[builder.index].unlocked if "unlocked" in structures[builder.index] else false): + builder.index = i + builder.update_structure() found_unlocked = true break - - # If no structures are unlocked, unlock ONLY the road for the first mission - if not found_unlocked and builder.structures.size() > 0: - # Find and unlock only the straight road structure - var road_index = -1 - for i in range(builder.structures.size()): - var structure = builder.structures[i] - if structure.model and structure.model.resource_path.contains("road-straight"): - if "unlocked" in structure: - structure.unlocked = true - road_index = i - print("Unlocked initial road structure: " + structure.model.resource_path) - break - - # Set builder to use the road as the initial structure - if road_index >= 0: - builder.index = road_index - builder.update_structure() - else: - # Fallback to first structure if road not found - var structure = builder.structures[0] - if "unlocked" in structure: - structure.unlocked = true - builder.index = 0 - builder.update_structure() - else: - print("WARNING: First structure doesn't have an 'unlocked' property") # Show the unlocked items panel if we unlocked anything - print("Unlocked " + str(unlocked_structures.size()) + " structures in total") if unlocked_structures.size() > 0: - print("Showing unlocked items panel...") - # Make sure all structures in the unlock list are properly marked as unlocked - for structure in unlocked_structures: - if "unlocked" in structure: - structure.unlocked = true - print("Confirmed structure is unlocked: " + structure.model.resource_path) - _show_unlocked_items_panel(unlocked_structures) - else: - print("No structures unlocked, not showing panel") # Shows a panel with the newly unlocked items func _show_unlocked_items_panel(unlocked_structures): # Check if panel is already showing if is_unlocked_panel_showing: - print("WARNING: Panel is already showing, skipping duplicate show") return - print("Showing unlocked items panel with " + str(unlocked_structures.size()) + " structures") - # Set panel state to showing - prevents mission starts while panel is visible is_unlocked_panel_showing = true @@ -946,7 +924,6 @@ func _show_unlocked_items_panel(unlocked_structures): if hud: for child in hud.get_children(): if child.name.contains("UnlockedItems") or (child is Control and child.get_script() != null and "unlocked" in child.get_script().resource_path.to_lower()): - print("Found existing panel in HUD: " + child.name) existing_panels.append(child) # Check in CanvasLayer @@ -954,12 +931,10 @@ func _show_unlocked_items_panel(unlocked_structures): if canvas: for child in canvas.get_children(): if child.name.contains("UnlockedItems") or (child is Control and child.get_script() != null and "unlocked" in child.get_script().resource_path.to_lower()): - print("Found existing panel in CanvasLayer: " + child.name) existing_panels.append(child) # Remove any existing panels for panel in existing_panels: - print("Removing existing panel: " + panel.name) panel.queue_free() # Wait a short delay before showing the panel @@ -968,21 +943,17 @@ func _show_unlocked_items_panel(unlocked_structures): # Load the panel scene var unlocked_panel_scene = load("res://scenes/unlocked_items_panel.tscn") if unlocked_panel_scene: - print("Successfully loaded unlocked_items_panel.tscn") var unlocked_panel = unlocked_panel_scene.instantiate() # Always add to HUD if available if hud: - print("Adding panel to HUD") hud.add_child(unlocked_panel) else: # Fallback to CanvasLayer if HUD not available if canvas: - print("Adding panel to CanvasLayer") canvas.add_child(unlocked_panel) else: # Final fallback to root - print("Adding panel to root") get_tree().root.add_child(unlocked_panel) # Wait for panel to be added @@ -998,7 +969,6 @@ func _show_unlocked_items_panel(unlocked_structures): # Connect the closed signal unlocked_panel.closed.connect(func(): - print("Unlocked panel was closed") # Reset the panel showing state is_unlocked_panel_showing = false @@ -1007,21 +977,15 @@ func _show_unlocked_items_panel(unlocked_structures): # Update the mission UI with the current objective if mission_ui and current_mission: - print("Updating mission UI after unlocked panel closed") mission_ui.update_mission_display(current_mission) # Process any delayed mission starts _process_delayed_mission_starts() ) - else: - push_error("Could not load unlocked_items_panel scene") - # Even if we couldn't load the panel, make sure to reset the state - is_unlocked_panel_showing = false # Public function to show all unlocked structures when requested func show_unlocked_structures_panel(): if not builder: - print("Cannot show unlocked structures - builder not found") return var all_unlocked = [] @@ -1029,7 +993,6 @@ func show_unlocked_structures_panel(): if "unlocked" in structure and structure.unlocked: all_unlocked.append(structure) - print("Showing panel with all " + str(all_unlocked.size()) + " unlocked structures") # Pause the game when showing the panel get_tree().paused = true _show_unlocked_items_panel(all_unlocked) @@ -1037,87 +1000,89 @@ func show_unlocked_structures_panel(): # Functions for communication with learning companion func _on_game_started_for_companion(): if learning_companion_connected and JSBridge.has_interface(): - print("Sending gameStarted event to learning companion") - JSBridge.get_interface().sendGameStarted() + var js_interface = JSBridge.get_interface() + if js_interface and js_interface.has_method("onGameStarted"): + js_interface.onGameStarted() func _on_mission_started_for_companion(mission): if learning_companion_connected and JSBridge.has_interface(): - print("Sending missionStarted event to learning companion for mission: " + mission.id) - - # Only send dialog if it exists - if mission.companion_dialog.has("mission_started"): - var dialog_data = mission.companion_dialog["mission_started"] - JSBridge.get_interface().sendCompanionDialog("mission_started", dialog_data) + var js_interface = JSBridge.get_interface() + if js_interface and js_interface.has_method("sendCompanionDialog"): + # Only send dialog if it exists and is valid + if mission.companion_dialog and mission.companion_dialog.has("mission_started"): + var dialog_data = mission.companion_dialog["mission_started"] + if dialog_data: + js_interface.sendCompanionDialog("mission_started", dialog_data) func _on_mission_completed_for_companion(mission): if learning_companion_connected and JSBridge.has_interface(): - print("Sending missionCompleted event to learning companion for mission: " + mission.id) - - # Only send dialog if it exists - if mission.companion_dialog.has("mission_completed"): - var dialog_data = mission.companion_dialog["mission_completed"] - JSBridge.get_interface().sendCompanionDialog("mission_completed", dialog_data) + var js_interface = JSBridge.get_interface() + if js_interface and js_interface.has_method("sendCompanionDialog"): + # Only send dialog if it exists and is valid + if mission.companion_dialog and mission.companion_dialog.has("mission_completed"): + var dialog_data = mission.companion_dialog["mission_completed"] + if dialog_data: + js_interface.sendCompanionDialog("mission_completed", dialog_data) func _on_all_missions_completed_for_companion(): if learning_companion_connected and JSBridge.has_interface(): - print("Sending allMissionsCompleted event to learning companion") - JSBridge.get_interface().sendAllMissionsCompleted() + var js_interface = JSBridge.get_interface() + if js_interface and js_interface.has_method("sendAllMissionsCompleted"): + js_interface.sendAllMissionsCompleted() # Helper function to send dialog to the companion func _send_companion_dialog(dialog_key, mission): - if learning_companion_connected and JSBridge.has_interface() and mission.companion_dialog.has(dialog_key): - var dialog_data = mission.companion_dialog[dialog_key] - JSBridge.get_interface().sendCompanionDialog(dialog_key, dialog_data) - return true + if learning_companion_connected and JSBridge.has_interface(): + var js_interface = JSBridge.get_interface() + if js_interface and js_interface.has_method("sendCompanionDialog"): + # Only send dialog if it exists and is valid + if mission.companion_dialog and mission.companion_dialog.has(dialog_key): + var dialog_data = mission.companion_dialog[dialog_key] + if dialog_data: + js_interface.sendCompanionDialog(dialog_key, dialog_data) + return true return false # Helper function to update the current objective to the next incomplete one func update_current_objective(mission = null): - print("Updating current objective") - # If no mission was provided, use the current mission if mission == null: mission = current_mission if not mission: - print("ERROR: No mission provided for update_current_objective") return - print("Mission objectives count: " + str(mission.objectives.size())) - - # Look for the first incomplete objective + # Find the next incomplete objective + var found_current = false for objective in mission.objectives: + # If we haven't found the current objective yet, keep looking + if not found_current: + if objective == current_objective: + found_current = true + continue + + # Once we've found the current objective, look for the next incomplete one if not objective.completed: - print("Found incomplete objective: " + str(objective.type)) current_objective = objective - print("Updated current objective: " + str(current_objective.type) + " - " + current_objective.description) # Force UI update if mission_ui: - print("Forcing mission UI update after objective change") mission_ui.update_mission_display(mission) return - # If all objectives are complete, keep the last one as current and complete the mission - if mission.objectives.size() > 0: - print("All objectives complete") - current_objective = mission.objectives[-1] - print("Keeping last objective as current: " + str(current_objective.type)) - - # Force UI update - if mission_ui: - print("Forcing mission UI update after all objectives complete") - mission_ui.update_mission_display(mission) + # If we didn't find a next incomplete objective, check if all are complete + var all_complete = true + for objective in mission.objectives: + if not objective.completed: + all_complete = false + break - # Complete the mission when we've found that all objectives are complete - if mission.id in active_missions: - print("Checking mission completion") - check_mission_completion(mission.id) + if all_complete: + complete_mission(mission.id) # Fallback to force a connection if the normal method doesn't work func _force_learning_companion_connection(): if not learning_companion_connected and JSBridge.has_interface(): - print("Forcing learning companion connection") learning_companion_connected = true # Connect signals @@ -1130,10 +1095,8 @@ func _force_learning_companion_connection(): if current_mission: _on_mission_started_for_companion(current_mission) - func population_updated(new_population: Variant) -> void: if current_mission and current_objective and current_objective.type == ObjectiveType.REACH_POPULATION: - print("Population updated: " + str(new_population) + " / " + str(current_objective.target_count)) # Update the current count to match the actual population current_objective.current_count = new_population @@ -1164,18 +1127,15 @@ func check_objective_completion(mission_id, objective_type): # Function to reset an objective's count to a specific value func reset_objective_count(objective_type, new_count): if not current_mission: - print("ERROR: No current mission to reset objective count for") return var mission_id = current_mission.id if not active_missions.has(mission_id): - print("ERROR: Current mission ID " + mission_id + " not found in active_missions!") return var mission = active_missions[mission_id] for objective in mission.objectives: if objective.type == objective_type: - print("Resetting objective count for type " + str(objective_type) + " from " + str(objective.current_count) + " to " + str(new_count)) objective.current_count = new_count # Update completion status based on new count @@ -1224,3 +1184,70 @@ func check_mission_completion(mission_id): func update_mission_ui(): if mission_ui: mission_ui.update_missions(active_missions) + +# Add new function to load custom configurations +func load_mission_config(config: MissionData) -> void: + if mission_loader: + # Convert the mission data to a dictionary format + var mission_dict = { + "missions": [{ + "id": config.id, + "title": config.title, + "description": config.description, + "objectives": config.objectives, + "rewards": config.rewards, + "next_mission_id": config.next_mission_id, + "graph_path": config.graph_path, + "full_screen_path": config.full_screen_path, + "intro_text": config.intro_text, + "question_text": config.question_text, + "correct_answer": config.correct_answer, + "feedback_text": config.feedback_text, + "incorrect_feedback": config.incorrect_feedback, + "company_data": config.company_data, + "power_math_content": config.power_math_content, + "num_of_user_inputs": config.num_of_user_inputs, + "input_labels": config.input_labels, + "companion_dialog": config.companion_dialog, + "unlocked_items": config.unlocked_items, + "starting_structures": config.starting_structures + }] + } + mission_loader.load_from_js(mission_dict) + +func _on_init_data_received(data): + print("Godot received mission data: ", data) + print("Type: ", typeof(data), " Keys: ", data.keys() if typeof(data) == TYPE_DICTIONARY else "") + + if typeof(data) == TYPE_STRING: + var parsed = JSON.parse_string(data) + if typeof(parsed) == TYPE_DICTIONARY: + data = parsed + else: + print("Failed to parse mission data string!") + + if not data: + push_error("Received empty initialization data") + return + + if not data.has("missions"): + push_error("No missions found in initialization data") + return + + var missions = data["missions"] + print("Missions array: ", missions) + + for mission_data in missions: + print("Processing mission data: ", mission_data) + var mission = MissionData.new() + mission.from_dictionary(mission_data) + active_missions[mission.id] = mission + print("Added mission: ", mission.id) + + # Start the first mission if available + if active_missions.size() > 0: + var first_mission = active_missions.values()[0] + print("Starting first mission: ", first_mission.id) + start_mission(first_mission) + else: + push_error("No missions available to start") diff --git a/scripts/mission/mission_objective.gd b/scripts/mission/mission_objective.gd index 30dca04..0026eba 100644 --- a/scripts/mission/mission_objective.gd +++ b/scripts/mission/mission_objective.gd @@ -1,23 +1,87 @@ extends Resource class_name MissionObjective -const ObjectiveType = preload("res://configs/data.config.gd").ObjectiveType +const PatternRule = preload("res://scripts/mission/pattern_rule.gd") +const PatternRules = preload("res://scripts/mission/pattern_rules.gd") -@export var type: ObjectiveType -@export var target_count: int = 1 +enum ObjectiveType { + BUILD = 0, + POPULATION = 1, + POWER = 2, + PATTERN = 3, # Pattern matching type + LEARNING = 4 # Learning objective type +} + +@export var type: ObjectiveType = ObjectiveType.BUILD +@export var target_count: int = 0 @export var current_count: int = 0 @export var description: String = "" @export var completed: bool = false +@export var structure: Structure # The structure to build/check for +@export var pattern_rules: PatternRules # Rules for pattern matching -@export_subgroup("Structure") -@export var structure: Structure +func check_pattern(builder: Node) -> bool: + if type != ObjectiveType.PATTERN || !pattern_rules: + return false + + # Get the grid from the builder + var grid = builder.get_node("Grid") + if !grid: + return false + + # Scan the grid for the pattern + var grid_size = grid.get_grid_size() + for x in range(grid_size.x - pattern_rules.pattern_size.x + 1): + for y in range(grid_size.y - pattern_rules.pattern_size.y + 1): + if check_pattern_at_position(grid, Vector2i(x, y)): + return true + + return false -func is_completed() -> bool: - return current_count >= target_count +func check_pattern_at_position(grid: Node, start_pos: Vector2i) -> bool: + # Check each position in the pattern + for rule in pattern_rules.rules: + var check_pos = start_pos + rule.offset + var cell = grid.get_cell(check_pos.x, check_pos.y) + + # Check if the cell matches the rule + if !cell: + return false + + match rule.type: + PatternRule.RuleType.STRUCTURE: + if !cell.has_structure(rule.structure): + return false + PatternRule.RuleType.EMPTY: + if cell.has_any_structure(): + return false + PatternRule.RuleType.ROTATION: + if cell.get_rotation() != rule.rotation: + return false + + return true -func progress(amount: int = 1) -> void: - current_count = min(current_count + amount, target_count) - completed = is_completed() +func update_progress(builder: Node) -> void: + match type: + ObjectiveType.BUILD: + if structure: + current_count = builder.count_structure(structure) + ObjectiveType.POPULATION: + current_count = builder.get_total_population() + ObjectiveType.POWER: + current_count = builder.get_total_power() + ObjectiveType.PATTERN: + completed = check_pattern(builder) + if completed: + current_count = target_count + ObjectiveType.LEARNING: + # Learning objectives are completed through UI interaction + pass + + completed = (type == ObjectiveType.PATTERN && completed) || (type == ObjectiveType.LEARNING && completed) || current_count >= target_count + +func is_completed() -> bool: + return completed # Function to reduce the counter (for demolition) func regress(amount: int = 1) -> void: diff --git a/scripts/mission/pattern_rule.gd b/scripts/mission/pattern_rule.gd new file mode 100644 index 0000000..a64caf4 --- /dev/null +++ b/scripts/mission/pattern_rule.gd @@ -0,0 +1,13 @@ +extends Resource +class_name PatternRule + +enum RuleType { + STRUCTURE, # Check for specific structure + EMPTY, # Check for empty space + ROTATION # Check structure rotation +} + +@export var type: RuleType = RuleType.STRUCTURE +@export var offset: Vector2i +@export var structure: Structure # Structure to check for if type is STRUCTURE +@export var rotation: int # Rotation to check for if type is ROTATION \ No newline at end of file diff --git a/scripts/mission/pattern_rule.gd.uid b/scripts/mission/pattern_rule.gd.uid new file mode 100644 index 0000000..06196f2 --- /dev/null +++ b/scripts/mission/pattern_rule.gd.uid @@ -0,0 +1 @@ +uid://clv4vhawbuihu diff --git a/scripts/mission/pattern_rules.gd b/scripts/mission/pattern_rules.gd new file mode 100644 index 0000000..086b5a5 --- /dev/null +++ b/scripts/mission/pattern_rules.gd @@ -0,0 +1,5 @@ +extends Resource +class_name PatternRules + +@export var pattern_size: Vector2i = Vector2i(2, 2) # Size of the pattern grid +@export var rules: Array[PatternRule] # Array of pattern rules to check \ No newline at end of file diff --git a/scripts/mission/pattern_rules.gd.uid b/scripts/mission/pattern_rules.gd.uid new file mode 100644 index 0000000..3bb696b --- /dev/null +++ b/scripts/mission/pattern_rules.gd.uid @@ -0,0 +1 @@ +uid://dq0hn1a4b0c0 diff --git a/scripts/mission/structure_unlocking.gd b/scripts/mission/structure_unlocking.gd new file mode 100644 index 0000000..c6f9569 --- /dev/null +++ b/scripts/mission/structure_unlocking.gd @@ -0,0 +1,83 @@ +extends Node + +# Process structure unlocking based on mission data +static func process_mission_structures(structures: Array[Structure], mission_data): + print("\n=== Processing Mission Structures ===") + print("Mission ID: ", mission_data.id) + + # Print current unlock status + print("\nCurrent structure status:") + for i in range(structures.size()): + var structure = structures[i] + if structure.model: + print("Structure ", i, ": ", structure.model.resource_path, " - Unlocked: ", structure.unlocked if "unlocked" in structure else "no unlock property") + + # Don't lock all structures at start - only unlock new ones + var paths_to_unlock = [] + + # Only add starting structures - unlocked_items are handled when mission completes + if mission_data.starting_structures.size() > 0: + print("\nProcessing starting structures: ", mission_data.starting_structures) + paths_to_unlock.append_array(mission_data.starting_structures) + + # Process all paths to unlock + print("\nAttempting to unlock ", paths_to_unlock.size(), " structures") + for path in paths_to_unlock: + unlock_structure_by_path(structures, path) + + # Print final unlock status + print("\nFinal structure status:") + for i in range(structures.size()): + var structure = structures[i] + if structure.model: + print("Structure ", i, ": ", structure.model.resource_path, " - Unlocked: ", structure.unlocked if "unlocked" in structure else "no unlock property") + + print("=== Structure Processing Complete ===\n") + +# Helper function to unlock a structure by its resource path +static func unlock_structure_by_path(structures: Array[Structure], path: String): + print("\nTrying to unlock structure with path: ", path) + + # Print all structures and their current unlock status + print("\nCurrent structure status:") + for i in range(structures.size()): + var structure = structures[i] + if structure.model: + print("Structure ", i, ": ", structure.model.resource_path, " - Unlocked: ", structure.unlocked if "unlocked" in structure else "no unlock property") + + print("\nStarting structure matching...") + for structure in structures: + if not structure.model: + print("WARNING: Structure has no model!") + continue + + var structure_path = structure.model.resource_path + print("\nChecking structure: ", structure_path) + + # Try exact path match first + if structure_path == path: + print("Found exact path match, unlocking") + structure.unlocked = true + break + + # Try converting between structures/ and models/ paths + if path.ends_with(".tres") and "structures/" in path: + var glb_path = path.replace("structures/", "models/").replace(".tres", ".glb") + if structure_path == glb_path: + print("Found converted path match (tres->glb), unlocking") + structure.unlocked = true + break + + if path.ends_with(".glb") and "models/" in path: + var tres_path = path.replace("models/", "structures/").replace(".glb", ".tres") + if structure_path == tres_path: + print("Found converted path match (glb->tres), unlocking") + structure.unlocked = true + break + + # Print final unlock status for all structures + print("\nFinal structure status after matching:") + for i in range(structures.size()): + var structure = structures[i] + if structure.model: + print("Structure ", i, ": ", structure.model.resource_path, " - Unlocked: ", structure.unlocked if "unlocked" in structure else "no unlock property") diff --git a/scripts/mission/structure_unlocking.gd.uid b/scripts/mission/structure_unlocking.gd.uid new file mode 100644 index 0000000..6e76228 --- /dev/null +++ b/scripts/mission/structure_unlocking.gd.uid @@ -0,0 +1 @@ +uid://d4j6txm8aicsd diff --git a/scripts/mission/unlocked_items_panel.gd b/scripts/mission/unlocked_items_panel.gd index c5bed70..9ed34e6 100644 --- a/scripts/mission/unlocked_items_panel.gd +++ b/scripts/mission/unlocked_items_panel.gd @@ -33,7 +33,6 @@ func setup(unlocked_structures): # Debug info about structures for i in range(unlocked_structures.size()): if unlocked_structures[i].model: - print("Structure " + str(i) + ": " + unlocked_structures[i].model.resource_path) if "title" in unlocked_structures[i]: print(" Title: " + unlocked_structures[i].title) if "description" in unlocked_structures[i]: @@ -163,7 +162,12 @@ func show_all_unlocked_structures(): var all_unlocked = [] # Get all unlocked structures from the builder - for structure in builder.structures: + var structures = builder.get_structures() + if not structures: + print("ERROR: No structures available") + return + + for structure in structures: if "unlocked" in structure and structure.unlocked: all_unlocked.append(structure) diff --git a/scripts/mission_select_menu.gd b/scripts/mission_select_menu.gd index b021cc0..7be3ecd 100644 --- a/scripts/mission_select_menu.gd +++ b/scripts/mission_select_menu.gd @@ -120,45 +120,70 @@ func _unlock_structures_up_to_mission(mission_id: String): # Function to unlock a specific structure by path func _unlock_structure(item_path: String): - print("Unlocking structure: " + item_path) + print("\nAttempting to unlock structure: " + item_path) + + # Get structures from builder + var structures = builder.get_structures() + if not structures: + print("ERROR: No structures available") + return + + # Convert .tres path to .glb path for comparison + var glb_path = item_path.replace(".tres", ".glb") + print("Looking for matching structure with paths:") + print("Original path: " + item_path) + print("GLB path: " + glb_path) # Find the structure in builder's structures - for structure in builder.structures: + var found = false + for structure in structures: if structure.model: - # Check for exact match - if structure.model.resource_path == item_path: - if "unlocked" in structure: - structure.unlocked = true - print("SUCCESS: Unlocked structure: " + structure.model.resource_path) + print("Checking structure: " + structure.model.resource_path) - # Check for filename match - elif structure.model.resource_path.get_file() == item_path.get_file(): + # Check for exact match with either path + if structure.model.resource_path == item_path or structure.model.resource_path == glb_path: if "unlocked" in structure: structure.unlocked = true - print("SUCCESS: Unlocked structure by filename: " + structure.model.resource_path) + print("SUCCESS: Unlocked structure by exact match: " + structure.model.resource_path) + found = true + break - # Check for contains match - elif item_path.get_file() in structure.model.resource_path: + # Check for base name match (without extension) + elif structure.model.resource_path.get_basename() == item_path.get_basename(): if "unlocked" in structure: structure.unlocked = true - print("SUCCESS: Unlocked structure by partial match: " + structure.model.resource_path) + print("SUCCESS: Unlocked structure by base name match: " + structure.model.resource_path) + found = true + break + + if not found: + print("WARNING: No matching structure found for: " + item_path) + print("Available structures:") + for structure in structures: + if structure.model: + print(" " + structure.model.resource_path) # Function to update the builder after unlocking structures func _update_builder_structures(): if builder: + var structures = builder.get_structures() + if not structures: + print("ERROR: No structures available") + return + # Find a valid unlocked structure to set as current var found_unlocked = false - for i in range(builder.structures.size()): - if "unlocked" in builder.structures[i] and builder.structures[i].unlocked: + for i in range(structures.size()): + if "unlocked" in structures[i] and structures[i].unlocked: builder.index = i builder.update_structure() found_unlocked = true break - if not found_unlocked and builder.structures.size() > 0: + if not found_unlocked and structures.size() > 0: # Force unlock the first structure as fallback - if "unlocked" in builder.structures[0]: - builder.structures[0].unlocked = true + if "unlocked" in structures[0]: + structures[0].unlocked = true builder.index = 0 builder.update_structure() diff --git a/scripts/sound_manager.gd b/scripts/sound_manager.gd index f613353..3bf6387 100644 --- a/scripts/sound_manager.gd +++ b/scripts/sound_manager.gd @@ -50,7 +50,10 @@ const SFX_PATH = "res://audio/sfx/" func _ready(): print("SoundManager: Initializing...") - # For web platform, we need to wait for user interaction before initializing audio + # Create audio buses first + _initialize_audio() + + # For web platform, we need to wait for user interaction before enabling audio if OS.has_feature("web"): print("SoundManager: Web platform detected, waiting for user interaction") # Connect to the JavaScript bridge @@ -68,30 +71,41 @@ func _ready(): }); """) else: - print("SoundManager: Desktop platform, initializing audio immediately") - # For non-web platforms, initialize audio immediately - _initialize_audio() + print("SoundManager: Desktop platform, audio initialization complete") + audio_ready.emit() func _on_audio_ready(): print("SoundManager: Audio ready signal received") - _initialize_audio() + audio_ready.emit() func _initialize_audio(): print("SoundManager: Initializing audio buses") - # Set up audio buses if they don't exist + + # Create audio buses if they don't exist var music_bus_index = AudioServer.get_bus_index("Music") if music_bus_index == -1: print("SoundManager: Creating Music bus") - AudioServer.add_bus(AudioServer.bus_count) - AudioServer.set_bus_name(AudioServer.bus_count - 1, "Music") - music_bus_index = AudioServer.get_bus_index("Music") + AudioServer.add_bus() + music_bus_index = AudioServer.bus_count - 1 + AudioServer.set_bus_name(music_bus_index, "Music") + AudioServer.set_bus_send(music_bus_index, "Master") var sfx_bus_index = AudioServer.get_bus_index("SFX") if sfx_bus_index == -1: print("SoundManager: Creating SFX bus") - AudioServer.add_bus(AudioServer.bus_count) - AudioServer.set_bus_name(AudioServer.bus_count - 1, "SFX") - sfx_bus_index = AudioServer.get_bus_index("SFX") + AudioServer.add_bus() + sfx_bus_index = AudioServer.bus_count - 1 + AudioServer.set_bus_name(sfx_bus_index, "SFX") + AudioServer.set_bus_send(sfx_bus_index, "Master") + + # Get the final bus indices after creation + music_bus_index = AudioServer.get_bus_index("Music") + sfx_bus_index = AudioServer.get_bus_index("SFX") + + # Verify bus indices are valid + if music_bus_index == -1 or sfx_bus_index == -1: + push_error("SoundManager: Failed to create audio buses") + return # Apply current volume settings print("SoundManager: Applying initial volume settings") @@ -106,7 +120,6 @@ func _initialize_audio(): # Mark audio as initialized audio_initialized = true print("SoundManager: Audio initialization complete") - audio_ready.emit() # Volume control functions func set_music_volume(volume: float): diff --git a/structures/building-garage.tres b/structures/building-garage.tres index 26b9547..9106d2c 100644 --- a/structures/building-garage.tres +++ b/structures/building-garage.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://bqb6g3t0tebno"] [ext_resource type="PackedScene" uid="uid://d0nnrx2y4px2v" path="res://models/building-garage.glb" id="1_gyclk"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="2_jrinw"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="2_jrinw"] [resource] script = ExtResource("2_jrinw") @@ -14,5 +14,6 @@ kW_usage = 0.0 kW_production = 0.0 selector_scale = 2.8 unlocked = false +spawn_builder = false description = "Description" thumbnail = "Thumbnail" diff --git a/structures/building-small-a.tres b/structures/building-small-a.tres index 6e9dce4..e15af55 100644 --- a/structures/building-small-a.tres +++ b/structures/building-small-a.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://cntgl86ianngh"] [ext_resource type="PackedScene" uid="uid://cnycdi6t5tj01" path="res://models/building-small-a.glb" id="1_v5apy"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="2_q3i1h"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="2_q3i1h"] [resource] script = ExtResource("2_q3i1h") @@ -14,6 +14,6 @@ kW_usage = 1.0 kW_production = 0.0 selector_scale = 2.8 unlocked = false -spawn_builder = true +spawn_builder = false description = "A small residential building that can house 1 person. Perfect for getting your city started!" thumbnail = "res://sprites/residential/residential-building-red.png" diff --git a/structures/building-small-b.tres b/structures/building-small-b.tres index 83d3023..3e12fcd 100644 --- a/structures/building-small-b.tres +++ b/structures/building-small-b.tres @@ -1,11 +1,11 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://c5fveedgvunju"] [ext_resource type="PackedScene" uid="uid://d2h51qlls136h" path="res://models/building-small-b.glb" id="1_klt7o"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="2_a2t3e"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="2_a2t3e"] [resource] script = ExtResource("2_a2t3e") -title = "" +title = "Residential Building B" model = ExtResource("1_klt7o") type = 1 price = 60 @@ -14,5 +14,6 @@ kW_usage = 1.0 kW_production = 0.0 selector_scale = 2.8 unlocked = false -description = "Description" -thumbnail = "Thumbnail" +spawn_builder = false +description = "A slightly larger residential building that can house 1 person. A good upgrade from the basic house!" +thumbnail = "res://sprites/residential/residential-building-blue.png" diff --git a/structures/building-small-c.tres b/structures/building-small-c.tres index 5c118dd..cb095b9 100644 --- a/structures/building-small-c.tres +++ b/structures/building-small-c.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://bh65eqgid4kxy"] [ext_resource type="PackedScene" uid="uid://m74mvao50wnm" path="res://models/building-small-c.glb" id="1_6yyww"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="2_rkiq0"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="2_rkiq0"] [resource] script = ExtResource("2_rkiq0") diff --git a/structures/grass-trees-tall.tres b/structures/grass-trees-tall.tres index eee83c8..c837c7f 100644 --- a/structures/grass-trees-tall.tres +++ b/structures/grass-trees-tall.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://y6jafhfnhbrp"] [ext_resource type="PackedScene" uid="uid://dy26b1ba2j2v1" path="res://models/grass-trees-tall.glb" id="1_nbdd1"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="2_b2sah"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="2_b2sah"] [resource] script = ExtResource("2_b2sah") diff --git a/structures/grass-trees.tres b/structures/grass-trees.tres index 4e4790b..79f5d90 100644 --- a/structures/grass-trees.tres +++ b/structures/grass-trees.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://ccb475jeg7ym5"] [ext_resource type="PackedScene" uid="uid://b1711sieed2u6" path="res://models/grass-trees.glb" id="1_lcgc1"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="2_pnpij"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="2_pnpij"] [resource] script = ExtResource("2_pnpij") diff --git a/structures/grass.tres b/structures/grass.tres index 9cd4830..58b0815 100644 --- a/structures/grass.tres +++ b/structures/grass.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://tm532uesguhk"] [ext_resource type="PackedScene" uid="uid://cr3btp34bp3eg" path="res://models/grass.glb" id="1_2n0ef"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="2_1i4lf"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="2_1i4lf"] [resource] script = ExtResource("2_1i4lf") diff --git a/structures/power-plant.tres b/structures/power-plant.tres index 7dd9b82..5f15160 100644 --- a/structures/power-plant.tres +++ b/structures/power-plant.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://c4qbn3d85prxx"] [ext_resource type="PackedScene" uid="uid://ckxkrnomcegue" path="res://models/power_plant.glb" id="1_r8n8k"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="3_oloyn"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="3_oloyn"] [resource] script = ExtResource("3_oloyn") diff --git a/structures/road-intersection.tres b/structures/road-intersection.tres index 08d3e8e..75bdeeb 100644 --- a/structures/road-intersection.tres +++ b/structures/road-intersection.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://dveu4dnue0d54"] [ext_resource type="PackedScene" uid="uid://euxdh7lkq0oj" path="res://models/road-intersection.glb" id="1_pnjl2"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="2_3eq5k"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="2_3eq5k"] [resource] script = ExtResource("2_3eq5k") diff --git a/structures/road-straight-lightposts.tres b/structures/road-straight-lightposts.tres index 1ebf03f..c56a7fd 100644 --- a/structures/road-straight-lightposts.tres +++ b/structures/road-straight-lightposts.tres @@ -1,7 +1,7 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://mxrnqinnsqnt"] [ext_resource type="PackedScene" uid="uid://5kchntr735l" path="res://models/road-straight-lightposts.glb" id="1_i07jw"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="2_470aq"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="2_470aq"] [resource] script = ExtResource("2_470aq") diff --git a/structures/road-straight.tres b/structures/road-straight.tres index 6ba2eb9..c001982 100644 --- a/structures/road-straight.tres +++ b/structures/road-straight.tres @@ -1,6 +1,6 @@ [gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://dv14kkhb6umkv"] -[ext_resource type="Script" uid="uid://uxn26t1x4ehr" path="res://scripts/structure.gd" id="1_5fmmh"] +[ext_resource type="Script" path="res://scripts/structure.gd" id="1_5fmmh"] [ext_resource type="PackedScene" uid="uid://do24bjaohw3vy" path="res://models/road-straight.glb" id="1_ump1f"] [resource] @@ -13,7 +13,7 @@ population_count = 0 kW_usage = 0.0 kW_production = 0.0 selector_scale = 2.8 -unlocked = true +unlocked = false spawn_builder = false description = "A basic road for connecting parts of your city." thumbnail = "res://models/road-straight.glb"