Topic readme.md
Readme, explanation & example
Introduction
This page/document should hopefully help explain how the host handles various bits and pieces relevant to quests. It includes explanations and a fully working Gerenium Quest example which will be live (or already is) on the test server and subsequently main server. It will be updated as the live script is updated to give an idea of how to make a quest.
NOTE: In the code blocks containing definitions, x4 spaces represent a tab. This is an issue with LDoc replacing tab characters with a fixed number of spaces. It is stressed that for any definitions, tabs rather than spaces are used.
Tools
Lua Documentation
Item Generator
Files
A quest comprises of two files.
- A zone/map file
- A lua script
Zone/Map File explanation
A zone/map file (they're the same thing, the terms are interchangable) defines a map on the server, it represents one quadrant on the map either in space or the underspace. Cythris, TYV, Starbase etc are each defined in separate zone files. In a zone file, the majority of content for a zone is defined - items, mobs, tiles, fields.
Valid definitions
Zone files can have a number of definitions for different objects ingame. Allowed definitions include:
- #DEF_ITEM
- #DEF_QUEST
- #DEF_COMBINE
- #DEF_MOBILE
The format for these is as followed with x4 spaces replaced with \t (tab). The initial field is case-insensitive.
#DEF_COMBINE FINAL_ITEM_ID SKILL_REQUIRED LEVEL ITEM_REQUIRED_ID ITEM_REQUIRED_ID ITEM_REQUIRED_ID ITEM_REQUIRED_ID ITEM_REQUIRED_ID ITEM_REQUIRED_ID ITEM_REQUIRED_ID ITEM_REQUIRED_ID ITEM_REQUIRED_ID #DEF_QUEST STARTMOB FILENAME LEVEL
Both #DEF_ITEM, #DEF_COMBINE, please use the web tools provided to generate definitions for these.
IDs
The host uses IDs to identify everything however there are a few "special" ranges. Any ID below 10000 is absolute - it will not be changed, it will stick with what it's been given. These are reserved for very common or global items such as ores - Silver, Gold etc. Any ID above 10000 inside a zone file will be modified to a calculated offset for that zone. This means that it is possible to have relative IDs in zonefiles eliminating the need to have to keep track of what item numbers do what. For example, we may have a zonefile Cythris.txt:
#DEF_ITEM 10001 WEAP TestWeapon 5 7 0 2 1 0 20 0 2 4 0 30 5000
It is then possible in the Lua file to find TestWeapon by using the item(id) function which handles fixing up offsets for you, e.g:
local testweaponid = item(1)
For all quests it is necessary to use IDs beginning from 10000.
Lua file
The lua file is the quest script and has to implement at a minimum, 3 functions.
Each quest script must implement the following functions.
function init() end function update() end
Without these, the script will fail to load. In addition to these, a quest MUST call
set_start()
and
set_finish()
at some point. Whether based on something in the update() function or it calls it in a function of the callback it doesn't matter.
add_talk_to_mob_callback(startmob,"start","Thankyou %P for starting the quest.",0,"start") function start() set_start() end
The server will run the init function once when the script is definition is read at startup. It can be used for things such as adding chat to mob and creating the start callback as seen in the Gerenium example further down.
Limitations/Workflow
Currently quests are player oriented although global and group accomodations are planned for quests such as planet mining or Defense Nexus.
The general workflow is
- Player talks to mob
- Player activates quest
- Player does some action or collection of actions
- Player returns to mob
- Player finishes quest, gets experience, money or items
OR - Player aborts the quest, gets nothing
Gerenium Quest Example
StarbaseL1.txt
#DEF_ZONETITLE Starbase Level 1 #DEF_ITEM 10001 QUEST Gerenium Ore 26 24 1 0 0 0 0 0 0 0 0 0 1 #DEF_ITEM 10002 QUEST Gerenium Container 1 26 1 0 0 0 0 0 0 0 0 0 1 #DEF_ITEM 10003 QUEST Contained Gerenium 1 10 1 0 0 0 0 0 0 0 0 0 1 #Def_Item 10004 SYSTEM Gerenium Plate 33 26 0 3 4 10 3 0 0 0 0 1 250 #Def_Item 10005 SYSTEM Gerenium Plate 34 26 0 3 4 10 3 0 0 0 0 2 250 #Def_Item 10006 SYSTEM Gerenium Plate 35 26 0 3 3 10 3 0 0 0 0 3 250 #Def_Item 10007 SYSTEM Gerenium Plate 36 26 0 3 3 10 3 0 0 0 0 4 250 #DEF_COMBINE 10003 0 0 10001 10001 10001 10001 10001 10001 10002 0 0 0 #Def_Quest gerenium.lua 10002 Gerenium Quest
Gerenium.lua
local fes_rebels = 0 function init(startmob) -- Set up all the chat messages for Fes Rebels add_talk_to_mob(startmob,"[CLICK]","Hello there, %P, I am the famous and immobile %N. Do you need a [job]?") add_talk_to_mob(startmob,"job","Great, I think I'm going to be able to help you. A slight distance away in the west lay the Scythe fleet.") add_talk_to_mob(startmob,"job","They hold a rare ore called [gerenium]") add_talk_to_mob(startmob,"gerenium","Yes, by combining SIX (6) gerenium in a container, it will produce a strong compound used for armor.") add_talk_to_mob(startmob,"gerenium","Would you like to [start] this quest?") add_talk_to_mob_callback(startmob,"start","Good. I can provide you with a [container] if needs be. I look forward to seeing you later.", 0, "start") add_talk_to_mob_callback(startmob,"container","Here is one container. Fabricate it (/fabricate) it with 6 Gerenium Ore to create Contained Gerenium.",1 , "giveContainer") add_talk_to_mob(startmob,"container","Once you have Contained Gerenium, come back and ask me for a [Fore],[Aft],[Port] or [sb] plate.",1) --allow the player to manually try to finish add_talk_to_mob_callback(startmob,"finish","I hope we meet again.",1,"finish") add_talk_to_mob_callback(startmob,"fore","Let me check if you have the ore.",1,"handleFore") add_talk_to_mob_callback(startmob,"port","Let me check if you have the ore.",1,"handlePort") add_talk_to_mob_callback(startmob,"aft","Let me check if you have the ore.",1,"handleAft") add_talk_to_mob_callback(startmob,"sb","Let me check if you have the ore.",1,"handleSb") -- Save his ID to a global variable so we don't have to run a search for him again fes_rebels = startmob end function start() --This activates the quest on the player set_start() end function handleFore() --Call handleplate with ID of a Fore gerenium plate and the prefix handlePlate(item(4), "fore") end function handleAft() --Call handleplate with ID of an Aft gerenium plate and the prefix handlePlate(item(5), "aft") end function handlePort() --Call handleplate with ID of a Port gerenium plate and the prefix handlePlate(item(6), "port") end function handleSb() --Call handleplate with ID of a Starboard gerenium plate and the prefix handlePlate(item(7), "sb") end --Handle plate function, will check for an ID and give an item if the player has contained gerenium function handlePlate(id, side) --check if they've got a contained gerenium if(check_item(item(3)) == 1) then create_chat_from_mob(fes_rebels, "Here you go sir.") --remove a contained gerenium remove_item(item(3)) --give the item an id give_item(id) if(load_param("geren_"..side) ~= "y") then save_param("geren_"..side, "y") give_xp() end else --tell the user the problem create_chat_from_mob(fes_rebels, "Unfortunately I cannot supply a ".. side .. " plate without a Contained Gerenium.") end end function giveContainer() --Give the item a container give_item(item(2)) end function update() --Get the id of the mob the player killed last local last_killed_id = get_player_last_killed() --stop it executing here to prevent unnecessary checks if(last_killed_id == 0) then return end --Get the name of the mob local last_killed_name = find_mob_name_by_id(last_killed_id) --Make sure the mob exists if(string.len(last_killed_name) > 0) then if(string.match(last_killed_name,"Scythe") ~= nil) then --50% chance to give the player a gerenium ore if(math.random(0,99) < 50) then give_item(item(1)) write_text_to_screen("You found a Gerenium Ore!",29) end end end --automatically check if the player has finished checkIfFinished() end --Unset the parameters for each plate from the player. --This allows the quest to be done more than once, but experience --to only be given for one cycle local function unsetPlateParameters() unset_param("geren_fore") unset_param("geren_aft") unset_param("geren_port") unset_param("geren_sb") end --function to check if the player has satisfied all of the requirements local function checkIfFinished() local fore = false local aft = false local port = false local sb = false --Check which of the plates the player has created if(load_param("geren_fore") == "y") then fore = true end if(load_param("geren_aft") == "y") then aft = true end if(load_param("geren_port") == "y") then port = true end if(load_param("geren_sb") == "y") then sb = true end --if they have made a complete set if(fore == true and aft == true and port == true and sb == true) then --check if the player has already finished the quest before local alreadyFinished = load_param("geren_finish") --if not, give them some experience and set that they have as a parameter if(alreadyFinished ~= "y") then give_xp() save_param("geren_finish","y") end --create a message from Fes create_chat_from_mob(fes_rebels, "Well done for completing the quest. Good luck in your future endeavors.") --reset the status of the plates so the quest can be done again unsetAllPlateParameters() --deactivate the quest from the player set_finish() end end function finish() --set the quest finished on the player, this means update() no longer runs for this player checkIfFinished() end