[Home] [Downloads] [Search] [Help/forum]


Register forum user name Search FAQ

Gammon Forum

[Folder]  Entire forum
-> [Folder]  SMAUG
. -> [Folder]  Lua
. . -> [Subject]  Lua task system - tasks file definition

Lua task system - tasks file definition

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page


Posted by Nick Gammon   Australia  (23,016 posts)  [Biography] bio   Forum Administrator
Date Tue 10 Jul 2007 12:40 AM (UTC)
Message
This post describes how to set up tasks in the Lua-based task system.

Tasks are stored in a file tasklist.lua.

Inside that file are the definitions for the all_tasks table. This is a table of all possible tasks (that a player might eventually do, be currently doing, or have done previously).

A minimal definition would be:


all_tasks = {}


That defines no tasks. Now we can add entries for each task, like this:


all_tasks.academy1 = {
  -- task definition here
  }  -- end academy1 task
  
all_tasks.academy2 = {
  -- task definition here
  }  -- end academy2 task


Each task is its own table, with fields as described below. Tasks have an identifying "task id" which is the table key (eg. "academy1"). Tasks IDs should be in lower case as player input is forced to lower case. If you make an upper-case ID it won't be found. I will put commas after each field example, as that is how they would appear in the table definition.


  • name - Summary to show in task list (keep to below about 50 characters) (required). eg.

    
    name = "Find teacher Domick",
    


  • description - Multiple line description of task purpose. eg.

    
    description = [[
    Mistress Tsythia wants you to visit Domick in The Laboratory of Skills 
    and Spells.
    Please give him this note ('&Ygive note domick&W').]],  
    


  • giver - vnum of task giver mob (required). eg.

    
    giver = 10399,    -- vnum of task giver: Mistress Tsythia
    


  • receiver - vnum of task to receive the task hand-in. If omitted, task received by task-giver. eg.

    
    receiver = 10340, -- vnum of task receiver: Domick
    


  • min_level - minimum level you need to be to see this task. If omitted, no minimum level.

    This is intended to stop low-level players being given ridiculously hard quests. eg.

    
    min_level = 1,    -- minimum level to attain task  
    


  • max_level - maximum level you can be to see this task. If omitted, no maximum level.

    This is intended to stop high-level players being given ridiculously easy quests. eg.

    
    max_level = 5,    -- maximum level to attain task
    


  • available - function that returns false if task is not available. If omitted, task is always available. You could test for completion of earlier tasks, player class, etc. eg.

    
    -- is task available? (check prerequisites, class, etc.)
    available = function () 
      return completed_tasks.academy2 ~= nil  -- have to do "academy2" task first
    end,
    


  • accept- function called when task is accepted. If omitted, nothing special is done. Return false if task can not be accepted (might return false if you need to put something in inventory, and it is full). eg.

    
      -- do stuff for accepting (like put things in inventory)
    accept = function ()
      task_item (36)  -- give player a note
    end,  -- end accept
    


  • complete - function called when task is completed (finished / handed in). If omitted, nothing special is done. Return false if task can not be finished (might return false if you need to put something in inventory, and it is full). eg.

    
    -- do stuff for completing (like task rewards)
    complete = function ()
      task_xp (20)
      task_item (10308)  -- a plate of armour
      task_gold (100)
      send ("&WDomick tells you: 'Good work!")      
    end, -- complete function
    


  • abandon - function called when task is abandoned. If omitted, nothing special is done (might remove task items from inventory).

    
    -- do stuff for abandoning (like removing task items - use with caution)
    abandon = function ()
      mud.destroy_item (10308)  -- remove task item
    end,  -- end accept
    
    


  • time_limit - time limit in minutes - task must be completed in that time (real time). If omitted, no time limit. eg.

    
      time_limit = 10,  -- time limit in minutes
    


  • subtasks - table of subtasks which need to be completed - see below. If omitted, there are no subtasks, and task can be handed in immediately. Ssubtasks are keyed by number and are shown in order given.

    Subtasks do not need to be completed in any particular order. If you want to arrange that the player does one thing and then another thing, make different tasks, and make the second task dependent on the first one.

    Many subtasks have a 'count' - this lets you specify that they must "kill 5 mobs" or "obtain 10 items".





Subtasks

