Log in

View Full Version : Task System (preliminary work)


Derision
08-07-2008, 02:35 PM
I've been looking at whether it would be possible to get the Task System working. The OPcodes and
structs are pretty much squared away (a lot of this was already mapped out in the code, so I just
filled in the gaps with some info from a packet collect by Solid11 over at PEQs repository).

At the moment, I have written code to send the relevant OPcodes to the client and I'd thought I'd
share.

Bring up the Task Selector:

http://www.rama.demon.co.uk/taskpics/task1.jpg

Send Task Description and Activity packets:

http://www.rama.demon.co.uk/taskpics/task2.jpg

Send Task Stage Completed packet:

http://www.rama.demon.co.uk/taskpics/task3.jpg

Send Task History:

http://www.rama.demon.co.uk/taskpics/task4.jpg

I don't know what should go in the 'Quest Progression' part of that window ... maybe an Opcode I
am missing. I'll have to hop on live and see.

I haven't seen any packets relating to the 'Shared Tasks', but that is not a particular priority for me.

At the moment, all I have are some #commands to bring up these windows etc, as a test. There is still
a lot of work to do to integrate it into a working Task system. If anyone has any thoughts on how to
tie it in to, for example, the quest system, feel free to post your ideas.

So_1337
08-07-2008, 02:57 PM
Deliver 2 Elven Bottle of Wine to KLS
Kill 4 Forum Trolls
Hahaha! Talented and funny!

Isn't this one of the primary roadblocks on any sort of LDoN functionality? I know getting any form of instancing working is also a pretty big hold-up, but I believe that the original form of LDoN didn't really have any -- It was simply 10 different versions of the same zone that could handle a group each. The Rujarkian Hills 'instance' was ruja-rujj, for example. Though I'm sure this is already common knowledge around here.

Just wondering, since that's the first I remember the task window ever coming into play. I know it was used for quests after that, but I didn't play much at all during that period and am thus unfamiliar. Was it retroactive at all? Did it handle some older quests by chance? My gut feeling is that it didn't.

Andrew80k
08-07-2008, 03:02 PM
Dude!

I've been thinking about this for a while, but haven't had the time to get into it much. I think it would be great if we could tie it into the quest system. I haven't come up with a good solution, because I just don't know enough about how it works within the client. Basically, how it's passed to the client. Is all the quest data passed into the client at the time the quest is assigned, and then how do the updates affect it?

I was thinking about doing something on the order of quest::taskassign(blah, blah,blah) or however it worked out to assign tasks. Then quest::update(blah,blah), or what ever as far as how the data is then passed to the client. That is if it could even be integrated into the quest system.

Anyway, that's an awesome start. Thanks for taking it on...

So_1337
08-07-2008, 03:07 PM
Having no idea whatsoever how it's actually handled, I feel perfectly qualified to pitch an idea for how it should work.

Initiate a quest with an NPC. That should pass the quest completion criteria to the client's task window.

quest::task(type,quantity,id);

Where type is the type of quest (collect or kill), quantity is how many must be collected/killed, and id is either the item ID or NPC ID.

Is there an op_code triggered by looting a certain item ID or killing an NPC of a certain type?

Feel free to shoo me away from this thread. I know I'm in far over my head. Just pitching that out there, though, as a rough example.

Andrew80k
08-07-2008, 03:08 PM
Hahaha! Talented and funny!

Isn't this one of the primary roadblocks on any sort of LDoN functionality? I know getting any form of instancing working is also a pretty big hold-up, but I believe that the original form of LDoN didn't really have any -- It was simply 10 different versions of the same zone that could handle a group each. The Rujarkian Hills 'instance' was ruja-rujj, for example. Though I'm sure this is already common knowledge around here.

Just wondering, since that's the first I remember the task window ever coming into play. I know it was used for quests after that, but I didn't play much at all during that period and am thus unfamiliar. Was it retroactive at all? Did it handle some older quests by chance? My gut feeling is that it didn't.

Nah. The older quests were never "retrofitted" for the task system, which is a failing in Live, IMO. Would have been handy for those long epic quests. Or even the smaller ones. I think most of the "older" quests eventually yielded mostly crappy, in comparison, stuff so was thought to be more work than it is worth. It would be really nice to work it into the emu quest system though so as to rectify it if possible. We still have a lot of older quests that haven't been completed that could be fitted to make it work if it was possible to have it work that way.

Derision
08-07-2008, 03:14 PM
Is there an op_code triggered by looting a certain item ID or killing an NPC of a certain type?

No, the way I see it working is, whenever you kill a mob, or loot something, the server will need to check if you have any active tasks, and if killing that mob, or looting that item, was an objective of the task, then incrementing the kill/loot count for the task and sending the Task Complete packet when you have killed/looted the required number.


Feel free to shoo me away from this thread. I know I'm in far over my head. Just pitching that out there, though, as a rough example.

I welcome anyones ideas. I never actually did any of these Tasks when I played on live.

So_1337
08-07-2008, 03:26 PM
That sounds about right. I'm trying to remember the different quest types. I remember kill and collection, as those were the easiest. My friends and I pretty much kept requesting a new task until we got one of those, heh. Again, though, this only applies to LDoN. I suppose it could apply to many different quests that came later and fit the format correctly. Might need someone with a little more insight as to how it was used on Live, but your understanding of it sounds pretty spot-on thus far. It's the application of the system that's going to take some understanding.

Derision
08-07-2008, 03:34 PM
I'm trying to remember the different quest types. I remember kill and collection, as those were the easiest.

There is an 'Activity Type' field, which determines, whether the activity is loot, deliver, kill etc. I've not tried all the possible values yet, but I know there is an 'Explore' type, which I imagine could be tied into the quest proximity detection in some way.

Andrew80k
08-07-2008, 03:34 PM
That sounds about right. I'm trying to remember the different quest types. I remember kill and collection, as those were the easiest. My friends and I pretty much kept requesting a new task until we got one of those, heh. Again, though, this only applies to LDoN. I suppose it could apply to many different quests that came later and fit the format correctly. Might need someone with a little more insight as to how it was used on Live, but your understanding of it sounds pretty spot-on thus far. It's the application of the system that's going to take some understanding.

Most of the task quests involved kill and collect. There were locate explore type quests as well, where you just ran around looking for stuff. These were mostly to get questers familiar with the zones and such. I don't have the latest expansion so I'm not sure if there are other types in the later ones. I've done a lot in the DoN and a several in the Depths of Darkhollow. Most of those were kill and collect.

Andrew80k
08-07-2008, 03:37 PM
There is an 'Activity Type' field, which determines, whether the activity is loot, deliver, kill etc. I've not tried all the possible values yet, but I know there is an 'Explore' type, which I imagine could be tied into the quest proximity detection in some way.

Yeah, set up an invisible mob/object and set a proximity around it. Have the quest for that object send a task update. If you have the task your task updates, if not the client will likely ignore it.

Flare83
08-07-2008, 03:55 PM
Awsomeness Derision, did you used to work for Sony? lol j/k but nonetheless great work.

Flare83
08-07-2008, 04:04 PM
Damn edit button

The main things i remember from the task system was

EQlive must of kept a table for what quests you completed. Becuase some of the quests where long 12 mission arcs.
DoN used it heavely for its raids/group content.
GoD/OoW used the alt+z window for it's missions. i think they are alot different but on the other hand might be alot alike /shrug.
Ldon used alt+v i think

KLS
08-07-2008, 05:35 PM
No, the way I see it working is, whenever you kill a mob, or loot something, the server will need to check if you have any active tasks, and if killing that mob, or looting that item, was an objective of the task, then incrementing the kill/loot count for the task and sending the Task Complete packet when you have killed/looted the required number.

Basically, we can already handle this kind of stuff via player quests too, proximity mobs for explore etc.

Would add a internal task tracking system for time, completion/failure and maybe item amounts since that would be cumbersome then could probably do the rest via quests.

quest::updatetaskvalue(taskfield,value)
quest::enabletaskforplayer()
quest::disabletaskforplayer()
quest::opentaskwindow()
quest::istaskcompleted(taskid)

etc. probably more or different.

Biggest issue if you've gotten most the packets worked out will probably be trying to with some finesse track the quests offered. Since quests offered to a player will vary based on: who the player is(race,class), what they've done(tasks/quests complete), which npc is giving it.

