A downloadable tool

About

QuestManager is a framework specialized in managing quests and events for Ren'Py. Create and manage quests for your game with powerful tools that limit the amount of code for your project. The framework is easily customizable and suitable for novice programmers.

You can use it for:

  • Create quests and events (with a name and ID).
  • Classify these quests and events into categories (make a To Do list).
  • Group the categories into chapters allowing you to divide your game into different chapters (like a book or a movie by Q. Tarantino )
  • Assign a "status" to each quest (hidden, unlocked, in progress, completed, done, cancelled, failed)
  • You can trigger events depending on the progress of a certain quest (start a dialog if a quest is completed, start a dialog if all quests of a category are completed, move to another chapter if all quests of the chapter are completed, etc.)
  • Included are many functions to sort and organize your quests within your game.
  • A 100% customizable diary interface.
  • Free and OPenSource!

OS: Window, Mac Linux, Android


How  to install the framework in your game

Adding the framework in your game

  1. Download the framework with the download button at the end of this page.
  2. Unzip the QuestManager.zip file to your home.
  3. Go to the QuestManager file and copy the questmanager folder
  4. Past it into game folder of your project


Activating the framework in your script

To use the framework you must initialize it in your game code ! 

Open the main script of your game where the start label is located. Usually this label is located in the script.rpy file

  • In your script.rpy file add the following line before label start:
default quest = Manager()



Displaying the diary screen

You can display the log at any time by adding the following code anywhere between your dialogs:

show screen diary
Example:


You can display a button to let the player open the diary.  Add the below code after the label start in your script.rpy file

show screen diary_open_btn

You can customize the button by creating new background image or in the questmanager/gui.rpy file. 


Getting Started

Create a new quest

To create a new quest you must follow the following syntax:

Quest("id", "title", "category", "state")

or if you allow the Ren'Py translation

Quest("id", _("title"), _("category"), "state")
  1. The id is a string not displayed in the game. It allows the algorithm to find a quest in the chapter. It must be unique for each quest.
  2. The title of the quest is displayed in game. It is only meant to be displayed in the game. The algorithm does not use the title. The title must be contained between _() to allow renpy to do translations (don't forget the underscore before the parenthesis)
  3. The category is also displayed in-game and is also used by the algorithm to rank the quests. It is also a string contained between _() for the translation
  4. The state is a string not displayed in game. The default state is "pending" but you can optionally add it if you want another default state.

By default when you create a new quest, it will be in the "pending" state and hidden with ??? in the diary.  You can modify this default state by adding a new state in string form

List of all the states

"pending"Default state!  The quest is posted in the diary but the text is hidden by ???
"unlocked"
The quest is displayed in the diary.
"in progress"
The player is doing the quest.
"completed"The player has completed the quest but must return to the Non-Player Character to validate it.
"done"The quest is over.
"canceled"The quest is cancelled and the player cannot start it again (it is removed from the chapter).
"failed"The player has failed to complete his quest.

You can customize state display in the questmanager/gui.rpy file

Exemple:




Create a new chapter

Chapters are arrays that contain all the quests that the player must complete. You can create a single chapter for your entire game. But if your game is very long, we recommend you to create several chapters like in a book, so that the player can better find his way through the game.

All chapters must be declared after the default quest = Manager() line and before the start label !

your_chapter = (your_quest1, your_quest2, your_quest3)

/!\ Don't forget the commas between the quests

Example:

chapter01 = (
            Quest("id01", _("Introduction"), _("General")), 
            Quest("id02", _("First dialog"), _("General")),
            Quest("id03", _("New category"), _("Category 1")),
            )






Functions to manage your quests

The following functions allow you to manipulate your quests. You can test their status, whether they are completed or not, trigger actions and dialogs depending on the player's progress in their quests, etc.

You can add them directly after your characters' dialogues. Don't forget to add the $ sign before each function.


Loading and deleting chapter into the manager

  • Load the chapter into the manager memory.
$ quest.load(chapter_name)
  • Delete the chapter from the manager memory.
$ quest.free()


Functions to do some tests

These different functions allow you to perform actions according to the progress of the quests. They are useful to start a dialogue or an action when the player talks to a npc.

  • Return True if the category exists in the chapter
$ quest.exists("quest_id")
  • Return the category
$ quest.is_in("quest_id")
  • Return True if the ID has the right state
$ quest.is_state("quest_id", " quest_state")
  • Return True if all the events of a category are done
 $ quest.is_category_over("your_category")
  • Return True if all the events from all the categories into the chapter are done
$ quest.is_chapter_over()


Some functions to change the state of quests

The following functions allow you to manipulate the status of quests. For example, when the player has completed a quest, you can use these functions to validate the current quest and unlock the next quests.


  • Check if the event has the right state, otherwise it is updated
 $ quest.check("quest_id", "quest_state")

Example



The quest.update() function is a little bit tricky to use ! 

The update function allows you to manage several quests at the same time. It is very powerful but can be quite complicated to use for beginners.


Its syntax is as follows:

$ quest.update(id="", state="", unchanged = [], category="")

Yes, it looks terrible, but I will explain how it works ;)
Imagine you have a category with 10 quests. You can handle these quests in different ways.

  • changing all the quest state from the first quest to the target id