Each task consists of zero or more subtasks. Probably 1 to 3 subtasks would be normal for many tasks. When you do "show task" the current stage with each subtask is shown (eg. killed 3/5 mobs, obtained 1/10 items).

If you have no subtasks, then the task can be finished immediately. This would be useful if you are trying to get the player from one place to another. (eg. Mayor of Town A wants you to report to the Mayor of Town B).


  • description - sub task description (keep reasonably short - probably 50 characters max). This should be a short phrase succinctly describing the subtask, without puctuation (eg. "Naga slain", "Bread purchased", "Sword repaired").

    As the player works on the subtask a count is appended (eg. "Naga slain: 3/5").


  • type - type of subtask - this is a string that indicates the events to look for to trigger a "subtask completed" message.


    • killmob - must kill 'count' mobs in vnums table

    • visitroom - must visit one of the rooms in the vnums table

    • bribe - must bribe one of the mobs in the vnums table with 'count' coins

    • give - must give 'count' objects of vnum 'item' to one of the mobs in the vnums table

    • get - must get 'count' objects of vnum 'item' (into inventory)

    • buy - must buy 'count' objects of vnum 'item'

    • wear - must wear 'count' objects of vnum 'item'

    • drop - must drop 'count' objects of vnum 'item'

    • repair - must repair 'count' objects of vnum 'item'

    • use - must use 'count' objects of vnum 'item'

    • possess - must have 'count' objects of vnum 'item' in inventory


  • count - number of items to get/buy/drop etc., count of mobs to kill, size of bribe. If omitted, defaults to 1.

  • vnums - table of vnums of mobs (turned into vnum lookup table)

  • item - vnum of item to get/buy/drop etc. (required, where applicable)

  • complete - function that is called when this subtask is completed. If omitted, nothing special is done. This could be used to spawn additional mobs when a boss is killed, for example.



Difference between 'get' and 'possess'.

Subtask type 'get' counts when you obtain the item, even if you subsequently lose it. If the player drops an item and picks it up again this will count as two "gets".

Subtask type 'possess' counts possession of the item, giving it away before handing in will fail the subtask. "Possess" items are destroyed on task completion. The "possess" subtask type is more useful to make sure a player is obtaining items.

Vnum tables

Subtasks that use the "vnums" table item are designed to allow "fuzzy" tasks. In other words, if you need to "kill 5 naga" then the naga might be "bone naga" or "naga mages". Thus you might put the vnums for both of them in the vnums table.

Example subtasks

The subtask below requires the player to have in their inventory 5 loaves of bread:


subtasks = {  -- table of sub tasks

    {  -- subtask 1
     description = "Bread obtained",
     type = "possess",
     item = 21021,  -- A loaf of bread
     count = 5,
     },  -- end subtask
  
     },   -- end subtasks table


The subtask below requires the player to purchase one piece of meat:


subtasks = {  -- table of sub tasks

    {  -- subtask 1
     description = "Meat purchased",
     type = "buy",
     item = 10317,  -- Dried rabbit meat
     },  -- end subtask
  
     },   -- end subtasks table

   }   -- end of task academy5      



Below are three subtasks, to kill various mobs:


subtasks = {  -- table of sub tasks

     {  -- subtask 1
     description = "Naga slain",
     type = "killmob",
     vnums = { 10302 },   -- The bone naga
     count = 5,
     },  -- end subtask 1
  
    {  -- subtask 2
     description = "Wolf slain",
     type = "killmob",
     vnums = { 10300 },   -- The dread wolf
     count = 10,
     },  -- end subtask 2
 
      {  -- subtask 3
     description = "Carrior crawler slain",
     type = "killmob",
     vnums = { 10303 },   -- A carrion crawler
     count = 8,
     },  -- end subtask 3
  
     },   -- end subtasks table



Example of a complete task