That said if you need help and I get time I'd be most excited to help you hammer out a system to do it.

trevius
08-08-2008, 03:11 AM
Maybe quest globals could be used for tracking purposes for tasks? They sounds to be similar systems and I think you would just need to allow the task window to work with the quest globals system. If so, it seems like it would minimize the work needed to get this finished. Or maybe use some of the code from the globals system to implement something similar to be used only for tasks. I am sure you would need a table for tracking them and similar fields.

KLS
08-08-2008, 04:49 AM
Actually it would probably be harder to integrate it into an old system than to create a new one as the system would probably be fairly straight forward really. For performance issues I think also it's probably not a good idea; think every time you have to do a quest action you need to re-export globals, integrating it into qglobals would probably inc the number of globals in use by a lot and make it just that much more work every time the server processed quests.

Derision
08-08-2008, 06:09 AM
Actually it would probably be harder to integrate it into an old system than to create a new one as the system would probably be fairly straight forward really.


Yes, I was looking at the quest system this morning, and that was my thought.

While I am at work, I thought I would start sketching out how to implement this,
and welcome any thoughts you have on my tentative design choices.

First the tables. Global tables for the stuff that doesn't change (once the task is written),
and character tables to record their progress.



CREATE TABLE GlobalTasks (
id int(11) unsigned NOT NULL,
duration int(11) unsgined NOT NULL,
description varchar(4000) NOT NULL,
reward varchar(100) NOT NULL,
startzone int(11) NOT NULL,
PRIMARY KEY(id)
)

CREATE TABLE GlobalActivities (
id int(11) unsigned NOT NULL,
activityid int(11) unsigned default '0',
activitytype tinyint unsigned, // Kill, Loot, Deliver, Explore, etc
text1 VARCHAR(100) default '', // For Deliver tasks, this is the NPC name to deliver to, or name of mob for kill tasks etc
text2 VARCHAR(100) default '', // For Deliver tasks, this is the text name of the item to deliver, or item to loot for loot tasks
itemid int(11), // item number for loot tasks.
npcid int(11), // npcid for kill tasks
exploreid int(11) default 0, // For explore tasks, this is a unique number to identify the proximity event that needs to be triggered
goalcount tinyint default 1, // How many things to kill, deliver, loot, etc
zoneid int(11), // The ID number of the zone that this task is performed in
PRIMARY KEY(id, activityid)
)

I am unsure as to whether the text1/text2 fields are required,
or whether I should just pull the npc name/item name as
required based on their id. The npc name/item name is sent as
text in the Task packets. Keeping the text fields as well would
allow the Task designer to be a bit vaguer/ more 'roleplay' in
their objectives if they wished, e.g. 'Kill the master of Karnor'
rather than 'Kill Venril Sathir'.


CREATE TABLE CharacterTasks (
charid int(11) unsigned NOT NULL,
taskid int(11) unsigned NOT NULL,
acceptedtime int(11) unsigned, // Timestamp of when the player accepted the task
completedtime int(11) unsigned default '0', // 0 for an unfished task
PRIMARY KEY(charid, taskid)
)

CREATE TABLE CharacterActivities (
charid int(11) unsigned NOT NULL,
taskid int(11) unsigned NOT NULL,
activityid int(11) unsigned,
donecount tinyint default '0',
completed tinyint(1) default '0', // Not strictly needed, but probably quicker than cross referencing the Global Activity table to check if an activity is complete
PRIMARY KEY(charid, taskid, activityid)
)



The active and completed task information is not retained by the client, certainly not across
logins, and probably not across zoning, so needs to be resent after zoning.

As I see it, zone will need to load the global task and activity tables in their entirety on
zone bootup. This may become an issue later on if their are lots of tasks written. As this is
global static data, it could be a candidate for shared memory, but I will leave that for the
future.

The next issue is how to represent the Tasks in memory. Each Task has a unique ID. I am leaning
toward #defining a MAXTASKID (say 10000 ?), and using a fixed size array ...

TaskInformation* Tasks[MAXTASKID]

The benefit I see of doing this is fast cross referencing to the Task/Activity information from
the per-character data. I think this would also make it easier to #reloadtask a single task
during development.

Onto the per-character info. Should I restrict a character to a maximum number of active tasks, e.g. 20 ?
The benefit I see to this is it constrains the amount of checking that needs to be done on killing/looting
to see if there is a matching goal in the characters active activities.

Pseudo Code:

On NPC Kill or Loot:
for each active task the character has:
for each open activity in that Task:
if ActivityGoal == Kill This NPCType or Loot this item.id Increment Goal Count

It did occur to me that an extra flag could be added to the npc_types and item tables, 'involvedintask',
so that the code could check this flag and if it is set to No, not bother checking the characters
active tasks.

Task initiation will be done through the existing Perl quest system, so the usual checks
for class, race, faction can be done before the NPC initiates the Task Chooser. (Also provide
a function so that a check can be made in Perl to see if the player has already completed
a particular task, so as not to offer it again).

I also see Task Completion/Reward as being handled by the Perl quest system, i.e. the last
activity in a Task would be go speak to an NPC who would then do something along the lines
of:


if quest::ActiveTask(1234) && quest::TaskActivityComplete(1234,10) .... give reward, quest::TaskComplete(1234)


I would be interested in any links to quests on Alla that use the Task system. I've
been using http://everquest.allakhazam.com/db/quest.html?quest=3237 as a guide, as
that is the one in the packet collect I was looking at.

Andrew80k
08-08-2008, 10:19 AM
Looks like you have a good handle on it, and your initial approach seems viable to me. I would think that limiting the number of active quests a toon can have is wise at this point. Once you get started implementing it, I'm sure you'll come across other challenges. As for tasks, I'm mostly familiar with these...

This is an example of a collect task:

http://everquest.allakhazam.com/db/quest.html?quest=4320

This is a combo kill/collect:

http://everquest.allakhazam.com/db/quest.html?quest=3065

I know we're not up to DoN yet, but these tasks are examples.

KLS
08-08-2008, 04:54 PM
Task initiation will be done through the existing Perl quest system, so the usual checks
for class, race, faction can be done before the NPC initiates the Task Chooser. (Also provide
a function so that a check can be made in Perl to see if the player has already completed
a particular task, so as not to offer it again).

See this to me presents a unique problem in that it would be cumbersome if not impossible to write quests to include all the tasks a person has from a given npc. Keep in mind some task givers are giving out lots and lots of tasks, especially the ones for shards and such give out literal boatloads of tasks.

Personally I'd do something like:

CREATE TABLE TaskSet (
id int(11) unsigned NOT NULL,
globaltaskid int(11) unsgined NOT NULL,
PRIMARY KEY(id, globaltaskid)
)


Would allow you to group tasks together into tasksets and the quest code could be simplified to quest::BringUpTaskWindow(taskset). Different npcs offer different tasks and more than 1 at a time if you qualify for them on live.

Would also need some way of enabling the tasks if one were to go with such an implementation.
CREATE TABLE CharacterTasksEnabled (
charid int(11) unsigned NOT NULL,
taskid int(11) unsigned NOT NULL,
enabled tinyint(1) default '0',
PRIMARY KEY(charid, taskid)
)

Could then offer quest::EnableTask(taskid), quest::DisableTask(taskid), etc to make it much simpler to write quests that use the task system.

Putting it in shared memory is also probably a better option as the structures are probably going to need to be in some cases quite large and with the assumed 10000 entries it would really add up for a server that loads quite a few zones. A couple MB per zone doesn't seem like a big deal until you load up 50.

wexford
08-09-2008, 03:22 AM
Ok I have to say this is awesome! Ive been waiting for tasks to work since i came to eqemu! Awesome work derision

Derision
08-09-2008, 05:37 AM
Keep in mind some task givers are giving out lots and lots of tasks, especially the ones for shards and such give out literal boatloads of tasks.