## example
$ quest.update("quest07", "unlocked")

>> All the quest from quest01 to quest07 are unlocked

  • Changing the state from a quest to another
## example
$ quest.update(("quest02", "quest05"), "unlocked" )

>> All the quests from the number 2 to the 5 are unlocked

  • Changing the state from a quest to another but the last one has a different state than the previous one.
## example
$ quest.update(("quest02", "quest05"), ("completed", "unlocked"))

>> All the quests from the number 2 to the number 4 are completed and the number 5 is unlocked

  • Changing the state from a quest to another but you can exclude one state.
## example
$ quest.update(("quest02", "quest05"), ("completed", "unlocked") , ["failed"])

>> All the quests from the number 2 to the number 4 are completed and the number 5 is unlocked but if a quest is failed it is not updated.

  • Changing the state from a quest to another but you can exclude several states.
## example
$ quest.update(("quest02", "quest05"), ("completed", "unlocked"), ["failed", "completed"])

==> All the quests from the number 2 to the number 4 are completed and the number 5 is unlocked but if a quest is failed  or completed it is not updated.

  • Update all quests in a category but exclude those with a certain state.
## example
$ quest.update(category="my_category" , state="completed", unchanged= ["failed", "completed"])

>> All the quests in the category my_category are updated to competed but if a quest is failed  or completed it is not updated.


Adding or removing categories from the chapter

You can add or remove categories or quests during the game. But when a chapter is freed it returns to its original state.

  1. Adding a new category into the chapter during the game  (The added categories will not be stored when the chapter is freed)
$ quest.add(your_new_quest)
  • Adding multiple quests
$ quest.add([your_quest01, your_quest02, your_quest03])

example:

$ quest.add([
            Quest("intro01", _("Add an event 1"), _("Introduction")), 
            Quest("intro02", _("Add an event 2"), _("Category")),
        ])
  • Removing a category from the chapter
$ quest.remove("your_category_name")


Customize

You can easily customize the diary interface. Open the questmanager/gui.rpy file.

The code is commented to allow you to easily modify it. You can set the number of categories and quests that should be displayed on the left page and on the right page. You can change the fonts, text size, style of each state, etc.



Lastly...

If you have any question, feel free to ask me in comments ;)

StatusIn development
CategoryTool
Rating
Rated 5.0 out of 5 stars
(6 total ratings)
AuthorNerdChickenGames
Tagsframework, Management, Ren'Py

Download

Download
QuestManager Demo.zip 3.6 MB
Download
QuestManager-0.1.2.zip 1.9 MB

Development log

Comments

Log in with itch.io to leave a comment.

Thx it works amazing. If I want to add two more sub-classes, such as description and requirement, where else do I need to change in the screens?


init python:
    import collections
    class Quest ():
        def __init__(self, id, title, category, description, requirement, state= "pending"): 
            self.id = id             self.title = title             self.category = category             self.description = description             self.requirement = requirement             self.state = state

I only have 2 missions so far, this is what I have:

define prologue_quest = (
                    Quest("old_friend", _("Old Friend"), _("Prologue"), "Meet up with Jack.", "None", "unlocked"),
                    Quest("betrayer_on_the_hills", _("Betrayer on The Hills"), _("Prologue"), _("Assassinate The Enforcer. Leave no evidence."), _("Completed old_friend")),
                    # Quest("id", _("title"), _("category"), _("description"), _("requirement"), "state"),
                    )

Hi, how can I add more categories on the left page? I have put this in the gui file,   defines left_page = {( ("General"),("Categoria1"),)}    but it appears on the right page

Hello everyone,
how can I change the path of the questmanager folder?
I tried that code below but it doesn't work.

Code:
from myfolder.questmanager.engine.classes import Quest 


Old path: game/questmanager 
New path: game/myfolder/questmanager 


Has anyone solved this before?

Thank you 🙏

Hello there! I hope you are doing excellent, and let me tell you that I absolutely love this framework! 