all_tasks.academy4 = {

 -- name of task - shown in task list
  name = "Getting your hands dirty",

  -- description - shown when you do "task show x"
  description = [[
Mistress Tsythia would like you to head for the battlegrounds, and
kill 4 wolves, 3 naga and 2 carrion crawlers.

Your reward for doing this is 1000 gold.

]],

  giver = 10399,    -- vnum of task giver:  Mistress Tsythia
  
  -- receiver = 10399, -- vnum of task receiver: Mistress Tsythia
  
  min_level = 1,    -- minimum level to attain task
  
  max_level = 5,    -- maximum level to attain task
  
  time_limit = nil,  -- time limit in minutes
  
  -- it task available? (check prerequisites, class, etc.)
  available = function () 
   return completed_tasks.academy3 ~= nil
   end,
  
    -- do stuff for accepting (like put things in inventory)
  accept = function ()
    end,  -- end accept
  
  -- do stuff for abandoning (like removing task items)
  abandon = function ()
    end,  -- end accept

  -- do stuff for completing (like task rewards)
  complete = function ()
      task_xp (5000)
      task_gold (1000)
      end, -- complete function
      
 -- table of subtasks 
 -- each subtask is its own table
 -- required fields: description / type
 
 subtasks = {  -- table of sub tasks

     {  -- subtask 1
     description = "Naga slain",
     type = "killmob",
     vnums = { 10302 }, 
     count = 3,
     },  -- end subtask
  
    {  -- subtask 2
     description = "Wolf slain",
     type = "killmob",
     vnums = { 10300 }, 
     count = 4,
     },  -- end subtask
 
      {  -- subtask 3
     description = "Carrior crawler slain",
     type = "killmob",
     vnums = { 10303 }, 
     count = 2,
     },  -- end subtask
  
     },   -- end subtasks table

   }   -- end of task academy4      


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (23,016 posts)  [Biography] bio   Forum Administrator
Date Reply #1 on Tue 10 Jul 2007 12:47 AM (UTC)
Message
Any player can accept any number of tasks simultaneously. There is a limit coded into the task system which you can change to your requirements (eg. 10 tasks at one time).

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (23,016 posts)  [Biography] bio   Forum Administrator
Date Reply #2 on Tue 10 Jul 2007 01:00 AM (UTC)
Message
Warning re exploits

You will need to be careful when making tasks that give players things, upon acceptance (eg. a note to take somewhere).

They could sell the note, abandon the task, reacquire it, and repeat. That way they could quickly make a lot of gold.

Or, if the taskitem was valuable in some way (eg. a sword) then they might give it to another player, abandon the task, reacquire it, and repeat.

I suggest only giving things to players, on task acceptance, that defeat this approach, like this:


  • Make task items untradeable
  • Make task items have zero value, so they can't be sold


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (23,016 posts)  [Biography] bio   Forum Administrator
Date Reply #3 on Tue 10 Jul 2007 01:04 AM (UTC)

Amended on Tue 10 Jul 2007 01:06 AM (UTC) by Nick Gammon

Message
Example player task state file

This is an example of the file that is saved when the player is saved. This is saved in file "../player/k/Kedaeder.lua".


-- Saved at: Tue 10 Jul 2007 09:57:24 EST

-- Extra save file for Kedaeder


--  Current tasks

tasks.current_tasks = {}
  tasks.current_tasks.academy4 = {}
    tasks.current_tasks.academy4.acquired_time = 1184023293
    tasks.current_tasks.academy4.subtasks = {}
      tasks.current_tasks.academy4.subtasks[1] = {}
        tasks.current_tasks.academy4.subtasks[1].count = 1
        tasks.current_tasks.academy4.subtasks[1].done = false
      tasks.current_tasks.academy4.subtasks[2] = {}
        tasks.current_tasks.academy4.subtasks[2].count = 1
        tasks.current_tasks.academy4.subtasks[2].done = false
      tasks.current_tasks.academy4.subtasks[3] = {}
        tasks.current_tasks.academy4.subtasks[3].count = 1
        tasks.current_tasks.academy4.subtasks[3].done = false
  tasks.current_tasks.academy6 = {}
    tasks.current_tasks.academy6.acquired_time = 1184021188
    tasks.current_tasks.academy6.subtasks = {}
      tasks.current_tasks.academy6.subtasks[1] = {}
        tasks.current_tasks.academy6.subtasks[1].done = false

--  Completed tasks

tasks.completed_tasks = {}
  tasks.completed_tasks.academy2 = 1184022341
  tasks.completed_tasks.academy5 = 1184022708
  tasks.completed_tasks.academy3 = 1184023142
  tasks.completed_tasks.academy1 = 1184021762

--  Various other things

tasks.task_flags = {}
  tasks.task_flags.completed_hint = true
  tasks.task_flags.accepted_hint = true
  tasks.task_flags.available_hint = true
  tasks.task_flags.whereis_hint = true
  tasks.task_flags.finished_hint = true