I already have the feature coded to call the task chooser from Perl with up to 10 tasks (could be increased by changing a #define):


$args ="1,2";
quest::taskchooser(eval($args));


So the initiating quest can build up the $args string with the list of Tasks the player is eligible for. When I've got the whole system working end-to-end, I'll revisit this to see about implementing it as you suggest.

Shared memory I will leave til last, as it's not something I've ever worked with.

Bulle
08-09-2008, 03:37 PM
First, allow me to say that your findings are very promising. A good Quest Journal was really a missing part of EQEmu (and in fact of EQ for some quests).

I did not play with the task system very much on Live, it really came when I was taking a break from the game. There is one thing you should be careful of : may be some Live tasks have simultaneaous activities. Something like "Make 7 flame Posts" and "Get banned for one week", that you need to complete before you can progress to the next activity. As you see I am sticking to your examples spirit :)

Regarding the design, you could make the Quest Journal have even more reach by separating the low-level Journal handling from the Task system. In short, it could allow quest designers to track quests in the Journal even for quests that are not formatted like tasks. Let me take an example, this time from a quest idea I actually started implementing through the normal Perl system..

"The young gnome had been playing a few pranks to several personalities in Ak'anon, following the directions of the enchanter guild mistress. The last one had put him in hot waters though : passing for a half-elf had been easy with the illusion spell the enchantress had given him, but he was still shaking about the thought of what would have happened had he answered to the necromancer in the wrong way. But the real problem was : what to do with the letter the necromancer asked him to deliver to the dark elf necromancer guild master in Neriak ! Clearly he had gotten more than the enchantress had hoped for, surely she sent him there on purpose, not just to play one more prank. He could certainly bring the letter to her, or may be actually delivering the letter to its actual recipient would make him rich. Neriak was a wealthy city."

At some point the character can choose one of two major paths in a quest. Having the Task Task system handle that could be tricky. Handling arbitrary quest progress triggers (like we do in Perl sometimes) would be overkill. It is made for simple tasks and let's face it, many quests are like that. On the other hand it would be very nice to allow regular Perl quests to benefit from the Journal, given the quest writer accepts the extra work naturally.

You could achieve that by untying the actual quest progress (task progress) from the Task system logic. The tables would be unchanged, except the comment for completed would not apply : for arbitrary quests donecount has no meaning. The activity would be complete when the completed field is filled.

What does actually change then ? Answer : the way the tables are managed. At the moment may be you are thinking of wiring the table management into the task system. Instead you could separate the table management, and expose all "atomic" operations on those tables as quest:: xxx calls in Perl scripts, on top of using them for the task system of course.

Quest writers could then decide when to :
* quest::start_task(taskid, activityid) : the quest could start at any activity, defined by the Perl script
* quest::complete_activity(taskid, activityid) : completed date set by the server
* quest::start_activity(taskid,activityid) : this activity is started. Several activities could be up at the same time.
* quest::complete_task(taskid) : completed date set by the server

Of course those "manual" activities would not track progress , the Perl script does. But the player would at least see the quests he is on and the text for the current activity.

It would be the quest writer responsibility to start the next step(s) after completing the previous one(s), to detect when an activity is complete etc. A few checks could be added to avoid inconsistencies, like tasks completed whereas some activities are not complete for this task. But the code need not ensure an open task has an ongoing activity. The Perl scripts pilot the Quest Journal, and try to reproduce faithfully the facts. The Task system in this case is not active. With an activity_type of "Unmanaged" or somesuch it would be easy to deactivate the task system for those "quest" tasks and activities.

Ultimately this could lead to a flexible, semi-automated quest/task system : quests/tasks and their steps would be defined in the DB, with the transitions from a set of steps to the next ones. Each activity/step could either be handled by Perl, disabling any automated counting of objectives, or be fully supported by the engine for easy activities (loot, kill, explore). This would just depend on the activity_type. But it can be built one step at a time :)

By doing that we could have an emu better than Live with regards to quest tracking : even old quests could be tracked by the Quest Journal, given they are reworked of course.

I suggest this because I doubt it would be much more work to structure the code to allow the Task system to be optional with regards to the Quest Journal. Most of the things to write are the same, you just need to let the Task System pilot the Quest Journal, not intermix them and make them dependent on one another.

I hope this did not read like gibberish :)

Derision
08-09-2008, 04:00 PM
There is one thing you should be careful of : may be some Live tasks have simultaneaous activities. Something like "Make 7 flame Posts" and "Get banned for one week", that you need to complete before you can progress to the next activity.

That's a good point. The task I have been using as my guide has a sequential set of activities, where one must be completed before the next is revealed.

There are two types of task activity packet. One for completed and 'in progress' tasks which sends the details of the goal, and progress toward completion.

The second type is really just a placeholder, which consists just of an Activity Number, but no details of what the task is. These show up as ??? in the Task Journal.

It would be easy to alter the table and code to add a predecessor activity field. I know, (and you can see from the example in my first post), that it is possible to have more than one activity in progress displayed at the same time.

As for your other points, I skimmed over them, but they sound interesting, and I will look them over again and see what's possible as I continue to implement the system :)

Derision
08-10-2008, 02:38 PM
I've been beavering away at this since Friday and thought I would provide an update on what I have functional so far:

Database Load routine for global task data
Database Load/Save for character task data

The database save is synchronous, but it only writes out anything that has been changed. I'll have to see if this can be done asynchronously like the saving of the other character data is.

Active task information is sent to the client when it enters a zone and so is retained across logins and zoning.

Initial Perl interface to bring up the Task Chooser with a list of up to 10 tasks:

The way I have it working right now, is the NPC has a list of all the tasks he can offer ($tasklist). It then checks whether the player already has each task in the list already assigned, (quest::istaskactive) and thus builds up a list of tasks it will offer ($tasksoffered), not including any tasks already active. quest::taskchooser then brings up the task selector window.


@tasklist =(1,2);
$tasksoffered = "";
foreach $task(@tasklist) {
if(!quest::istaskactive($task)) {
if($tasksoffered eq "") {
$tasksoffered = $task;
}
else {
$tasksoffered = $tasksoffered . "," . $task;
}
}
}
if($tasksoffered ne "") {
quest::taskchooser(eval($tasksoffered));
}


I have also added a new sub EVENT_TASKACCEPTED. This tells the NPC what task you accepted, so it can respond appropriately, summon an item etc. (When you accept the Children of the Fay task, you are given an Elven Bottle of Wine that you have to deliver).


sub EVENT_TASKACCEPTED {
quest::say("You accepted task $task_id");
if($task_id eq "1") {
quest::summonitem(36078);
}
}


You can remove a task by clicking the Remove button in the Task Journal window.

Two more Perl quest functions, quest::istaskactivityactive(taskid, activityid) and quest::flagtaskactivitycomplete(taskid, activityid).

This code checks when you hand in the Elven Bottle of Wine to see if you are on activity 0 of the Children of the Fay task (task 1), and if so, accepts the item, and flags that activity complete, sending the 'Task Stage completed' message, and unlocking the next activity:


