smacky * r3441 /trunk/maps/lua/quest_builder.lua:
* RemoveQuestItems() is called automatically from qb:Finish()
* Add goal and reward parameters to qb:AddQuest(),
These are optional functions which are defined in the talk script.
If specified they are called automarically by qb:RegisterQuest() (goal) and qb:Finish() (reward),
allowing the talk script to cleanly separate 'do' code (creating objects, etc) from 'tell' code (ib, etc).
The first change means qb:RemoveQuestItems() is redundant. Unless someone can think of a reason scripters need to call it/it shouldn't be called automatically, I'll actually remove it from qb.lua.
The second change allows you to more clearly 'group' your code according to purpose.
For example, with goal and reward functions Fanrir's script is like this (I'll just do one quest):
require("quest_builder")
local qb = QuestBuilder()
local questnr
local function questGoals()
---------
-- "Mouse Hunt"
---------
elseif questnr == 3 then
qb:AddQuestTarget(3, 2, 2, "mouse", "Mouse"):AddQuestItem(2, "quest_object", "tail_rat.101", "Mouse tail")
local ds = DataStore("fanrir", player)
if not ds:Get("weapon given") then
ds:Set("weapon given", true)
ds:WasChanged()
local weaponarch = {
[game:GetSkillNr("slash weapons") ] = "shortsword",
[game:GetSkillNr("impact weapons")] = "mstar_small",
[game:GetSkillNr("cleave weapons")] = "axe_small",
[game:GetSkillNr("pierce weapons")] = "dagger_large"
}
for k, v in pairs(weaponarch) do
skill = player:FindSkill(k)
if skill and skill.experience == 0 and not player:GetEquipment(game.EQUIP_WEAPON1) then
local weapon = player:CreateObjectInsideEx(v, 1, game.IDENTIFIED)
assert(weapon, "Could not create weapon!")
player:Apply(weapon, game.APPLY_ALWAYS)
player:Write(npc.name .. " says: Here, take this weapon for the task.")
break
end
end
end
end
end
local function questRewards()
---------
-- "Mouse Hunt"
---------
elseif questnr == 3 then
player:AddMoney(10, 0, 0, 0)
end
end
qb:AddQuest("Mouse Hunt", game.QUEST_KILLITEM, nil, nil, nil, nil, questGoals, questRewards)
questnr = qb:Build(player)
-- ...
local function topic_questAccept()
---------
-- Player is eligible for a quest.
---------
else
ib:SetTitle(qb:GetName(questnr))
---------
-- "Mouse Hunt"
---------
elseif questnr == 3 then
ib:SetMsg("|Hint -- Attacking mobs|\n")
ib:AddMsg("\n'~Mobs~' is just another word for monsters and monsters are anything alive (or later on, undead too!) " ..
"that is your enemy. So mice are monsters are mobs.\n")
ib:AddMsg("\nOK, now that introductions are over, the important question: how do you attack them? " ..
"There are three steps to attacking a mob:\n")
ib:AddMsg("\n~(1)~ turn on combat mode -- do this by pressing ~C~ " ..
"(pressing it a second time turns combat mode off again -- you can see which mode you are in by looking at " ..
"the icon in the lower left part of the screen);\n")
ib:AddMsg("\n~(2)~ target a mob -- do this by pressing ~X~ " ..
"(this will actually cycle through all visible mobs so you might need to " ..
"repeat this step several times to get the right one); and\n")
ib:AddMsg("\n~(3)~ stand next to the mob and you will automatically attack him.\n")
ib:AddMsg("\nDon't forget, most mobs fight back!")
ib:SetDesc("Return to Fanrir's larder and exterminate some of the mice down there for him.\n\n" ..
"Bring back two mouse tails to prove your valour.", 10, 0, 0, 0)
qb:RegisterQuest(3, ib)
-- ...
local function topic_questComplete()
---------
-- Quest really is complete.
---------
else
---------
-- "Mouse Hunt"
---------
elseif questnr == 3 then
ib:SetMsg("Many thanks! That should slow them down a bit.\n")
ib:AddMsg("\nWell, that deserves a reward. Here you go.")
ib:SetDesc("", 10, 0, 0, 0)
qb:Finish(3, "10 copper coins")
The drawbacks are that (a) questnr needs to be declared before it is used in the goal/reward functions but is assigned by qb:Build() which must be called after all the qb:AddQuest() calls which reference the goal/reward functions which must be already defined... and (b) all the nil arguments to qb:AddQuest().
We're stuck with (a). It's easy to work around by delaring questnr before the function definitions, and just assigning it from qb:Build() (as above). Just a little messy-looking.
(b) is certainly fixable with a bit of parameter-juggling, though this is a fiddly and boring process for me to script so I haven't done it yet. Also, I'm not sure it is a worthwhile thing to have happen every runtime just for very slightly easier to write scripts.
Anyway, comments?