diff --git a/configs/data.config.gd b/configs/data.config.gd new file mode 100644 index 0000000..cd424b3 --- /dev/null +++ b/configs/data.config.gd @@ -0,0 +1,8 @@ +# Mission Configs +enum ObjectiveType { + BUILD_STRUCTURE, + BUILD_RESIDENTIAL, + REACH_CASH_AMOUNT, + REACH_POPULATION, + LEARNING, +} diff --git a/global/event_bus.gd b/global/event_bus.gd new file mode 100644 index 0000000..a92004f --- /dev/null +++ b/global/event_bus.gd @@ -0,0 +1,10 @@ +extends Node + +signal population_update(count:int) + +var current_scene = null + +func _ready(): + var root = get_tree().root + # Using a negative index counts from the end, so this gets the last child node of `root`. + current_scene = root.get_child(-1) diff --git a/global/globals.gd b/global/globals.gd new file mode 100644 index 0000000..b3eaf78 --- /dev/null +++ b/global/globals.gd @@ -0,0 +1,17 @@ +extends Node + +@export var population: int = 0 + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + pass # Replace with function body. + + +func set_population_count(count: int) -> void: + # Update the population count + population += count + + # Emit the signal to notify other nodes + EventBus.population_update.emit(population) + + # Print the updated population for debugging diff --git a/mission/fifth_mission.tres b/mission/fifth_mission.tres deleted file mode 100644 index 72f925f..0000000 --- a/mission/fifth_mission.tres +++ /dev/null @@ -1,79 +0,0 @@ -[gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://p3xwn2mp6bm6"] - -[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_mum3p"] - -[sub_resource type="Resource" id="Resource_c06be"] -script = ExtResource("1_dhx01") -type = 7 -target_count = 1 -current_count = 0 -description = "Calculate how many power plants are needed to supply electricity to 40 houses." -structure_index = -1 -completed = false - -[resource] -script = ExtResource("2_mum3p") -id = "5" -title = "Residential Energy Usage" -description = "" -objectives = Array[ExtResource("1_dhx01")]([SubResource("Resource_c06be")]) -rewards = { -"cash": 0 -} -next_mission_id = "6" -graph_path = "" -full_screen_path = "" -intro_text = "A neighborhood is calculating energy usage from gaming consoles and TVs. -At House A, they ran 2 gaming consoles and 3 TVs and used a total of 660 kilowatt-hours (kWh) of electricity. -At House B, they ran 4 gaming consoles and 1 TV and used 760 kWh of electricity." -question_text = "" -correct_answer = "150,70" -feedback_text = "Correct! You've accurately calculated that gaming consoles use 150 kWh and TVs use 70 kWh. Using a system of equations: 2x + 3y = 660 and 4x + y = 760, you can solve by substitution to find x = 150 and y = 70." -incorrect_feedback = "Not quite right. Try setting up a system of equations: -- House A: 2 gaming consoles + 3 TVs = 660 kWh -- House B: 4 gaming consoles + 1 TV = 760 kWh -Let x be the kWh for gaming consoles and y be the kWh for TVs. -So we have: 2x + 3y = 660 and 4x + y = 760" -company_data = "" -power_math_content = "" -num_of_user_inputs = 2 -input_labels = Array[String](["Gaming Consoles", "TVs"]) -companion_dialog = { -"correct_answer": { -"animation": "celebration", -"duration": 5000, -"text": "Excellent work! You correctly determined that gaming consoles use 150 kWh and TVs use 70 kWh." -}, -"hint_request": { -"animation": "thinking", -"duration": 5000, -"text": "Try setting up two equations: 2x + 3y = 660 for House A and 4x + y = 760 for House B, where x is the energy used by consoles and y is the energy used by TVs." -}, -"hint_second": { -"animation": "thinking", -"duration": 5000, -"text": "You can solve this by substitution. Rearrange the second equation to find y = 760 - 4x, then substitute this into the first equation." -}, -"incorrect_answer": { -"animation": "sad", -"duration": 5000, -"text": "Not quite right. Let's try setting up the equations again. Remember, we have 2 consoles and 3 TVs using 660 kWh at House A, and 4 consoles and 1 TV using 760 kWh at House B." -}, -"mission_completed": { -"animation": "happy", -"duration": 5000, -"text": "Now that we know the energy usage, we can plan our city's power needs much better. Well done!" -}, -"mission_started": { -"animation": "greeting", -"duration": 5000, -"text": "Let's tackle a challenging energy problem! We need to figure out how much electricity gaming consoles and TVs use." -}, -"question_shown": { -"animation": "thinking", -"duration": 5000, -"text": "This is a system of equations problem. We have two houses with different combinations of gaming consoles and TVs." -} -} -unlocked_items = Array[String](["res://models/power_plant.glb"]) diff --git a/mission/first_mission.tres b/mission/first_mission.tres deleted file mode 100644 index f5a4fbc..0000000 --- a/mission/first_mission.tres +++ /dev/null @@ -1,63 +0,0 @@ -[gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://x5h4xutbldq3"] - -[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="1_nv6c6"] -[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_yfbrc"] - -[sub_resource type="Resource" id="Resource_ywws1"] -script = ExtResource("1_yfbrc") -type = 2 -target_count = 1 -current_count = 0 -description = "Build a road" -structure_index = -1 -completed = false - -[resource] -script = ExtResource("1_nv6c6") -id = "1" -title = "Building Roads" -description = "Welcome to the city builder! Let's start by placing your first road." -objectives = Array[ExtResource("1_yfbrc")]([SubResource("Resource_ywws1")]) -rewards = { -"cash": 250 -} -next_mission_id = "2" -graph_path = "" -full_screen_path = "" -intro_text = "Welcome to Stem City! Let's learn how to build a city from the ground up. Start by building a road." -question_text = "" -correct_answer = "" -feedback_text = "" -incorrect_feedback = "" -company_data = "" -power_math_content = "" -num_of_user_inputs = 1 -input_labels = Array[String]([]) -companion_dialog = { -"correct_answer": { -"animation": "happy", -"duration": 5000, -"text": ["Great job! That's the right answer!", "Perfect! You got it right!"] -}, -"incorrect_answer": { -"animation": "sad", -"duration": 5000, -"text": ["Hmm, that doesn't look right. Let's try again.", "Not quite right. Don't worry, you can try again!"] -}, -"mission_completed": { -"animation": "happy", -"duration": 6000, -"text": ["You've completed your first mission! Great job building your first road!"] -}, -"mission_started": { -"animation": "excited", -"duration": 6000, -"text": ["Welcome to Stem City! I'm your learning companion. Let's build a city together!", "Time to start our adventure in Stem City! I'll help you build your first city."] -}, -"objective_completed_2": { -"animation": "happy", -"duration": 5000, -"text": ["You built a road! Now your citizens can move around the city.", "Nice work on that road! Roads help connect different parts of your city."] -} -} -unlocked_items = Array[String](["res://models/building-small-a.glb"]) diff --git a/mission/fourth_mission.tres b/mission/fourth_mission.tres deleted file mode 100644 index 078cada..0000000 --- a/mission/fourth_mission.tres +++ /dev/null @@ -1,68 +0,0 @@ -[gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://bho4qh41asyk1"] - -[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_mum3p"] - -[sub_resource type="Resource" id="Resource_c06be"] -script = ExtResource("1_dhx01") -type = 3 -target_count = 40 -current_count = 0 -description = "Build 40 residential buildings with construction workers" -structure_index = -1 -completed = false - -[resource] -script = ExtResource("2_mum3p") -id = "4" -title = "City Expansion Project" -description = "Your city needs to grow! Build 40 residential buildings using your team of construction workers. Watch as they construct each building from the ground up!" -objectives = Array[ExtResource("1_dhx01")]([SubResource("Resource_c06be")]) -rewards = { -"cash": 0 -} -next_mission_id = "5" -graph_path = "" -full_screen_path = "" -intro_text = "Your city is expanding rapidly! Now that you've learned which construction company is more efficient, it's time to put them to work." -question_text = "" -correct_answer = "" -feedback_text = "" -incorrect_feedback = "" -company_data = "" -power_math_content = "" -num_of_user_inputs = 1 -input_labels = Array[String]([]) -companion_dialog = { -"hint_request": { -"animation": "thinking", -"duration": 5000, -"text": "Try placing the construction workers near where you want to build. They'll automatically start constructing buildings!" -}, -"mission_completed": { -"animation": "celebration", -"duration": 5000, -"text": "Amazing job! You've successfully built all 40 residential buildings. The city looks fantastic!" -}, -"mission_progress_25": { -"animation": "happy", -"duration": 5000, -"text": "Great progress! You've completed 25% of the buildings. Keep it up!" -}, -"mission_progress_50": { -"animation": "excited", -"duration": 5000, -"text": "Halfway there! The city is really taking shape now." -}, -"mission_progress_75": { -"animation": "excited", -"duration": 5000, -"text": "Almost there! Just a few more buildings to go." -}, -"mission_started": { -"animation": "greeting", -"duration": 5000, -"text": "Welcome to the City Expansion Project! We need to build 40 residential buildings using our construction workers." -} -} -unlocked_items = Array[String]([]) diff --git a/mission/second_mission.tres b/mission/second_mission.tres deleted file mode 100644 index 0733835..0000000 --- a/mission/second_mission.tres +++ /dev/null @@ -1,63 +0,0 @@ -[gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://cjr36hqnmyn0x"] - -[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_mum3p"] - -[sub_resource type="Resource" id="Resource_7c02e"] -script = ExtResource("1_dhx01") -type = 3 -target_count = 1 -current_count = 0 -description = "Build a residential building" -structure_index = -1 -completed = false - -[resource] -script = ExtResource("2_mum3p") -id = "2" -title = "Building Homes" -description = "Now that we have a road, let's build a residential building for our citizens!" -objectives = Array[ExtResource("1_dhx01")]([SubResource("Resource_7c02e")]) -rewards = { -"cash": 250 -} -next_mission_id = "3" -graph_path = "" -full_screen_path = "" -intro_text = "Great job on the road! Now let's build a residential building where our citizens can live." -question_text = "" -correct_answer = "" -feedback_text = "" -incorrect_feedback = "" -company_data = "" -power_math_content = "" -num_of_user_inputs = 1 -input_labels = Array[String]([]) -companion_dialog = { -"correct_answer": { -"animation": "happy", -"duration": 5000, -"text": ["Great job! That's the right answer!", "Perfect! You got it right!"] -}, -"incorrect_answer": { -"animation": "sad", -"duration": 5000, -"text": ["Hmm, that doesn't look right. Let's try again.", "Not quite right. Don't worry, you can try again!"] -}, -"mission_completed": { -"animation": "happy", -"duration": 6000, -"text": ["You've completed your second mission! Great job building your first residential building!"] -}, -"mission_started": { -"animation": "excited", -"duration": 6000, -"text": ["Now it's time to build homes for our citizens!", "Let's add a residential building to our city!"] -}, -"objective_completed_3": { -"animation": "excited", -"duration": 5000, -"text": ["Amazing! You built your first residential building where people can live.", "You just built a home for your city residents! The population is growing."] -} -} -unlocked_items = Array[String](["res://models/grass-trees.glb", "res://models/grass.glb"]) diff --git a/mission/sixth_mission.tres b/mission/sixth_mission.tres deleted file mode 100644 index c2e4983..0000000 --- a/mission/sixth_mission.tres +++ /dev/null @@ -1,68 +0,0 @@ -[gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://bv4r7ebpjdce4"] - -[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_nxtw6"] -[ext_resource type="Script" path="res://scripts/mission/mission_data.gd" id="2_83mjp"] - -[sub_resource type="Resource" id="Resource_power_plant"] -script = ExtResource("1_nxtw6") -type = 10 -target_count = 1 -current_count = 0 -description = "Build a power plant to provide electricity to your city" -structure_index = 7 -completed = false - -[resource] -script = ExtResource("2_83mjp") -id = "6" -title = "Powering Your City" -description = "Now that you've calculated how many power plants you need, it's time to build one to power your growing city of 40 houses." -objectives = Array[ExtResource("1_nxtw6")]([SubResource("Resource_power_plant")]) -rewards = { -"cash": 1000 -} -next_mission_id = "" -graph_path = "" -full_screen_path = "" -intro_text = "Your calculations showed that one power plant will be sufficient to power all 40 houses in your city. Let's build that power plant now to keep your residents happy!" -question_text = "" -correct_answer = "" -feedback_text = "" -incorrect_feedback = "" -company_data = "" -power_math_content = "" -num_of_user_inputs = 1 -input_labels = Array[String]([]) -companion_dialog = { -"building_selected": { -"animation": "happy", -"duration": 5000, -"text": "Great choice! The power plant will supply all the energy our residents need." -}, -"hint_request": { -"animation": "thinking", -"duration": 5000, -"text": "Click on the power plant in your building menu and then place it in an open area of your city." -}, -"mission_completed": { -"animation": "celebration", -"duration": 5000, -"text": "Congratulations! Your city now has power for all residents. You've learned how to use systems of equations to solve real-world problems!" -}, -"mission_started": { -"animation": "greeting", -"duration": 5000, -"text": "Time to power up our city! Based on our calculations, we need to build a power plant to provide electricity to all 40 houses." -}, -"placement_hint": { -"animation": "thinking", -"duration": 5000, -"text": "Try to place the power plant away from residential areas but close enough to supply power efficiently." -}, -"placement_success": { -"animation": "excited", -"duration": 5000, -"text": "Perfect placement! Now the power plant can distribute electricity to all the houses in your city." -} -} -unlocked_items = Array[String]([]) diff --git a/mission/third_mission.tres b/mission/third_mission.tres deleted file mode 100644 index 20b5330..0000000 --- a/mission/third_mission.tres +++ /dev/null @@ -1,63 +0,0 @@ -[gd_resource type="Resource" script_class="MissionData" load_steps=4 format=3 uid="uid://dykbopx8n3c3v"] - -[ext_resource type="Script" path="res://scripts/mission/mission_objective.gd" id="1_l3spi"] -[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 = 7 -target_count = 1 -current_count = 0 -description = "Compare two construction companies and determine which one is more efficient for building 40 houses in a week." -structure_index = -1 -completed = false - -[resource] -script = ExtResource("2_b4llw") -id = "3" -title = "Compare Construction Companies" -description = "As your city grows, you need to choose the most efficient construction company." -objectives = Array[ExtResource("1_l3spi")]([SubResource("Resource_c06be")]) -rewards = { -"cash": 500 -} -next_mission_id = "4" -graph_path = "res://images/mission_2.png" -full_screen_path = "" -intro_text = "Your city is rapidly growing, and you need to build houses to accommodate new residents! Two different construction companies offer to help. Study the company data below, find the unit rates (houses per worker), and determine which company would require fewer workers to build 40 houses in a week. Which company requires fewer workers to build 40 houses in a week? (A or B)" -question_text = "Which company requires fewer workers to build 40 houses in a week? (A or B)" -correct_answer = "A" -feedback_text = "Correct! Company A (City Builders Inc.) would require fewer workers to build 40 houses. Company A builds at a rate of 4 houses per worker per week, while Company B builds at a rate of 3 houses per worker per week. For 40 houses, Company A needs 10 workers while Company B needs about 13.33 workers." -incorrect_feedback = "Not quite right. Look carefully at the data for both companies. Compare their rates: Company A builds 4 houses per worker per week, while Company B builds 3 houses per worker per week. Calculate how many workers each would need for 40 houses." -company_data = "" -power_math_content = "" -num_of_user_inputs = 1 -input_labels = Array[String]([]) -companion_dialog = { -"correct_answer": { -"animation": "happy", -"duration": 5000, -"text": ["Perfect! Company A is more efficient because each worker builds more houses per week.", "Exactly right! You found the company that can build the houses with fewer workers."] -}, -"incorrect_answer": { -"animation": "sad", -"duration": 5000, -"text": ["Let's think about this differently. Look at how many houses each worker can build per week and calculate from there.", "Not quite right. Check the rates carefully: how many houses can one worker build in a week for each company?"] -}, -"mission_completed": { -"animation": "happy", -"duration": 6000, -"text": "Great job selecting the most efficient construction company! Your city will grow faster now." -}, -"mission_started": { -"animation": "excited", -"duration": 6000, -"text": ["It's time to expand our city! We need to choose the most efficient construction company.", "We have two construction companies offering their services. Let's analyze which one is better!"] -}, -"objective_completed_7": { -"animation": "happy", -"duration": 5000, -"text": ["You've solved the construction company problem! That's good mathematical thinking.", "You've made a wise decision based on the data. That's how city planners work!"] -} -} -unlocked_items = Array[String](["res://models/road-corner.glb"]) diff --git a/models/building-small-d.glb b/models/building-small-d.glb deleted file mode 100644 index e654827..0000000 Binary files a/models/building-small-d.glb and /dev/null differ diff --git a/models/building-small-d.glb.import b/models/building-small-d.glb.import deleted file mode 100644 index 94d07a2..0000000 --- a/models/building-small-d.glb.import +++ /dev/null @@ -1,36 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://h0vrvst3cumo" -path="res://.godot/imported/building-small-d.glb-5e1b608dc43429cd8ce16f120ad53455.scn" - -[deps] - -source_file="res://models/building-small-d.glb" -dest_files=["res://.godot/imported/building-small-d.glb-5e1b608dc43429cd8ce16f120ad53455.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/project.godot b/project.godot index 8f2d8ca..f2649e6 100644 --- a/project.godot +++ b/project.godot @@ -25,6 +25,8 @@ general/default_playback_type.web=0 [autoload] SoundManager="*res://scripts/sound_manager.gd" +EventBus="*res://global/event_bus.gd" +Globals="*res://global/globals.gd" [display] diff --git a/resources/generic_text_panel.resource.gd b/resources/generic_text_panel.resource.gd index 93d69f8..2a46957 100644 --- a/resources/generic_text_panel.resource.gd +++ b/resources/generic_text_panel.resource.gd @@ -2,7 +2,7 @@ extends Resource class_name GenericText -@export_enum("intro", "outro") var panel_type +@export_enum("intro", "outro", "mission") var panel_type @export var title: String = "Welcome to Stem City" @export_multiline var body_text: String = "Some sample body" @export var button_text: String = "Close" diff --git a/scenes/main.tscn b/scenes/main.tscn index 1a4d90c..c350a0f 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=34 format=3 uid="uid://vgwrcfy1qawf"] +[gd_scene load_steps=63 format=3 uid="uid://vgwrcfy1qawf"] [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"] @@ -8,44 +8,67 @@ [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="Script" path="res://scripts/view.gd" id="8_yovpv"] +[ext_resource type="Resource" uid="uid://tm532uesguhk" path="res://structures/grass.tres" id="9_2t3p4"] +[ext_resource type="Resource" uid="uid://d2jplegnkl6u2" path="res://structures/road-corner.tres" id="10_ii8xx"] [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://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="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="Script" path="res://scripts/mission/mission_data.gd" id="14_vcrh8"] -[ext_resource type="Resource" uid="uid://x5h4xutbldq3" path="res://mission/first_mission.tres" id="15_obmwc"] -[ext_resource type="Resource" uid="uid://cjr36hqnmyn0x" path="res://mission/second_mission.tres" id="16_rl54y"] -[ext_resource type="Resource" uid="uid://dykbopx8n3c3v" path="res://mission/third_mission.tres" id="17_rrdy6"] +[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="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="Resource" uid="uid://bho4qh41asyk1" path="res://mission/fourth_mission.tres" id="18_h4fpv"] [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="Resource" uid="uid://p3xwn2mp6bm6" path="res://mission/fifth_mission.tres" id="19_e8sub"] [ext_resource type="Script" path="res://scripts/game_manager.gd" id="20_game_manager"] -[ext_resource type="Resource" uid="uid://bv4r7ebpjdce4" path="res://mission/sixth_mission.tres" id="20_r0ysx"] +[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="PackedScene" uid="uid://cb2rylpbex3ep" path="res://models/building-arcology.glb" id="27_m8wco"] +[ext_resource type="Resource" uid="uid://dtal0tl2ee336" path="res://structures/store.tres" id="21_y11qv"] +[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="Resource" uid="uid://qwiwim2pg88f" path="res://mission/unit_1.02/market_research_4.tres" id="26_lvk23"] +[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://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://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"] +[ext_resource type="Resource" uid="uid://doxd30r8qbgdq" path="res://mission/unit_1.03_1.05/traffic_flow_4.tres" id="34_21t20"] +[ext_resource type="Resource" uid="uid://duaxn13myfx22" path="res://mission/unit_1.06/sustainable_dev_1.tres" id="35_o0bjh"] +[ext_resource type="Resource" uid="uid://fuxb3pfbbwjm" path="res://mission/unit_1.06/sustainable_dev_2.tres" id="36_2wodh"] +[ext_resource type="Resource" uid="uid://byd5jxiutxpky" path="res://mission/unit_1.06/sustainable_dev_3.tres" id="37_psgx1"] +[ext_resource type="Resource" uid="uid://daug1o7kppqit" path="res://mission/unit_1.06/sustainable_dev_4.tres" id="38_hw762"] +[ext_resource type="Resource" uid="uid://cp7tcpktwlrkt" path="res://mission/unit_1.06/urban_planning_1.tres" id="39_ymw5p"] +[ext_resource type="Resource" uid="uid://c3q1afcvwi4rk" path="res://mission/unit_1.06/urban_planning_2.tres" id="40_uggp1"] +[ext_resource type="Resource" uid="uid://ct1k7n2oopwdu" path="res://mission/unit_1.06/urban_planning_3.tres" id="41_f0dxf"] +[ext_resource type="Resource" uid="uid://d1fykuxfmh2q1" path="res://mission/unit_1.06/urban_planning_4.tres" id="42_fv8gl"] +[ext_resource type="Resource" uid="uid://detwnqsq87r30" path="res://mission/unit_1.07/economic_forecast_1.tres" id="43_qvne6"] +[ext_resource type="Resource" uid="uid://bj7tjuknfaeyg" path="res://mission/unit_1.07/economic_forecast_2.tres" id="44_haub2"] +[ext_resource type="Resource" uid="uid://ctyrlnq5cxuiu" path="res://mission/unit_1.07/economic_forecast_3.tres" id="45_xs8xk"] +[ext_resource type="Resource" uid="uid://ct45gjmw5b7pa" path="res://mission/unit_1.07/economic_forecast_4.tres" id="46_pob6d"] +[ext_resource type="Resource" uid="uid://bwrkqv42wk8f" path="res://mission/unit_1.07/resource_alloc_1.tres" id="47_6w4y8"] +[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"] [sub_resource type="Resource" id="Resource_1gdbm"] script = ExtResource("14_76jlq") panel_type = 0 title = "Welcome to Stem City " -body_text = "Hi League Community, +body_text = "Welcome to Stem City! Your goal is to build a thriving community from the ground up. As you complete missions, you'll unlock new structures to expand and improve your city. - Each mission introduces important Math concepts used in urban planning and city management. You'll apply mathematics while watching your city grow. +As the new city planner, you need to establish a baseline understanding of your growing community. The mayor has requested a comprehensive census to guide future development. -You are the very first group of students who get to test this. So keep in mind there will be bugs, but do note them. -We are aware of the following bugs: -- Population count may be off by 1 -- Lighting Baking in Web Builds are too bright -- We don't restrict building off of roads which will cause workers not to reach buildings -- Building overlap -- No builders for Power Plant Ready to start planning your city? Click Close to see the controls and begin your first mission! @@ -127,7 +150,7 @@ outro_text_resource = SubResource("Resource_ja86h") [node name="Builder" type="Node3D" parent="." node_paths=PackedStringArray("selector", "selector_container", "view_camera", "gridmap", "cash_display")] script = ExtResource("1_jybm7") -structures = Array[ExtResource("2_54v6r")]([ExtResource("2_bwyku"), ExtResource("5_v5o2m"), ExtResource("6_fwsy4")]) +structures = Array[ExtResource("2_54v6r")]([ExtResource("2_bwyku"), ExtResource("5_v5o2m"), ExtResource("6_fwsy4"), ExtResource("21_y11qv"), ExtResource("9_2t3p4"), ExtResource("10_ii8xx"), ExtResource("11_20frt"), ExtResource("12_xtc7p")]) selector = NodePath("Selector") selector_container = NodePath("Selector/Container") view_camera = NodePath("../View/Camera") @@ -179,7 +202,7 @@ resource_data = ExtResource("14_76jlq") [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("18_h4fpv"), ExtResource("19_e8sub"), ExtResource("20_r0ysx")]) +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"), ExtResource("46_pob6d"), ExtResource("47_6w4y8"), ExtResource("48_ck35a"), ExtResource("49_cvgxw"), ExtResource("50_6ke0d")]) mission_ui = NodePath("MissionPanel") builder = NodePath("../Builder") character_scene = ExtResource("18_8lrh8") @@ -217,6 +240,7 @@ theme_override_fonts/font = ExtResource("17_vlub6") theme_override_font_sizes/font_size = 24 text = "Mission Title" horizontal_alignment = 1 +autowrap_mode = 2 [node name="HSeparator" type="HSeparator" parent="MissionManager/MissionPanel/MarginContainer/VBoxContainer"] layout_mode = 2 @@ -369,4 +393,5 @@ offset_bottom = 23.0 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10, -16, -14) [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/mission_panel.tscn b/scenes/mission_panel.tscn index fb794e6..fc8c9b1 100644 --- a/scenes/mission_panel.tscn +++ b/scenes/mission_panel.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=2 format=3 uid="uid://cam5blhxixlnb"] +[gd_scene load_steps=2 format=3 uid="uid://bo6c8g64ixmo"] [ext_resource type="Script" path="res://scripts/mission/mission_ui.gd" id="1_wl28p"] diff --git a/scenes/objective_label.tscn b/scenes/objective_label.tscn deleted file mode 100644 index 9109c9f..0000000 --- a/scenes/objective_label.tscn +++ /dev/null @@ -1,13 +0,0 @@ -[gd_scene format=3 uid="uid://b7oa3hlu1ki3v"] - -[node name="ObjectiveLabel" type="Control"] -layout_mode = 3 -anchors_preset = 0 -offset_right = 40.0 -offset_bottom = 23.0 - -[node name="Label" type="Label" parent="."] -layout_mode = 0 -offset_right = 40.0 -offset_bottom = 23.0 -text = "Objective" diff --git a/scripts/NavigationNPC.gd b/scripts/NavigationNPC.gd index 01bdac8..53e6940 100644 --- a/scripts/NavigationNPC.gd +++ b/scripts/NavigationNPC.gd @@ -36,7 +36,6 @@ func _ready() -> void: func _start_initial_movement(): await get_tree().process_frame pick_random_target() - print("Initial movement target set for character at ", global_position) # Force movement to a specific target func _unhandled_input(event: InputEvent) -> void: diff --git a/scripts/audio_bridge.gd b/scripts/audio_bridge.gd index 819b041..629ad21 100644 --- a/scripts/audio_bridge.gd +++ b/scripts/audio_bridge.gd @@ -106,7 +106,6 @@ func connect_to_sound_manager() -> bool: })(); """ - // Set up the callback js.set_callback("godot_audio_state_callback", Callable(self, "_on_audio_state_received")) result = js.eval(post_message_script) diff --git a/scripts/builder.gd b/scripts/builder.gd index 550d60a..943eded 100644 --- a/scripts/builder.gd +++ b/scripts/builder.gd @@ -66,7 +66,7 @@ func _ready(): if structure.model.resource_path.contains("power_plant"): # Scale power plant model to be much smaller (0.5x) transform = transform.scaled(Vector3(0.5, 0.5, 0.5)) - elif structure.type == Structure.StructureType.RESIDENTIAL_BUILDING or structure.type == Structure.StructureType.ROAD: + else: # Scale buildings and roads to be consistent (3x) transform = transform.scaled(Vector3(3.0, 3.0, 3.0)) @@ -254,8 +254,7 @@ func action_build(gridmap_position): # Make sure any existing NPCs are children of the navigation region _move_characters_to_navregion() elif is_power_plant: - # Special handling for power plants - add directly as a child of the builder - _add_power_plant(gridmap_position, index) + #add_power_plant(gridmap_position, index) # We still set the cell item for collision detection gridmap.set_cell_item(gridmap_position, index, gridmap.get_orthogonal_index_from_basis(selector.basis)) @@ -493,16 +492,10 @@ func update_structure(): _model.scale = Vector3(0.5, 0.5, 0.5) # Center the power plant model within the selector _model.position = Vector3(-3.0, 0.0, 3.0) # Reset position - elif (structures[index].type == Structure.StructureType.RESIDENTIAL_BUILDING - or structures[index].type == Structure.StructureType.ROAD - or structures[index].type == Structure.StructureType.TERRAIN - or structures[index].model.resource_path.contains("grass")): + else: # Scale buildings, roads, and decorative terrain to match (3x) _model.scale = Vector3(3.0, 3.0, 3.0) _model.position.y += 0.0 # No need for Y adjustment with scaling - else: - # Standard positioning for other structures - _model.position.y += 0.25 # Get the selector scale from the structure resource var scale_factor = structures[index].selector_scale @@ -646,11 +639,9 @@ func _update_mission_objective_on_demolish(): var mission_manager = get_node_or_null("/root/Main/MissionManager") if mission_manager and mission_manager.current_mission: - # Check if we're in mission 3 (build 40 residential buildings) - if mission_manager.current_mission.id != "3": # For other missions, use the normal method var mission_id = mission_manager.current_mission.id - mission_manager.update_objective_progress(mission_id, MissionObjective.ObjectiveType.BUILD_RESIDENTIAL, -1) + mission_manager.update_objective_progress(mission_id, MissionObjective.ObjectiveType, -1) # Function to remove terrain (grass or trees) func _remove_terrain(position: Vector3): diff --git a/scripts/game_manager.gd b/scripts/game_manager.gd index c36c874..1617c5e 100644 --- a/scripts/game_manager.gd +++ b/scripts/game_manager.gd @@ -1,6 +1,11 @@ extends Node -# This script handles overall game management tasks +# This script handles overall game management tasks, including audio management and UI interactions. +var config = ConfigFile.new() + + + + var music_player: AudioStreamPlayer var building_sfx: AudioStreamPlayer @@ -14,6 +19,11 @@ var construction_sfx: AudioStreamPlayer func _ready(): + # Load data from a file. + var err = config.load("global://config.cfg") + # If the file didn't load, ignore it. + if err != OK: + return # Register SoundManager in the main loop for JavaScript bridge to find Engine.get_main_loop().set_meta("sound_manager", get_node_or_null("/root/SoundManager")) @@ -296,3 +306,21 @@ func _on_mission_manager_all_missions_completed() -> void: if generic_text_panel and outro_text_resource: generic_text_panel.apply_resource_data(outro_text_resource) generic_text_panel.show_panel() + + +func _on_mission_manager_mission_started(mission: MissionData) -> void: + var mission_manager: Node = get_node_or_null("/root/Main/MissionManager") + if mission_manager and mission_manager.mission_ui: + mission_manager.mission_ui.update_mission_display(mission) + + var mission_text = GenericText.new() + mission_text.panel_type = 2 + mission_text.title = mission.title + mission_text.body_text = mission.description + mission_text.button_text = "Start Mission" + + print(generic_text_panel) + if generic_text_panel: + generic_text_panel.apply_resource_data(mission_text) + generic_text_panel.show_panel() + diff --git a/scripts/hud_manager.gd b/scripts/hud_manager.gd index 08d09d4..279c9f4 100644 --- a/scripts/hud_manager.gd +++ b/scripts/hud_manager.gd @@ -1,16 +1,15 @@ extends Node # Signals -signal population_updated(new_population) -signal electricity_updated(usage, production) +signal electricity_updated(usage, production) # Variables var total_population: int = 0 var total_kW_usage: float = 0.0 var total_kW_production: float = 0.0 # References -var builder +var buildeJuj var building_construction_manager var population_label: Label var electricity_label: Label @@ -19,14 +18,17 @@ var population_tooltip: Control var electricity_tooltip: Control var controls_panel: PanelContainer var sound_panel: PanelContainer +var builder:Node func _ready(): # Connect to signals from the builder builder = get_node_or_null("/root/Main/Builder") - population_updated.connect(update_population_count) if builder: builder.structure_placed.connect(_on_structure_placed) builder.structure_removed.connect(_on_structure_removed) + + +# EventBus.population_update.connect(set_population_count) # Initialize UI elements population_label = $HBoxContainer/PopulationItem/PopulationLabel @@ -34,6 +36,8 @@ func _ready(): electricity_indicator = $HBoxContainer/ElectricityItem/ElectricityValues/ElectricityIndicator population_tooltip = $PopulationTooltip electricity_tooltip = $ElectricityTooltip + + # Ensure electricity indicator starts with red color if electricity_indicator: @@ -58,7 +62,15 @@ func _ready(): electricity_tooltip.visible = false # Update HUD - update_hud() + update_hud() + + +func _process(delta): + # Update the population label if it changes + if population_label and Globals.population != total_population: + total_population = Globals.population + population_label.text = str(total_population) + # Called when a structure is placed func _on_structure_placed(structure_index, position): @@ -119,7 +131,7 @@ func _on_structure_removed(structure_index, position): # Update Population -func update_population_count(count: int): +func set_population_count(count: int): total_population += count population_label.text = str(total_population) diff --git a/scripts/mission/building_construction_manager.gd b/scripts/mission/building_construction_manager.gd index a504e59..133d655 100644 --- a/scripts/mission/building_construction_manager.gd +++ b/scripts/mission/building_construction_manager.gd @@ -1,13 +1,19 @@ extends Node class_name BuildingConstructionManager +# Constants +const ObjectiveType = preload("res://configs/data.config.gd").ObjectiveType + + # Signals signal construction_completed(position) signal worker_construction_started signal worker_construction_ended + const CONSTRUCTION_TIME = 10.0 # seconds to build a building + # References to necessary scenes and resources var worker_scene: PackedScene var hud_manager: Node @@ -15,14 +21,18 @@ var nav_region: NavigationRegion3D var builder: Node3D var building_plot_scene: PackedScene var final_building_scene: PackedScene +var mission_manager: MissionManager # Keep track of all construction sites var construction_sites = {} # position (Vector3) -> construction data (dict) func _ready(): + # 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") if not worker_scene: worker_scene = load("res://people/character-female-a.glb") if not worker_scene: @@ -259,8 +269,8 @@ 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 _on_update_population(count: int): - hud_manager.population_updated.emit(count) +func update_population(count: int): + Globals.set_population_count(count) @@ -293,7 +303,7 @@ func _complete_construction(position: Vector3): _place_final_building(position, site["structure_index"]) # Update mission objective now that construction is complete - _update_mission_objective_on_completion(site["structure_index"]) +# _update_mission_objective_on_completion(site["structure_index"]) # Check if we should spawn a resident var mission_manager = builder.get_node_or_null("/root/Main/MissionManager") @@ -307,40 +317,11 @@ func _complete_construction(position: Vector3): # Spawn a resident from the new building (except for first building in mission 1) if should_spawn_resident: _spawn_resident_from_building(position) - - # Update population in the HUD when construction is complete - # Try different possible paths to find the HUD - var hud = get_node_or_null("/root/Main/CanvasLayer/HUD") - - # If not found, try to find it by group (we added the HUD to "hud" group) - if not hud: - var hud_nodes = get_tree().get_nodes_in_group("hud") - if hud_nodes.size() > 0: - hud = hud_nodes[0] - - # If not found, try other common paths - if not hud: - var scene_root = get_tree().get_root() - for child in scene_root.get_children(): - if child.name == "Main": - if child.has_node("CanvasLayer/HUD"): - hud = child.get_node("CanvasLayer/HUD") - break - - # Last resort - try to find using builder's cash_display - if not hud and builder and builder.cash_display: - var parent = builder.cash_display.get_parent() - while parent and parent.get_parent(): - if "HUD" in parent.name: - hud = parent - break - parent = parent.get_parent() - - if hud and site["structure_index"] >= 0 and site["structure_index"] < builder.structures.size(): - var structure = builder.structures[site["structure_index"]] - - if structure.type == Structure.StructureType.RESIDENTIAL_BUILDING and structure.population_count > 0: - _on_update_population(structure.population_count) + + var structure = builder.structures[site["structure_index"]] + + if structure.type == Structure.StructureType.RESIDENTIAL_BUILDING and structure.population_count > 0: + update_population(structure.population_count) # hud.total_population += structure.population_count # hud.update_hud() # hud.population_updated.emit(hud.total_population) @@ -365,35 +346,8 @@ func handle_demolition(position: Vector3): # Remove the entry from the dictionary construction_sites.erase(position) - -# Function to update mission objective when construction is complete -func _update_mission_objective_on_completion(structure_index: int): - # Get reference to mission manager - var mission_manager = builder.get_node_or_null("/root/Main/MissionManager") + - if mission_manager and mission_manager.current_mission: - # Check if this is a residential building - if structure_index >= 0 and structure_index < builder.structures.size(): - var structure = builder.structures[structure_index] - - if structure.type == Structure.StructureType.RESIDENTIAL_BUILDING: - # For mission 3, we'll rely on the fix_mission.gd script to maintain an accurate count - # This prevents double counting, as we just need to make sure buildings are counted - # based on their actual presence in the scene - if mission_manager.current_mission.id == "3": - # Instead of directly updating, we'll wait for the fix script to apply the proper count - pass - - # Special handling for mission 1 - elif mission_manager.current_mission.id == "1": - # For mission 1, we need to make sure the objectives are updated - mission_manager.update_objective_progress( - mission_manager.current_mission.id, - MissionObjective.ObjectiveType.BUILD_RESIDENTIAL - ) - - # Trigger an immediate progress check - mission_manager.check_mission_progress(mission_manager.current_mission.id) # Place the final building at the construction site func _place_final_building(position: Vector3, structure_index: int): diff --git a/scripts/mission/construction_worker.gd b/scripts/mission/construction_worker.gd index 5a029ad..2d1a6a8 100644 --- a/scripts/mission/construction_worker.gd +++ b/scripts/mission/construction_worker.gd @@ -216,24 +216,21 @@ func loop_construction_sound(): # Play the sound again construction_sound.play() - print("DEBUG: Looping sound for worker " + str(my_sound_id)) - else: - print("DEBUG: Cannot loop sound - either worker not active or sound not set up") + func finish_construction(): - print("DEBUG: Worker " + str(my_sound_id) + " finishing construction") is_construction_active = false construction_finished = true # Stop the construction sound if construction_sound and construction_sound.playing: construction_sound.stop() - print("DEBUG: Stopped sound for worker " + str(my_sound_id)) + # Stop the sound loop timer if loop_timer and loop_timer.is_inside_tree(): loop_timer.stop() - print("DEBUG: Stopped timer for worker " + str(my_sound_id)) + # Emit signal for compatibility construction_ended.emit() diff --git a/scripts/mission/mission_manager.gd b/scripts/mission/mission_manager.gd index 7c7c7b2..4bc3411 100644 --- a/scripts/mission/mission_manager.gd +++ b/scripts/mission/mission_manager.gd @@ -4,6 +4,7 @@ class_name MissionManager # Add the JavaScript bridge for HTML5 export # 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 signal mission_started(mission: MissionData) signal mission_completed(mission: MissionData) @@ -18,14 +19,15 @@ signal all_missions_completed() @export var character_scene: PackedScene var current_mission: MissionData +var current_objective: MissionObjective var active_missions: Dictionary = {} # mission_id: MissionData var character_spawned: bool = false var learning_companion_connected: bool = false # Panel state tracking -var is_unlocked_panel_showing = false -var delayed_mission_start_queue = [] # Queue of missions to start after unlocked panel closes +var is_unlocked_panel_showing: bool = false +var delayed_mission_start_queue = [] # Queue of missions to start after unlocked panel closes # Mission skip variables var skip_key_presses: int = 0 @@ -39,7 +41,8 @@ var learning_panel var fullscreen_learning_panel func _ready(): - + + EventBus.population_update.connect(population_updated) if builder: # Connect to builder signals builder.connect("structure_placed", _on_structure_placed) @@ -225,138 +228,14 @@ func start_mission(mission: MissionData): current_mission = mission active_missions[mission.id] = mission + mission_started.emit(current_mission) - # Send mission started event to the learning companion - # This will also send the companion dialog data - _on_mission_started_for_companion(mission) + # Set the first objective as the current objective + if mission.objectives.size() > 0: + current_objective = mission.objectives[0] + print("Set current objective: " + str(current_objective.type) + " - " + current_objective.description) - # Fix for mission 3 to ensure accurate count - if mission.id == "3": - # Reset the residential building count to 0 to avoid any double counting - for objective in mission.objectives: - if objective.type == MissionObjective.ObjectiveType.BUILD_RESIDENTIAL: - objective.current_count = 0 - objective.completed = false - - # Load and run the fix script to count actual buildings - var FixMissionScript = load("res://scripts/fix_mission.gd") - if FixMissionScript: - var fix_node = Node.new() - fix_node.set_script(FixMissionScript) - fix_node.name = "FixMissionHelper" - add_child(fix_node) - - # Add decorative structures and curved roads - # Use more robust checking - fallback to ID for backward compatibility - var is_construction_or_expansion = (mission.id == "2" or mission.id == "3") - if is_construction_or_expansion and builder: - # Check if we need to add the road-corner and decoration structures - var has_road_corner = false - var has_grass_trees_tall = false - var has_grass = false - - # Look through existing structures to see if we already have them - for structure in builder.structures: - if structure.model.resource_path.contains("road-corner"): - has_road_corner = true - elif structure.model.resource_path.contains("grass-trees-tall"): - has_grass_trees_tall = true - elif structure.model.resource_path.contains("grass") and not structure.model.resource_path.contains("trees"): - has_grass = true - - # Add the road-corner if missing - if not has_road_corner: - var road_corner = load("res://structures/road-corner.tres") - if road_corner: - builder.structures.append(road_corner) - - # Add the grass-trees-tall if missing - if not has_grass_trees_tall: - var grass_trees_tall = load("res://structures/grass-trees-tall.tres") - if grass_trees_tall: - builder.structures.append(grass_trees_tall) - - # Add the grass if missing - if not has_grass: - var grass = load("res://structures/grass.tres") - if grass: - builder.structures.append(grass) - - # Special handling for power plant mission: add power plant - # Use more robust checking for power missions - check power_math_content as well - elif (mission.id == "5" or mission.power_math_content != "") and builder: - # Check if we need to add the power plant - var has_power_plant = false - - # Look through existing structures to see if we already have it - for structure in builder.structures: - if structure.model.resource_path.contains("power_plant"): - has_power_plant = true - break - - # Add the power plant if missing - if not has_power_plant: - var power_plant = load("res://structures/power-plant.tres") - if power_plant: - builder.structures.append(power_plant) - - # Update the mesh library to include the new structures - if builder.gridmap and builder.gridmap.mesh_library: - var mesh_library = builder.gridmap.mesh_library - - # Update mesh library for any new structures - for i in range(builder.structures.size()): - var structure = builder.structures[i] - if i >= mesh_library.get_item_list().size(): - var id = mesh_library.get_last_unused_item_id() - mesh_library.create_item(id) - mesh_library.set_item_mesh(id, builder.get_mesh(structure.model)) - - # Apply appropriate scaling for all road types, buildings, and terrain - var transform = Transform3D() - if structure.model.resource_path.contains("power_plant"): - # Scale power plant model to be much smaller (0.5x) - transform = transform.scaled(Vector3(0.5, 0.5, 0.5)) - elif (structure.type == Structure.StructureType.RESIDENTIAL_BUILDING - or structure.type == Structure.StructureType.ROAD - or structure.type == Structure.StructureType.TERRAIN - or structure.model.resource_path.contains("grass")): - # Scale buildings, roads, and decorative terrain to be consistent (3x) - transform = transform.scaled(Vector3(3.0, 3.0, 3.0)) - - mesh_library.set_item_mesh_transform(id, transform) - - # Make sure the builder's structure selector is updated - builder.update_structure() - # Check if mission has a learning objective - var has_learning_objective = false - # Make sure mission has valid objectives data - if mission != null and mission.objectives != null: - for objective in mission.objectives: - if objective != null and objective.type == MissionObjective.ObjectiveType.LEARNING: - has_learning_objective = true - break - - # Show learning panel if mission has a learning objective - if has_learning_objective: - # Determine which panel to use based on whether full_screen_path is provided - if not mission.full_screen_path.is_empty(): - # Use fullscreen panel for fullscreen missions - if fullscreen_learning_panel: - fullscreen_learning_panel.show_fullscreen_panel(mission) - else: - print("ERROR: Fullscreen learning panel not available but mission requires it") - else: - # Use regular panel for traditional missions - if learning_panel: - learning_panel.show_learning_panel(mission) - else: - print("ERROR: Regular learning panel not available") - - # Emit signal and update UI - mission_started.emit(mission) - update_mission_ui() func complete_mission(mission_id: String): if not active_missions.has(mission_id): @@ -376,8 +255,8 @@ func complete_mission(mission_id: String): print("Handling structure unlocking for mission: " + mission.id) _handle_structure_unlocking(mission) - # Remove from active missions - active_missions.erase(mission_id) + # Keep a copy of the mission for UI display during transition + var completed_mission = mission # Figure out if there's a next mission var next_mission: MissionData @@ -391,45 +270,74 @@ func complete_mission(mission_id: String): # Emit mission completed signal mission_completed.emit(mission) - # Start the next mission if one is available + # Only remove from active missions after we're ready to show the next one + # This ensures the UI always has a mission to display if next_mission: - # Start the next mission after a short delay + # Keep the active mission during the delay await get_tree().create_timer(2.0).timeout + + # Only now remove the old mission + active_missions.erase(mission_id) + + # Start the next mission start_mission(next_mission) else: + # Only remove after delay for last mission too + await get_tree().create_timer(2.0).timeout + 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(mission_id, objective_type, count_change = 1): - if not active_missions.has(mission_id): - return +func update_objective_progress(structure:Structure = null): + match current_objective.type: + ObjectiveType.BUILD_RESIDENTIAL: + current_objective.current_count += structure.population_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) ## So Companion can react + update_current_objective(current_mission) + ObjectiveType.BUILD_STRUCTURE: + current_objective.current_count += 1 + 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) ## So Companion can react + update_current_objective(current_mission) # Go ahead and progress to nex objective if it exists. + 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) ## So Companion can react + update_current_objective(current_mission) # Go ahead and progress to nex objective if it exists. + + # IF this is true then objectives are completed + - var mission = active_missions[mission_id] - for objective in mission.objectives: - if objective.type == objective_type: - objective.current_count += count_change - - # Only update to completed if we've reached the target - if objective.current_count >= objective.target_count and not objective.completed: - objective.completed = true - objective_completed.emit(objective) - - # Send dialog event if available - var dialog_key = "objective_completed_" + str(objective.type) - _send_companion_dialog(dialog_key, mission) - - # Update UI - update_mission_ui() - - # Emit progress signal for objective - objective_progress.emit(objective, objective.current_count) - - # Check if the mission is complete - check_mission_completion(mission_id) - break + + update_mission_ui() + objective_progress.emit(current_objective, current_objective.current_count) + + + + + +func is_structure_of_current_mission(structure:Structure): + if not current_mission: + print("ERROR: No current mission to check structure against") + return false + if current_objective.structure == structure: + return true + else: + return false + func check_objective_completion(mission_id, objective_type): if not active_missions.has(mission_id): @@ -469,6 +377,9 @@ func reset_objective_count(objective_type, new_count): # Send dialog event if available var dialog_key = "objective_completed_" + str(objective.type) _send_companion_dialog(dialog_key, mission) + + # Update current objective to next incomplete one + update_current_objective(mission) # Update UI update_mission_ui() @@ -511,16 +422,18 @@ func _on_structure_placed(structure_index, position): var structure = builder.structures[structure_index] print("Structure placed: " + structure.model.resource_path) - # Update objectives based on structure type + # Check if this structure is needed for the current objective + if current_mission and is_structure_of_current_mission(structure): + # Update the objective progress + update_objective_progress(structure) + if current_mission: - if structure.type == Structure.StructureType.ROAD: - update_objective_progress(current_mission.id, MissionObjective.ObjectiveType.BUILD_ROAD) - elif structure.type == Structure.StructureType.RESIDENTIAL_BUILDING: + 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 current_mission.id == "1" and not character_spawned: + if character_spawned: # Only spawn a new character if: # 1. This is mission 1 # 2. We haven't spawned a character yet @@ -535,16 +448,6 @@ func _on_structure_placed(structure_index, position): if spawn_character: # This will be done after construction completes in mission_manager._on_construction_completed print("Character will be spawned after construction completes") - else: - # Update the objective progress for building a residential structure - update_objective_progress(current_mission.id, MissionObjective.ObjectiveType.BUILD_RESIDENTIAL) - else: - # Normal case - not mission 1 or character already spawned - update_objective_progress(current_mission.id, MissionObjective.ObjectiveType.BUILD_RESIDENTIAL) - elif structure.type == Structure.StructureType.POWER_PLANT: - # For mission 5, we update the economy/power objective when a power plant is built - if current_mission.id == "6": - update_objective_progress(current_mission.id, MissionObjective.ObjectiveType.ECONOMY) # Check for power plant unlocking in normal gameplay if structure.type == Structure.StructureType.POWER_PLANT: @@ -558,21 +461,6 @@ func _on_structure_placed(structure_index, position): hud.total_kW_production += power_produced hud.update_hud() -# # Check for residential building placement to update population -# if structure.type == Structure.StructureType.RESIDENTIAL_BUILDING: -# # This should increase the city's population -# var population_added = structure.population_count -# if population_added > 0: -# # Get the HUD if available -# var hud = get_node_or_null("/root/Main/CanvasLayer/HUD") -# if hud: -# # Update the population display -# hud.total_population += population_added -# hud.update_hud() -# -# # Emit signal for population update -# hud.population_updated.emit(hud.total_population) - # Only used for mission 3, to disable builder functionality during the companion dialog func _on_learning_panel_opened(): if builder: @@ -765,9 +653,6 @@ func _spawn_character_on_road(building_position: Vector3): # Set character as spawned to prevent multiple spawns character_spawned = true - # Update the objective progress for meeting a character - if current_mission and current_mission.id == "1": - update_objective_progress(current_mission.id, MissionObjective.ObjectiveType.MEET_CHARACTER) # Make sure the character has auto-patrol is enabled if the character supports it if character.get("auto_patrol") != null: @@ -998,33 +883,13 @@ func _handle_structure_unlocking(mission): # If we already have explicit unlocked items defined, skip the hardcoded rules var has_explicit_unlocks = mission is Resource and "unlocked_items" in mission and mission.unlocked_items.size() > 0 - # Check for power plant unlocking in power-related missions (only if no explicit unlocks) - if (not has_explicit_unlocks) and (mission.id == "4" or mission.id == "5" or mission.power_math_content != ""): - print("Using hardcoded power plant unlocks for mission: " + mission.id) - for structure in builder.structures: - if structure.model and structure.model.resource_path.contains("power_plant"): - # Make sure structure has the unlocked property before setting it - if "unlocked" in structure: - structure.unlocked = true - # Only add to unlocked_structures if not already there - if not unlocked_structures.has(structure): - unlocked_structures.append(structure) - else: - print("WARNING: Power plant structure doesn't have an 'unlocked' property") - - # Check for curved roads and decorations in city expansion missions (only if no explicit unlocks) - if (not has_explicit_unlocks) and (mission.id == "2" or mission.id == "3"): - print("Using hardcoded curved roads and decorations for mission: " + mission.id) - for structure in builder.structures: - if structure.model and (structure.model.resource_path.contains("road-corner") or structure.model.resource_path.contains("grass-trees-tall")): - # Make sure structure has the unlocked property before setting it - if "unlocked" in structure: - structure.unlocked = true - # Only add to unlocked_structures if not already there - if not unlocked_structures.has(structure): - unlocked_structures.append(structure) - else: - print("WARNING: Road/decoration structure doesn't have an 'unlocked' property") + # Commented out hardcoded power plant unlocking + # Only use explicit unlocks from the mission data's unlocked_items array + # No more hardcoded behavior for specific mission IDs + + # Commented out hardcoded curved roads and decorations unlocking + # Only use explicit unlocks from the mission data's unlocked_items array + # No more hardcoded behavior for specific mission IDs # Make sure the builder starts with a valid unlocked structure selected var found_unlocked = false @@ -1223,6 +1088,30 @@ func _send_companion_dialog(dialog_key, mission): JSBridge.get_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): + # If no mission was provided, use the current mission + if mission == null: + mission = current_mission + + if not mission: + return + + # Look for the first incomplete objective + for objective in mission.objectives: + if not objective.completed: + current_objective = objective + print("Updated current objective: " + str(current_objective.type) + " - " + current_objective.description) + return + + # If all objectives are complete, keep the last one as current and complete the mission + if mission.objectives.size() > 0: + current_objective = mission.objectives[-1] + print("All objectives complete, keeping last one as current objective") + # Complete the mission when we've found that all objectives are complete + if mission.id in active_missions: + check_mission_completion(mission.id) # Fallback to force a connection if the normal method doesn't work func _force_learning_companion_connection(): @@ -1239,3 +1128,8 @@ func _force_learning_companion_connection(): # Send initial event if we've already started if current_mission: _on_mission_started_for_companion(current_mission) + + +func population_updated(new_population: Variant) -> void: + if current_objective.type == ObjectiveType.REACH_POPULATION: + update_objective_progress() diff --git a/scripts/mission/mission_objective.gd b/scripts/mission/mission_objective.gd index 38420db..30dca04 100644 --- a/scripts/mission/mission_objective.gd +++ b/scripts/mission/mission_objective.gd @@ -1,27 +1,17 @@ extends Resource class_name MissionObjective -enum ObjectiveType { - BUILD_STRUCTURE, - BUILD_SPECIFIC_STRUCTURE, - BUILD_ROAD, - BUILD_RESIDENTIAL, - BUILD_COMMERCIAL, - BUILD_INDUSTRIAL, - REACH_CASH_AMOUNT, - LEARNING, - CUSTOM, - MEET_CHARACTER, - ECONOMY -} +const ObjectiveType = preload("res://configs/data.config.gd").ObjectiveType @export var type: ObjectiveType @export var target_count: int = 1 @export var current_count: int = 0 @export var description: String = "" -@export var structure_index: int = -1 # For BUILD_SPECIFIC_STRUCTURE type @export var completed: bool = false +@export_subgroup("Structure") +@export var structure: Structure + func is_completed() -> bool: return current_count >= target_count diff --git a/scripts/mission/mission_ui.gd b/scripts/mission/mission_ui.gd index e04c1cc..4362d30 100644 --- a/scripts/mission/mission_ui.gd +++ b/scripts/mission/mission_ui.gd @@ -54,11 +54,11 @@ func update_mission_display(mission: MissionData): label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART # Format the objective text - var progress = "" - if objective.target_count > 1: - progress = " (%d/%d)" % [objective.current_count, objective.target_count] +# var progress = "" +# if objective.target_count && objective.type > 1: +# progress = " (%d/%d)" % [objective.current_count, objective.target_count] - label.text = "%s%s" % [objective.description, progress] + label.text = objective.description # Style completed objectives differently if objective.completed: diff --git a/scripts/sound_manager.gd b/scripts/sound_manager.gd index 6db63f3..be80df7 100644 --- a/scripts/sound_manager.gd +++ b/scripts/sound_manager.gd @@ -11,7 +11,7 @@ var react_sound_bridge = null # Will be instantiated from a script var audio_bridge = null # Will be instantiated from a script # Volume ranges from 0.0 to 1.0 -var music_volume: float = 0.1 +var music_volume: float = 0.0 var sfx_volume: float = 0.1 # Mute states diff --git a/structures/building-small-d.tres b/structures/building-small-d.tres deleted file mode 100644 index 3632028..0000000 --- a/structures/building-small-d.tres +++ /dev/null @@ -1,14 +0,0 @@ -[gd_resource type="Resource" script_class="Structure" load_steps=3 format=3 uid="uid://dtal0tl2ee336"] - -[ext_resource type="PackedScene" uid="uid://h0vrvst3cumo" path="res://models/building-small-d.glb" id="1_164xq"] -[ext_resource type="Script" uid="uid://smbpvh2nwds4" path="res://scripts/structure.gd" id="2_8ewai"] - -[resource] -script = ExtResource("2_8ewai") -model = ExtResource("1_164xq") -type = 1 -price = 70 -population_count = 1 -kW_usage = 1.0 -kW_production = 0.0 -selector_scale = 2.8