4 local feature
= r2
.Features
.Quest
10 feature
.Components
= {}
12 feature
.Components
.Quest
=
14 BaseClass
="LogicEntity",
17 Menu
="ui:interface:r2ed_feature_menu",
19 DisplayerProperties
= "R2::CDisplayerLua",
20 DisplayerPropertiesParams
= "questDisplayer",
22 DisplayerUI
= "R2::CDisplayerLua",
23 DisplayerUIParams
= "defaultUIDisplayer",
24 DisplayerVisual
= "R2::CDisplayerVisualEntity",
28 ApplicableActions
= { "activate", "deactivate", "validate current task", "complete"},
30 Events
= {"activation", "deactivation", "success"},
32 Conditions
= { "is active", "is inactive", "is finished" },
42 {Name
="InstanceId", Type
="String", WidgetStyle
="StaticText", Visible
= false},
43 {Name
="Components", Type
="Table"},
44 {Name
="Name", Type
="String", MaxNumChar
="32"},
46 {Name
="TaskNumber", Type
="Number", Category
="uiR2EDRollout_Targets", WidgetStyle
="EnumDropDown", Enum
={"1", "2", "3", "4", "5"},},
47 {Name
="TaskStep1Id", Type
="RefId", Category
="uiR2EDRollout_Targets", PickFunction
="r2:canPickTaskComponent", SetRefIdFunction
="r2:setTaskComponentTarget",Visible
= function(this
) return this
:displayRefId(1) end},
48 {Name
="TaskStep2Id", Type
="RefId", Category
="uiR2EDRollout_Targets", PickFunction
="r2:canPickTaskComponent", SetRefIdFunction
="r2:setTaskComponentTarget",Visible
= function(this
) return this
:displayRefId(2) end},
49 {Name
="TaskStep3Id", Type
="RefId", Category
="uiR2EDRollout_Targets", PickFunction
="r2:canPickTaskComponent", SetRefIdFunction
="r2:setTaskComponentTarget",Visible
= function(this
) return this
:displayRefId(3) end},
50 {Name
="TaskStep4Id", Type
="RefId", Category
="uiR2EDRollout_Targets", PickFunction
="r2:canPickTaskComponent", SetRefIdFunction
="r2:setTaskComponentTarget",Visible
= function(this
) return this
:displayRefId(4) end},
51 {Name
="TaskStep5Id", Type
="RefId", Category
="uiR2EDRollout_Targets", PickFunction
="r2:canPickTaskComponent", SetRefIdFunction
="r2:setTaskComponentTarget",Visible
= function(this
) return this
:displayRefId(5) end},
53 {Name
="QuestCompletedText", Type
="String", Category
="uiR2EDRollout_TextToSay"},
55 {Name
="Active", Type
="Number", WidgetStyle
="Boolean", DefaultValue
="1"},
56 {Name
="Repeatable", Type
="Number", WidgetStyle
="Boolean", DefaultValue
="0"},
61 getAvailableCommands
= function(this
, dest
)
62 r2
.Classes
.LogicEntity
.getAvailableCommands(this
, dest
) -- fill by ancestor
63 this
:getAvailableDisplayModeCommands(dest
)
66 getParentTreeNode
= function(this
)
67 return this
:getFeatureParentTreeNode()
70 appendInstancesByType
= function(this
, destTable
, kind
)
71 assert(type(kind
) == "string")
72 --this:delegate():appendInstancesByType(destTable, kind)
73 r2
.Classes
.LogicEntity
.appendInstancesByType(this
, destTable
, kind
)
74 for k
, component
in specPairs(this
.Components
) do
75 component
:appendInstancesByType(destTable
, kind
)
79 getSelectBarSons
= function(this
)
83 canHaveSelectBarSons
= function(this
)
87 onPostCreate
= function(this
)
88 --this:createGhostComponents()
89 if this
.User
.DisplayProp
and this
.User
.DisplayProp
== 1 then
90 r2
:setSelectedInstanceId(this
.InstanceId
)
91 r2
:showProperties(this
)
92 this
.User
.DisplayProp
= nil
96 pretranslate
= function(this
, context
)
97 r2
.Translator
.createAiGroup(this
, context
)
104 local component
= feature
.Components
.Quest
107 function component
:displayRefId(index
)
108 local nbRefId
= self
.TaskNumber
+ 1
109 if index
<= nbRefId
then
115 function component
:textAdapter(text
)
117 assert(type(text
) == "string")
120 str
=string.gsub(str
, "<quest_name>", self
.Name
)
124 -----------------------------------------------------------------------------------------------------------
125 -----------------------------------------------------------------------------------------------------------
126 local questDisplayerTable
= clone(r2
:propertySheetDisplayer())
129 -- If the message is received by a client that didn't request the modification, we must make sure this client
130 -- doesn't modify the data because it has already been done by the initial client.
132 local function checkPickedEntity(this
, instanceId
, attributeName
)
133 if instanceId
== "" then
136 local tmpInstance
= r2
:getInstanceFromId(instanceId
)
140 local attrName
= "Task" ..i
.. "Id"
141 if attrName
~= attributeName
and this
[attrName
] == tmpInstance
.InstanceId
then
150 local oldOnAttrModified
= questDisplayerTable
.onAttrModified
151 function questDisplayerTable
:onAttrModified(instance
, attributeName
)
153 oldOnAttrModified(self
, instance
, attributeName
)
155 if attributeName
== "TaskNumber" then
156 local propertySheet
= r2
:getPropertySheet(instance
)
157 local nbRefId
= instance
.TaskNumber
+ 1
161 local name
= "TaskStep"..tostring(i
).."Id"
162 local refId
= propertySheet
:find(name
)
163 local refIdName
= refId
:find("name")
164 refIdName
.hardtext
= "NONE"
165 r2
.requestSetNode(instance
.InstanceId
, name
, "")
169 propertySheet
.Env
.updatePropVisibility()
173 if (string.find(attributeName
, "Id") == nil or attributeName
== "InstanceId") then return end
175 local propertySheet
= r2
:getPropertySheet(instance
)
176 local refId
= propertySheet
:find(attributeName
)
177 if refId
== nil then return end
178 local refIdName
= refId
:find("name")
179 local instanceId
= instance
[attributeName
]
180 if not instanceId
then
184 if instanceId
== "" then
185 refIdName
.hardtext
= "NONE"
189 local inserted
= checkPickedEntity(instance
, instanceId
, attributeName
)
190 if inserted
== true then
191 local tmpInstance
= r2
:getInstanceFromId(instanceId
)
192 refIdName
.hardtext
= tmpInstance
.Name
194 r2
.requestSetNode(instance
.InstanceId
, attributeName
, "")
196 instance
.User
.onHrcMove
= false
199 function questDisplayerTable
:onSelect(instance
, isSelected
)
200 r2
:logicEntityPropertySheetDisplayer():onSelect(instance
, isSelected
)
203 function component
:onTargetInstancePreHrcMove(targetAttr
, targetIndexInArray
)
205 local targetId
= self
[targetAttr
]
206 local tmpInstance
= r2
:getInstanceFromId(targetId
)
207 tmpInstance
.User
.SelfModified
= true
213 function r2
:questDisplayer()
214 return questDisplayerTable
-- returned shared displayer to avoid wasting memory
217 ---------------------------------------------------------------------------------------
218 ---------------------------------------------------------------------------------------
219 function component
:createGhostComponents(act
)
226 local propertyName
= "TaskStep"..tonumber(id
).."Id"
227 if comp
[propertyName
] ~= nil and comp
[propertyName
] ~= "" then
228 local taskInstance
= r2
:getInstanceFromId(comp
[propertyName
])
230 if firstId
== true then
231 if comp
.Active
== 1 then
232 r2
.requestSetGhostNode(taskInstance
.InstanceId
, "Active", 1)
234 local eventHandler
= r2
.newComponent("LogicEntityAction")
235 eventHandler
.Event
.Type
= "activation"
236 eventHandler
.Event
.Value
= ""
237 eventHandler
.Name
= "activation"
239 local action
= r2
.newComponent("ActionStep")
241 action
.Entity
= r2
.RefId(taskInstance
.InstanceId
)
242 action
.Action
.Type
= "activate"
243 action
.Action
.Value
= ""
245 table.insert(eventHandler
.Actions
, action
)
247 local behaviorId
= comp
.Behavior
.InstanceId
249 r2
.requestInsertGhostNode(behaviorId
, "Actions", -1, "", eventHandler
)
253 r2
.requestSetGhostNode(taskInstance
.InstanceId
, "Active", 0)
255 r2
.requestSetGhostNode(taskInstance
.InstanceId
, "Repeatable", 0)
258 local eventHandler
= r2
.newComponent("LogicEntityAction")
259 eventHandler
.Event
.Type
= "deactivation"
260 eventHandler
.Event
.Value
= ""
261 eventHandler
.Name
= "deactivation"
263 local action
= r2
.newComponent("ActionStep")
265 action
.Entity
= r2
.RefId(taskInstance
.InstanceId
)
266 action
.Action
.Type
= "deactivate"
267 action
.Action
.Value
= ""
269 table.insert(eventHandler
.Actions
, action
)
271 local behaviorId
= comp
.Behavior
.InstanceId
273 r2
.requestInsertGhostNode(behaviorId
, "Actions", -1, "", eventHandler
)
283 function component
:getTaskRtIds(context
)
286 local taskId
= self
["TaskStep"..id
.."Id"]
287 if taskId
and taskId
~= "" then
288 local rtGroup
= r2
.Translator
.getRtGroup(context
, taskId
)
290 if rtGroup
.Id
and rtGroup
.Id
~= "" then
291 prefix
= r2
:getNamespace()..rtGroup
.Id
.."."
293 table.insert(rtGroups
, prefix
)
299 function component
:getTaskInstances(context
)
302 local taskId
= self
["TaskStep"..id
.."Id"]
303 if taskId
and taskId
~= "" then
304 local instance
= r2
:getInstanceFromId(taskId
)
306 table.insert(instances
, instance
)
313 function component
:translate(context
)
317 -- 4 (for steps) : init (activate reinit default values on mission steps)
318 -- 8 : quest completed
319 -- 9 : validate task step
320 r2
.Translator
.translateAiGroup(self
, context
)
322 local rtGrp
= r2
.Translator
.getRtGroup(context
, self
.InstanceId
)
324 local taskInstances
= self
:getTaskInstances(context
)
325 if table.getn(taskInstances
) == 0 then return end
326 local taskRtGrps
= self
:getTaskRtIds(context
)
328 local baseAct
= r2
.Scenario
:getBaseAct()
329 local baseActRtGrp
= r2
.Translator
.getRtGroup(context
, baseAct
.InstanceId
)
334 -- v2 = current step index
335 -- v3 = completed (at least once)
336 local rtAction1
= r2
.Translator
.createAction("set_value", rtGrp
.Id
, "Active", self
.Active
)
337 local rtAction2
= r2
.Translator
.createAction("set_value", rtGrp
.Id
, "v1", self
.Repeatable
)
338 local rtAction3
= r2
.Translator
.createAction("set_value", rtGrp
.Id
, "v2", 1)
339 local rtAction4
= r2
.Translator
.createAction("set_value", rtGrp
.Id
, "v3", 0)
340 local rtAction
= r2
.Translator
.createAction("multi_actions", { rtAction1
, rtAction2
, rtAction3
, } )
341 r2
.Translator
.translateAiGroupEvent("start_of_state" , self
, context
, rtAction
)
346 local k
, v
= next(taskInstances
, nil)
349 local taskInstance
= v
351 local rtActionIncrement
= r2
.Translator
.createAction("increment_quest_step_index", rtGrp
.Id
, taskIndex
)
352 local event
= r2
.Translator
.getEventFromType(taskInstance
, context
, "succeeded") --get the right event for "succeeded"
353 r2
.Translator
.translateAiGroupEvent(event
.Event
, taskInstance
, context
, rtActionIncrement
)
355 k
, v
= next(taskInstances
, k
)
360 local actionValidateTask
= r2
.Translator
.createAction("validate_quest_step", rtGrp
.Id
, taskRtGrps
)
362 r2
.Translator
.translateAiGroupEvent("user_event_9", self
, context
, actionValidateTask
)
366 --Deactivation (event 5)
368 local rtAction
= r2
.Translator
.createAction("multi_actions", {
369 r2
.Translator
.createAction("set_value", rtGrp
.Id
, "Active", 0 ),
370 r2
.Translator
.createAction("set_value", rtGrp
.Id
, "v2", 0 ),
372 r2
.Translator
.translateAiGroupEvent("user_event_5", self
, context
, rtAction
)
375 --Mission completed (event 8)
377 local actionBroadcast
= r2
.Translator
.createAction("broadcast_msg", baseActRtGrp
.Id
, self
:textAdapter(self
.QuestCompletedText
))
379 local actionRepeatable
= r2
.Translator
.createAction("if_value_equal", rtGrp
.Id
, "v1", 1, --if Repeatable
380 r2
.Translator
.createAction("multi_actions", {
381 r2
.Translator
.createAction("set_value", rtGrp
.Id
, "Active", 1 ),
382 r2
.Translator
.createAction("set_value", rtGrp
.Id
, "v2", 1 ),
383 r2
.Translator
.createAction("set_value", rtGrp
.Id
, "v3", 1 ),
386 local actionNotRepeatable
= r2
.Translator
.createAction("if_value_equal", rtGrp
.Id
, "v1", 0, -- if not Repeatable
387 r2
.Translator
.createAction("multi_actions", {
388 r2
.Translator
.createAction("user_event_trigger", rtGrp
.Id
, 5),
389 r2
.Translator
.createAction("set_value", rtGrp
.Id
, "v3", 1 ),
393 local actionCompleted
= r2
.Translator
.createAction("multi_actions", {
394 actionRepeatable
, actionNotRepeatable
, actionBroadcast
,
396 r2
.Translator
.translateAiGroupEvent("user_event_8", self
, context
, actionCompleted
)
398 r2
.Translator
.translateFeatureActivation(self
, context
)
402 component
.getLogicAction
= function(entity
, context
, action
)
404 assert( action
.Class
== "ActionStep")
405 local component
= r2
:getInstanceFromId(action
.Entity
)
407 local rtGrp
= r2
.Translator
.getRtGroup(context
, component
.InstanceId
)
411 if rtGrp
.Id
and rtGrp
.Id
~= "" then
412 prefix
= r2
:getNamespace() .. rtGrp
.Id
.."."
415 local taskRtGrps
= component
:getTaskRtIds(context
)
417 if action
.Action
.Type
== "validate current task" then
418 local actionSet
= r2
.Translator
.createAction("set_value", rtGrp
.Id
, "v2", prefix
.."v2 + 1")
419 local actionEvent
= r2
.Translator
.createAction("user_event_trigger", rtGrp
.Id
, 9)
420 --local actionValidateStep = r2.Translator.createAction("validate_task_step", rtGrp.Id, taskRtGrps)
421 local rtAction
= r2
.Translator
.createAction("multi_actions", {actionSet
, actionEvent
})
422 local ifActive
= r2
.Translator
.createAction("if_value_equal", rtGrp
.Id
, "Active", 1, rtAction
)
423 return ifActive
, ifActive
425 elseif action
.Action
.Type
== "complete" then
427 local actionEventComplete
= r2
.Translator
.createAction("user_event_trigger", rtGrp
.Id
, 8)
428 local ifActive
= r2
.Translator
.createAction("if_value_equal", rtGrp
.Id
, "Active", 1, actionEventComplete
)
430 return ifActive
, ifActive
433 return r2
.Translator
.getFeatureActivationLogicAction(rtGrp
, action
)
436 component
.getLogicCondition
= function(this
, context
, condition
)
438 assert( condition
.Class
== "ConditionStep")
439 local component
= r2
:getInstanceFromId(condition
.Entity
)
441 local rtNpcGrp
= r2
.Translator
.getRtGroup(context
, component
.InstanceId
)
445 if condition
.Condition
.Type
== "is active" then
446 local action1
= r2
.Translator
.createAction("if_value_equal", rtNpcGrp
.Id
, "Active", 1);
447 return action1
, action1
448 elseif condition
.Condition
.Type
== "is inactive" then
449 local action1
= r2
.Translator
.createAction("if_value_equal", rtNpcGrp
.Id
, "Active", 0);
450 return action1
, action1
451 elseif condition
.Condition
.Type
== "is finished" then
452 local action1
= r2
.Translator
.createAction("if_value_equal", rtNpcGrp
.Id
, "v3", 1);
453 return action1
, action1
459 component
.getLogicEvent
= function(this
, context
, event
)
460 assert( event
.Class
== "LogicEntityAction")
462 local rtNpcGrp
= r2
.Translator
.getRtGroup(context
, this
.InstanceId
)
465 local eventType
= tostring(event
.Event
.Type
)
467 local eventHandler
, lastCondition
= nil, nil
469 if eventType
== "success" then
470 return r2
.Translator
.getComponentUserEvent(rtNpcGrp
, 8)
473 return r2
.Translator
.getFeatureActivationLogicEvent(rtNpcGrp
, event
)
476 component
.createComponent
= function(x
, y
)
478 local questCompletedText
= i18n
.get("uiR2EdQuest_QuestCompletedText"):toUtf8()
480 local comp
= r2
.newComponent("Quest")
483 comp
.Base
= r2
.Translator
.getDebugBase("palette.entities.botobjects.bot_chat")
484 comp
.Name
= r2
:genInstanceName(i18n
.get("uiR2EdQuest")):toUtf8()
486 comp
.QuestCompletedText
= questCompletedText
491 comp
.Position
.z
= r2
:snapZToGround(x
, y
)
493 comp
._Seed
= os
.time()
498 component
.create
= function()
499 if r2
:getLeftQuota() <= 0 then
503 local function paramsOk(resultTable
)
506 local x
= tonumber( resultTable
["X"] )
507 local y
= tonumber( resultTable
["Y"] )
508 local showAgain
= tonumber(resultTable
["Display"])
511 if showAgain
== 1 then
512 r2
.setDisplayInfo("Quest", 0)
513 else r2
.setDisplayInfo("Quest", 1) end
517 debugInfo("Can't create Component")
520 local component
= feature
.Components
.Quest
.createComponent( x
, y
)
521 r2
:setCookie(component
.InstanceId
, "DisplayProp", 1)
522 r2
.requestInsertNode(r2
:getCurrentAct().InstanceId
, "Features", -1, "", component
)
525 local function paramsCancel()
526 debugInfo("Cancel form for 'Quest' creation")
528 local function posOk(x
, y
, z
)
529 debugInfo(string.format("Validate creation of 'Quest' at pos (%d, %d, %d)", x
, y
, z
))
530 if r2
.mustDisplayInfo("Quest") == 1 then
531 r2
.displayFeatureHelp("Quest")
533 r2
.requestNewAction(i18n
.get("uiR2EDNewQuestAction"))
534 local component
= feature
.Components
.Quest
.createComponent( x
, y
)
535 r2
:setCookie(component
.InstanceId
, "DisplayProp", 1)
536 r2
.requestInsertNode(r2
:getCurrentAct().InstanceId
, "Features", -1, "", component
)
538 local function posCancel()
539 debugInfo("Cancel choice 'Quest' position")
541 local creature
= r2
.Translator
.getDebugCreature("object_component_bot_chat.creature")
542 r2
:choosePos(creature
, posOk
, posCancel
, "createFeatureQuest")
546 function component
:registerMenu(logicEntityMenu
)
547 local name
= i18n
.get("uiR2EdQuest")
548 logicEntityMenu
:addLine(ucstring(name
), "lua", "", "Quest")
551 function component
:getLogicTranslations()
552 local logicTranslations
= {
553 ["ApplicableActions"] = {
554 ["activate"] = { menu
=i18n
.get( "uiR2AA0Activate" ):toUtf8(),
555 text
=i18n
.get( "uiR2AA1Activate" ):toUtf8()},
556 ["deactivate"] = { menu
=i18n
.get( "uiR2AA0Deactivate" ):toUtf8(),
557 text
=i18n
.get( "uiR2AA1Deactivate" ):toUtf8()},
558 ["validate current task"] = { menu
=i18n
.get( "uiR2AA0ValidateCurrentTask" ):toUtf8(),
559 text
=i18n
.get( "uiR2AA1ValidateCurrentTask" ):toUtf8()},
560 ["complete"] = { menu
=i18n
.get( "uiR2AA0CompleteQuest" ):toUtf8(),
561 text
=i18n
.get( "uiR2AA1CompleteQuest" ):toUtf8()},
564 ["activation"] = { menu
=i18n
.get( "uiR2Event0Activation" ):toUtf8(),
565 text
=i18n
.get( "uiR2Event1Activation" ):toUtf8()},
566 ["deactivation"] = { menu
=i18n
.get( "uiR2Event0Deactivation" ):toUtf8(),
567 text
=i18n
.get( "uiR2Event1Deactivation" ):toUtf8()},
568 ["success"] = { menu
=i18n
.get( "uiR2Event0TaskSuccess" ):toUtf8(),
569 text
=i18n
.get( "uiR2Event1TaskSuccess" ):toUtf8()},
572 ["is active"] = { menu
=i18n
.get( "uiR2Test0Active" ):toUtf8(),
573 text
=i18n
.get( "uiR2Test1Active" ):toUtf8()},
574 ["is inactive"] = { menu
=i18n
.get( "uiR2Test0Inactive" ):toUtf8(),
575 text
=i18n
.get( "uiR2Test1Inactive" ):toUtf8()},
576 ["is finished"] = { menu
=i18n
.get( "uiR2Test0TaskSuccess" ):toUtf8(),
577 text
=i18n
.get( "uiR2Test1TaskSuccess" ):toUtf8()},
580 return logicTranslations
584 r2
.Features
["Quest"] = feature