sub EVENT_ITEM {
if (plugin::check_handin(\%itemcount, 36078 => 1)) {
if(quest::istaskactivityactive(1,0)) {
quest::say("Thank You!");
quest::flagtaskactivitycomplete(1,0);
}


I'm still undecided about how to implement the predecessor activity requirements. E.g. say a task has 10 activities and when you completed activity 1, activities 2 and 3 open up. Task 4 then won't open up until tasks 2 and 3 are complete.

As I see it, I can either put a limit on how many predecessors an activity can have (let's say 4), and then have four columns in the table, predecessor1, predecessor2, etc.

Or, have a text field which could contain a comma separated list of predecessors, e.g. "2,3". I dislike this because it means I have to parse the string to get at the predecessor info.

I'm leaning toward option 1 (a fixed, small number of predecessors and having a column for each).

Still lots left to do!

AndMetal
08-11-2008, 12:40 AM
I'm still undecided about how to implement the predecessor activity requirements. E.g. say a task has 10 activities and when you completed activity 1, activities 2 and 3 open up. Task 4 then won't open up until tasks 2 and 3 are complete.

As I see it, I can either put a limit on how many predecessors an activity can have (let's say 4), and then have four columns in the table, predecessor1, predecessor2, etc.

Or, have a text field which could contain a comma separated list of predecessors, e.g. "2,3". I dislike this because it means I have to parse the string to get at the predecessor info.

I'm leaning toward option 1 (a fixed, small number of predecessors and having a column for each).

Still lots left to do!

I think something like the "_entries" or "_metadata" tables currently in the database would work best, similar to what KLS recommended above. Here's an example:

CREATE TABLE TaskOrder (
taskid int(11) unsigned NOT NULL,
activityid int(11) unsgined NOT NULL,
step int(11) unsigned NOT NULL,
PRIMARY KEY(taskid, activityid)
)

"step" could be used to group each stage, so using your example, activity 1 would be step 1, activities 2 & 3 would be step 2, and activity 4 would be step 3:

taskid activityid step
1 1 1
1 2 2
1 3 2
1 4 3

That way, it's more dynamic, and doesn't create a large table if you want something more than 4 prerequisites deep.

Hope this gives you some ideas, the whole task system seems REAL promising :-)

Derision
08-11-2008, 01:39 PM
"step" could be used to group each stage

Thanks! I think just adding a 'step' column to the activity table, rather than creating another table should suffice.

Anyway, I've hit upon another snag. I've just implemented the code to update 'Kill' and 'Loot' activities, based on NPCTypeID or itemid respectively, which works great, however ...

I wanted to add a Kill activity to kill 5 Orc Centurions, but there are 40 entries for Orc Centurions in the npc_types table!

As they say, no plan survives contact with the enemy! I would welcome ideas on this one. Doing a lookup against a list of 40 NPC IDs per kill seems a bit OTT. Maybe some sort of sub-string match again the NPC name may be a less expensive way to go.

Andrew80k
08-11-2008, 02:07 PM
Hmm. Could be you just let any of them meet the requirements. Or you could just filter them out like you say. It probably makes more sense to filter them out and then let any of the resulting id's after you filter them to your satisfaction, meet the requirements for the task.

AndMetal
08-11-2008, 02:32 PM
As they say, no plan survives contact with the enemy! I would welcome ideas on this one. Doing a lookup against a list of 40 NPC IDs per kill seems a bit OTT. Maybe some sort of sub-string match again the NPC name may be a less expensive way to go.

I think an easy way to do this would be to allow either a # (NPC ID for a specific mob) or a string. Then, the server can check to see which it is. If it's a #, use the specific NPC ID. If it's a string, allow multiples based on the string (SELECT name FROM npc_types WHERE name LIKE '%an_orc%'). I think it would be a lot easier to utilize overall (an_orc for example, instead of an_orc_warrior, an_orc_oracle, or an_orc_pawn). However, in the same token, I believe it could cause problems for mobs that have different names, but are different (lower) levels (read: exploit).

As much as I like the first option, I think the "better" way to do it would be to create a similar lookup table like I mentioned above. Yes, it is another table, but it makes it much more powerful overall. That way, you could also include named mobs that are rare spawns to include towards the kill target. Yeah, it seems like more work in the database, but that's also what relational databases are for: creating complex relationships between data sets :-)

KLS
08-11-2008, 02:45 PM
Use quests for the kill component =p

AndMetal
08-11-2008, 03:00 PM
Use quests for the kill component =p

*smacks forehead* I should have had a V8!

Derision
08-11-2008, 03:27 PM
Use quests for the kill component =p

Thanks :)

I've now mapped out some more of the activity types:




Activity Type Codes:

1 Deliver x to y
2 Kill n MobX
3 Loot n ItemA
4 Speak With x
5 Explore y
6 Create n ItemA using Tradeskills
7 Fish for n ItemA
8 Forage n ItemA
9 Use on
10 Use on
11 Touch ItemA



So 1, 2, 4 and 5 can be handled through quests.

3 I already have handled by hooking into Corpse::LootItem, and I imagine 6, 7 and 8 should be done by hooking into the code as well.

I'm guessing that the 'Touch' activity means clicking on a clickable-object, like a door or something. I found a task on Alla that has 'touch' as an activity:

http://everquest.allakhazam.com/db/quest.html?quest=3151

But it's not clear what it means.

Flare83
08-11-2008, 03:37 PM
I'm guessing that the 'Touch' activity means clicking on a clickable-object, like a door or something. I found a task on Alla that has 'touch' as an activity:

http://everquest.allakhazam.com/db/quest.html?quest=3151

But it's not clear what it means.

It means zone into a certain instanced / zone basically ~.~

Bulle
08-12-2008, 01:26 PM
When you say : for kills, handling through quests, do you actually mean patching/creating many NPCs Perl quest files ? There can be an orc_centurion in several zones, some of them actually "dinging" the quest..

As the kill activity is very common, having a lookup table (ID of activity, ID of mob) seems worth doing. Especially as you can attach this list/set to the activity in a field once it is loaded from the DB. It probably is not in the scope of Live-like, but extending this to several activity types you could then have activities that accept looting "any rusty weapon". Not trying to make my shopping list for the first implementation, just trying to keep doors open here :)

Or may be you thought of another way through quests ?

As a professional programmer let me say one thing : filtering on the name (or a part of the name) will inevitably create unsolvable situations, or to say it bluntly, it will suck. It always does when you start doing such things.

Derision
08-12-2008, 02:05 PM
When you say : for kills, handling through quests, do you actually mean patching/creating many NPCs Perl quest files ? There can be an orc_centurion in several zones, some of them actually "dinging" the quest.

I took it to mean calling the task activity update method from within sub EVENT_DEATH, which works.


As the kill activity is very common, having a lookup table (ID of activity, ID of mob) seems worth doing. Especially as you can attach this list/set to the activity in a field once it is loaded from the DB.

My concern was, in the case of an Orc Centurion, having to check through a list of 40 NPCIDs every time the player killed something to see if he had killed an Orc Centurion. It occurs to me now that if the list is sorted, I could do a binary search on larger lists, so maybe it wouldn't be so bad :)

I could always include both methods and have a flag to indicate whether the activity count update was to come from a quest, or be checked from a list.

KLS
08-12-2008, 02:14 PM
EVENT_KILLED_MERIT was designed with mob kill quests in mind. You could make 40 different quest files or you could just make a single an_orc_centurion.pl. It basically just simplifies the problem that was discussed above but is hardly the only solution.

Bulle
08-13-2008, 02:44 PM
You really have two ways of processing quests : the configured way, and the custom way.

At the moment EQEmu "shines" in the custom way. I put shine in quotes because I hate Perl, but other than that it is very much open-ended :) With the Perl scripts you can do a lot of things, it just takes time, knowledge and patience (did I mention "time" ?).

The other way is what wow-emulators provide : table-driven definitions to easily specify kill quests, loot quests, explore quests and a few others. The list is limited, the configuration tolerated is limited, but it is very efficient (in that the server handles it, and it avoids the silly Perl syntax errors).

Both can co-exist. The server can first check the "configured" quests, and then the fully-custom ones. At the moment EQEmu is lacking in the second option, which covers a big portion of the quest/task neeeds. If we had that, many "newcomers" could write their own basic quests, by tweaking tables instead of writing Perl. I am not only speaking of "Live"-like quests there, many custom quests would become very easy.

This is really what I was hinting at, that there are two parts in what you would like to implement, Derision :
* Exposing the functionality (opcodes) allowing the Quest Journal to work. Providing the functionality through functions in C++ and possibly Quest:: Perl function calls. This is the basis for task tracking.
* creating an "easy-quest" framework, using the requirements of the EQ Task system as a guideline.

You can have all those alternatives in a game :
* easy and limited quests with no tracking
* complex and open-ended quests with no tracking (as it is at the moment)
* easy and tracked quests (Quest Journal + Task system, what you are trying to achieve , and what basic wow emu supports)
* complex and tracked quests (what I am suggesting you enable by opening the Quest Journal implementation)

Not trying to scare you off there, but the task you have started encompasses all four, as adding the third one to the second one is close to enabling the four programming-wise. If your design is good you should get the other two as a nearly-free bonus. If not, well... You will still get the third one ! Just do not be puzzled when you realize the task you embarked on is tough. eh eh. The end-result will be awesome, but the price has to be paid !

At least that is my analysis of what is going on :cool: I wish I could offer my help on this project, but I will be quite busy in the coming month. Still if you would like to submit some interfaces (function or quest:: Perl prototypes...) for review, some of us could find the time to provide some feedback. It is up to you.

Bulle
08-13-2008, 02:56 PM
I think you can forget your worries about scanning 40 mob IDs in a list, as long as everything is already in memory : our regular CPUs do that in no time. Doing a binary search for that small a number is not worth it. From 500 IDs on OK may be... Or may be from 5000... You have to profile that to be sure.