I have a quick question. Is there a way to completely hide quests if they are in a specific state? I've modified the screen to not show any quests under "pending" status, however as you can see in my screenshot they are still kinda there, but they are just a blank space, and if you scroll down most of it would be just blank spaces. My guess is that it has to do with how the Quest and Manager classes work, but I'm no Python expert so I'm completely lost here. Any help would be really appreciated! 

This is really well done! Thank you! I had a quick question though. I try to manage my .rpy files with referencing or calls so I can manage the pieces a little better, especially if I need to change a quest later. I don't have to search through a HUGE file of codes to find the one I need. I was wondering if you could help me figure out why mine isn't working? I've tried to leave the default quest = Manager() in the script file and then use a call to load the quests in a different file as well as putting the default quest = Manager() in the referenced file and using a call quest_load in my script but it isn't recognizing Quest at that point. It gives me a NameError Quest is not defined when I do that. The only way I've gotten it to work is to load it into my script file first. Am I stuck with having it that way or is there something I'm missing that I need to add to be able to do this? Thank you in advance for your help!

Hi. Thank you for making this awesome Manager. 

I got a question while customizing QuestManager, and this is it: Can you tell me how to subtract the prefix '~' and suffix '~' from screen evs_block? I'd like to remove the wave mark on ~General~ and ~Introduction~.

I found this in the screen evs_block under \questmanager\engine\screens. The code block looks like this:

screen evs_block(cat, evlist, prefix=" {b}-{/b} ", completed_suffix="{image=completed}", progress_suffix="{image=in_progress}", unknown=_("? ? ?")):

    text " "+__(cat)+" ":

        style "category_style"


the text ""+__(cat)+"": is where the ~ should be in your block. I just removed mine but left the category area in case I wanted to change it around later. I hope this helps!

(2 edits)

Hi thanks for your comment :) You can remove the prefix by modifying the code. Go to the screens folder from questmanager folder and look for the diary.rpy file. At line 73 replace the line

text "~ "+__(cat)+" ~":

 by

text __(cat):

and it should work !

  File "game/houselocations.rpy", line 15, in script

    if quest.is_state("mom2", "unlocked"):

  File "game/houselocations.rpy", line 15, in <module>

    if quest.is_state("mom2", "unlocked"):

  File "game/questmanager/engine/classes.rpy", line 89, in is_state

    if self._search(id, category).state == state:

AttributeError: 'NoneType' object has no attribute 'state'

This error mean that the name of the quest "mom2" doesn't exist. Is the quest "mom2" declared into the chapter ???

(1 edit)

yes but i solved it differently i changed the classes.rpy a little bit.

how can I write two or 3 values in § quest.is_state?

do you have discord for a few questions?

Deleted post

Did you solve it?

Deleted post
Deleted 1 year ago
Deleted 1 year ago
(1 edit)

Hi, this error mean that the name of the quest "qnicolas01" doesn't exist. Is the quest "qnicolas01" declared into the chapter ???

Deleted post

Hey, there. I have a bug where I just drag and dropped your folder into my project with no edits and its throwing this error Exception: Screen diary_open_btn is not known. Is there a way the screens are supposed to be setup? 

Did you solve this problem? If yes, please tell me how you did it.

I already figured it out myself, thanks u anyway :)

I actually have not. I moved on to a different part of the code with a plan of returning. Mind sharing what you did to solve this? 

u need to write this into file screens.rpy

There is code

This is awesome and I'm so thankful, that you have given us this amazing tool! I have one question, that is probably, already answered, but im just not finding it. 


How can I activate events, depending on the status of a Quest? 
Example: If quest with Id "007" is unlocked jump to this label, elif quest with id "008" is unlocked jump to... and so on.

So basically what would be the code for having jumps depending on the Quests? 

Probably a simple If script line, but I rather ask an expert like you, before I do something wrong.

Thank you <3

Hi thank for your nice comment !
You can easily activate events depending on the status with the quest.is_state() function. This is an example: 


# Define the chapter
define test = (
Quest("test01", _("Test01"), _("Introduction"), "completed"),
Quest("test02", _("Test02"), _("Introduction"), "in progress"),

)

label start:

#Load the chapter into the game
$ quest.load(test)

#Add the conditional state
if quest.is_state("test01", " completed"):
jump choice01
else:
jump choice02

label choice01:
c "First"

label choice02:
c "Two"

Thank you so much. I understood this. I'm amazed by myself. :3 Thank you. This explanation was clear and straight to the point. Thank you so much :)

Deleted post

Thanks :)

This is awesome, mate! Thanks for your hard work :D

(+1)

Your welcome :)