Merge branch 'fixes' into main/gingo-test
[ryzomcore.git] / ryzom / common / data_common / r2 / r2_features.lua
blob9ef14c1a6b4cc2833fcdb819f88721f7e6489a05
2 -- for client : register a component into C using the 'registerGenerator' function and add
3 -- it into the list of classes
6 -- copy class properties & methods
7 local reservedMembers = { Prop = true,
8 BaseClass = true,
9 NameToProp = true,
10 -- native properties
11 Parent = true,
12 ParentInstance= true,
13 IndexInParent = true,
14 User = true,
15 Size = true,
16 DisplayerUI = true,
17 DisplayerVisual = true,
18 DisplayerProperties = true,
19 Selectable = true,
20 SelectableFromRoot = true
23 -- check is a string is a valid identifier (e.g begin with an alphabetic letter followed by alpha numeric letters)
24 local function isValidIdentifier(id)
25 return string.match(id, "[%a_][%w_]*")
26 end
28 -- register a new class (features, components ...)
29 r2.registerComponent = function(generator, package)
30 -- check that all identifiers are correct
31 local badProps = {}
32 if generator.Prop == nil then
33 generator.Prop = {}
34 end
35 -- serach invalid identifiers
36 for k, prop in pairs(generator.Prop) do
38 if (type(prop) ~= "table") then
39 debugWarning("Invalid property found in ".. generator.Name)
40 end
42 if not isValidIdentifier( prop.Name ) then
43 debugWarning("Invalid property name found : '" .. tostring(prop.Name) ..
44 "' in class " .. tostring(generator.Name) .. ". Property is ignored")
45 table.insert(badProps, k)
46 end
47 if reservedMembers[prop.Name] then
48 debugWarning("Invalid property name found : '" .. tostring(prop.Name) ..
49 "' in class " .. tostring(generator.Name) .. ". This is the name of a native poperty, and can't be redefined")
50 table.insert(badProps, k)
51 end
52 end
53 -- check that no identifier is duplicated
54 local propName = {}
55 for k, prop in pairs(generator.Prop) do
56 if propName[prop.Name] ~= nil then
57 debugWarning("Duplicated property found when registering class " .. tostring(generator.Name) .. ", property = " .. tostring(prop.Name))
58 debugWarning("Aborting class registration.")
59 return
60 end
61 propName[prop.Name] = true
62 end
63 -- remove bad properties from the class
64 for k, prop in pairs(badProps) do
65 generator.Prop[prop] = nil
66 end
68 local name = nil
70 if package then
71 name = generator.Name
72 --name = package:getUniqId() .. "|" .. generator.Name TODO
73 else
74 name = generator.Name;
75 end
77 if r2.Classes[name] ~= nil then
78 debugWarning("Component registered twice : " .. generator.Name)
79 return
80 end
81 if type(name) ~= "string" then
82 debugWarning("Can't register class, 'Name' field not found or bad type")
83 assert(false)
84 end
85 r2.Classes[name] = generator
86 end
88 -- private : perform subclassing by copying properties / methods of the base class into the class passed as a parameter
89 -- only methods / props that are present in the base class and not in the derived class are copied
90 -- subclass is done recursively so after calling 'subclass' on a class definition it will be complete
91 function r2.Subclass(classDef)
92 assert(classDef)
93 assert(type(classDef) == "table")
94 if classDef.BaseClass ~= "" and classDef.BaseClass ~= nil then
95 local baseClass = r2.Classes[classDef.BaseClass]
96 if baseClass == nil then
97 debugInfo("Cant found base class " .. strify(classDef.BaseClass) .. " of class " .. strify(classDef.Name))
98 return
99 end
100 --debugInfo("sub classing " .. tostring(classDef.Name) .. " from " .. tostring(baseClass.Name))
101 -- make sure that base class is complete, too
102 r2.Subclass(baseClass)
103 for key, value in pairs(baseClass) do
104 if classDef[key] == nil then
105 -- if property or method not defined in derived class then copy from the base class
106 -- if this is a method, then just replace with a function that will delegate
107 -- the call to the parent class
108 --if type(value) == "function" and key ~= "delegate" then
109 -- assert(type(key) == "string")
110 -- local localKey = key -- apparently, closure are not supported with locals from the enclosing 'for' loop
111 -- local function delegator(this, ...)
112 --debugInfo("Calling parent version in parent class '" .. tostring(baseClass.Name) .. "' for " .. tostring(localKey))
113 -- TODO nico : here if would be much faster to call the
114 -- first parent class where function is defined instead
115 -- of chaining the calls to 'delegate'
116 -- There are 1 thing to rememeber however :
117 -- * The this pointer could be a delegated one,
118 -- so when doing the call directly this should be with the non-delgated this (to have a polymorphic call)
120 -- local delegated = this:delegate()
121 -- return delegated[localKey](delegated, unpack(arg))
122 -- end
123 -- classDef[key] = delegator
124 --else
125 classDef[key] = value
126 --end
127 end
129 -- copy instances properties
130 assert(classDef.NameToProp)
131 assert(baseClass.NameToProp)
132 for key, prop in pairs(baseClass.Prop) do
133 -- if property not declared in derived class then add it
134 if classDef.NameToProp[prop.Name] == nil then
135 -- its okay to make a reference here because classes definitions are read-only
136 classDef.NameToProp[prop.Name] = prop
137 table.insert(classDef.Prop, prop)
141 -- else no-op
144 function r2.getLoadedFeaturesStatic()
145 local loadedFeatures =
147 --Mob Spawners
148 {"r2_features_boss_spawner.lua", "BossSpawnerFeature", "uiR2EdMobSpawnersCategory"},
149 {"r2_features_timed_spawn.lua", "TimedSpawner", "uiR2EdMobSpawnersCategory"},
150 {"r2_features_scenery_object_remover.lua", "SceneryObjectRemoverFeature", "uiR2EdMobSpawnersCategory"},
152 --Chests
153 {"r2_features_easter_egg.lua", "EasterEggFeature", "uiR2EdChestsCategory"},
154 {"r2_features_random_chest.lua", "RandomChest", "uiR2EdChestsCategory"},
155 {"r2_features_get_item_from_scenery.lua", "GetItemFromSceneryObject", "uiR2EdChestsCategory"},
158 --Tasks
159 {"r2_features_give_item.lua", "GiveItemFeature", "uiR2EdTaskStepCategory"},
160 {"r2_features_talk_to.lua", "TalkToFeature", "uiR2EdTaskStepCategory"},
161 {"r2_features_request_item.lua", "RequestItemFeature", "uiR2EdTaskStepCategory"},
162 {"r2_features_visit_zone.lua", "VisitZone", "uiR2EdTasksCategory"},
163 {"r2_features_target_mob.lua", "TargetMob", "uiR2EdTasksCategory"},
164 {"r2_features_kill_npc.lua", "KillNpc", "uiR2EdTasksCategory"},
165 {"r2_features_hunt_task.lua", "HuntTask", "uiR2EdTasksCategory"},
166 {"r2_features_delivery_task.lua", "DeliveryTask", "uiR2EdTasksCategory"},
167 {"r2_features_get_item_from_scenery_task.lua", "GetItemFromSceneryObjectTaskStep", "uiR2EdTaskStepCategory"},
168 {"r2_features_scenery_object_interaction_task.lua", "SceneryObjectInteractionTaskStep", "uiR2EdTaskStepCategory"},
171 --Triggers
172 {"r2_features_timer.lua", "TimerFeature", "uiR2EdTriggersCategory"},
173 {"r2_features_zone_triggers.lua", "ZoneTrigger", "uiR2EdTriggersCategory"},
174 {"r2_features_user_trigger.lua", "UserTriggerFeature", "uiR2EdTriggersCategory"},
175 {"r2_features_man_hunt.lua", "ManHuntFeature", "uiR2EdTriggersCategory"},
176 {"r2_features_scenery_object_interaction.lua", "SceneryObjectInteractionFeature", "uiR2EdTriggersCategory"},
177 {"r2_features_proximity_dialog.lua", "ChatSequence", "uiR2EdTriggersCategory"},
178 --{"r2_features_reward_provider.lua", "RewardProvider", "uiR2EdTriggersCategory"},
180 --MacroComponents
181 {"r2_features_ambush.lua", "Ambush", "uiR2EdMacroComponentsCategory"},
182 {"r2_features_loot_spawner.lua", "LootSpawnerFeature", "uiR2EdMacroComponentsCategory"},
183 {"r2_features_hidden_chest.lua", "HiddenChest", "uiR2EdMacroComponentsCategory"},
184 {"r2_features_proximity_dialog.lua", "ProximityDialog", "uiR2EdMacroComponentsCategory"},
185 {"r2_features_bandits_camp.lua", "BanditCampFeature", "uiR2EdMacroComponentsCategory"},
186 {"r2_features_fauna.lua", "FaunaFeature", "uiR2EdMacroComponentsCategory"},
189 return loadedFeatures
192 function r2.doFileProtected(filename)
193 local ok, msg = pcall(r2.doFile, filename)
194 if not ok then
195 debugInfo("Error while loading component '"..filename.."' err: "..msg)
200 r2.loadFeatures = function()
202 r2.doFileProtected("r2_features_default.lua")
204 r2.doFileProtected("r2_features_npc_groups.lua")
205 r2.doFileProtected("r2_features_counter.lua")
206 r2.doFileProtected("r2_features_reward_provider.lua")
208 --Loading features
209 r2.doFileProtected("r2_features_loaded.lua")
211 local loadedFeatures = r2.getLoadedFeaturesStatic()
212 local k, v = next(loadedFeatures, nil)
213 while k do
214 if v and v[1] then
215 r2.doFileProtected(v[1])
217 k, v = next(loadedFeatures, k)
220 if config.R2EDLoadDynamicFeatures == 1 then
221 local loadedFeatures = r2.getLoadedFeaturesDynamic()
222 local k, v = next(loadedFeatures, nil)
223 while k do
224 if v and v[1] then
225 r2.doFileProtected(v[1])
227 k, v = next(loadedFeatures, k)
231 r2.doFileProtected("r2_texts.lua")
232 r2.doFileProtected("r2_logic.lua")
233 r2.doFileProtected("r2_logic_entities.lua")
234 r2.doFileProtected("r2_event_handler_system.lua")
235 r2.doFileProtected("r2_unit_test.lua")
237 r2.doFileProtected("r2_core_user_component_manager.lua")
238 --r2_core.UserComponentManager:init()
240 --debugInfo("REGISTERING FEATURES")
241 r2.UserComponentsManager:updateUserComponents()
243 local featureId, feature = next(r2.Features, nil)
244 while (featureId ~= nil)
246 --debugInfo("Registering feature " .. feature.Name)
247 local componentId, component = next(feature.Components, nil)
248 while (component ~= nil)
250 --debugInfo(" Registering feature component " .. component.Name)
251 r2.registerComponent(component)
252 componentId, component = next(feature.Components, componentId)
255 featureId, feature = next(r2.Features, featureId);
259 -- Function to init default scenario stuffs, with the given client ID
260 -- tmp : returns ids for the scenario, the first act, and the default group
261 r2.initBaseScenario = function()
263 local function ici(index)
264 -- debugInfo(colorTag(255, 255, 0) .. "ICI " .. tostring(index))
266 -- create scenario
267 ici(1)
268 local scenario= r2.newComponent("Scenario")
269 if (scenario == nil) then
270 debugWarning("Failed to create Scenario");
271 return
273 ici(2)
274 --debugInfo("Scenario created with id " .. scenario.InstanceId)
275 scenario.title = "TestMap"
276 scenario.shortDescription = "TestMap"
277 scenario.optimalNumberOfPlayer = 1
278 -- create first act & default feature group
281 local act =r2.newComponent("Act")
282 act.States = {}
283 if (act == nil) then
284 debugWarning("Failed to create first 'Act'");
285 return
286 end
288 local features = act.Features
289 local tmpDefault = r2.newComponent("DefaultFeature")
290 if (tmpDefault == nil) then
291 debugWarning("Failed to create default feature");
292 return
294 table.insert(features, tmpDefault)
295 table.insert(scenario.Acts, act)
299 -- By default create act I and have it selected
302 local act =r2.newComponent("Act")
303 -- force to select the act 1 at display
304 r2.ActUIDisplayer.LastSelfCreatedActInstanceId = act.InstanceId
305 act.States = {}
306 if (act == nil) then
307 debugWarning("Failed to create secondary 'Act'");
308 return
309 end
312 act.Name = i18n.get("uiR2EDAct1"):toUtf8()
313 act.Title = i18n.get("uiR2EDAct1"):toUtf8() -- obsolete
315 local features = act.Features
316 local tmpDefault = r2.newComponent("DefaultFeature")
317 if (tmpDefault == nil) then
318 debugWarning("Failed to create default feature");
319 return
321 table.insert(features, tmpDefault)
322 table.insert(scenario.Acts, act)
324 r2.requestCreateScenario(scenario)
328 -- called by the frame work to reset the current scenario
329 -- function r2.resetScenario()
331 -- do
333 -- r2.requestEraseNode(r2.ScenarioInstanceId, "Acts" )
336 -- local acts= {}
338 -- do
339 -- local act =r2.newComponent("Act")
340 -- local features = act.Features
341 -- local tmpDefault = r2.newComponent("DefaultFeature")
342 -- table.insert(features, tmpDefault)
343 -- table.insert(acts, act)
344 -- end
345 -- do
346 -- local act =r2.newComponent("Act")
347 -- local features = act.Features
348 -- local tmpDefault = r2.newComponent("DefaultFeature")
349 -- r2.ActUIDisplayer.LastSelfCreatedActInstanceId = act.InstanceId
350 -- act.Title = i18n.get("uiR2EDAct1"):toUtf8()
351 -- table.insert(features, tmpDefault)
352 -- table.insert(acts, act)
353 -- -- table.insert(scenario.Acts, act)
354 -- end
357 -- r2.requestInsertNode(r2.ScenarioInstanceId, "", -1, "Acts", acts)
358 -- r2.requestReconnection()
359 -- end
360 --end
363 -- called when a gm/ai has do a scheduleStartAct (Animation or test time)
364 function r2.onScheduleStartAct(errorId, actId, nbSeconds)
365 if (r2.Mode == "DM" or r2.Mode == "AnimationModeDm") then
366 if errorId == 0 then
367 local ucStringMsg = ucstring()
369 local str = "Act " .. actId
370 if nbSeconds ~= 0 then
371 str = str .. " will start in " .. nbSeconds .. " seconds"
373 ucStringMsg:fromUtf8(str)
374 displaySystemInfo(ucStringMsg, "BC")
375 elseif errorId == 1 then
376 messageBox("Act ".. actId .." can not be started because another act is already starting.")
377 elseif errorId == 2 then
378 messageBox("Act ".. actId .." can not be started because this act does not exist.")
383 function r2.onDisconnected()
384 local str = "You have been disconnected by the server."
385 local ucStringMsg = ucstring()
386 messageBox(str)
387 ucStringMsg:fromUtf8(str)
388 displaySystemInfo(ucStringMsg, "BC")
391 function r2.onKicked(timeBeforeDisconnection, kicked)
392 if kicked then
393 local str = "You have been kicked. You must come back to mainland or leave this session otherwise you will be disconnected in "
394 .. tostring(timeBeforeDisconnection) .. " secondes."
395 local ucStringMsg = ucstring()
396 messageBox(str)
397 ucStringMsg:fromUtf8(str)
398 displaySystemInfo(ucStringMsg, "BC")
399 else
400 local str = "You have been unkicked."
401 local ucStringMsg = ucstring()
402 messageBox(str)
403 ucStringMsg:fromUtf8(str)
404 displaySystemInfo(ucStringMsg, "BC")
409 -- called in start mode of a dm
410 function r2.onRuntimeActUpdated(runtimeAct)
411 -- use runtimeAct or r2.getRunTimeActs()
412 r2.AnimGlobals.Acts = runtimeAct
413 -- update the ui
414 r2.ui.AnimBar:update()
417 function r2.onTalkingAsListUpdated()
418 r2.ui.AnimBar:updateDMControlledEntitiesWindow()
423 function r2.onIncarnatingListUpdated()
424 r2.ui.AnimBar:updateDMControlledEntitiesWindow()
428 function r2.onScenarioHeaderUpdated(scenario)
429 local ui=getUI('ui:interface:r2ed_scenario_control')
430 if ui.active == true then
431 ui.active = false
432 ui.active = true
435 -- inspect(scenario)
436 -- or use r2.getScenarioHeader();
439 function r2.onSystemMessageReceived(msgType, msgWho, msg)
441 local ucStringMsg = ucstring()
442 ucStringMsg:fromUtf8(msg)
443 if string.len(msg) > 2 and string.sub(msg, 1, 2) == "ui" then
444 ucStringMsg = i18n.get(msg)
445 msg = ucStringMsg:toString()
447 if msgType == "BC" or msgType == "BC_ML" then
448 printMsgML(msg)
449 elseif msgType == "SYS" or msgType == "DM" then
451 local str = ""
452 if msgType == "DM" then
453 str = "(AM ONLY)"..str
454 if (r2.Mode ~= "DM" and r2.Mode ~= "AnimationModeDm") then return end
457 if string.len(msgWho) ~= 0 then
458 str = str .. msgWho .. ": "
461 str = str.. msg
462 printMsgML(msg)
463 elseif msgType == "ERR" then
464 printMsgML(msg)
465 messageBox(msg)
472 -- TMP : place holder function to know the current act
473 if not r2.getCurrentActIndex then
474 debugInfo("Creating place holder for r2.getCurrentActIndex")
475 function r2.getCurrentActIndex()
476 return 1
480 function r2.onUserTriggerDescriptionUpdated(userTrigger)
481 -- use userTrigger or r2.getUserTriggers()
482 r2.AnimGlobals.UserTriggers = userTrigger
483 r2.ui.AnimBar:update()
486 function r2.onCurrentActIndexUpdated( actIndex)
487 -- actIndex==r2.getCurrentActIndex())
490 -- called when a session has begin but no scenario has been created
491 function r2.onEmptyScenarioUpdated()
492 if r2.Mode == "AnimationModeLoading" then
493 UnitTest.testLoadAnimationScenarioUi()
495 elseif r2.Mode == "AnimationModeWaitingForLoading" then
496 UnitTest.testWaitAnimationScenarioLoadingUi()
497 else
498 --UnitTest.testCreateScenarioUi()
499 r2.acts:openScenarioActEditor(true, true)
503 -- called by the framework when the scenario has been updated
504 function r2.onScenarioUpdated(scenario, startingActIndex)
506 --luaObject(scenario)
507 --breakPoint()
509 if (scenario == nil) then
510 r2.onEmptyScenarioUpdated()
511 return
512 else
513 hide('ui:interface:r2ed_form_CreateNewAdventureStep2')
516 r2.Scenario = r2:getInstanceFromId(scenario.InstanceId)
517 r2.ScenarioInstanceId = scenario.InstanceId
519 -- add permanent nodes to act node
520 r2:defaultUIDisplayer():addPermanentNodes()
522 if r2.Version.updateVersion() then
523 r2.setScenarioUpToDate(true)
524 else
525 r2.setScenarioUpToDate(false)
528 local currentAct = nil
530 assert(startingActIndex);
531 assert( type(startingActIndex) == "number");
533 if startingActIndex < table.getn(scenario.Acts) then
534 r2.DefaultActInstanceId = scenario.Acts[startingActIndex].InstanceId
535 r2.ActUIDisplayer.LastSelfCreatedActInstanceId = scenario.Acts[startingActIndex].InstanceId
536 if scenario.Acts[startingActIndex].Features.Size > 0 then
537 r2.DefaultFeatureInstanceId = scenario.Acts[startingActIndex].Features[0].InstanceId
539 currentAct=scenario.Acts[startingActIndex]
541 r2.ScenarioWindow:setAct(currentAct)
542 else
543 r2.DefaultActInstanceId = scenario.Acts[0].InstanceId
544 r2.ActUIDisplayer.LastSelfCreatedActInstanceId = scenario.Acts[0].InstanceId
545 if scenario.Acts[0].Features.Size > 0 then
546 r2.DefaultFeatureInstanceId = scenario.Acts[0].Features[0].InstanceId
548 currentAct=scenario.Acts[0]
552 if scenario ~= nil and currentAct ~= nil then
553 r2.Scenario.User.SelectedActInstanceId = tostring(currentAct.InstanceId)
554 r2.Scenario.User.SelectedLocationInstanceId = tostring(currentAct.LocationId)
557 r2.ScenarioWindow:updateScenarioProperties()
558 -- usefull to know if the scenario is updating
559 ld.lock = 0
561 if not r2.RingAccess.LoadAnimation and not r2.getIsAnimationSession() then
562 local ok, level, err = r2.RingAccess.verifyScenario()
563 r2.updateScenarioAck(ok, level, err.What)
564 return
567 r2.acts.deleteOldScenario = false
569 if r2.getUseVerboseRingAccess() then
570 r2.RingAccess.dumpRingAccess()
575 function r2.verifyScenario()
576 local ok, level, err = r2.RingAccess.verifyScenario()
577 local msg=""
578 if not ok then
579 printMsg(err.What)
580 msg = err.What
581 end
582 return ok, msg
585 function r2.printMsg(msg)
586 r2.printMsg(msg)
589 -- assign default menu for each classes
590 function r2.initDefaultMenuSetup()
591 forEach(r2.Classes,
592 function(k, v)
593 if v.Menu ~= nil and v.onSetupMenu == nil then
594 v.onSetupMenu = r2.defaultMenuSetup
600 -- assign default menu for each classes
601 function r2.initDefaultPropertyDisplayer()
602 for k, class in pairs(r2.Classes) do
603 if class.BuildPropertySheet == true then
604 if class.DisplayerProperties == nil then
605 class.DisplayerProperties = "R2::CDisplayerLua"
606 class.DisplayerPropertiesParams = "propertySheetDisplayer"
612 -- setup the classes
613 function r2.setupClasses()
614 -- first build a table that gives access to a property from its name
615 for k, class in pairs(r2.Classes) do
616 class.NameToProp = {}
617 for k, prop in pairs(class.Prop) do
618 if prop.Name == nil then
619 debugInfo("Found a property in class " .. tostring(class.Name) .. " with no field 'Name'")
621 class.NameToProp[prop.Name] = prop
624 -- perform subclassing
625 for k, class in pairs(r2.Classes) do
626 r2.Subclass(class)
628 -- register into C
629 for k, class in pairs(r2.Classes) do
630 r2.registerGenerator(class)
636 -- returns a table which map each instanceId of the scenario component's to each component
637 r2.createComponentsMap = function (scenario)
638 function createComponentsMapImpl (t, components)
639 if ( type(t) == "table")
640 then
641 if (t.InstanceId ~= nil)
642 then
643 components[t.InstanceId] = t
645 for key, value in pairs(t) do
646 createComponentsMapImpl(value, components)
650 local components = {}
651 createComponentsMapImpl(scenario, components)
652 return components
658 r2.updateActCost = function(act)
659 assert(act)
660 local cost = 0
661 local staticCost = 0
662 local features = act.Features
663 assert(features ~= nil )
664 local featureId, feature = next(features, nil)
665 while (featureId ~= nil)
667 -- feature:getCost() is obsolete
668 if feature.User.GhostDuplicate ~= true then
669 if feature and feature.getAiCost then
670 local added = feature:getAiCost()
671 if added then
672 cost = cost + added
675 if feature and feature.getStaticObjectCost then
676 local added = feature:getStaticObjectCost()
677 if added then
678 staticCost = staticCost + added
682 featureId, feature = next(features, featureId)
685 -- NB nico : removed cost from the real object and put is in the 'User' table (interfere with undo redo, because considered
686 -- as an action)
688 act:setLocalCost(cost)
689 --if (act.Cost ~= cost) then
690 -- r2.requestSetLocalNode(act.InstanceId, "Cost", cost)
691 -- r2.requestCommitLocalNode(act.InstanceId, "Cost")
692 --end
694 act:setLocalStaticCost(staticCost)
695 --if (act.StaticCost ~= staticCost) then
696 -- r2.requestSetLocalNode(act.InstanceId, "StaticCost", staticCost)
697 -- r2.requestCommitLocalNode(act.InstanceId, "StaticCost")
698 --end
705 r2.registerText = function(text)
707 --TODO : when several texts are registered "at the same time", the local scenario
708 --has not the time to receive the changes, and a new entry is created.
710 local checkText = r2.Features["TextManager"].checkText
711 local textMgr = getTextMgr()
712 if(textMgr==nil)
713 then
714 debugInfo("text mgr nil!!")
716 local result = checkText(textMgr,text)
717 if result.Count ~= 0
718 then
720 --the entry already exist, just increment the counter
721 r2.requestSetNode(result.InstanceId,"Count",result.Count+1)
722 --temporaire
723 --result.Count = result.Count + 1
724 --/temporaire
725 debugInfo("Entry already exist")
726 else
727 --the entry don't exist, insert it
728 result.Count=1
729 -- debugInfo("New entry created")
730 r2.requestInsertNode(r2.Scenario.Texts.InstanceId,"Texts",-1,"",result)
732 --temporaire
733 --table.insert(r2.TextMgr.Texts,result)
734 --temporaire
736 return result
739 getTextMgr = function()
740 --return r2.TextMgr
741 return r2.Scenario.Texts
744 r2.unregisterText = function(text)
746 local removeText = r2.Features["TextManager"].removeText
747 removeText(r2.Scenario.Texts,text)
750 r2.unregisterTextFromId = function(id)
752 local text = r2.getText(id)
753 if text ~= nil
754 then
755 r2.unregisterText(text)
759 r2.getText = function(id)
760 local textMgr = getTextMgr()
761 return r2.Features["TextManager"].getText(textMgr, id)
764 r2.split = function(str, sep)
765 assert( type(str) == "string")
766 local ret = {}
767 local start=0
768 if sep == nil then sep = "\n" end
769 local fin=string.find(str, sep)
771 while fin ~= nil do
772 local tmp = string.sub(str,start,fin-1)
773 if string.len(tmp)~=0
774 then
775 table.insert(ret,tmp)
777 start = fin+1
778 fin = string.find(str,sep,start)
781 if start<string.len(str)
782 then
783 local tmp =string.sub(str,start)
784 if string.len(tmp)~=0
785 then
786 table.insert(ret,tmp)
789 return ret
792 r2.dumpAI = function(rtAct, rtGrp)
793 if 1 == 0
794 then
796 local event = Actions.createEvent("timer_t0_triggered", "", rtGrp.Id)
798 local action = Actions.createAction("code","print(\"timer_t0_triggered\");\n"
799 .. "print(\"--------".. rtGrp.Id .. "---\");\n"
800 .. "print(\"oldActivitySequenceVar:\",oldActivitySequenceVar);\n"
801 .. "print(\"currentActivitySequenceVar:\",currentActivitySequenceVar);\n"
802 .. "print(\"oldActivityStepVar:\", oldActivityStepVar);\n"
803 .. "print(\"v2:\",v2);\n"
804 .. "print(\"oldChatStepVar:\", oldChatStepVar);\n"
805 .. "print(\"v1:\",v1);\n"
806 .. "print(\"oldChatSequenceVar:\", oldChatSequenceVar);\n"
807 .. "print(\"v0:\",v0);\n"
808 .. "print(\"----------------\");\n"
812 table.insert(rtAct.Actions, action)
813 table.insert(rtAct.Events, event)
814 table.insert(event.ActionsId, action.Id)
818 local event = Actions.createEvent("timer_t1_triggered", "", rtGrp.Id)
820 local action = Actions.createAction("code", "print(\"timer_t1_triggered\");\n"
821 .. "print(\"--------".. rtGrp.Id .. "---\");\n"
822 .. "print(\"oldActivitySequenceVar:\",oldActivitySequenceVar);\n"
823 .. "print(\"currentActivitySequenceVar:\",currentActivitySequenceVar);\n"
824 .. "print(\"oldActivityStepVar:\",oldActivityStepVar);\n"
825 .. "print(\"v2:\",v2);\n"
826 .. "print(\"oldChatStepVar:\",oldChatStepVar);\n"
827 .. "print(\"v1:\",v1);\n"
828 .. "print(\"oldChatSequenceVar:\",oldChatSequenceVar);\n"
829 .. "print(\"v0:\",v0);\n"
830 .. "print(\"----------------\");\n"
833 table.insert(rtAct.Actions, action)
834 table.insert(rtAct.Events, event)
835 table.insert(event.ActionsId, action.Id)
839 local event = Actions.createEvent("variable_v0_changed", "", rtGrp.Id)
841 local action = Actions.createAction("code", "print(\"variable_v0_changed\");\n"
842 .. "print(\"--------".. rtGrp.Id .. "---\");\n"
843 .. "print(\"oldActivitySequenceVar:\",oldActivitySequenceVar);\n"
844 .. "print(\"currentActivitySequenceVar:\",currentActivitySequenceVar);\n"
845 .. "print(\"oldActivityStepVar:\",oldActivityStepVar);\n"
846 .. "print(\"v2:\",v2);\n"
847 .. "print(\"oldChatStepVar:\",oldChatStepVar);\n"
848 .. "print(\"v1:\",v1);\n"
849 .. "print(\"oldChatSequenceVar:\",oldChatSequenceVar);\n"
850 .. "print(\"v0:\",v0);\n"
851 .. "print(\"----------------\");\n"
854 table.insert(rtAct.Actions, action)
855 table.insert(rtAct.Events, event)
856 table.insert(event.ActionsId, action.Id)
860 local event = Actions.createEvent("variable_v1_changed", "", rtGrp.Id)
862 local action = Actions.createAction("code", "print(\"variable_v1_changed\");\n"
863 .. "print(\"--------".. rtGrp.Id .. "---\");\n"
864 .. "print(\"oldActivitySequenceVar:\",oldActivitySequenceVar);\n"
865 .. "print(\"currentActivitySequenceVar:\",currentActivitySequenceVar);\n"
866 .. "print(\"oldActivityStepVar:\",oldActivityStepVar);\n"
867 .. "print(\"v2:\",v2);\n"
868 .. "print(\"oldChatStepVar:\",oldChatStepVar);\n"
869 .. "print(\"v1:\",v1);\n"
870 .. "print(\"oldChatSequenceVar:\",oldChatSequenceVar);\n"
871 .. "print(\"v0:\",v0);\n"
872 .. "print(\"----------------\");\n"
875 table.insert(rtAct.Actions, action)
876 table.insert(rtAct.Events, event)
877 table.insert(event.ActionsId, action.Id)
882 local event = Actions.createEvent("variable_v2_changed", "", rtGrp.Id)
884 local action = Actions.createAction("code", "print(\"variable_v2_changed\");\n"
885 .. "print(\"--------".. rtGrp.Id .. "---\");\n"
886 .. "print(\"oldActivitySequenceVar:\",oldActivitySequenceVar);\n"
887 .. "print(\"currentActivitySequenceVar:\",currentActivitySequenceVar);\n"
888 .. "print(\"oldActivityStepVar:\",oldActivityStepVar);\n"
889 .. "print(\"v2:\",v2);\n"
890 .. "print(\"oldChatStepVar:\",oldChatStepVar);\n"
891 .. "print(\"v1:\",v1);\n"
892 .. "print(\"oldChatSequenceVar:\",oldChatSequenceVar);\n"
893 .. "print(\"v0:\",v0);\n"
894 .. "print(\"----------------\");\n"
897 table.insert(rtAct.Actions, action)
898 table.insert(rtAct.Events, event)
899 table.insert(event.ActionsId, action.Id)
906 if r2.getInstanceFromId == nil
907 then
908 r2.getInstanceFromId = function(instanceId)
910 local function look(node,instanceId)
911 if node.InstanceId ~=nil
912 then
913 -- debugInfo("looking in "..node.InstanceId)
914 else
915 -- debugInfo("no instance id!!")
917 --look if this node is the good one
918 if node.InstanceId == instanceId
919 then
920 --then return it
921 return node
922 else
923 --else, look in its children
924 local children = node.Children
925 if children == nil
926 then
927 return nil
928 else
929 local max = table.getn(children)
930 for i=1,max do
931 local tmp = look(children[i],instanceId)
932 if tmp ~=nil
933 then
934 return tmp
940 local tmp = look(r2.Scenario,instanceId)
941 if tmp~=nil
942 then
943 return tmp
945 tmp = look(r2.Scenario.Acts,instanceId)
946 if tmp~=nil
947 then
948 return tmp
950 tmp = look(r2.Scenario.Texts,instanceId)
951 if tmp~=nil
952 then
953 return tmp
955 return nil
962 r2.getAiCost = function(instance)
963 -- if the object is a ghost duplicate (when shift-dragging for exemple),
964 -- don't take the cost into acount
965 if instance.User.GhostDuplicate then return 0 end
966 local cost = 1
967 local components = instance.Components
969 if components and table.getn(components) ~= 0 then
970 local key, value = next(components, nil)
971 while key do
972 if value.getAiCost then
973 cost = cost + value:getAiCost()
975 key, value = next(components, key)
979 local ghosts = instance.Ghosts
980 if ghosts and table.getn(ghosts) ~= 0 then
981 local key, value = next(ghosts, nil)
982 while key do
983 if value.getAiCost then
984 cost = cost + value:getAiCost()
986 key, value = next(ghosts, key)
989 return cost
992 r2.getStaticObjectCost = function(instance)
993 -- if the object is a ghost duplicate (when shift-dragging for exemple),
994 -- don't take the cost into acount
995 if instance.User.GhostDuplicate then return 0 end
996 local cost = 0
997 local components = instance.Components
999 if components and table.getn(components) ~= 0 then
1000 local key, value = next(components, nil)
1001 while key do
1002 if value.getStaticObjectCost then
1003 cost = cost + value:getStaticObjectCost()
1005 key, value = next(components, key)
1008 return cost
1009 end
1011 --r2.displayFeatureHelp = function(title, help)
1012 r2.displayFeatureHelp = function(className)
1014 local title = "uiR2Ed"..className.."_HelpTitle"
1016 local test = i18n.get(title)
1017 if not test then
1018 debugInfo("Entry not found in translation file")
1019 assert(nil)
1022 local help = "uiR2Ed"..className.."_HelpText"
1023 test = i18n.hasTranslation(help)
1024 if not test then
1025 debugInfo("Entry not found in translation file")
1026 assert(nil)
1029 local checkBox = getUI("ui:interface:feature_help:content:custom_bbox_enabled")
1030 assert(checkBox)
1031 local chkBoxText = getUI("ui:interface:feature_help:content:text_custom")
1032 assert(chkBoxText)
1034 if className == "Npc" then
1035 debugInfo("ClassName = " ..className)
1036 checkBox.active = false
1037 chkBoxText.active = false
1038 else
1039 checkBox.active = true
1040 chkBoxText.active = true
1041 local pushed = false
1042 if r2.mustDisplayInfo(className) == 1 then pushed = true end
1043 checkBox.pushed = pushed
1046 local uiInfo = getUI("ui:interface:feature_help")
1048 --local scrW, scrH = getWindowSize()
1049 --uiInfo.x = 0
1050 --uiInfo.y = scrH
1051 --uiInfo.h = scrH / 2
1052 --uiInfo.pop_min_h= scrH / 2
1053 --uiInfo.pop_max_h= scrH / 2
1054 uiInfo.active = true
1055 uiInfo:invalidateCoords()
1056 uiInfo:updateCoords()
1057 uiInfo.title = title
1058 uiInfo.Env.uc_title = title
1059 local uiText = getUI("ui:interface:feature_help:content:enclosing:help_text_enclosed:help_text")
1060 assert(uiText)
1061 uiText.uc_hardtext_format = ucstring(i18n.get(help))
1062 uiInfo:invalidateCoords()
1063 uiInfo:updateCoords()
1065 --local textH = uiText.h_real
1066 --local localH = textH + 90
1067 --if localH > scrH then
1068 -- localH = scrH
1069 --end
1070 --uiInfo.h = localH
1071 --uiInfo.pop_min_h= localH
1072 --uiInfo.pop_max_h= localH
1074 uiInfo:invalidateCoords()
1075 uiInfo:updateCoords()
1076 uiInfo:center()
1078 setTopWindow(uiInfo)
1082 function r2.setFeatureDisplayHelp()
1084 local checkBox = getUI("ui:interface:feature_help:content:custom_bbox_enabled")
1085 assert(checkBox)
1086 local isChecked = checkBox.pushed
1087 debugInfo("checked: " ..tostring(isChecked))
1089 local ui = getUI("ui:interface:feature_help")
1090 local name = ui.Env.uc_title
1091 local len = string.len(name) - 10 - 6
1092 local className = string.sub(name, -10-len, 6+len) --removing uiR2Ed and _HelpTitle
1093 --formName = formName .."Form"
1095 assert(className)
1096 --debugInfo("Form name: " ..formName)
1098 if isChecked == false then
1099 r2.setDisplayInfo(className, 1)
1100 else r2.setDisplayInfo(className, 0) end
1104 function r2.getDisplayButtonHeader(func, buttonText)
1105 local header =
1106 string.format(
1108 <ctrl style="text_button_16" id="help" posref="TL TL" color="255 255 255 255" col_over="255 255 255 255" col_pushed="255 255 255 255"
1109 onclick_l="lua" params_l="%s" hardtext="%s"/>
1110 ]], func, buttonText)
1112 return header
1115 function r2.updateLogicEvents(this, invalidEvents)
1116 assert(invalidEvents)
1117 assert(this)
1119 local actions = this.Behavior.Actions
1120 assert(actions)
1123 local function updateLogicEvent(k, action)
1125 local event = action.Event
1126 assert(event)
1127 if invalidEvents[event.Type] then
1128 local instanceId = tostring(event.InstanceId)
1129 r2.requestSetNode(instanceId, "Type", tostring(invalidEvents[event.Type]))
1133 forEach(actions, updateLogicEvent)
1137 function r2.updateLogicActions(this, invalidActions, entityClass)
1138 assert(invalidActions)
1139 assert(this)
1140 assert(entityClass)
1142 local instance = r2:getInstanceFromId(this.Entity)
1143 if not instance or not instance:isKindOf(entityClass) then
1144 return
1147 local action = this.Action
1148 assert(action)
1150 if invalidActions[action.Type] then
1151 r2.requestSetNode(action.InstanceId, "Type", invalidActions[action.Type])
1156 function r2.onRingAccessUpdated(access)
1157 r2:buildPaletteUI()
1158 r2.acts:initActsEditor()
1159 updateBanditCampEnum()
1160 -- also available by r2.getRingAccess()
1163 function r2:checkAiQuota(size)
1165 if not size then size = 1 end
1166 local leftQuota, leftAIQuota, leftStaticQuota = r2:getLeftQuota()
1168 if leftAIQuota < size then
1169 displaySystemInfo(i18n.get("uiR2EDMakeRoomAi"), "BC")
1171 return false
1173 return true
1176 function r2:checkStaticQuota(size)
1177 if not size then size = 1 end
1178 local leftQuota, leftAIQuota, leftStaticQuota = r2:getLeftQuota()
1179 if leftStaticQuota < size then
1180 displaySystemInfo(i18n.get("uiR2EDMakeRoomStaticObject"), "BC")
1181 return false
1183 return true
1186 function r2.DisplayNpcHeader()
1187 local npc = r2:getSelectedInstance()
1188 if not npc then
1189 return ""
1192 if npc:isGrouped() then
1193 local header =
1195 <view type="text" id="t" multi_line="true" sizeref="w" w="-36" x="4" y="-2" posref="TL TL" global_color="true" fontsize="12" shadow="true" hardtext="uiR2EdNpcHeader"/>
1197 return header
1198 else
1199 return ""
1204 function r2.mustDisplayProp(prop)