What matters is that you read the ID list only very rarely from the database. DB queries cost. If it is all loaded in one shot at startup, then it is not a concern. Just make sure you do not issue one DB query per activity, as it would be a killer. For example, issue one query to load all activities at once, then one query to load all dependent mob IDs at once, then do any activity-dispatching (list creation and populating) in-memory. If you add proper "ORDER BY" sections to your queries you can even scan your activity list and your mob ID list in parallel, making it a very efficient process.

Derision
08-15-2008, 04:47 PM
I've been busy with work this week and not had as much time as I would have liked to work on this, but today I figured out the Titanium OPcode to flag a task as complete (which is different from 6.2) and make it display the green 'Task Completed' message (I think I have found the struct values to make it display 'Task Failed', but I haven't got around to testing that yet.

http://www.rama.demon.co.uk/taskpics/taskdone.jpg

The more astute amongst you will note that the 'Children of the Fay' task does not finish in Kurn's tower, however I used a bit of 'artistic license' is setting the task goals during development.

There is still quite a bit left to do, but the system is now functional end-to-end for tasks with talk/kill and loot activities. Hopefully I will get a lot more done over the weekend.

trevius
08-16-2008, 04:01 AM
That is so awesome! I am currently working on a custom zone that will use qglobals to track kills similar to tasks. But, it would certainly be cool to use the real task system for it instead!

Derision
08-22-2008, 03:52 PM
I've started to document how the system works on the Wiki, the overview page links to the pages I've written so far:

http://www.eqemulator.net/wiki/wikka.php?wakka=TaskSystemOverview

There are still some Perl interfaces to be written, and a few tweaks to the tables, code cleanup and testing (robustness against bad data in the tables, discovering the limits on the number of active tasks, task selector entries, completed tasks, etc, that I can send to the client without it crashing) before it will be ready for an alpha release.

Andrew80k
08-24-2008, 10:55 PM
Dude! Can't wait... I love seeing stuff like this getting done in the emu.

bleh9
09-14-2008, 04:01 PM
Knowing nothing about tasks, here's some quick thoughts after a cursory look. ;)

1. Why have activity types? Why not push complexity out to scripts?


sub EVENT_ITEM
{
if (quest::hastask(1234)) {
quest::completetask(1234); # completetask() gives any rewards
quest::givetask(12345); # givetask() gives any items needed to complete task
}
}


2. Are tasks accessed so frequently that they need to be in memory? Why not just query the database? Especially if number of tasks increases, this will leave resources to the server (e.g., for disk caching). In any case, please don't put it into shared memory as suggested -- there's too much there as it is.

3. Could the step info be removed and replaced by prerequisites? A single lookup table should suffice:


create table tasks (
task_id int primary key
-- whatever else a task needs
);

create table task_prerequisites (
task_id int references tasks(task_id) on delete cascade,
task_id_prereq int references tasks(task_id) on delete cascade
);


Most tasks will only have one entry in this table (e.g., task 3 requires task 2), but also allows for requiring disparate tasks to be completed before beginning another.

4. Why not create a one-to-many relation for task rewards? Either an aggregate reward table as follows or a reward table for each type (e.g., task_exp_rewards, task_coin_rewards). This can allow for


create table task_rewards (
task_id int references tasks(task_id),
exp int,
coin int,
item_id references items(id) -- think that's the column name; don't have schema handy
);


On a semi-unrelated note, I've seen very little eqemu code that uses JOINs when it comes to SQL, and I don't know that I've ever seen any foreign keys. Is this a MyISAM effect? :D

trevius
09-30-2008, 09:26 AM
Holy cow Derision! Tonight was the first time I got to really check out the new system and try actually creating a task. It is very complex, but also very versatile! I can't believe you did all of the work on this alone lol. Even the wiki pages by themselves must have taken forever! I think this system has alot of potential and I will definitely try to push the limits with making some interesting tasks on my server :D

Huge thanks for putting this whole thing together. I still can't believe how much work this must have been lol. Jeez! You do some amazing work, but damn man, nice job!

Makes me glad the new SVN is setup so I can finally test all of this without having to mess with code updates.

joligario
09-30-2008, 09:28 AM
Wrote my first task today... wow that can get involved!

I have a couple ideas/requests/observations:
1. Under the rewards, if there is a cash reward can you display the amount or at least have it say Cash?
2. The reward text does not show on the task screen unless it is an item.
3. Under description, can you set up a description for the initial task window? For example: [0, This is my general description.][1, This is my description for step 1][2,3, This is my description for shared steps 2 and 3.]. Currently it is blank if step 1 and 2 are shared but if there is only 1 step, the main task window shows the entire text from the first step.
4. In activities, even though activitytype is over-ridden if text3 is populated, setting it to 0 will produce erroneous results in the task window. Currently you have default set to 0.
5. You have done an OUTSTANDING job on this!

I think that's it for now. Learning a lot and noticing that we now have many more possibilities with this system. Thanks!

CRAP, please move this to the discussion thread!!!

ChaosSlayer
09-30-2008, 11:18 AM
I have a question on task system.

When goal is set to loot say 50 Wolf Pelts.
When players loots the pelts- where do they go? To players inventory?
Cuase if system grants you credit when you loot the petl, once you looted it, you can turn around and sell it, but you allready got the credit for looting it.

OR does the system automaticly destroyes all goal looted items after giving player the credit to prevent cheating?

Andrew80k
09-30-2008, 11:31 AM
Most of the time, but not all, the things you are required to loot either have to be turned in to the quest giver, or they are no drop. Depends on the task. It's sort of up to the task creator.

So_1337
09-30-2008, 11:36 AM
I just wanted to stop in and mention that this task system is hot like fire. Excellent work.

ChaosSlayer
09-30-2008, 11:44 AM
Most of the time, but not all, the things you are required to loot either have to be turned in to the quest giver, or they are no drop. Depends on the task. It's sort of up to the task creator.

well how do you turn in 50 quest items to an npc AT ONCE? =)
Or can task system handles this 1 item at a time? and count the turn ins?

Derision
09-30-2008, 03:02 PM
well how do you turn in 50 quest items to an npc AT ONCE? =)
Or can task system handles this 1 item at a time? and count the turn ins?

The task system counts the turn ins, so you can turn in 25 one day, and then 25 the next day to complete the activity, or whatever, until you have turned in a total of 50.

Wrote my first task today... wow that can get involved!

Yeah, it really needs a GUI to assist in writing the tasks.


4. In activities, even though activitytype is over-ridden if text3 is populated, setting it to 0 will produce erroneous results in the task window. Currently you have default set to 0.

The activitytype is not overridden if text3 is populated (i.e. the task system will still handle it if the activity is not under Perl quest control), it is just not displayed as 'Deliver To', 'Kill', etc. You're right though, the default activitytype of 0 is invalid. I've just comitted a change to the SVN to send activities that have an activitytype of 0 as a type 9 to the client, which should fix that problem. I'll look into the other issues you raised.



1. Under the rewards, if there is a cash reward can you display the amount or at least have it say Cash?
2. The reward text does not show on the task screen unless it is an item.


There is a flag in the packet struct which makes the client display 'You gain experience!' if it is set. I am not aware of a flag that will make it display details of a cash reward, however:

In Rev24, I fixed it so the Reward text field will be displayed even if RewardID==0, so if you want a task to have a cash-only reward, set RewardID to 0 and put the details of the cash reward in the Reward field. If you want to give an item and cash and want the player to know they will get both, then the only way currently is to put the ItemID in the RewardID field, and then put eg. 'Item x and 20 plat' in the Reward text field.

trevius
09-30-2008, 05:16 PM
Yeah, it really needs a GUI to assist in writing the tasks.

LOL, I would love to see what GeorgeS could do as a tool for this. But it sounds like a tool would be as hard to make as the system itself was. :P

joligario
10-01-2008, 11:52 PM
Next suggestion:

Alter the task table to have minlevel and maxlevel fields
Create a bool function for CheckTaskLevel()
Create perl quest function quest::istaskappropriate(taskid)

With those, we could let the system do the level checks for us. Not really a big deal, but just might be handy.

joligario
10-02-2008, 01:31 AM
Odd text display. Here is what I am talking about. Please look at this task with your previous and new revisions. You'll notice the text gets cut short also.