You can see that academy4 and academy6 tasks are still ongoing (they are still in the current_tasks table), and the counts for the various subtasks are in them.

Tasks academy1, academy2, academy3 and academy5 are completed. The number is the completion time.

The task_flags table is used to stop the same hint being shown to the same player repeatedly.

If you need to "uncomplete" a task for a player for some reason, just delete the appropriate line from the completed_tasks table. However you will need to do this when the player is not connected, or the change will be overwritten the next time the player saves.


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Darwin   USA  (125 posts)  [Biography] bio
Date Reply #4 on Tue 24 Jul 2007 10:06 AM (UTC)
Message
In your sample file:
tasks.completed_tasks = {}
  tasks.completed_tasks.academy2 = 1184022341
  tasks.completed_tasks.academy5 = 1184022708
  tasks.completed_tasks.academy3 = 1184023142
  tasks.completed_tasks.academy1 = 1184021762


If you were to set ...
  tasks.completed_tasks.academy2 = nil


Would that give the same effect as deleting that line from the file? As in, would it be possible to set that as nil while the character was still logged in and have it save so they could do that task again?
[Go to top] top

Posted by Nick Gammon   Australia  (23,016 posts)  [Biography] bio   Forum Administrator
Date Reply #5 on Tue 24 Jul 2007 11:11 AM (UTC)
Message
Setting it to nil is the same as deleting the line from the file.

You can't do it while they are logged in as it resaves the file when they log out.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Darwin   USA  (125 posts)  [Biography] bio
Date Reply #6 on Tue 24 Jul 2007 10:07 PM (UTC)
Message
Quote:
You can't do it while they are logged in as it resaves the file when they log out.

Suppose you created a function to set the completed task to nil? I'm not saying set the task to nil in the file but to do it via script function as everything else is done. It would, therefor, be the same as deleting the line from the file?
[Go to top] top

Posted by Nick Gammon   Australia  (23,016 posts)  [Biography] bio   Forum Administrator
Date Reply #7 on Tue 24 Jul 2007 10:45 PM (UTC)

Amended on Tue 24 Jul 2007 10:46 PM (UTC) by Nick Gammon

Message
Yes that would work. It would have to be in the context of the person whose task it is. That is, if you are an admin and want to clear someone else's task, you would need to get their character pointer, not your own. Eg.


 call_lua (target, "clear_task", "task_name");


... where "target" is their character pointer, and you have written a function "clear_task". In that case the function could look something like this:


function clear_task (which)
  tasks.completed_tasks [which] = nil
end -- function clear_task


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Rash   United Kingdom  (56 posts)  [Biography] bio
Date Reply #8 on Sat 30 Jan 2010 12:13 PM (UTC)
Message
Nick Gammon said:

Yes that would work. It would have to be in the context of the person whose task it is. That is, if you are an admin and want to clear someone else's task, you would need to get their character pointer, not your own. Eg.


 call_lua (target, "clear_task", "task_name");


... where "target" is their character pointer, and you have written a function "clear_task". In that case the function could look something like this:


function clear_task (which)
  tasks.completed_tasks [which] = nil
end -- function clear_task



How exactly would you go about getting the characters pointer and assigning to to "target". I'm not sure how this would be done. Still wrapping my head around Lua one bit at a time.
[Go to top] top

Posted by Nick Gammon   Australia  (23,016 posts)  [Biography] bio   Forum Administrator
Date Reply #9 on Sat 30 Jan 2010 07:32 PM (UTC)
Message
It's been a while since I worked on this. The "target" in this case is simply the character pointer in Smaug (This is not Lua code, it is C code).

This is the prototype for call_lua which is the function you mentioned:


void call_lua (CHAR_DATA * ch, const char * fname, const char * argument);


So a command handler (in C) to do that might roughly look like:


void do_clear_task( CHAR_DATA * ch, const char *argument )
{
   char arg1[MAX_INPUT_LENGTH];
   CHAR_DATA *victim;

   if( !ch->desc )
      return;

   argument = one_argument( argument, arg1 );

   if( ( victim = get_char_room( ch, arg1 ) ) == NULL )
     {
      send_to_char( "They're not here.\r\n", ch );
      return;
     }
   else
     {
     call_lua (victim, "clear_task", "task_name");
     }
} 


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


31,012 views.

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at HostDash]