diff --git a/addons/dialogic_additions/Quest/event_quest_activate.gd b/addons/dialogic_additions/Quest/event_quest_activate.gd index 32a53f5..17b6a60 100644 --- a/addons/dialogic_additions/Quest/event_quest_activate.gd +++ b/addons/dialogic_additions/Quest/event_quest_activate.gd @@ -8,7 +8,7 @@ var quest_resource: String func _execute() -> void: var resource = ResourceLoader.load(quest_resource) - QuestManager.ChangeQuestStatus(resource,QuestEventUtils.QuestStatus.ACTIVE) + QuestManager.ChangeQuestStatus(resource,QuestEventUtils.QuestStatus.AVAILABLE) QuestManager.SetFollowQuest(resource) finish() # called to continue with the next event diff --git a/addons/dialogic_additions/Quest/event_quest_condition.gd b/addons/dialogic_additions/Quest/event_quest_condition.gd new file mode 100644 index 0000000..54c141c --- /dev/null +++ b/addons/dialogic_additions/Quest/event_quest_condition.gd @@ -0,0 +1,163 @@ +@tool +extends DialogicEvent +class_name DialogicQuestConditionEvent + +## Event that allows branching a timeline based on a condition. + +#enum ConditionTypes {IF, ELIF, ELSE} + +### Settings +## condition type (see [ConditionTypes]). Defaults to if. +#var condition_type := ConditionTypes.IF +## The condition as a string. Will be executed as an Expression. +#var condition := "" +var quest_resource: String +var compare_status: QuestEventUtils.QuestStatusOrActive + +################################################################################ +## EXECUTE +################################################################################ + +func _execute() -> void: + var resource = ResourceLoader.load(quest_resource) + + var result: bool + if compare_status == QuestEventUtils.QuestStatusOrActive.ACTIVE: + result = QuestManager.GetFollowQuest() == resource + elif compare_status == QuestEventUtils.QuestStatusOrActive.NOT_ACTIVE: + result = QuestManager.GetFollowQuest() != resource + else: + result = QuestManager.GetQuestStatus(resource).status == compare_status + + if not result: + var idx: int = dialogic.current_event_idx + var ignore := 1 + while true: + idx += 1 + if not dialogic.current_timeline.get_event(idx) or ignore == 0: + break + elif dialogic.current_timeline.get_event(idx).can_contain_events: + ignore += 1 + elif dialogic.current_timeline.get_event(idx) is DialogicEndBranchEvent: + ignore -= 1 + + dialogic.current_event_idx = idx-1 + finish() + + +## only called if the previous event was an end-branch event +## return true if this event should be executed if the previous event was an end-branch event +func should_execute_this_branch() -> bool: + return true + + +################################################################################ +## INITIALIZE +################################################################################ + +func _init() -> void: + event_name = "Quest Condition" + set_default_color('Color3') + event_category = "Quest" + event_sorting_index = 1 + can_contain_events = true + + +# return a control node that should show on the END BRANCH node +func get_end_branch_control() -> Control: + return load(get_script().resource_path.get_base_dir().path_join('ui_quest_condition_end.tscn')).instantiate() + +################################################################################ +## SAVING/LOADING +################################################################################ + +func to_text() -> String: + return 'ifquest ' + quest_resource + ', ' + str(compare_status) + ':' + + +func from_text(string:String) -> void: + #if string.strip_edges().begins_with('if'): + # condition = string.strip_edges().trim_prefix('if ').trim_suffix(':').strip_edges() + # condition_type = ConditionTypes.IF + var strings:Array[String] + strings.assign(string.strip_edges().trim_prefix('ifquest ').trim_suffix(':').strip_edges().split(',')) + quest_resource = strings[0].strip_edges() + var compare_string: String = strings[1].strip_edges() + if compare_string.is_valid_int(): + compare_status = compare_string.to_int() + else: + compare_status = QuestEventUtils.QuestStatusOrActive.get(compare_string) + + +func is_valid_event(string:String) -> bool: + if string.strip_edges().begins_with('ifquest '): + return true + return false + + +################################################################################ +## EDITOR REPRESENTATION +################################################################################ + +func build_event_editor() -> void: + add_header_label("IF") + add_header_edit( + "quest_resource", + ValueType.DYNAMIC_OPTIONS, + { + "mode":2, + "suggestions_func":QuestEventUtils.quest_resource_suggestrions + }) + add_header_label("IS") + add_header_edit("compare_status",ValueType.FIXED_OPTIONS,{ + 'options': [ + { + 'label': 'HIDDEN', + 'value': QuestEventUtils.QuestStatusOrActive.HIDDEN, + }, + { + 'label': 'AVAILABLE', + 'value': QuestEventUtils.QuestStatusOrActive.AVAILABLE, + }, + { + 'label': 'DONE', + 'value': QuestEventUtils.QuestStatusOrActive.DONE, + }, + { + 'label': 'CANCLED', + 'value': QuestEventUtils.QuestStatusOrActive.CANCLED, + }, + { + 'label': 'ACTIVE', + 'value': QuestEventUtils.QuestStatusOrActive.ACTIVE, + }, + { + 'label': 'NOT_ACTIVE', + 'value': QuestEventUtils.QuestStatusOrActive.NOT_ACTIVE, + } + ]}) + +func _get_icon() -> Resource: + return load("res://addons/dialogic/Modules/Condition/icon.svg") + +####################### CODE COMPLETION ######################################## +################################################################################ + +func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void: + pass + + +func _get_start_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit) -> void: + TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'ifquest', 'ifquest ', TextNode.syntax_highlighter.code_flow_color) + + +#################### SYNTAX HIGHLIGHTING ####################################### +################################################################################ + + +func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, line:String) -> Dictionary: + var word := line.get_slice(' ', 0) + dict[line.find(word)] = {"color":Highlighter.code_flow_color} + dict[line.find(word)+len(word)] = {"color":Highlighter.normal_color} + dict = Highlighter.color_condition(dict, line) + return dict diff --git a/addons/dialogic_additions/Quest/event_quest_condition.gd.uid b/addons/dialogic_additions/Quest/event_quest_condition.gd.uid new file mode 100644 index 0000000..84887f9 --- /dev/null +++ b/addons/dialogic_additions/Quest/event_quest_condition.gd.uid @@ -0,0 +1 @@ +uid://b2ggc2f5kh61j diff --git a/addons/dialogic_additions/Quest/event_utils.gd b/addons/dialogic_additions/Quest/event_utils.gd index 4ea02c1..1c33b0c 100644 --- a/addons/dialogic_additions/Quest/event_utils.gd +++ b/addons/dialogic_additions/Quest/event_utils.gd @@ -1,12 +1,22 @@ +@tool class_name QuestEventUtils enum QuestStatus{ HIDDEN = 0, - ACTIVE = 1, + AVAILABLE = 1, DONE = 2, CANCLED = 3 } +enum QuestStatusOrActive{ + HIDDEN = 0, + AVAILABLE = 1, + DONE = 2, + CANCLED = 3, + ACTIVE = 4, + NOT_ACTIVE = 5 +} + static func quest_resource_suggestrions(search_text:String) -> Dictionary: var ret_val = {} diff --git a/addons/dialogic_additions/Quest/index.gd b/addons/dialogic_additions/Quest/index.gd index 7f49210..70fd002 100644 --- a/addons/dialogic_additions/Quest/index.gd +++ b/addons/dialogic_additions/Quest/index.gd @@ -4,5 +4,6 @@ extends DialogicIndexer func _get_events() -> Array: return [ this_folder.path_join('event_quest_activate.gd'), - this_folder.path_join('event_quest_complete.gd') + this_folder.path_join('event_quest_complete.gd'), + this_folder.path_join('event_quest_condition.gd') ] diff --git a/addons/dialogic_additions/Quest/ui_condition_end.gd b/addons/dialogic_additions/Quest/ui_condition_end.gd new file mode 100644 index 0000000..1ab7269 --- /dev/null +++ b/addons/dialogic_additions/Quest/ui_condition_end.gd @@ -0,0 +1,51 @@ +@tool +extends HBoxContainer + +var parent_resource: DialogicEvent = null + + +func _ready() -> void: + $AddElif.button_up.connect(add_elif) + $AddElse.button_up.connect(add_else) + + +func refresh() -> void: + if parent_resource is DialogicQuestConditionEvent: + # hide add elif and add else button on ELSE event + $AddElif.visible = false# parent_resource.condition_type != DialogicConditionEvent.ConditionTypes.ELSE + $AddElse.visible = true# parent_resource.condition_type != DialogicConditionEvent.ConditionTypes.ELSE + $Label.text = "End of If Quest" #"End of "+["IF", "ELIF", "ELSE"][parent_resource.condition_type]+" ("+parent_resource.condition+")" + + # hide add add else button if followed by ELIF or ELSE event + var timeline_editor := find_parent('VisualEditor') + if timeline_editor: + var next_event: DialogicEvent = null + if timeline_editor.get_block_below(get_parent()): + next_event = timeline_editor.get_block_below(get_parent()).resource + if next_event is DialogicConditionEvent: + if next_event.condition_type != DialogicConditionEvent.ConditionTypes.IF: + $AddElse.hide() + #if parent_resource.condition_type == DialogicConditionEvent.ConditionTypes.ELSE: + # $Label.text = "End of ELSE" + else: + hide() + + +func add_elif() -> void: + var timeline := find_parent('VisualEditor') + if timeline: + var resource := DialogicConditionEvent.new() + resource.condition_type = DialogicConditionEvent.ConditionTypes.ELIF + timeline.add_event_undoable(resource, get_parent().get_index()+1) + timeline.indent_events() + timeline.something_changed() + + +func add_else() -> void: + var timeline := find_parent('VisualEditor') + if timeline: + var resource := DialogicConditionEvent.new() + resource.condition_type = DialogicConditionEvent.ConditionTypes.ELSE + timeline.add_event_undoable(resource, get_parent().get_index()+1) + timeline.indent_events() + timeline.something_changed() diff --git a/addons/dialogic_additions/Quest/ui_condition_end.gd.uid b/addons/dialogic_additions/Quest/ui_condition_end.gd.uid new file mode 100644 index 0000000..6552d88 --- /dev/null +++ b/addons/dialogic_additions/Quest/ui_condition_end.gd.uid @@ -0,0 +1 @@ +uid://dlrnhnnonum4o diff --git a/addons/dialogic_additions/Quest/ui_quest_condition_end.tscn b/addons/dialogic_additions/Quest/ui_quest_condition_end.tscn new file mode 100644 index 0000000..6d6d1b8 --- /dev/null +++ b/addons/dialogic_additions/Quest/ui_quest_condition_end.tscn @@ -0,0 +1,20 @@ +[gd_scene load_steps=2 format=3 uid="uid://dnrpcgjkyoiau"] + +[ext_resource type="Script" uid="uid://dlrnhnnonum4o" path="res://addons/dialogic_additions/Quest/ui_condition_end.gd" id="1_f3miq"] + +[node name="Condition_End" type="HBoxContainer"] +offset_right = 90.0 +offset_bottom = 23.0 +script = ExtResource("1_f3miq") + +[node name="Label" type="Label" parent="."] +layout_mode = 2 +text = "End of condition X" + +[node name="AddElif" type="Button" parent="."] +layout_mode = 2 +text = "Add Elif" + +[node name="AddElse" type="Button" parent="."] +layout_mode = 2 +text = "Add Else" diff --git a/dialog/quests/tomatoes/quest2_tomatoes_interim.dtl b/dialog/quests/tomatoes/quest2_tomatoes_interim.dtl index 6d26037..6860ab8 100644 --- a/dialog/quests/tomatoes/quest2_tomatoes_interim.dtl +++ b/dialog/quests/tomatoes/quest2_tomatoes_interim.dtl @@ -1,5 +1,6 @@ join Yeli center join vesna center +[quest_complete quest_resource="res://resources/quests/demo/5_talk_yeli_3.tres"] Yeli (_part_side): Great! Now I need you to plant some tomatoes! label plant tomatoes Yeli (_part_side): Use the hoe to break up the soil. Then plant the seeds and water the fields. @@ -7,4 +8,5 @@ Yeli (_part_side): Got it? - Of course! - Wait … How do I plant the tomatoes again? jump plant tomatoes +[quest_activate quest_resource="res://resources/quests/demo/6_till_and_water.tres"] [end_timeline] diff --git a/dialog/quests/tomatoes/quest2_tomatoes_start.dtl b/dialog/quests/tomatoes/quest2_tomatoes_start.dtl index 0741a8f..d1878bd 100644 --- a/dialog/quests/tomatoes/quest2_tomatoes_start.dtl +++ b/dialog/quests/tomatoes/quest2_tomatoes_start.dtl @@ -1,5 +1,6 @@ join Yeli center join vesna center +[quest_complete quest_resource="res://resources/quests/demo/3_talk_yeli_2.tres"] Yeli (_part_side): Thank you, my child! Your Yeli is not so agile anymore. vesna: But you’re diligent! You’ve started with the preparation for dinner. Yeli (_part_side): Indeed, I have. @@ -7,4 +8,5 @@ Yeli (_part_side): But, oh my, those ducks messed up the tomatos. Yeli (_part_side): Oh, would you like to assist me? vesna: What do I have to do? Yeli (_part_side): First, take the hoe and watering can over there! Then come back to me! +[quest_activate quest_resource="res://resources/quests/demo/4_collect_tools.tres"] [end_timeline] diff --git a/dialog/testing/test_1.dtl b/dialog/testing/test_1.dtl new file mode 100644 index 0000000..6ad2abf --- /dev/null +++ b/dialog/testing/test_1.dtl @@ -0,0 +1,15 @@ +Quest\: {ACTIVEQUEST} +ifquest res://resources/quests/test/test_01.tres, 4: + Test 1 active +else: + Test 1 is not active + ifquest res://resources/quests/test/test_01.tres, 1: + But its available + else: + And not available +ifquest res://resources/quests/test/test_02.tres, 4: + Test 2 active + ifquest res://resources/quests/test/test_02.tres, 1: + And Available +else: + Else 2 diff --git a/dialog/testing/test_1.dtl.uid b/dialog/testing/test_1.dtl.uid new file mode 100644 index 0000000..1c7b490 --- /dev/null +++ b/dialog/testing/test_1.dtl.uid @@ -0,0 +1 @@ +uid://xfkdvitmhgln diff --git a/dialog/yeli_quest_select.dtl b/dialog/yeli_quest_select.dtl index 19a79cf..924ba48 100644 --- a/dialog/yeli_quest_select.dtl +++ b/dialog/yeli_quest_select.dtl @@ -1,4 +1,8 @@ if {ACTIVEQUEST} == "1_talk_yeli_1": jump quest1_ducks_start/ +elif {ACTIVEQUEST} == "3_talk_yeli_2": + jump quest2_tomatoes_start/ +elif {ACTIVEQUEST} == "5_talk_yeli_3": + jump quest2_tomatoes_interim/ else: - No Dialog for active quest {ACTIVEQUEST} + No Dialog for active quest "{ACTIVEQUEST}" diff --git a/prefabs/quests/quest_manager_autoload.tscn b/prefabs/quests/quest_manager_autoload.tscn index 203ab26..547c5e4 100644 --- a/prefabs/quests/quest_manager_autoload.tscn +++ b/prefabs/quests/quest_manager_autoload.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://bworek1jcmq0e"] [ext_resource type="Script" uid="uid://dl2uhq12p3qks" path="res://scripts/CSharp/Common/Quest/QuestManager.cs" id="1_anowe"] -[ext_resource type="Script" uid="uid://bukwr1h3hn8sx" path="res://scripts/GdScript/dialogic_var_setter.gd" id="4_v86gc"] +[ext_resource type="Script" path="res://scripts/GdScript/dialogic_var_setter.gd" id="4_v86gc"] [node name="QuestManager" type="Node"] script = ExtResource("1_anowe") diff --git a/project.godot b/project.godot index b1097bf..b1c0c11 100644 --- a/project.godot +++ b/project.godot @@ -28,10 +28,10 @@ buses/default_bus_layout="uid://b6dwkmkyb0axk" SceneTransition="*res://scenes/SceneTransition.tscn" Dialogic="*res://addons/dialogic/Core/DialogicGameHandler.gd" InventoryManager="*res://scripts/CSharp/Common/Inventory/InventoryManager.cs" -Signal_Debugger="*res://addons/SignalVisualizer/Debugger/SignalDebugger.gd" FightManagerAutoload="*res://prefabs/fight/fight_manager_autoload.tscn" InputService="*res://scripts/CSharp/Common/Services/InputService.cs" QuestManager="*res://prefabs/quests/quest_manager_autoload.tscn" +Signal_Debugger="*res://addons/SignalVisualizer/Debugger/SignalDebugger.gd" [dialogic] @@ -59,6 +59,7 @@ directories/dtl_directory={ "quest5_forest_start": "res://dialog/quests/forest/quest5_forest_start.dtl", "semi_cat": "res://dialog/semi_cat.dtl", "talk_to_plant": "res://dialog/talk_to_plant.dtl", +"test_1": "res://dialog/testing/test_1.dtl", "test_time_line": "res://dialog/test_time_line.dtl", "yeli_intro_01": "res://dialog/Scene1_farm_outside/yeli_intro_01.dtl", "yeli_intro_02": "res://dialog/Scene1_farm_outside/yeli_intro_02.dtl", @@ -111,6 +112,9 @@ directories/tres_directory={ "1_talk_yeli_1": "res://resources/quests/demo/1_talk_yeli_1.tres", "2_collect_ducks": "res://resources/quests/demo/2_collect_ducks.tres", "3_talk_yeli_2": "res://resources/quests/demo/3_talk_yeli_2.tres", +"4_collect_tools": "res://resources/quests/demo/4_collect_tools.tres", +"5_talk_yeli_3": "res://resources/quests/demo/5_talk_yeli_3.tres", +"6_till_and_water": "res://resources/quests/demo/6_till_and_water.tres", "Babushka_NPC_Namebox_background": "res://dialog/Babushka_NPC_Namebox_background.tres", "InputFieldsStyle": "res://addons/dialogic/Editor/Events/styles/InputFieldsStyle.tres", "MainTheme": "res://addons/dialogic/Editor/Theme/MainTheme.tres", @@ -145,9 +149,9 @@ directories/tres_directory={ "speaker_textbox_style": "res://addons/dialogic/Modules/DefaultLayoutParts/Style_SpeakerTextbox/speaker_textbox_style.tres", "speechbubble": "res://dialog/speechbubble.tres", "test": "res://resources/items/test.tres", -"test_01": "res://resources/quests/test_01.tres", -"test_02": "res://resources/quests/test_02.tres", -"test_03": "res://resources/quests/test_03.tres", +"test/test_01": "res://resources/quests/test/test_01.tres", +"test/test_02": "res://resources/quests/test/test_02.tres", +"test/test_03": "res://resources/quests/test/test_03.tres", "textbubble_style": "res://addons/dialogic/Modules/DefaultLayoutParts/Style_TextBubbles/textbubble_style.tres", "tomato": "res://resources/items/tomato.tres", "tomato_seed": "res://resources/items/tomato_seed.tres", diff --git a/resources/quests/demo/3_talk_yeli_2.tres b/resources/quests/demo/3_talk_yeli_2.tres index fa8fead..e496a76 100644 --- a/resources/quests/demo/3_talk_yeli_2.tres +++ b/resources/quests/demo/3_talk_yeli_2.tres @@ -4,7 +4,7 @@ [resource] script = ExtResource("1_70pjl") -id = "3_talk_yeil_2" +id = "3_talk_yeli_2" title = "Talk to Yeli again" description = "All ducks are collected. Head back to yeli." metadata/_custom_type_script = "uid://vji5lp4qc8pp" diff --git a/resources/quests/demo/4_collect_tools.tres b/resources/quests/demo/4_collect_tools.tres new file mode 100644 index 0000000..4f6926b --- /dev/null +++ b/resources/quests/demo/4_collect_tools.tres @@ -0,0 +1,10 @@ +[gd_resource type="Resource" script_class="QuestResource" load_steps=2 format=3 uid="uid://d2swjixbnqkbw"] + +[ext_resource type="Script" uid="uid://vji5lp4qc8pp" path="res://scripts/CSharp/Common/Quest/QuestResource.cs" id="1_e51xd"] + +[resource] +script = ExtResource("1_e51xd") +id = "4_collect_tools" +title = "Collect the farm tools" +description = "Collect the Watering Can next to the well and the Hoe by the fence." +metadata/_custom_type_script = "uid://vji5lp4qc8pp" diff --git a/resources/quests/demo/5_talk_yeli_3.tres b/resources/quests/demo/5_talk_yeli_3.tres new file mode 100644 index 0000000..d82af6c --- /dev/null +++ b/resources/quests/demo/5_talk_yeli_3.tres @@ -0,0 +1,10 @@ +[gd_resource type="Resource" script_class="QuestResource" load_steps=2 format=3 uid="uid://5t8g0firdif0"] + +[ext_resource type="Script" uid="uid://vji5lp4qc8pp" path="res://scripts/CSharp/Common/Quest/QuestResource.cs" id="1_x7fvu"] + +[resource] +script = ExtResource("1_x7fvu") +id = "5_talk_yeli_3" +title = "Talk to Yeli again" +description = "After the long and agonizing task of finding and collecting two tools, go talk to Yeli once again." +metadata/_custom_type_script = "uid://vji5lp4qc8pp" diff --git a/resources/quests/demo/6_till_and_water.tres b/resources/quests/demo/6_till_and_water.tres new file mode 100644 index 0000000..d5b6206 --- /dev/null +++ b/resources/quests/demo/6_till_and_water.tres @@ -0,0 +1,10 @@ +[gd_resource type="Resource" script_class="QuestResource" load_steps=2 format=3 uid="uid://h05jgxqtq37m"] + +[ext_resource type="Script" uid="uid://vji5lp4qc8pp" path="res://scripts/CSharp/Common/Quest/QuestResource.cs" id="1_745w5"] + +[resource] +script = ExtResource("1_745w5") +id = "6_till_and_water" +title = "Till and water the fields" +description = "Use the hoe to break up the soil. Then plant the seeds and water the fields." +metadata/_custom_type_script = "uid://vji5lp4qc8pp" diff --git a/resources/quests/test_01.tres b/resources/quests/test/test_01.tres similarity index 100% rename from resources/quests/test_01.tres rename to resources/quests/test/test_01.tres diff --git a/resources/quests/test_02.tres b/resources/quests/test/test_02.tres similarity index 100% rename from resources/quests/test_02.tres rename to resources/quests/test/test_02.tres diff --git a/resources/quests/test_03.tres b/resources/quests/test/test_03.tres similarity index 100% rename from resources/quests/test_03.tres rename to resources/quests/test/test_03.tres diff --git a/scenes/Babushka_scene_farm_outside_2d.tscn b/scenes/Babushka_scene_farm_outside_2d.tscn index 03ab03d..d3824b4 100644 --- a/scenes/Babushka_scene_farm_outside_2d.tscn +++ b/scenes/Babushka_scene_farm_outside_2d.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=107 format=3 uid="uid://gigb28qk8t12"] +[gd_scene load_steps=113 format=3 uid="uid://gigb28qk8t12"] [ext_resource type="PackedScene" uid="uid://c25udixd5m6l0" path="res://prefabs/characters/Player2D.tscn" id="1_7wfwe"] [ext_resource type="Texture2D" uid="uid://8sr11ex30n0m" path="res://art/mockups/Kenney_Backgrounds/Samples/uncolored_hills.png" id="2_7b2ri"] @@ -69,6 +69,10 @@ [ext_resource type="PackedScene" uid="uid://muuxxgvx33fp" path="res://prefabs/farm/duck.tscn" id="62_i36hd"] [ext_resource type="Script" uid="uid://cldtt4atgymm5" path="res://scripts/CSharp/Common/Quest/QuestTrigger.cs" id="66_2065p"] [ext_resource type="Resource" uid="uid://cm8kftow8br00" path="res://resources/quests/demo/1_talk_yeli_1.tres" id="67_tm0yg"] +[ext_resource type="Script" uid="uid://c741nyedy26mx" path="res://scripts/CSharp/Common/QuestBehaviour/DetectInventoryContains.cs" id="68_hux6i"] +[ext_resource type="Resource" uid="uid://d2swjixbnqkbw" path="res://resources/quests/demo/4_collect_tools.tres" id="68_lbnqo"] +[ext_resource type="Script" uid="uid://be54lnb6gg81f" path="res://scripts/CSharp/Common/Inventory/ItemInstance.cs" id="69_4rgbr"] +[ext_resource type="Resource" uid="uid://5t8g0firdif0" path="res://resources/quests/demo/5_talk_yeli_3.tres" id="69_l4wxt"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_wtdui"] shader = ExtResource("13_7p0hq") @@ -262,6 +266,18 @@ stream_0/stream = ExtResource("39_di1ed") stream_1/stream = ExtResource("40_ceriq") stream_2/stream = ExtResource("49_d77e7") +[sub_resource type="Resource" id="Resource_y820s"] +script = ExtResource("69_4rgbr") +blueprint = ExtResource("28_ipqaa") +amount = 1 +metadata/_custom_type_script = "uid://be54lnb6gg81f" + +[sub_resource type="Resource" id="Resource_50loj"] +script = ExtResource("69_4rgbr") +blueprint = ExtResource("28_6b2nr") +amount = 1 +metadata/_custom_type_script = "uid://be54lnb6gg81f" + [node name="BabushkaSceneFarmOutside2d" type="Node2D"] script = ExtResource("34_e5b7x") _sceneNamesToLoad = PackedStringArray("res://scenes/Babushka_scene_indoor_common_room.tscn") @@ -2356,14 +2372,22 @@ max_distance = 2e+07 playback_type = 2 script = ExtResource("40_w3jkj") -[node name="QuestInstantStart" type="Node" parent="."] +[node name="SpeicialQuestTrigger" type="Node" parent="."] -[node name="QuestTrigger" type="Node" parent="QuestInstantStart"] +[node name="QuestInstantStart" type="Node" parent="SpeicialQuestTrigger"] + +[node name="QuestTrigger" type="Node" parent="SpeicialQuestTrigger/QuestInstantStart"] script = ExtResource("66_2065p") questResource = ExtResource("67_tm0yg") toStatus = 1 makeCurrent = true +[node name="ToolsCollectedTrigger" type="Node" parent="SpeicialQuestTrigger"] +script = ExtResource("68_hux6i") +_itemsToContain = Array[Resource]([SubResource("Resource_y820s"), SubResource("Resource_50loj")]) +_onActiveQuest = ExtResource("68_lbnqo") +_toNextQuest = ExtResource("69_l4wxt") + [connection signal="FilledWateringCan" from="YSorted/Vesna" to="Audio/SFX/FillWater SFX2" method="PlayOneShot"] [connection signal="WateringField" from="YSorted/Vesna/FarmingControls" to="Audio/SFX/Watering SFX" method="PlayOneShot"] [connection signal="InteractedTool" from="YSorted/Brünnen/InteractionArea" to="YSorted/Vesna" method="TryFillWateringCan"] @@ -2373,9 +2397,15 @@ makeCurrent = true [connection signal="FieldCreated" from="YSorted/Farm visuals/FieldParent" to="Audio/SFX/Farming SFX" method="PlayOneShot"] [connection signal="input_event" from="YSorted/Farm visuals/FieldParent/Area2D" to="YSorted/Vesna/FarmingControls" method="InputEventPressedOn"] [connection signal="GoalReached" from="YSorted/ducks" to="YSorted/ducks/DialogicToggle" method="ToggleDialogue"] +[connection signal="DuckCollected" from="YSorted/ducks/Duck2" to="YSorted/ducks" method="Increment"] +[connection signal="DuckCollected" from="YSorted/ducks/Duck3" to="YSorted/ducks" method="Increment"] +[connection signal="DuckCollected" from="YSorted/ducks/Duck4" to="YSorted/ducks" method="Increment"] +[connection signal="DuckCollected" from="YSorted/ducks/Duck5" to="YSorted/ducks" method="Increment"] +[connection signal="DuckCollected" from="YSorted/ducks/Duck6" to="YSorted/ducks" method="Increment"] +[connection signal="DuckCollected" from="YSorted/ducks/Duck7" to="YSorted/ducks" method="Increment"] [connection signal="Dialogue" from="YSorted/ducks/DialogicToggle" to="YSorted/ducks/dialogic starter" method="open"] [connection signal="finished" from="Audio/Background Music Ramp up" to="Audio/Background Music loop" method="PlayFromOffset"] -[connection signal="ready" from="QuestInstantStart" to="QuestInstantStart/QuestTrigger" method="Trigger"] +[connection signal="ready" from="SpeicialQuestTrigger/QuestInstantStart" to="SpeicialQuestTrigger/QuestInstantStart/QuestTrigger" method="Trigger"] [editable path="YSorted/Vesna"] [editable path="YSorted/Brünnen/InteractionArea"] diff --git a/scenes/testing/babushka_tests_book.tscn b/scenes/testing/babushka_tests_book.tscn index 3a5a51e..69cc57f 100644 --- a/scenes/testing/babushka_tests_book.tscn +++ b/scenes/testing/babushka_tests_book.tscn @@ -2,9 +2,9 @@ [ext_resource type="PackedScene" uid="uid://cqcs80xsgygeb" path="res://prefabs/UI/Book/Book.tscn" id="1_bd7dq"] [ext_resource type="Script" uid="uid://cg0oqug38c81n" path="res://scripts/CSharp/Common/Quest/QuestTestingScript.cs" id="2_sv6jn"] -[ext_resource type="Resource" uid="uid://0aruj4lm74n6" path="res://resources/quests/test_01.tres" id="3_nhtae"] -[ext_resource type="Resource" uid="uid://be1dmc6d2mxl5" path="res://resources/quests/test_02.tres" id="4_kr4yw"] -[ext_resource type="Resource" uid="uid://tmmnsg1bge2" path="res://resources/quests/test_03.tres" id="5_4cktu"] +[ext_resource type="Resource" uid="uid://0aruj4lm74n6" path="res://resources/quests/test/test_01.tres" id="3_nhtae"] +[ext_resource type="Resource" uid="uid://be1dmc6d2mxl5" path="res://resources/quests/test/test_02.tres" id="4_kr4yw"] +[ext_resource type="Resource" uid="uid://tmmnsg1bge2" path="res://resources/quests/test/test_03.tres" id="5_4cktu"] [node name="BabushkaTestsBook" type="Node"] diff --git a/scenes/testing/babushka_tests_quest_dialogic.tscn b/scenes/testing/babushka_tests_quest_dialogic.tscn new file mode 100644 index 0000000..20ea34c --- /dev/null +++ b/scenes/testing/babushka_tests_quest_dialogic.tscn @@ -0,0 +1,74 @@ +[gd_scene load_steps=5 format=3 uid="uid://baunkb4wwtl32"] + +[ext_resource type="Script" uid="uid://cldtt4atgymm5" path="res://scripts/CSharp/Common/Quest/QuestTrigger.cs" id="1_wnfrg"] +[ext_resource type="Resource" uid="uid://0aruj4lm74n6" path="res://resources/quests/test/test_01.tres" id="2_nud5h"] +[ext_resource type="Resource" uid="uid://be1dmc6d2mxl5" path="res://resources/quests/test/test_02.tres" id="3_tb5fn"] +[ext_resource type="Script" uid="uid://d2486x6upmwqq" path="res://scripts/GdScript/dialogic_starter.gd" id="4_6p0xc"] + +[node name="BabushkaTestsQuestDialogic" type="Node2D"] + +[node name="Button" type="Button" parent="."] +offset_left = 105.0 +offset_top = 47.0 +offset_right = 423.0 +offset_bottom = 185.0 +text = "Start Quest 1" + +[node name="Node" type="Node" parent="Button"] +script = ExtResource("1_wnfrg") +questResource = ExtResource("2_nud5h") +toStatus = 1 +makeCurrent = true + +[node name="Button2" type="Button" parent="."] +offset_left = 460.0 +offset_top = 49.0 +offset_right = 778.0 +offset_bottom = 187.0 +text = "End Quest 1" + +[node name="Node" type="Node" parent="Button2"] +script = ExtResource("1_wnfrg") +questResource = ExtResource("2_nud5h") +toStatus = 2 + +[node name="Button3" type="Button" parent="."] +offset_left = 105.0 +offset_top = 215.0 +offset_right = 423.0 +offset_bottom = 353.0 +text = "Start Quest 2" + +[node name="Node" type="Node" parent="Button3"] +script = ExtResource("1_wnfrg") +questResource = ExtResource("3_tb5fn") +toStatus = 1 +makeCurrent = true + +[node name="Button4" type="Button" parent="."] +offset_left = 460.0 +offset_top = 217.0 +offset_right = 778.0 +offset_bottom = 355.0 +text = "End Quest 2" + +[node name="Node" type="Node" parent="Button4"] +script = ExtResource("1_wnfrg") +questResource = ExtResource("3_tb5fn") +toStatus = 2 + +[node name="Button5" type="Button" parent="."] +offset_left = 1314.0 +offset_top = 67.0 +offset_right = 1632.0 +offset_bottom = 205.0 +text = "Start Dialog" + +[node name="Node" type="Node" parent="Button5"] +script = ExtResource("4_6p0xc") + +[connection signal="pressed" from="Button" to="Button/Node" method="Trigger"] +[connection signal="pressed" from="Button2" to="Button2/Node" method="Trigger"] +[connection signal="pressed" from="Button3" to="Button3/Node" method="Trigger"] +[connection signal="pressed" from="Button4" to="Button4/Node" method="Trigger"] +[connection signal="pressed" from="Button5" to="Button5/Node" method="open" binds= ["test_1"]] diff --git a/scenes/testing/babushka_tests_quests.tscn b/scenes/testing/babushka_tests_quests.tscn index c8c595f..9a496ea 100644 --- a/scenes/testing/babushka_tests_quests.tscn +++ b/scenes/testing/babushka_tests_quests.tscn @@ -2,9 +2,9 @@ [ext_resource type="PackedScene" uid="uid://cgjc4wurbgimy" path="res://prefabs/UI/Inventory/Inventory.tscn" id="1_opxcj"] [ext_resource type="Script" uid="uid://cldtt4atgymm5" path="res://scripts/CSharp/Common/Quest/QuestTrigger.cs" id="3_sx4ix"] -[ext_resource type="Resource" uid="uid://0aruj4lm74n6" path="res://resources/quests/test_01.tres" id="4_qyyck"] -[ext_resource type="Resource" uid="uid://be1dmc6d2mxl5" path="res://resources/quests/test_02.tres" id="5_sokiv"] -[ext_resource type="Resource" uid="uid://tmmnsg1bge2" path="res://resources/quests/test_03.tres" id="6_ajsa7"] +[ext_resource type="Resource" uid="uid://0aruj4lm74n6" path="res://resources/quests/test/test_01.tres" id="4_qyyck"] +[ext_resource type="Resource" uid="uid://be1dmc6d2mxl5" path="res://resources/quests/test/test_02.tres" id="5_sokiv"] +[ext_resource type="Resource" uid="uid://tmmnsg1bge2" path="res://resources/quests/test/test_03.tres" id="6_ajsa7"] [node name="BabushkaTestsQuests" type="Node2D"] diff --git a/scripts/CSharp/Common/Inventory/InventoryInstance.cs b/scripts/CSharp/Common/Inventory/InventoryInstance.cs index 5070b69..8812fe7 100644 --- a/scripts/CSharp/Common/Inventory/InventoryInstance.cs +++ b/scripts/CSharp/Common/Inventory/InventoryInstance.cs @@ -2,6 +2,7 @@ using System; using Godot; using System.Collections.Generic; +using System.Linq; namespace Babushka.scripts.CSharp.Common.Inventory; @@ -120,12 +121,29 @@ public partial class InventoryInstance : Node { if (destinationSlot < 0 || destinationSlot >= _slots.Count) return InventoryActionResult.DestinationDoesNotExists; - + if (!_slots[destinationSlot].IsEmpty()) return InventoryActionResult.DestinationFull; - + _slots[destinationSlot].itemInstance = itemInstance; EmitSignal(SignalName.InventoryContentsChanged); return InventoryActionResult.Success; } -} \ No newline at end of file + + public int TotalItemsOfBlueprint(ItemResource blueprint) + { + return _slots + .Where(i => !i.IsEmpty() && i.itemInstance!.blueprint == blueprint) + .Sum(i => i.itemInstance!.amount); + } + + public bool HasItems(ItemInstance item) + { + return TotalItemsOfBlueprint(item.blueprint) >= item.amount; + } + + public bool HasItems(IEnumerable items) + { + return items.All(HasItems); + } +} diff --git a/scripts/CSharp/Common/Inventory/ItemInstance.cs b/scripts/CSharp/Common/Inventory/ItemInstance.cs index 0aaa528..84e240c 100644 --- a/scripts/CSharp/Common/Inventory/ItemInstance.cs +++ b/scripts/CSharp/Common/Inventory/ItemInstance.cs @@ -1,9 +1,13 @@ -namespace Babushka.scripts.CSharp.Common.Inventory; +using Godot; +namespace Babushka.scripts.CSharp.Common.Inventory; -public class ItemInstance +// Do not instantiate this resource +// But it has to be a resource because Godot +[GlobalClass] +public partial class ItemInstance: Resource { - public ItemResource blueprint; - public int amount = 1; + [Export] public ItemResource blueprint; + [Export] public int amount = 1; public ItemInstance Clone() { diff --git a/scripts/CSharp/Common/Quest/QuestManager.cs b/scripts/CSharp/Common/Quest/QuestManager.cs index bde1b93..a3fc64a 100644 --- a/scripts/CSharp/Common/Quest/QuestManager.cs +++ b/scripts/CSharp/Common/Quest/QuestManager.cs @@ -19,9 +19,6 @@ public partial class QuestManager : Node [Signal] public delegate void DialogicActiveQuestEventHandler(string value); - [Export(PropertyHint.ArrayType)] - public QuestResource[] questsAccessibleFromDialogic; - public override void _EnterTree() { Instance = this; @@ -81,12 +78,4 @@ public partial class QuestManager : Node EmitSignalQuestsChanged(); EmitSignalDialogicActiveQuest(_followQuest?.id ?? "none"); } - - // functions to call from Dialogic - public void DlSetQuestActiveAndFollow(string questId) - { - var resource = questsAccessibleFromDialogic.First(qr => qr.id == questId); - ChangeQuestStatus(resource, QuestStatus.Status.Active); - SetFollowQuest(resource); - } } diff --git a/scripts/CSharp/Common/Quest/QuestTestingScript.cs b/scripts/CSharp/Common/Quest/QuestTestingScript.cs index 180e73a..64e084b 100644 --- a/scripts/CSharp/Common/Quest/QuestTestingScript.cs +++ b/scripts/CSharp/Common/Quest/QuestTestingScript.cs @@ -1,20 +1,22 @@ using Godot; using System; using System.Collections.Generic; +using System.Diagnostics; using Babushka.scripts.CSharp.Common.Quest; using Godot.Collections; public partial class QuestTestingScript : Node { [Export(PropertyHint.ArrayType)] - private Array _questsToActivate; + private Array? _questsToActivate; public override void _EnterTree() { + Debug.Assert(_questsToActivate != null); + foreach (var questResource in _questsToActivate) { - QuestManager.Instance.ChangeQuestStatus(questResource, QuestStatus.Status.Active); + QuestManager.Instance!.ChangeQuestStatus(questResource, QuestStatus.Status.Active); } - } } diff --git a/scripts/CSharp/Common/QuestBehaviour/DetectInventoryContains.cs b/scripts/CSharp/Common/QuestBehaviour/DetectInventoryContains.cs new file mode 100644 index 0000000..a5a5f8b --- /dev/null +++ b/scripts/CSharp/Common/QuestBehaviour/DetectInventoryContains.cs @@ -0,0 +1,33 @@ +using Godot; +using System; +using System.Collections.Generic; +using System.Linq; +using Babushka.scripts.CSharp.Common.Inventory; +using Babushka.scripts.CSharp.Common.Quest; + +public partial class DetectInventoryContains : QuestFulfillmentBase +{ + [Export(PropertyHint.ArrayType)] private ItemInstance[] _itemsToContain = null!; + + public override void _Ready() + { + QuestManager.Instance!.QuestsChanged += CheckInventory; + InventoryManager.Instance.playerInventory.InventoryContentsChanged += CheckInventory; + + CheckInventory(); + } + + public override void _ExitTree() + { + QuestManager.Instance!.QuestsChanged -= CheckInventory; + InventoryManager.Instance.playerInventory.InventoryContentsChanged -= CheckInventory; + } + + private void CheckInventory() + { + if (IsQuestActive() && InventoryManager.Instance.playerInventory.HasItems(_itemsToContain)) + { + Fulfill(); + } + } +} diff --git a/scripts/CSharp/Common/QuestBehaviour/DetectInventoryContains.cs.uid b/scripts/CSharp/Common/QuestBehaviour/DetectInventoryContains.cs.uid new file mode 100644 index 0000000..d6c5c39 --- /dev/null +++ b/scripts/CSharp/Common/QuestBehaviour/DetectInventoryContains.cs.uid @@ -0,0 +1 @@ +uid://c741nyedy26mx diff --git a/scripts/CSharp/Common/QuestBehaviour/DetectToolCollection.cs b/scripts/CSharp/Common/QuestBehaviour/DetectToolCollection.cs new file mode 100644 index 0000000..e9a7c1c --- /dev/null +++ b/scripts/CSharp/Common/QuestBehaviour/DetectToolCollection.cs @@ -0,0 +1,6 @@ +using Godot; +using System; + +public partial class DetectToolCollection : Node +{ +} diff --git a/scripts/CSharp/Common/QuestBehaviour/DetectToolCollection.cs.uid b/scripts/CSharp/Common/QuestBehaviour/DetectToolCollection.cs.uid new file mode 100644 index 0000000..0ed4b39 --- /dev/null +++ b/scripts/CSharp/Common/QuestBehaviour/DetectToolCollection.cs.uid @@ -0,0 +1 @@ +uid://caohn76m3n3nm diff --git a/scripts/CSharp/Common/QuestBehaviour/QuestFulfillmentBase.cs b/scripts/CSharp/Common/QuestBehaviour/QuestFulfillmentBase.cs new file mode 100644 index 0000000..8b551a6 --- /dev/null +++ b/scripts/CSharp/Common/QuestBehaviour/QuestFulfillmentBase.cs @@ -0,0 +1,35 @@ +using Godot; +using System; +using System.Linq; +using Babushka.scripts.CSharp.Common.Quest; + +public abstract partial class QuestFulfillmentBase : Node +{ + [Export] private QuestResource _onActiveQuest; + [Export] private QuestResource _toNextQuest; + + [Export] private bool _whenFulfilledSetActiveQuestToDone = true; + [Export] private bool _whenFulfilledSetNextQuestToActive = true; + [Export] private bool _whenFulfilledSetNextQuestToFollow = true; + + protected void Fulfill() + { + if (_whenFulfilledSetActiveQuestToDone) + { + QuestManager.Instance!.ChangeQuestStatus(_onActiveQuest, QuestStatus.Status.Done); + } + if (_whenFulfilledSetNextQuestToActive) + { + QuestManager.Instance!.ChangeQuestStatus(_toNextQuest, QuestStatus.Status.Active); + } + if (_whenFulfilledSetNextQuestToFollow) + { + QuestManager.Instance!.SetFollowQuest(_toNextQuest); + } + } + + protected bool IsQuestActive() + { + return QuestManager.Instance!.GetActiveQuests().Any(q => q.Key == _onActiveQuest); + } +} diff --git a/scripts/CSharp/Common/QuestBehaviour/QuestFulfillmentBase.cs.uid b/scripts/CSharp/Common/QuestBehaviour/QuestFulfillmentBase.cs.uid new file mode 100644 index 0000000..36935ca --- /dev/null +++ b/scripts/CSharp/Common/QuestBehaviour/QuestFulfillmentBase.cs.uid @@ -0,0 +1 @@ +uid://dw158xraniqkd