SQL Code:
INSERT INTO tasks VALUES(13, 0, 'They\'re a Bit Short','[1, They might as well call you a scout, because you\'ll be going out and doing some scouting on some very high-profile sites. These sites are rumored to be burial grounds for priests of an ancient civilization, but there is not much information on them than that. Enough delay, get going and explore the single dwarven hut along the path in the north.][2, If your findings are correct, there\'s nothing around there that even remotely suggests an ancient burial ground. It\'s unfortunate, but there\'s one more spot you need to check before we give up all hope. Go ahead and explore the large rock tower on goblin isle. Be careful, if there is a burial ground, there\'s no telling what kind of creatures lurk nearby.][3, It\'s unfortunate that you weren\'t able to find any remnants at all. Perhaps there will be more to find next time. In the meantime, you need to report your findings, so speak with Tarerd Gahar. That is all.]','Money and Experience', 0, 1433, 2000, 0, 68, 1);

INSERT INTO activities VALUES (13, 0, 0, 5, 'the dwarven hut', '', '', 1, 0, 1, 0, 68, 0);
INSERT INTO activities VALUES (13, 1, 1, 5, 'the large rock tower', '', '', 1, 0, 1, 0, 69, 0);
INSERT INTO activities VALUES (13, 2, 2, 4, '', '', 'Speak with Tarerd Gahar', 0, 2, 1, 0, 202, 0);

INSERT INTO proximities VALUES (68, 1, 390, 410, 2060, 2080, -10, 10);
INSERT INTO proximities VALUES (69, 1, -8515, -8455, -1260, -1200, 20, 70);

butcher\Gibi_Bilgum.pl:
#BeginFile: butcher\Gibi_Bilgum.pl (68090)
#Quest file for Butcherblock Mountains - Gibi Bilgum: They're a Bit Short

sub EVENT_SAY {
if($text=~/hail/i) {
quest::say("Get a load of my sister over yonder. She doesn't know when to give up the swashbuckling. Idiocy is more like it. She's not the only one around here with some [tasks] that need... well, tasking. You might say I'm a taskmaster, only without the whip. I'm not sure how to even use a whip though, so maybe it's for the best.");
}
if($text=~/tasks/i) {
if($ulevel >= 12) {
if(quest::istaskactive(13)) {
quest::say("They're a Bit Short is already in progress.");
}
else {
quest::taskselector(13); #Task: They're a Bit Short
}
}
else {
quest::say("I don't have any tasks suitable to one of your experience.");
}
}
}

sub EVENT_ITEM {
quest::say("I have no use for this, $name.");
plugin::return_items(\%itemcount);
}

#EndFile: butcher\Gibi_Bilgum.pl (68090)

poknowledge\#Tarerd_Gahar.pl:
#Tarerd_Gahar.pl
#The Magic Pool

sub EVENT_SAY {
if($text=~/hail/i) {
if(quest::istaskactivityactive(13,2)) {
quest::say("Thanks for contacting me, $name. Your information on this matter has been most useful.");
$client->Message(7,"The ideal of burial grounds nearby is one that can not be easily overlooked. That's exactly why you were sent to check these areas out. Sadly none of them turned out to be the rumored burial grounds, but there's plenty more land to cover, so you maybe called upon again. You'll be recieving some payment, mostly for your time investment, but partially for the danger involved. Good job.");
quest::updatetaskactivity(13,2);
}
else {
quest::say("I'm sorry, I have neither the time nor the patience to chat right now.");
}
}
if($text=~/pool/i) {
quest::say("Oh Tatlan and Wicas sent you did they? I'll tell you what I told them, nothing is free. If you want to know about the pools then I need something [from you] first.");
}
if($text=~/from me/i) {
quest::say("I'm sure it'll be easy for an adventurer as you. I am working on a potion, and I cannot currently travel to gather my last component. If you could bring me the blood of a Sarnak I'd be willing to share what I know.");
}
}

sub EVENT_ITEM {
if(plugin::check_handin(\%itemcount, 22519 => 1)) { #Sarnak Blood
quest::say("Ahh this is exactly what I was looking for. All the information I've gathered from these pools has come from Myrist. Thiran will give you the book I used as a reference. Give him this note so he knows I sent you.");
quest::summonitem(15958); #Note From Tarerd
}
else {
quest::say("I don't need this."); #text made up
plugin::return_items(\%itemcount);
}
}

#END of FILE Zone:poknowledge ID:202060 -- Tarerd_Gahar

Derision
10-02-2008, 12:54 PM
3. Under description, can you set up a description for the initial task window? For example: [0, This is my general description.][1, This is my description for step 1][2,3, This is my description for shared steps 2 and 3.]. Currently it is blank if step 1 and 2 are shared but if there is only 1 step, the main task window shows the entire text from the first step.


The way it works is that the entire description is sent to the client and it is the client which decides which portion to display based on which activity you are on. Are you saying it is not working like live ?

I think it maybe be possible to have an extra field in the task table for a description which is only displayed in the task selector window. If this new field was null, then it could just behave as at present.


Alter the task table to have minlevel and maxlevel fields
Create a bool function for CheckTaskLevel()
Create perl quest function quest::istaskappropriate(taskid)


This would be simple to do. Could let them default to 0 meaning no level restriction. Anyone else have any input on this feature (and the extra field for a description specific to the task selector window) ?


Odd text display. Here is what I am talking about. Please look at this task with your previous and new revisions. You'll notice the text gets cut short also.


I just ran through this task and can't see what you are referring to. Which text gets cut short ?

joligario
10-02-2008, 01:48 PM
Old method (before you stated rev24 was made):
http://i409.photobucket.com/albums/pp171/joligario/eq/EQ000011.jpghttp://i409.photobucket.com/albums/pp171/joligario/eq/EQ000012.jpg
http://i409.photobucket.com/albums/pp171/joligario/eq/EQ000013.jpghttp://i409.photobucket.com/albums/pp171/joligario/eq/EQ000014.jpg

As you can see, the reward "Money and Experience" does not show up under rewards or on the main task screen. The entire 1st step is shown instead.

