1 local function ObjectiveCouldBeFirst(self
)
2 if (self
.user_ignore
== nil and self
.auto_ignore
) or self
.user_ignore
then
6 for i
, j
in pairs(self
.after
) do
15 local function DefaultObjectiveKnown(self
)
16 if self
.user_ignore
== nil then
17 if (self
.filter_zone
and QuestHelper_Pref
.filter_zone
) or
18 (self
.filter_done
and QuestHelper_Pref
.filter_done
) or
19 (self
.filter_level
and QuestHelper_Pref
.filter_level
) then
22 elseif self
.user_ignore
then
26 for i
, j
in pairs(self
.after
) do
27 if i
.watched
and not i
:Known() then -- Need to know how to do everything before this objective.
35 local function ObjectiveReason(self
, short
)
36 local reason
, rc
= nil, 0
38 for r
, c
in pairs(self
.reasons
) do
39 if not reason
or c
> rc
or (c
== rc
and r
> reason
) then
45 if not reason
then reason
= "Do some extremely secret unspecified something." end
47 if not short
and self
.pos
and self
.pos
[6] then
48 reason
= reason
.. "\n" .. self
.pos
[6]
54 local function DummyObjectiveKnown(self
)
55 return (self
.o
.pos
or self
.fb
.pos
) and DefaultObjectiveKnown(self
)
58 local function ItemKnown(self
)
59 if not DefaultObjectiveKnown(self
) then return false end
62 for i
, npc
in ipairs(self
.o
.vendor
) do
63 local n
= self
.qh
:GetObjective("monster", npc
)
64 local faction
= n
.o
.faction
or n
.fb
.faction
65 if (not faction
or faction
== self
.qh
.faction
) and n
:Known() then
71 if self
.fb
.vendor
then
72 for i
, npc
in ipairs(self
.fb
.vendor
) do
73 local n
= self
.qh
:GetObjective("monster", npc
)
74 local faction
= n
.o
.faction
or n
.fb
.faction
75 if (not faction
or faction
== self
.qh
.faction
) and n
:Known() then
81 if self
.o
.pos
or self
.fb
.pos
then
85 if self
.o
.drop
then for monster
in pairs(self
.o
.drop
) do
86 if self
.qh
:GetObjective("monster", monster
):Known() then
91 if self
.fb
.drop
then for monster
in pairs(self
.fb
.drop
) do
92 if self
.qh
:GetObjective("monster", monster
):Known() then
97 if self
.o
.contained
then for item
in pairs(self
.o
.contained
) do
98 if self
.qh
:GetObjective("item", item
):Known() then
103 if self
.fb
.contained
then for item
in pairs(self
.fb
.contained
) do
104 if self
.qh
:GetObjective("item", item
):Known() then
110 local item
=self
.quest
.o
.item
111 item
= item
and item
[self
.obj
]
118 for monster
in pairs(item
.drop
) do
119 if self
.qh
:GetObjective("monster", monster
):Known() then
126 item
=self
.quest
.fb
.item
127 item
= item
and item
[self
.obj
]
133 for monster
in pairs(item
.drop
) do
134 if self
.qh
:GetObjective("monster", monster
):Known() then
145 local function ObjectiveAppendPositions(self
, objective
, weight
, why
)
148 if self
.o
.pos
then for i
, p
in ipairs(self
.o
.pos
) do
149 high
= math
.max(high
, p
[4])
152 if self
.fb
.pos
then for i
, p
in ipairs(self
.fb
.pos
) do
153 high
= math
.max(high
, p
[4])
158 if self
.o
.pos
then for i
, p
in ipairs(self
.o
.pos
) do
159 objective
:AddLoc(p
[1], p
[2], p
[3], p
[4]*high
, why
)
162 if self
.fb
.pos
then for i
, p
in ipairs(self
.fb
.pos
) do
163 objective
:AddLoc(p
[1], p
[2], p
[3], p
[4]*high
, why
)
168 local function ObjectivePrepareRouting(self
)
169 self
.setup_count
= self
.setup_count
+ 1
170 if not self
.setup
then
177 self
.d
= QuestHelper
:CreateTable()
178 self
.p
= QuestHelper
:CreateTable()
179 self
.nm
= QuestHelper
:CreateTable()
180 self
.nm2
= QuestHelper
:CreateTable()
181 self
.nl
= QuestHelper
:CreateTable()
183 self
:AppendPositions(self
, 1, nil)
188 local function ItemAppendPositions(self
, objective
, weight
, why
)
189 why2
= why
and why
.."\n" or ""
191 if self
.o
.vendor
then for i
, npc
in ipairs(self
.o
.vendor
) do
192 local n
= self
.qh
:GetObjective("monster", npc
)
193 local faction
= n
.o
.faction
or n
.fb
.faction
194 if (not faction
or faction
== self
.qh
.faction
) then
195 n
:AppendPositions(objective
, 1, why2
..QHFormat("OBJECTIVE_PURCHASE", npc
))
199 if self
.fb
.vendor
then for i
, npc
in ipairs(self
.fb
.vendor
) do
200 local n
= self
.qh
:GetObjective("monster", npc
)
201 local faction
= n
.o
.faction
or n
.fb
.faction
202 if (not faction
or faction
== self
.qh
.faction
) then
203 n
:AppendPositions(objective
, 1, why2
..QHFormat("OBJECTIVE_PURCHASE", npc
))
207 if next(objective
.p
, nil) then
208 -- If we have points from vendors, then always use vendors. I don't want it telling you to killing the
209 -- towns people just because you had to talk to them anyway, and it saves walking to the store.
213 if self
.o
.drop
then for monster
, count
in pairs(self
.o
.drop
) do
214 local m
= self
.qh
:GetObjective("monster", monster
)
215 m
:AppendPositions(objective
, m
.o
.looted
and count
/m
.o
.looted
or 1, why2
..QHFormat("OBJECTIVE_SLAY", monster
))
218 if self
.fb
.drop
then for monster
, count
in pairs(self
.fb
.drop
) do
219 local m
= self
.qh
:GetObjective("monster", monster
)
220 m
:AppendPositions(objective
, m
.fb
.looted
and count
/m
.fb
.looted
or 1, why2
..QHFormat("OBJECTIVE_SLAY", monster
))
223 if self
.o
.contained
then for item
, count
in pairs(self
.o
.contained
) do
224 local i
= self
.qh
:GetObjective("item", item
)
225 i
:AppendPositions(objective
, i
.o
.opened
and count
/i
.o
.opened
or 1, why2
..QHFormat("OBJECTIVE_LOOT", item
))
228 if self
.fb
.contained
then for item
, count
in pairs(self
.fb
.contained
) do
229 local i
= self
.qh
:GetObjective("item", item
)
230 i
:AppendPositions(objective
, i
.fb
.opened
and count
/i
.fb
.opened
or 1, why2
..QHFormat("OBJECTIVE_LOOT", item
))
233 if self
.o
.pos
then for i
, p
in ipairs(self
.o
.pos
) do
234 objective
:AddLoc(p
[1], p
[2], p
[3], p
[4], why
)
237 if self
.fb
.pos
then for i
, p
in ipairs(self
.fb
.pos
) do
238 objective
:AddLoc(p
[1], p
[2], p
[3], p
[4], why
)
242 local item_list
=self
.quest
.o
.item
244 local data
= item_list
[self
.obj
]
245 if data
and data
.drop
then
246 for monster
, count
in pairs(data
.drop
) do
247 local m
= self
.qh
:GetObjective("monster", monster
)
248 m
:AppendPositions(objective
, m
.o
.looted
and count
/m
.o
.looted
or 1, why2
..QHFormat("OBJECTIVE_SLAY", monster
))
250 elseif data
and data
.pos
then
251 for i
, p
in ipairs(data
.pos
) do
252 objective
:AddLoc(p
[1], p
[2], p
[3], p
[4], why
)
257 item_list
=self
.quest
.fb
.item
259 local data
= item_list
[self
.obj
]
260 if data
and data
.drop
then
261 for monster
, count
in pairs(data
.drop
) do
262 local m
= self
.qh
:GetObjective("monster", monster
)
263 m
:AppendPositions(objective
, m
.fb
.looted
and count
/m
.fb
.looted
or 1, why2
..QHFormat("OBJECTIVE_SLAY", monster
))
265 elseif data
and data
.pos
then
266 for i
, p
in ipairs(data
.pos
) do
267 objective
:AddLoc(p
[1], p
[2], p
[3], p
[4], why
)
299 local function AddLoc(self
, index
, x
, y
, w
, why
)
300 assert(not self
.setup
)
303 local pair
= QuestHelper_ZoneLookup
[index
]
304 local c
, z
= pair
[1], pair
[2]
305 x
, y
= self
.qh
.Astrolabe
:TranslateWorldMapPosition(c
, z
, x
, y
, c
, 0)
307 x
= x
* self
.qh
.continent_scales_x
[c
]
308 y
= y
* self
.qh
.continent_scales_y
[c
]
309 local list
= self
.qh
.zone_nodes
[index
]
311 local points
= self
.p
[list
]
313 points
= QuestHelper
:CreateTable()
314 self
.p
[list
] = points
317 for i
, p
in pairs(points
) do
318 local u
, v
= x
-p
[3], y
-p
[4]
319 if u
*u
+v
*v
< 25 then -- Combine points within a threshold of 5 seconds travel time.
320 p
[3] = (p
[3]*p
[5]+x
*w
)/(p
[5]+w
)
321 p
[4] = (p
[4]*p
[5]+y
*w
)/(p
[5]+w
)
330 local new
= QuestHelper
:CreateTable()
331 new
[1], new
[2], new
[3], new
[4], new
[5], new
[6], new
[7] = list
, nil, x
, y
, w
, why
, w
332 table.insert(points
, new
)
336 local function FinishAddLoc(self
)
339 for z
, pl
in pairs(self
.p
) do
340 for i
, p
in ipairs(pl
) do
348 -- Remove probably useless locations.
349 for z
, pl
in pairs(self
.p
) do
350 local remove_zone
= true
353 if pl
[i
][5] < mx
*0.2 then
354 QuestHelper
:ReleaseTable(pl
[i
])
362 QuestHelper
:ReleaseTable(self
.p
[z
])
367 local node_map
= self
.nm
368 local node_list
= self
.nl
370 for list
, pl
in pairs(self
.p
) do
371 local dist
= self
.d
[list
]
376 dist
= QuestHelper
:CreateTable()
380 for i
, point
in ipairs(pl
) do
381 point
[5] = mx
/point
[5] -- Will become 1 for the most desired location, and become larger and larger for less desireable locations.
383 point
[2] = QuestHelper
:CreateTable()
385 for i
, node
in ipairs(list
) do
386 local u
, v
= point
[3]-node
.x
, point
[4]-node
.y
387 local d
= math
.sqrt(u
*u
+v
*v
)
392 if d
*point
[5] < dist
[i
][1]*dist
[i
][2] then
393 dist
[i
][1], dist
[i
][2] = d
, point
[5]
394 node_map
[node
] = point
397 local pair
= QuestHelper
:CreateTable()
398 pair
[1], pair
[2] = d
, point
[5]
401 if not node_map
[node
] then
402 table.insert(node_list
, node
)
403 node_map
[node
] = point
405 u
, v
= node_map
[node
][3]-node
.x
, node_map
[node
][4]-node
.y
407 if dist
[i
][1]*dist
[i
][2] < math
.sqrt(u
*u
+v
*v
)*node_map
[node
][5] then
408 node_map
[node
] = point
416 if #node_list
== 0 then QuestHelper
:Error(self
.cat
.."/"..self
.obj
..": zero nodes!") end
418 assert(not self
.setup
)
420 table.insert(self
.qh
.prepared_objectives
, self
)
423 local function GetPosition(self
)
429 local function ComputeTravelTime(self
, pos
)
432 local graph
= self
.qh
.world_graph
435 graph
:PrepareSearch()
437 for z
, l
in pairs(self
.d
) do
438 for i
, n
in ipairs(z
) do
440 n
.e
, n
.w
= unpack(l
[i
])
442 elseif n
.e
* n
.w
< l
[i
][1]*l
[i
][2] then
443 n
.e
, n
.w
= unpack(l
[i
])
449 for i
, n
in ipairs(pos
[1]) do
450 graph
:AddStartNode(n
, d
[i
], nl
)
453 local e
= graph
:DoSearch(nl
)
458 local l
= self
.p
[pos
[1]]
460 local x
, y
= pos
[3], pos
[4]
463 for i
, n
in ipairs(l
) do
464 local u
, v
= x
-n
[3], y
-n
[4]
465 local d2
= math
.sqrt(u
*u
+v
*v
)
468 d
, e
, score
= d2
, n
, s
477 local function ComputeTravelTime2(self
, pos1
, pos2
)
480 local graph
= self
.qh
.world_graph
483 graph
:PrepareSearch()
485 for z
, l
in pairs(self
.d
) do
486 for i
, n
in ipairs(z
) do
488 n
.e
, n
.w
= unpack(l
[i
])
490 elseif n
.e
* n
.w
< l
[i
][1]*l
[i
][2] then
491 n
.e
, n
.w
= unpack(l
[i
])
497 for i
, n
in ipairs(pos1
[1]) do
498 graph
:AddStartNode(n
, d
[i
], nl
)
501 graph
:DoFullSearch(nl
)
503 graph
:PrepareSearch()
505 -- Now, we need to figure out how long it takes to get to each node.
506 for z
, point_list
in pairs(self
.p
) do
508 -- Will also consider min distance.
509 local x
, y
= pos1
[3], pos1
[4]
511 for i
, p
in ipairs(point_list
) do
512 local a
, b
= p
[3]-x
, p
[4]-y
513 local u
, v
= p
[3], p
[4]
514 local d
= math
.sqrt(a
*a
+b
*b
)
517 for i
, n
in ipairs(z
) do
519 local bleh
= math
.sqrt(a
*a
+b
*b
)+n
.g
528 for i
, p
in ipairs(point_list
) do
529 local x
, y
= p
[3], p
[4]
534 for i
, n
in ipairs(z
) do
535 local a
, b
= n
.x
-x
, n
.y
-y
536 local d2
= math
.sqrt(a
*a
+b
*b
)+n
.g
538 if not score
or s
< score
then
549 for i
, n
in ipairs(pos2
[1]) do
557 for z
, l
in pairs(self
.d
) do
558 for i
, n
in ipairs(z
) do
559 local x
, y
= n
.x
, n
.y
563 for i
, p
in ipairs(self
.p
[z
]) do
564 local a
, b
= x
-p
[3], y
-p
[4]
565 d
= p
[7]+math
.sqrt(a
*a
+b
*b
)
567 if not bs
or s
< bs
then
573 -- Using score instead of distance, because we want nodes we're not really interested in to be less likely to get chosen.
574 graph
:AddStartNode(n
, bs
, el
)
578 local e
= graph
:DoSearch(pos2
[1])
581 local d2
= e
.g
+e
.e
-e
.p
.g
+(e
.p
.g
/nm
[e
.p
][5]-nm
[e
.p
][7])
584 local total
= (d
+d2
)*e
[5]
587 local x
, y
= pos2
[3], pos2
[4]
588 for i
, p
in ipairs(self
.p
[el
]) do
589 local a
, b
= x
-p
[3], y
-p
[4]
590 local c
= math
.sqrt(a
*a
+b
*b
)
591 local t
= (p
[7]+c
)*p
[5]
593 total
, d
, d2
, e
= t
, p
[7], c
, p
602 local function DoneRouting(self
)
603 assert(self
.setup_count
> 0)
606 if self
.setup_count
== 1 then
608 QuestHelper
:ReleaseObjectivePathingInfo(self
)
609 for i
, obj
in ipairs(self
.qh
.prepared_objectives
) do
611 table.remove(self
.qh
.prepared_objectives
, i
)
616 self
.setup_count
= self
.setup_count
- 1
620 local next_objective_id
= 0
622 local function ObjectiveShare(self
)
623 self
.want_share
= true
626 local function ObjectiveUnshare(self
)
627 self
.want_share
= false
630 QuestHelper
.default_objective_param
=
632 CouldBeFirst
=ObjectiveCouldBeFirst
,
634 DefaultKnown
=DefaultObjectiveKnown
,
635 Known
=DummyObjectiveKnown
,
636 Reason
=ObjectiveReason
,
638 AppendPositions
=ObjectiveAppendPositions
,
639 PrepareRouting
=ObjectivePrepareRouting
,
641 FinishAddLoc
=FinishAddLoc
,
642 DoneRouting
=DoneRouting
,
644 Position
=GetPosition
,
645 TravelTime
=ComputeTravelTime
,
646 TravelTime2
=ComputeTravelTime2
,
648 Share
=ObjectiveShare
, -- Invoke to share this objective with your peers.
649 Unshare
=ObjectiveUnshare
, -- Invoke to stop sharing this objective.
652 QuestHelper
.default_objective_item_param
=
655 AppendPositions
= ItemAppendPositions
658 for key
, value
in pairs(QuestHelper
.default_objective_param
) do
659 if not QuestHelper
.default_objective_item_param
[key
] then
660 QuestHelper
.default_objective_item_param
[key
] = value
664 QuestHelper
.default_objective_meta
= { __index
= QuestHelper
.default_objective_param
}
665 QuestHelper
.default_objective_item_meta
= { __index
= QuestHelper
.default_objective_item_param
}
667 function QuestHelper
:NewObjectiveObject()
668 next_objective_id
= next_objective_id
+1
672 id
=next_objective_id
,
674 want_share
=false, -- True if we want this objective shared.
675 is_sharing
=false, -- Set to true if we've told other users about this objective.
677 user_ignore
=nil, -- When nil, will use filters. Will ignore, when true, always show (if known).
679 priority
=3, -- A hint as to what priority the quest should have. Should be 1, 2, 3, 4, or 5.
680 real_priority
=3, -- This will be set to the priority routing actually decided to assign it.
691 before
={}, -- List of objectives that this objective must appear before.
692 after
={}, -- List of objectives that this objective must appear after.
694 -- Routing related junk.
696 --[[ Will be created as needed.
699 nm=nil, -- Maps nodes to their nearest zone/list/x/y position.
700 nm2=nil, -- Maps nodes to their nears position, but dynamically set in TravelTime2.
701 nl=nil, -- List of all the nodes we need to consider.
702 location=nil, -- Will be set to the best position for the node.
703 pos=nil, -- Zone node list, distance list, x, y, reason.
705 }, QuestHelper
.default_objective_meta
)
708 function QuestHelper
:GetObjective(category
, objective
)
709 local objective_list
= self
.objective_objects
[category
]
711 if not objective_list
then
713 self
.objective_objects
[category
] = objective_list
716 local objective_object
= objective_list
[objective
]
718 if not objective_object
then
719 if category
== "quest" then
720 local _
, _
, level
, hash
, name
= string.find(objective
, "^(%d+)/(%d*)/(.*)$")
722 _
, _
, level
, name
= string.find(objective
, "^(%d+)/(.*)$")
728 if hash
== "" then hash
= nil end
729 objective_object
= self
:GetQuest(name
, tonumber(level
), tonumber(hash
))
730 objective_list
[objective
] = objective_object
731 return objective_object
734 objective_object
= self
:NewObjectiveObject()
736 objective_object
.cat
= category
737 objective_object
.obj
= objective
739 if category
== "item" then
740 setmetatable(objective_object
, QuestHelper
.default_objective_item_meta
)
741 objective_object
.icon_id
= 2
742 elseif category
== "monster" then
743 objective_object
.icon_id
= 1
744 elseif category
== "object" then
745 objective_object
.icon_id
= 3
746 elseif category
== "event" then
747 objective_object
.icon_id
= 4
748 elseif category
== "loc" then
749 objective_object
.icon_id
= 6
750 elseif category
== "reputation" then
751 objective_object
.icon_id
= 5
753 self
:TextOut("FIXME: Objective type '"..category
.."' for objective '"..objective
.."' isn't explicitly supported yet; hopefully the dummy handler will do something sensible.")
756 objective_list
[objective
] = objective_object
758 if category
== "loc" then
759 -- Loc is special, we don't store it, and construct it from the string.
760 -- Don't have any error checking here, will assume it's correct.
762 local _
, _
, c
, z
, x
, y
= string.find(objective
,"^(%d+),(%d+),([%d%.]+),([%d%.]+)$")
765 _
, _
, i
, x
, y
= string.find(objective
,"^(%d+),([%d%.]+),([%d%.]+)$")
767 i
= QuestHelper_IndexLookup
[c
][z
]
770 objective_object
.o
= {pos
={{tonumber(i
),tonumber(x
),tonumber(y
),1}}}
771 objective_object
.fb
= {}
773 objective_list
= QuestHelper_Objectives
[category
]
774 if not objective_list
then
776 QuestHelper_Objectives
[category
] = objective_list
778 objective_object
.o
= objective_list
[objective
]
779 if not objective_object
.o
then
780 objective_object
.o
= {}
781 objective_list
[objective
] = objective_object
.o
783 local l
= QuestHelper_StaticData
[self
.locale
]
785 objective_list
= l
.objective
[category
]
786 if objective_list
then
787 objective_object
.fb
= objective_list
[objective
]
790 if not objective_object
.fb
then
791 objective_object
.fb
= {}
794 -- TODO: If we have some other source of information (like LightHeaded) add its data to objective_object.fb
799 return objective_object
802 function QuestHelper
:AppendObjectivePosition(objective
, i
, x
, y
, w
)
803 local pos
= objective
.o
.pos
805 if objective
.o
.drop
or objective
.o
.contained
then
806 return -- If it's dropped by a monster, don't record the position we got the item at.
808 objective
.o
.pos
= self
:AppendPosition({}, i
, x
, y
, w
)
810 self
:AppendPosition(pos
, i
, x
, y
, w
)
814 function QuestHelper
:AppendObjectiveDrop(objective
, monster
, count
)
815 local drop
= objective
.o
.drop
817 drop
[monster
] = (drop
[monster
] or 0)+(count
or 1)
819 objective
.o
.drop
= {[monster
] = count
or 1}
820 objective
.o
.pos
= nil -- If it's dropped by a monster, then forget the position we found it at.
824 function QuestHelper
:AppendItemObjectiveDrop(item_object
, item_name
, monster_name
, count
)
825 local quest
= self
:ItemIsForQuest(item_object
, item_name
)
826 if quest
and not item_object
.o
.vendor
and not item_object
.o
.drop
and not item_object
.o
.pos
then
827 self
:AppendQuestDrop(quest
, item_name
, monster_name
, count
)
829 if not item_object
.o
.drop
and not item_object
.o
.pos
then
830 self
:PurgeQuestItem(item_object
, item_name
)
832 self
:AppendObjectiveDrop(item_object
, monster_name
, count
)
836 function QuestHelper
:AppendItemObjectivePosition(item_object
, item_name
, i
, x
, y
)
837 local quest
= self
:ItemIsForQuest(item_object
, item_name
)
838 if quest
and not item_object
.o
.vendor
and not item_object
.o
.drop
and not item_object
.o
.pos
then
839 self
:AppendQuestPosition(quest
, item_name
, i
, x
, y
)
841 if not item_object
.o
.vendor
and not item_object
.o
.drop
and not item_object
.o
.contained
and not item_object
.o
.pos
then
842 -- Just learned that this item doesn't depend on a quest to drop, remove any quest references to it.
843 self
:PurgeQuestItem(item_object
, item_name
)
845 self
:AppendObjectivePosition(item_object
, i
, x
, y
)
849 function QuestHelper
:AppendItemObjectiveContainer(objective
, container_name
, count
)
850 local container
= objective
.o
.contained
852 container
[container_name
] = (container
[container_name
] or 0)+(count
or 1)
854 objective
.o
.contained
= {[container_name
] = count
or 1}
855 objective
.o
.pos
= nil -- Forget the position.
859 function QuestHelper
:AddObjectiveWatch(objective
, reason
)
860 if not objective
.reasons
then
861 objective
.reasons
= {}
864 if not next(objective
.reasons
, nil) then
865 objective
.watched
= true
866 if self
.to_remove
[objective
] then
867 self
.to_remove
[objective
] = nil
869 self
.to_add
[objective
] = true
873 objective
.reasons
[reason
] = (objective
.reasons
[reason
] or 0) + 1
876 function QuestHelper
:RemoveObjectiveWatch(objective
, reason
)
877 if objective
.reasons
[reason
] == 1 then
878 objective
.reasons
[reason
] = nil
879 if not next(objective
.reasons
, nil) then
880 objective
.watched
= false
881 if self
.to_add
[objective
] then
882 self
.to_add
[objective
] = nil
884 self
.to_remove
[objective
] = true
888 objective
.reasons
[reason
] = objective
.reasons
[reason
] - 1
892 function QuestHelper
:ObjectiveObjectDependsOn(objective
, needs
)
893 assert(objective
~= needs
) -- If this was true, ObjectiveIsKnown would get in an infinite loop.
894 -- TODO: Needs sanity checking, especially now that dependencies can be assigned by remote users.
896 if not objective
.after
[needs
] then
897 if objective
.peer
then
898 for u
, l
in pairs(objective
.peer
) do
899 -- Make sure other users know that the dependencies for this objective changed.
900 objective
.peer
[u
] = math
.min(l
, 1)
903 objective
.after
[needs
] = true
904 needs
.before
[objective
] = true
908 function QuestHelper
:AddObjectiveOptionsToMenu(obj
, menu
)
909 local submenu
= self
:CreateMenu()
912 local name
= QHText("PRIORITY"..i
)
913 local item
= self
:CreateMenuItem(submenu
, name
)
916 if obj
.priority
== i
then
917 tex
= self
:CreateIconTexture(item
, 10)
918 elseif obj
.real_priority
== i
then
919 tex
= self
:CreateIconTexture(item
, 8)
921 tex
= self
:CreateIconTexture(item
, 12)
922 tex
:SetVertexColor(1, 1, 1, 0)
925 item
:AddTexture(tex
, true)
926 item
:SetFunction(self
.SetObjectivePriorityPrompt
, self
, obj
, i
)
929 self
:CreateMenuItem(menu
, QHText("PRIORITY")):SetSubmenu(submenu
)
932 submenu
= self
:CreateMenu(QHText("SHARING"))
933 local item
= self
:CreateMenuItem(submenu
, QHText("ENABLE"))
934 local tex
= self
:CreateIconTexture(item
, 10)
935 if not obj
.want_share
then tex
:SetVertexColor(1, 1, 1, 0) end
936 item
:AddTexture(tex
, true)
937 item
:SetFunction(obj
.Share
, obj
)
939 local item
= self
:CreateMenuItem(submenu
, QHText("DISABLE"))
940 local tex
= self
:CreateIconTexture(item
, 10)
941 if obj
.want_share
then tex
:SetVertexColor(1, 1, 1, 0) end
942 item
:AddTexture(tex
, true)
943 item
:SetFunction(obj
.Unshare
, obj
)
945 self
:CreateMenuItem(menu
, QHText("SHARING")):SetSubmenu(submenu
)
948 self
:CreateMenuItem(menu
, QHText("IGNORE")):SetFunction(self
.IgnoreObjective
, self
, obj
)
951 function QuestHelper
:IgnoreObjective(objective
)
952 if self
.user_objectives
[objective
] then
953 self
:RemoveObjectiveWatch(objective
, self
.user_objectives
[objective
])
954 self
.user_objectives
[objective
] = nil
956 objective
.user_ignore
= true
959 --self:ForceRouteUpdate()
962 function QuestHelper
:SetObjectivePriority(objective
, level
)
963 level
= math
.min(5, math
.max(1, math
.floor((tonumber(level
) or 3)+0.5)))
964 if level
~= objective
.priority
then
965 objective
.priority
= level
966 if objective
.peer
then
967 for u
, l
in pairs(objective
.peer
) do
968 -- Peers don't know about this new priority.
969 objective
.peer
[u
] = math
.min(l
, 2)
972 --self:ForceRouteUpdate()
976 local function CalcObjectivePriority(obj
)
977 local priority
= obj
.priority
979 for o
in pairs(obj
.before
) do
981 priority
= math
.min(priority
, CalcObjectivePriority(o
))
988 local function ApplyBlockPriority(obj
, level
)
989 for o
in pairs(obj
.before
) do
991 ApplyBlockPriority(o
, level
)
995 if obj
.priority
< level
then QuestHelper
:SetObjectivePriority(obj
, level
) end
998 function QuestHelper
:SetObjectivePriorityPrompt(objective
, level
)
999 self
:SetObjectivePriority(objective
, level
)
1000 if CalcObjectivePriority(objective
) ~= level
then
1001 local menu
= self
:CreateMenu()
1002 self
:CreateMenuTitle(menu
, QHText("IGNORED_PRIORITY_TITLE"))
1003 self
:CreateMenuItem(menu
, QHText("IGNORED_PRIORITY_FIX")):SetFunction(ApplyBlockPriority
, objective
, level
)
1004 self
:CreateMenuItem(menu
, QHText("IGNORED_PRIORITY_IGNORE")):SetFunction(self
.nop
)
1009 function QuestHelper
:SetObjectiveProgress(objective
, user
, have
, need
)
1010 if have
and need
then
1011 local list
= objective
.progress
1013 list
= self
:CreateTable()
1014 objective
.progress
= list
1017 local user_progress
= list
[user
]
1018 if not user_progress
then
1019 user_progress
= self
:CreateTable()
1020 list
[user
] = user_progress
1024 local a
, b
= tonumber(have
), tonumber(need
)
1035 user_progress
[1], user_progress
[2], user_progress
[3] = have
, need
, pct
1037 if objective
.progress
then
1038 if objective
.progress
[user
] then
1039 self
:ReleaseTable(objective
.progress
[user
])
1040 objective
.progress
[user
] = nil
1042 if not next(objective
.progress
, nil) then
1043 self
:ReleaseTable(objective
.progress
)
1044 objective
.progress
= nil