Ideas on Quest Engine?

Sylpheed 101 Sep 22, 2011 at 12:29

I’m currently making a game with bunch of quests…so I thought that I’ll be needing a Quest Engine that agnostically treats all events that will bump/trigger pending quests…so it should work in any game.

I want my code design where I can modify the quest parameters and stuff from an external data source (XML, database, plist, etc).

Here’s the process I’ve thought:
- Each action will correspond to a certain unique event id.
- Game will send the event id to the Quest Engine
- Quest engine will have an algorithm to check if a quest will respond to the event id…if it matches, it’ll bump the quest

So it’s like the Quest engine will always listen to events from the game. Now my problem is how to generate these unique event ID’s. For example, “Give potion to the merchant”. The code should be able to know that I was giving potion to a certain npc and generate an ID from there. So if I’m going to give an antidote instead of a potion or give the potion to a different npc, it’ll have a different ID and the quest will not be bumped.

Can you give me ideas for the algorithm of generating event ids? Or if this approach is impractical, can you suggest a better one?

7 Replies

Please log in or register to post a reply.

Reedbeta 167 Sep 22, 2011 at 17:07

Instead of an id, how about just using an event with parameters? You could have a GiveItem event whose parameters are a pointer to the item given and the NPC receiving the item. The quest can listen for GiveItem events, check to see if the parameters match those it’s looking for and ignore if not.

Sylpheed 101 Sep 22, 2011 at 17:31

Yeah I’ve already thought about grouping all events and they’ll just differ with the object/actor within the event. I was thinking of using hexadecimal representation of IDs but I think I’ll run out of combinations (using bitwise operators). If all of this is hardcoded then I can start right away.

Wait…I think I’m getting something from your statement. The game I’m working on is for iOS (Objective C). If I’m not wrong event is the same as “NSNotification”…I could pass an object (quest data) with that. This might work, I’ll try it tomorrow.

Also, they require me that the quests should be configurable through an external data source (remotely tuned). I hope I’ll be able to get the data structure ready.

I’m just new to game development (work and hobby) so my knowledge is not yet enough to make big games.

Anyway, thanks for the suggestion. I’m still open for ideas though so keep posting XD

Okay I got the events (NSNotification) planned. Theoretically, I can make this work. Only thing left is having an XML/plist to define these specific events. Here are the events that will surely be needed in the game:

  • BuyItem (params: itemId, itemType)
  • GiveItem (params: itemId, itemType, receiverId)
  • LevelUp (params: level)
  • InteractWithItem (params: itemId, itemType)
  • InteractWithNPC (params: npcId)

As you can see they have different parameters (will be wrapped in an object so I can point to it). How should I design the data structure that will accomodate all types of events? I don’t know if it’s possible to wrap these all up in one XML/plist…how does MMO games (very quest-oriented) handle these?

__________Smile_ 101 Sep 23, 2011 at 16:06

You could always transform any kind of data to the string of bytes (words/dwords) with dynamic length. Personally I prefer this approach when working with complex ID.

For working with text files you could store ID in readable text form:

<eventHandler ID="GiveItem 6345 weapon NPC1423">...</eventHandler>
Reedbeta 167 Sep 23, 2011 at 16:57

It sounds like there’s a relatively small set of possible params. You could just make an object that has all the possible params, and an event type (enum containing BuyItem, GiveItem, etc. as values). You’d just ignore the params that weren’t relevant for the given event type.

Sylpheed 101 Sep 26, 2011 at 03:31

The requirement will not allow me to do that. I currently have these fields:

@interface Quest : NSObject {
    // Global Data 
    int                 questId;            /** ID of the quest. Equivalent to the key in plist. */
    int                 clientId;           /** ID of the client or who gave the quest. Set to 0 if there's no client. */
    NSString            *title;             /** Quest name/title */
    int                 levelRequired;      /** Level required to unlock the quest */
    QuestHierarchy      hierarchy;         /** Parent quest or child quest */
    QuestStatus         status;             /** Status of the quest. */

    // Main Quest Fields
    NSMutableArray      *prerequisites;     /** Array of quest ID's needed before the quest gets unlocked */
    NSMutableArray      *tasks;             /** Array of tasks (quests) needed to complete the quest */
    // Timed Events
    float               timeRemaining;      /** Time remaining before the quest expires */
    float               timeLimit;          /** Time limit before the quest expires. Set to 0 for no limit. */
    // Progress
    int                 numProgress;        /** Incremental quest progress */
    int                 numRequired;        /** Number of times needed to repeat the quest */
    id <QuestDelegate>  delegate;           /** Quest delegate. */

I doubt these fields will be able to meet future requirements. I was planning to create a class for every type of event and dump all the required fields in there. With that, my Quest class doesn’t even need to know what event it needs to trigger, the event will just tell the Quest object that it was triggered.

But the problem with the structure of the external data source still persists. Is it practical that my data structure is not consistent? By consistency, the structure for each tree varies per event. I think I’m confused since I’ve been using consistent data structure up to now.

- BuyItem (params: itemId, itemType)
- GiveItem (params: itemId, itemType, receiverId)
- LevelUp (params: level)
- InteractWithItem (params: itemId, itemType)
- InteractWithNPC (params: npcId)

Let me know if this is a good approach.

Hmmm…that seems convincing. I’ll consider that but I’ll have to ask the Web department since they’ll be the ones who will generate the data source for me.

Reedbeta 167 Sep 26, 2011 at 04:12

It looks like you’re using Objective-C; I’m not familiar with that, but in C++ what I might do is make a base Event class that contains nothing but an event type (maybe a few other general things like a timestamp or whatever), then make derived classes for each type of event, containing the appropriate parameters. You’d have to do some casting based on the event type to the appropriate derived type. Something like:

enum EVENTID {
    // ... other events

class Event {
    EVENTID m_eventId;

class BuyItemEvent : public Event {
    Item * m_pItem;

class GiveItemEvent : public Event {
    Item * m_pItem;
    Npc * m_pReceiver;

// ... other classes

// Here's some code that looks for a specific event
void ProcessEvent (Event * pEvent) {
    if (pEvent->m_eventId != GiveItem)
    GiveItemEvent * pGiveItemEvent = static_cast<GiveItemEvent *>(pEvent);
    if (pGiveItemEvent->m_pItem != pItemDesired)
    if (pGiveItemEvent->m_pReceiver != pReceiverDesired)
    // ... do something with the event

// Here's some code that handles multiple kinds of events
void ProcessEvent (Event * pEvent) {
    switch (pEvent->m_eventid)
    case BuyItem:
            BuyItemEvent * pBuyItemEvent = static_cast<BuyItemEvent *>(pEvent);
            // ... do something with it
    case GiveItem:
            GiveItemEvent * pGiveItemEvent = static_cast<GiveItemEvent *>(pEvent);
            // ... do something with it
    // ... other cases

Maybe you can do something similar in Objective-C.

Sylpheed 101 Sep 26, 2011 at 05:34

Yeah, I’m developing iPhone games.

Yeah that’s what I’m trying. It’s perfectly a matter of fact it’s much easier to handle class hierarchy/inheritance in Objective-C. I’m gonna code this now.

For the datasource, I’ll use Smile’s idea. Thanks. I’m using this format for the QuestEvent.


Repetition and time may not be included for simplicity.

Good, looks like I’m on the right track. Thanks. I’ll post again if ever I encounter problems.