joligario
10-02-2008, 01:49 PM
New code (using cavedude's PEQ after you said rev24 was made):
http://i409.photobucket.com/albums/pp171/joligario/eq/EQ000007.jpghttp://i409.photobucket.com/albums/pp171/joligario/eq/EQ000008.jpg
http://i409.photobucket.com/albums/pp171/joligario/eq/EQ000009.jpghttp://i409.photobucket.com/albums/pp171/joligario/eq/EQ000010.jpg

The entire first step is shown again, however it is truncated. The following steps have no text any more. Money and Experience now shows up as a reward but not on the main task window.

Derision
10-02-2008, 02:23 PM
Putting the non-display of the reward on the task selection window aside for now, I don't see the other problems you are seeing:

http://www.rama.demon.co.uk/abs-task1.jpg

http://www.rama.demon.co.uk/abs-task2.jpg

http://www.rama.demon.co.uk/abs-task3.jpg

I think I am running Rev29, but I have made no changes to the task code since Rev24. This is on Linux. I'll try a Windows build on the off chance there is some incompatibilty that has crept in. Guess I should also test with your task as the only active one, as that is a difference between your test and mine.

janusd
10-02-2008, 05:23 PM
Adding the level check would be a big help as there were some Live quests that had level requirements before the quest giver would hand out those quests. You can see in the quest list for PoK in Alla http://everquest.allakhazam.com/db/qsearch.html?zone=158 that soem quests have a level minimum before the giver would hand it out. Or like this quest http://everquest.allakhazam.com/db/quest.html?quest=3157 I remember from Live. I know when I was piddling around years ago after they added these armor quests, I started a noob and ran through Gloomingdeep. Once I left, I went to the armor guys. They only give quests in order, but I had to level to the appropriate level before later quests would be given.

Derision
10-03-2008, 05:57 AM
The entire first step is shown again, however it is truncated. The following steps have no text any more. Money and Experience now shows up as a reward but not on the main task window.

What client are you using? By the look of it, it is the 6.2 client, however the order of the fields in the Quest Journal (Objective/Status/Zone) is different to how my 6.2 client displays it (Zone/Objective/Status).

joligario
10-03-2008, 06:08 AM
Yes, I see that... I am using Titanium.

Derision
10-03-2008, 06:14 AM
Yes, I see that... I am using Titanium.

But that isn't the Titanium UI. Is it a custom one, or did you copy the 6.2 UI into your Titanium directory ?

Edit: I did a /loadskin default_old and still can't reproduce this :(

joligario
10-03-2008, 01:14 PM
I installed Titanium and did loadskin default old. Other than that I haven't changed it...

Derision
10-03-2008, 01:47 PM
I installed Titanium and did loadskin default old. Other than that I haven't changed it...

This is on TGC ? I don't have a character high enough level to get the task there, unless Cavedude wants to level up character Derisiondwarf, account Derision to level 12 so I can go and test it on there :) . Assuming it's not a client issue, I can put some additional debug commands in to try and isolate the cause.

Derision
10-03-2008, 01:57 PM
Cavedude put it to me that the 'Stepped' column in the Tasks table is redundant. The reason it is there is to allow a sequential task to be created (where one activity must be completed before the next is unlocked) without the need to fill in the step field in the activity table.

I am proposing a change to do away with the 'Stepped' column:


Index: zone/tasks.cpp
================================================== =================
--- zone/tasks.cpp (revision 34)
+++ zone/tasks.cpp (working copy)
@@ -204,7 +204,7 @@
Tasks[TaskID]->RewardMethod = (TaskMethodType)atoi(row[8]);
Tasks[TaskID]->StartZone = atoi(row[9]);
Tasks[TaskID]->ActivityCount = 0;
- Tasks[TaskID]->SequenceMode = (SequenceType)atoi(row[10]);
+ Tasks[TaskID]->SequenceMode = ActivitiesSequential;
Tasks[TaskID]->LastStep = 0;

_log(TASKS__GLOBALLOAD,"TaskID: %5i, Duration: %8i, StartZone: %3i Reward: %s",
@@ -246,6 +246,10 @@
continue;
}
Tasks[TaskID]->Activity[Tasks[TaskID]->ActivityCount].StepNumber = Step;
+
+ if(Step != 0)
+ Tasks[TaskID]->SequenceMode = ActivitiesStepped;
+
if(Step >Tasks[TaskID]->LastStep) Tasks[TaskID]->LastStep = Step;

// Task Activities MUST be numbered sequentially from 0. If not, log an error


Required SQL:


ALTER TABLE `tasks` DROP `stepped` ;


The way this will work is if the step column for each activity is zero, then the task will be sequential (one activity must be completed before the next is unlocked), i.e. it will behave as if the stepped column in the task table was set to 0.

If there is a non-zero step number for any activity belonging to this task, then it will behave as if the stepped column was set to 1 (i.e. multiple activities can be being worked on at once).

I've tested this, just didn't want to commit it without posting about it first.

cavedude
10-03-2008, 02:38 PM
I say commit it, the task system is your baby, nobody knows it better than you!

Derision
10-03-2008, 03:37 PM
This is on TGC ? I don't have a character high enough level to get the task there, unless Cavedude wants to level up character Derisiondwarf, account Derision to level 12 so I can go and test it on there :) . Assuming it's not a client issue, I can put some additional debug commands in to try and isolate the cause.

I have tried this on TGC now (thanks Cavedude) and am seeing the same thing Joligario is seeing with truncated text, so it is definitely not client related. I'll do some more investigation.

Derision
10-03-2008, 04:18 PM
I say commit it, the task system is your baby, nobody knows it better than you!

I've committed this, along with a couple of changes to help try to diagnose the problem reported by Joligario (I changed #task show to output the Task Description, and also lowererd the required status to use the #task command (down to 150 from 250), since I currently couldn't use it on TGC :) )

Derision
10-04-2008, 05:12 AM
Next suggestion:

Alter the task table to have minlevel and maxlevel fields
Create a bool function for CheckTaskLevel()
Create perl quest function quest::istaskappropriate(taskid)

With those, we could let the system do the level checks for us. Not really a big deal, but just might be handy.

I've just committed this. There are new minlevel and maxlevel columns in the task table. If either is zero, it is ignored, so you can have no level restriction, only a minimum level, or only a maximum level, or both.

The level restrictions are enforced in the TaskSelector (a Task won't be sent if it doesn't meet the restrictions).

To augment this, I have slightly altered the way Task Sets work. Previously you had to enable/disable tasks in a set on a per player basis.

Now, if you put a TaskID of zero in a Task Set (which is an invalid TaskID), all the tasks in that set will automatically be available for a player, subject to a level restrictions.

This means you can create a task set for an NPC with a bunch of tasks with different level ranges and just call quest::tasksetselector(set number), and let the task system decide which tasks to offer the client based on the level restrictions.

I have also added quest::istaskappropriate(taskid) if you want to have an NPC tailor what it says to a player based on that.

joligario
10-05-2008, 06:05 AM
Just checking what new table is going to look like. Am I correct in assuming the following alter?

ALTER TABLE tasks ADD (minlevel int(3) not null default 0, maxlevel int(3) not null default 0);

Derision
10-05-2008, 06:16 AM
I made them unsigned TINYINT on the assumption that level will never go past 255.

Required SQL:
ALTER TABLE `tasks` ADD `minlevel` TINYINT UNSIGNED NOT NULL DEFAULT '0',
ADD `maxlevel` TINYINT UNSIGNED NOT NULL DEFAULT '0';

Derision
10-05-2008, 03:33 PM
I should have also mentioned that the Task Selector now checks to see if the player has any of the tasks it is being asked to offer already active and won't display them. If none of the tasks the Selector is asked to offer meet the required level range, or the client already has all those that do as active tasks, then the Selector window won't display.

This means that you don't need to check for tasks the client already has in your Perl quest, unless you want the NPC to say something in those circumstances.

ChaosSlayer
10-08-2008, 12:46 AM
question: does reward has to be a specific item/items OR can system be set up to choose and give a random item from a list?

also: can system handle an ongoing bounty? Like Gnoll Fang quest - which tecnicly NEVEr ends - you keep bringing in gnol fangs- you keep geting reward- there is no set/max number of fang to bring

trevius
10-08-2008, 01:06 AM
I imagine you could set that part up with a hash in a quest for when the task is completed. I wouldn't mind if there was a way to set rewards based on class, but I am pretty sure that can all be done with quests as well. I am going to make one really soon and will report if there are any issues. But, the system is already pretty complicated as it is lol. No reason to complicate it any further if the rest can be done with quests.

ChaosSlayer
10-08-2008, 01:22 AM
well I am not complaning- I am simply poundering if it worth the effort for me to move from standart perl quests to tasks =)

At the end the only thing you are getting are:
-progress tracking window
-ability to track mobs killed count
-ability to automaticly turn in LARGE number of quest items over any give time frame (otherwise you can only give NPC 4 items at a time OT set up a global variable to count your turn ins)

prety much everything else I am allready doing with standart quests.

Yeah the friendly user interface is nice, specialy for players - but CODING IT into DB going to be a pain for ME =)

KLS
10-08-2008, 06:25 AM
It'll prolly be considerably faster to make a task than a quest after people develop decent tools to help it along. It's a little imposing when you have to do all the SQL yourself I noticed. I started to work on a tool incidentally, but who knows if I'll ever get around to finishing it.

trevius
10-08-2008, 06:52 AM
Ya, I do think a tool would make a HUGE difference. But I also think that practice would make tasks go quicker as well. I know I didn't write quests as quickly and easily when I first started as I do now.

And yes, everything that can be done with the task system can be done with quests. But, having the option for variety is great! And being able to easily track progress of multi-stepped quests is awesome! I already made a task for my starter zone for new players. For people not used to the EQ Quest system, I think tasks could help them get used to it quicker.

steve
10-08-2008, 10:47 AM
Does the task system currently allow you to choose between multiple rewards? On Live, I've encountered a task that had as many as 3 choices. Each showed as their own tab in the reward window, and each tab listed a combination of these: Faction, Experience, Quest Item Reward, and plat. You then were able to pick which option suited you at the moment.

Derision
10-08-2008, 11:06 AM
Does the task system currently allow you to choose between multiple rewards? On Live, I've encountered a task that had as many as 3 choices. Each showed as their own tab in the reward window, and each tab listed a combination of these: Faction, Experience, Quest Item Reward, and plat. You then were able to pick which option suited you at the moment.

