shomykohai / quest-system

📜 A simple yet powerful quest system for Godot 4

Home Page:https://godotengine.org/asset-library/asset/2516

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use?

peterpants2 opened this issue · comments

What's the workflow for using this?

I tried creating a quest resource and defined an ID/Name/Description

I don't see a way to add it to the QuestManager easily. Should I extend the QuestManager with my resource?

Like add a line to quest_manager.gd
var quest1 = preload("simple_quest")?

Or rather do you have a simple example project?

You should first extetend the Quest class to make your quest logic

then use that class to create a quest resource (the actual quest).

After that, you should load the resource with ResourceLoader given the path.

var quest: Quest = ResourceLoader.load("<path/to/quest.tres>")

and then you do

QuestSystem.start_quest(quest)

Anyway, I surely have to add examples and documentation about the usage.

If you have any questions feel free to ask!

@peterpants2 here you go an example project!
QuestSystem example project.zip

What's the workflow for using this?

I tried creating a quest resource and defined an ID/Name/Description

I don't see a way to add it to the QuestManager easily. Should I extend the QuestManager with my resource?

Like add a line to quest_manager.gd
var quest1 = preload("simple_quest")?

Or rather do you have a simple example project?

Here's another example project: https://github.com/ShomyKohai/quest-system-example

This is based on Nathan Hoad's beginner dialogue tutorial, so you can also see how to use quest system with a dialogue addon, too.

Closing this as no updates were given from OP.

@peterpants2 here you go an example project! QuestSystem example project.zip

Hey @shomykohai I am also having some difficulties navigating around. I have tried both examples and in quoted one, even upon pressing start and complete quest, it does not trigger signal and print Completed.

EDIT: I see that wrong quest ID was there. But still, it works via additional function that sets the quest objective_completed to true. I thought calling QuestSystem.complete_quest(quest) would mark it as complete but no, signal is not called just by this.

This is how I imagined it:

game.gd

extends Node

@export var quest: Quest
@onready var button = %Button


func _ready():
	button.pressed.connect(_on_button_pressed)

	QuestSystem.start_quest(quest)


func _on_button_pressed():
	QuestSystem.complete_quest(quest)

quest.gd

extends Quest


func start():
	print("Quest started")


func update():
	pass


func complete():
	print("Complete!")

so when I press the button, quest gets completed. But I guess I need to set it to complete via different path.

Hey @shomykohai I am also having some difficulties navigating around. I have tried both examples and in quoted one, even upon pressing start and complete quest, it does not trigger signal and print Completed.

Could you check in the remote tab (it should be located in the dock when you run a scene) if the Quest resource has the objective_completed variable set to true and in which pool it located?

I have tried to set objective_completed to true in start() method ... after that calling QuestSystem.complete_quest(quest) method set it to complete and it got printed.

This is how I imagined it:

game.gd

extends Node

@export var quest: Quest
@onready var button = %Button


func _ready():
	button.pressed.connect(_on_button_pressed)

	QuestSystem.start_quest(quest)


func _on_button_pressed():
	QuestSystem.complete_quest(quest)

quest.gd

extends Quest


func start():
	print("Quest started")


func update():
	pass


func complete():
	print("Complete!")

so when I press the button, quest gets completed. But I guess I need to set it to complete via different path.

there it is!
It is important to set the quest_objective to true before calling complete!
This is intentional as I imagined it in a context where you'd want to know that you can complete the Quest (e.g. An UI that marks the Quest as completed and tells you have to go to an NPC to claim your rewards).

I have tried to set objective_completed to true in start() method ... after that calling QuestSystem.complete_quest(quest) method set it to complete and it got printed.

I suggest you setting that method in update if you want to make more complex quests!

Though now that I think about it, to be more coherent with the extensible and modular design of quest system, I'll probably add a setting in ProjectSettings to make the developer decide whether to use this option or not.

Yeah makes sense, thanks! Overall I think it is a good design, just the idea that complete_quest should ... well, complete it threw me off.

Yeah makes sense, thanks! Overall I think it is a good design, just the idea that complete_quest should ... well, complete it threw me off.

I guess I'll have to make the documentation clearer to understand!
If anything, feel free to ask

I have tried to set objective_completed to true in start() method ... after that calling QuestSystem.complete_quest(quest) method set it to complete and it got printed.

I suggest you setting that method in update if you want to make more complex quests!

Though now that I think about it, to be more coherent with the extensible and modular design of quest system, I'll probably add a setting in ProjectSettings to make the developer decide whether to use this option or not.

Sorry if that is stupid question, as I just started learning gamedev and Godot, but, how did you imagine setting objective_completed to true in update()? How would I call that method then?
I will try to think about having some higher level QuestManager to connect all these...

I guess something like that in the essence:

game.gd:

extends Node

@export var quest: Quest
@onready var button = %Button


func _ready():
	button.pressed.connect(_on_button_pressed)
	QuestSystem.start_quest(quest)


func _on_button_pressed():
	QuestManager.mark_quest_completed.emit(quest.id)
	QuestSystem.complete_quest(quest)

quest_manager - autoloaded

extends Node

signal mark_quest_completed(quest_id: int)

quest.gd:

extends Quest


func start():
	QuestManager.mark_quest_completed.connect(_on_quest_completed)
	print("Quest started")


func update():
	pass


func complete():
	print("Complete!")


func _on_quest_completed(quest_id: int):
	if quest_id == self.id:
		objective_completed = true

What do you think? That way boolean setting and calling complete can be also separated.

I have tried to set objective_completed to true in start() method ... after that calling QuestSystem.complete_quest(quest) method set it to complete and it got printed.

I suggest you setting that method in update if you want to make more complex quests!

Though now that I think about it, to be more coherent with the extensible and modular design of quest system, I'll probably add a setting in ProjectSettings to make the developer decide whether to use this option or not.

Sorry if that is stupid question, as I just started learning gamedev and Godot, but, how did you imagine setting objective_completed to true in update()? How would I call that method then?
I will try to think about having some higher level QuestManager to connect all these...

The way I do it in my game is by having various way actually to do it.
I can do it through dialogue (using Nathan dialogue Manager) by getting the Quest and manually setting the property.

Another way is: I simply have my quest connected to some signal, for example I have a global event autoload where I declare signal that I use across my project. Let's say I have an inventory_updated signal

# event_bus.gd

signa inventory_updated(item_id: String, new_quantity: int) 

and let's now assume I have an Inventory system that everytime a new item gets added or removed, it emits this signal.

in my quest I would have

extends Quest 
@export var item_to_gather: String
@export var quantity: int = 15

func start():
    EventBus.inventory_updated.connect(check_condition)

func check_condition(item_id: String, new_quantity: int):
    if item_id != item_to_gather: return
    if new_quantity >= quantity:
        objective_completed = true
    else:
        objective_completed = false

This way I let the Quest do its stuff without having me to do nothing, as it will automatically update whenever it receives this signal.
I also prefer this last way as I don't have to delegate the job to an autoload script or manually edit the QuestSystem plugin to meet my needs.

Edit: modified the code to avoid setting objective_completed to false whenever an item different from item_to_gather is, well, gathered.

Awesome, I get it! Thank you very much. Looking forward to future development of the addon and also using in in personal projects 😊

Awesome, I get it! Thank you very much. Looking forward to future development of the addon and also using in in personal projects 😊

Glad I could help you with that!