ID:267854
 
How would i go about making dynamic quests where the player brings an NPC to see another NPC and then rewards the player. I have no idea how to start... Please help.


Thanks,
~Master_Damien
Master_Damien wrote:
How would i go about making dynamic quests where the player brings an NPC to see another NPC and then rewards the player. I have no idea how to start... Please help.

This is kind of a big nut to crack, but it can be done. The key to this is deciding in advance how to organize your quests.

The first and most important big question is: Can players tackle the same task at the same time? Or while an NPC is following you, does someone else have to wait for that NPC to come back if you don't make it? In other words, how will quests work in a multiplayer environment?

Are your quests randomly generated? If not, should they or could they be?

Randomly generated quests can basically be set up to take on several predefined forms, such as:

  • One NPC needs to see another.
  • An NPC needs an item.
  • You have to defeat N of a certain monster.
  • A "boss" enemy has to be defeated.

    I only have a partial quest generation system myself, that I was working on for a project that's currently on hiatus.

    To answer you more simply, I think you can set up a simple system to handle your quests:
quest
/*
Most of these vars are either type paths or lists of type paths.
The action may be anything you want (string, type path, number) or a list of things.

reward is a type path or list of paths.
*/

var/item // may also be a person
var/recipient // place to bring item
var/action // action to perform to complete the exchange
var/reward // item given for completing the quest

proc/IsMatch(template, real)
if(istype(template, /list))
for(var/k in template)
if(IsMatch(k, real)) return 1
return 0
if(ispath(template)) return istype(real, template)
return template == real

proc/CheckQuest(mob/M, i, r, a)
var/k
if(!IsMatch(recipient, r)) return
if(!IsMatch(item, i)) return WrongItem(M, i, r, a)
if(!IsMatch(action, a)) return WrongAction(M, i, r, a)
if(CompleteQuest(M, i, r, a)) return
GiveReward(M, i, r, a)
del(src)

// return 1 if you want to modify the quest at this point so it's not finished
proc/CompleteQuest(mob/M, i, r, a)
// default behavior
if(istype(i, /datum)) del(i)

proc/GiveReward(mob/M, i, r, a)
if(istype(reward, /list))
for(var/k in reward)
// one kind of reward is an associative thing like "exp"=100
if(istext(k))
if(k in M.vars)
// if the vars aren't both numbers, you're on your own!
M.vars[k] += reward[k]
// another reward type: an item's type path
if(ispath(k))
new k(M)
// a third type: an already created item
if(istype(k, /atom/movable))
k:loc = M // yes, I just used the : operator!

proc/WrongItem(mob/M, i, r, a)
// fill this in yourself

proc/WrongAction(mob/M, i, r, a)
// fill this in yourself
With this you should be able to set up a pretty decent array of quests.

The goal here is to create a quest datum, and assign it to a player (perhaps by adding it to a list). The place where you deliver the item should know enough to check for an active quest when you do what you need to do. For example, if you have to deliver a certain package:
var/quest/Q = new
var/list/L = new
var/mob/shopkeeper/S
for(S) L += S
S = pick(L)
Q.recipient = S // deliver to this shopkeeper
Q.item = new/obj/package(usr)
Q.reward = list()
Q.action = "give"
Q.reward["exp"] = rand(2,4) * 25
if(!usr.activequests) usr.activequests = list()
usr.activequests += Q
usr << "<span class=dialogue><b>[src]:</b> Please deliver [Q.item] to [S].</span>"
And then on delivery, there's this:
mob/shopkeeper
// overrides the default Give() verb
Give(obj/O)
if(!O || !(O in usr)) return
if(!usr.activequests) return
var/found
for(var/quest/Q in usr.activequests)
Q.CheckQuest(usr, O, src, "give")
if(!Q) // quest was completed and deleted
usr << "<span class=dialogue><b>[src]:</b> Thank you.</span>"
return
if(Q.recipient == src) found = 1
if(found)
// this shopkeeper is expecting a package, but not this one
usr << "<span class=dialogue><b>[src]:</b> That isn't what I ordered.</span>"
else
usr << "<span class=dialogue><b>[src]:</b> There must be some mistake. I'm not expecting \a [O].</span>"

Lummox JR