No. Do you remember the name of a task with multiple rewards ? I've not seen a way of doing that. I suppose it's possibly an enhancement that was made to the Client after Titanium, or just part of the packet structure I didn't figure out.

steve
10-08-2008, 11:44 AM
Hmm, good point. Didn't think about that. I just started playing EQ again a month ago, so I missed out on the initial implementation of the task system. I'm not sure if other tasks had multiple reward choices before SoF launched.

The tasks I was referring to are the 'farm tasks' in Dragonscale Hills.
http://everquest.allakhazam.com/db/quest.html?quest=4393
http://everquest.allakhazam.com/db/quest.html?quest=4394
http://everquest.allakhazam.com/db/quest.html?quest=4395

nicholasjohn
10-08-2008, 12:05 PM
does anyone have a mirror for these links ?

SQL (with sample tasks): http://www.rama.demon.co.uk/tasks/tasktables.sql

Perl quests to support the sample tasks http://www.rama.demon.co.uk/tasks/tasksquests.rar

I keep getting errors when trying to download.
Thanks

ChaosSlayer
10-08-2008, 12:07 PM
Does the task system currently allow you to choose between multiple rewards? On Live, I've encountered a task that had as many as 3 choices. Each showed as their own tab in the reward window, and each tab listed a combination of these: Faction, Experience, Quest Item Reward, and plat. You then were able to pick which option suited you at the moment.

I think that one was added to LIVE after Titanium edition. The T client may not have that part coded in where special window opens up and you select the reward

steve
10-08-2008, 12:44 PM
I think that one was added to LIVE after Titanium edition. The T client may not have that part coded in where special window opens up and you select the reward
Yeah, I'm guessing you're correct. I don't see the EQUI_RewardSelectionWnd.xml file in the Titanium directory, which is the window for the task system.

Andrew80k
10-08-2008, 01:28 PM
Yeah, I'm guessing you're correct. I don't see the EQUI_RewardSelectionWnd.xml file in the Titanium directory, which is the window for the task system.
The task system was enhanced a bit for Serpent's Spine I think. I remember them doing some stuff for the hot zones and things to get better gear than what dropped in the old zones. They used that interface to let you pick. Definitely post titanium.

Derision
10-08-2008, 02:13 PM
does anyone have a mirror for these links ?

SQL (with sample tasks): http://www.rama.demon.co.uk/tasks/tasktables.sql

Perl quests to support the sample tasks http://www.rama.demon.co.uk/tasks/tasksquests.rar

I keep getting errors when trying to download.
Thanks

It appears to be working again now.

MNWatchdog
10-09-2008, 04:59 AM
What people can do to impliment item select is make a quest NPC that accepts the rewards and gives them a replacement item in a round robin manner. Make the items BoE and the quest NPC not accept the item once its NoDrop/not BoE.

For example, the inital reward is a Dagger, turn it in, you get a club, turn the club in, you get a sword, turn in the sword you get a spear, turn in the spear and you get the original dagger. Thats round robin.

joligario
10-23-2008, 03:05 PM
After Rock posted a task on PEQ, I noticed that Task Activity Type 2 (Kill) does not register when killing objects. In this case, it was the 'a vermin nest' (189443). Is there a method to cover this? Right now he has created a .pl script to update the task, but that seems excessive if we can have the task system take care of it the same as mobs.

Derision
10-23-2008, 03:26 PM
I can see where the problem is. The code to update tasks on kill doesn't execute if the NPC class is 'LDON_TREASURE' (62) which the vermin nests are.

I'll fix and test it tomorrow.

Rocker8956
10-23-2008, 04:43 PM
Hmm, I just figured this was an intended feature :) since killing objects is a little strange.

Congdar
10-27-2008, 12:25 PM
i get these on server/zone startup. I'm no longer getting the sql errors for 'minlevel' so I think I have all the sql correct.
these are in the error log files like eqemu_error_zone_0196.log


[10.27. - 08:13:03] [TASKS]Activity for non-existent task (1, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (1, 1) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (1, 2) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (1, 3) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (1, 4) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (1, 5) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (1, 6) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (1, 7) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (1, 8) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (2, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (2, 1) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (2, 2) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (3, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (3, 1) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (3, 2) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (4, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (4, 1) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (5, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (5, 1) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (5, 2) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (5, 3) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (5, 4) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (6, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (7, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (7, 1) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (7, 2) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (7, 3) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (8, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (8, 1) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (9, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (9, 1) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (10, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (10, 1) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (11, 0) while loading activities from database
[10.27. - 08:13:03] [TASKS]Activity for non-existent task (11, 1) while loading activities from database

Derision
10-27-2008, 12:37 PM
It looks like it could not read from the tasks table. Is there not an error earlier on, like

[TASKS]Error in TaskManager::LoadTasks: <MySQL Error>


If you are running Rev133 or later, did you add the repeatable column ?


ALTER TABLE `tasks` ADD `repeatable` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1';

Congdar
10-27-2008, 02:31 PM
i didn't get that error unless it is in a different file, and my tasks table does have the repeatable column in it. The output I listed above was the entire log file except the first line: Starting Log: logs/eqemu_error_zone_3344.log

joligario
10-27-2008, 03:15 PM
Run this:

SELECT id FROM tasks;

Congdar
10-27-2008, 03:35 PM
returns 1 row id=12 Extraordinary Rodents

Derision
10-27-2008, 03:50 PM
That's your problem then, you have entries in your activities table for tasks 1 through 11, but those tasks don't have entries in the task table.

Congdar
10-27-2008, 03:57 PM
so, how'd they get there and how do I delete them if that's the fix?
all I did was source in the sql from svn, i didn't actually try and use the task system.

Derision
10-27-2008, 04:09 PM
delete from activities where taskid < 12;


1_task_system.sql in SVN has the activities for my example tasks, but not the task rows for them, so anyone who has sourced this should execute this delete.

Congdar
10-27-2008, 04:25 PM
should I clear out tasksets as well? is there a "reset" of this task system?

Why would I delete them as you suggest above? They were part of the svn sql additions. Were they changed/corrected at some point maybe after I had already done the imports? I'd like to have it set up the way you intended but it seems to not be working correctly for me.

the rules relating to the task system... I don't have any in my rules table as I'm taking the default from the code settings. Does there need to be a non-default change in the database rule_values to have them work correctly?

joligario
10-27-2008, 04:42 PM
You can just add the sample tasks rather than delete them. Makes your DB more complete.

Derision
10-27-2008, 04:48 PM
My sample tasks 1 to 11, along with accompanying Perl quests and notes on the sample tasks are linked in this thread:

http://eqemulator.net/forums/showthread.php?t=26302

If you source the SQL from that thread, it will drop and recreate all the task related tables, and you will then need to execute the following SQL, as that thread predates these changes:


ALTER TABLE `tasks` DROP `stepped` ;
ALTER TABLE `tasks` ADD `minlevel` TINYINT UNSIGNED NOT NULL DEFAULT '0',
ADD `maxlevel` TINYINT UNSIGNED NOT NULL DEFAULT '0';
ALTER TABLE `tasks` ADD `repeatable` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1';



To 'reset' the task system, if you should ever want to:


truncate tasks;
truncate activities;
truncate character_tasks;
truncate character_activities;
truncate character_enabledtasks;
truncate completed_tasks;
truncate goallists;
truncate proximities;
truncate tasksets;


The default rule values are fine, no need to change them in the database.

Congdar
10-29-2008, 09:53 AM
thank you, all the logging errors are gone now.

Grundy
05-12-2010, 10:19 PM
If the activity is to collect a number of items and it hooks into Corpse::LootItem, does that mean there's no activity for picking up ground spawn items?

trevius
05-12-2010, 10:49 PM
Since almost every aspect of the task system is exported to perl (huge thanks to Derision for being awesome like that), the possibilities with tasks are nearly limitless. You can simple add the pickup part into your player.pl and have it update your task when they pick the item up. I have it working in my custom Crescent Reach zone and it works great.

Grundy
05-12-2010, 11:34 PM
Oh, cool. I didn't even know about that player.pl thing. I thought every quest was in a file with the NPC's name so I thought there were no quest functions for picking up items. I haven't done much quest editing because i don't know perl and i guess i'm too pampered at work using vb.net 2008 the IDE is so friendly and has intellisense and autocomplete i hate coding anything outside of visual studio now.