Merge branch 'fixes' into main/gingo-test
[ryzomcore.git] / ryzom / common / data_common / r2 / r2_features_fauna.lua
blob3ebc561a3ea1fb41d620e3965291082c4e389c3b
1 --
2 -- *****************
3 -- * FAUNA FEATURE *
4 -- *****************
5 --
6 -- The fauna feature contains 2 herds of creatures (herbivores and carnivores) that wander between 2 life zones (sleep zone and
7 -- food zone).There are 2 differents kinds of components in this feature: fauna system and creature.
8 -- The fauna system component is some kind of manager for the feature. It creates the creatures and their life zones, and then
9 -- store them in its components table, so that their createChostComponents call and translation are automatically done by
10 -- the translator.
11 -- The created life zones are affected to each of the creature components. But the properties panel of the creature components allows
12 -- the DM to choose other zones in the scenario through RefId picking.
15 r2.Features.FaunaFeature = {}
17 local feature = r2.Features.FaunaFeature
19 feature.Name="FaunaFeature"
21 feature.Description="Generates a pack of carnivores and a herd of herbivores that will wander between two life zones (sleep zone, food zone) each."
23 feature.Components = {}
26 -- *********************
27 -- * FEATURE FUNCTIONS *
28 -- *********************
31 --Form functions
33 -- Reinit makes sure the enums are reinitialized, ie contain all creatures (respectively herbivores or carnivores) from
34 -- the desert ecosystem and with a level between 1 and 50.
35 local function reinit(form, creature)
36 if form == nil then
37 debugInfo("Reinit impossible: nil form")
38 return
39 end
41 local creatureEnum = form:find(creature.."Race")
42 if creatureEnum == nil then
43 debugInfo("Reinit impossible: can't find "..creature.."Race enum")
44 return
45 end
46 creatureEnum:resetTexts()
48 local creaturePalette = {}
49 if creature == "Carnivore" then
50 creaturePalette = r2.Palette.Entries.creature.creatures_predators.instances
51 else
52 creaturePalette = r2.Palette.Entries.creature.creatures_passive.instances
53 end
55 local k, v = next(creaturePalette, nil)
56 while k do
57 if r2.isInPalette(v.Id) then
58 local paletteElt = r2.getPaletteElement(v.Id)
59 if paletteElt and paletteElt.RingAccess and
60 r2.RingAccess.testAccess(paletteElt.RingAccess) then
62 if paletteElt.Ecosystem == "Desert" and paletteElt.Level >= 1 and paletteElt.Level <= 50 then
63 creatureEnum:addText(ucstring(i18n.get(v.Translation)))
64 end
65 end
66 end
67 k, v = next(creaturePalette, k)
68 end
69 end
71 -- Returns the chosen bases from the form before creating the components.
72 local function getBase(creature, form)
73 if (form == nil) then
74 debugInfo("getBase: form is nil")
75 return
76 end
78 local creaturePalette = {}
79 if creature == "Carnivore" then
80 creaturePalette = r2.Palette.Entries.creature.creatures_predators.instances
81 else
82 creaturePalette = r2.Palette.Entries.creature.creatures_passive.instances
83 end
85 local creatureEnum = form:find(creature.."Race")
86 local race = creatureEnum.selection_text
88 local k, v = next(creaturePalette, nil)
89 while k do
90 local name = i18n.get(v.Translation):toUtf8()
91 if name == race then
92 return v.Id, name
93 end
94 k, v = next(creaturePalette, k)
95 end
96 end
98 -- When the selected ecosystem or level changes, the corresponding creature combobox is updated.
99 local function updateEnum(creature)
100 local currentForm = r2.CurrentForm
101 if (currentForm == nil) then
102 debugInfo("UpdatePredators: r2.CurrentForm is nil")
103 return
106 local creatureEnum = currentForm:find(creature.."Race")
107 local ecoEnum = currentForm:find(creature.."Ecosystem")
108 local currentEco = ecoEnum.selection_text
109 if currentEco == "Lakes" then
110 currentEco = "Lacustre"
113 local levelEnum = currentForm:find(creature.."Level")
114 local levelRange = levelEnum.selection + 1
115 local levelMin
116 local levelMax
117 if levelRange == 0 then
118 levelMin = 1
119 levelMax = 250
120 else
121 levelMin = (levelRange - 1) * 50 + 1
122 levelMax = levelMin + 49
123 end
125 creatureEnum:resetTexts()
127 local creaturePalette = {}
128 if creature == "Carnivore" then
129 creaturePalette = r2.Palette.Entries.creature.creatures_predators.instances
130 else
131 creaturePalette = r2.Palette.Entries.creature.creatures_passive.instances
134 local k, v = next(creaturePalette, nil)
135 while k do
136 if r2.isInPalette(v.Id) then
137 local paletteElt = r2.getPaletteElement(v.Id)
138 if paletteElt and paletteElt.RingAccess and
139 r2.RingAccess.testAccess(paletteElt.RingAccess) then
140 if paletteElt.Ecosystem == currentEco and paletteElt.Level >= levelMin and paletteElt.Level <= levelMax then
141 creatureEnum:addText(ucstring(i18n.get(v.Translation)))
145 k, v = next(creaturePalette, k)
149 -- Calls update function for the carnivores combobox.
150 local function updateCarnivores(form)
151 updateEnum("Carnivore")
154 -- Calls update function for the herbivores combobox.
155 local function updateHerbivores(form)
156 updateEnum("Herbivore")
159 local function resetForm()
161 local currentForm = r2:getForm("Fauna_Form")
162 assert(currentForm)
165 local creature = "Carnivore"
166 local ecoEnum = currentForm:find(creature.."Ecosystem")
167 ecoEnum.selection_text= "Desert"
168 local levelEnum = currentForm:find(creature.."Level")
169 levelEnum.selection = 0
170 updateCarnivores(form)
173 local creature = "Herbivore"
174 local ecoEnum = currentForm:find(creature.."Ecosystem")
175 ecoEnum.selection_text= "Desert"
176 local levelEnum = currentForm:find(creature.."Level")
177 levelEnum.selection = 0
178 updateHerbivores(form)
183 -- The creation form lets the DM choose the type of creatures and their number.
184 -- Like the palette tree, the available creatures are filtered by their ecosystems and level.
185 -- Each life cycle duration is defined in the properties panel of the creature component.
186 -- The creation form will return the chosen creature base when ok button is pressed.
187 -- The form is reinitialized each time the ok or cancel button is pressed.
189 feature.registerForms = function()
191 -- Initializes the creature comboboxes. Default ecosystem is desert and default level range is 1-50.
192 local function init(creature)
193 local initEnum = {}
195 local creaturePalette = {}
196 if not r2.Palette.Entries.creature then
197 return -- special case for the 'light' palette
199 if creature == "Carnivore" then
200 creaturePalette = r2.Palette.Entries.creature.creatures_predators.instances
201 else
202 creaturePalette = r2.Palette.Entries.creature.creatures_passive.instances
203 end
204 local k, v = next(creaturePalette, nil)
205 while k do
206 if r2.isInPalette(v.Id) then
207 local paletteElt = r2.getPaletteElement(v.Id)
208 if paletteElt then
209 if paletteElt.Ecosystem == "Desert" and paletteElt.Level >= 1 and paletteElt.Level <= 50 then
210 table.insert(initEnum, i18n.get(v.Translation))
214 k, v = next(creaturePalette, k)
217 return initEnum
220 r2.Forms.Fauna_Form =
222 Caption = "uiR2EdFauna",
223 Prop =
225 {Name="CarnivoresCount", Type="Number", Category="uiR2EDRollout_Carnivores", Min="1", Max="12", Default="3", Translation="uiR2EDProp_Count"},
226 {Name="CarnivoreRace", Type="Number", Category="uiR2EDRollout_Carnivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Race",
227 Enum= init("Carnivore")
229 {Name="CarnivoreEcosystem", Type="Number", Category="uiR2EDRollout_Carnivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Ecosystem",
230 Enum={"Desert", "Forest", "Jungle", "Lakes", "PrimeRoots", "Goo"},
231 onChange = updateCarnivores
233 {Name="CarnivoreLevel", Type="Number", Category="uiR2EDRollout_Carnivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Level",
234 Enum={"1-50", "51-100", "101-150", "151-200", "201-250"},
235 onChange = updateCarnivores
237 {Name="HerbivoresCount", Type="Number", Category="uiR2EDRollout_Herbivores", Min="1", Max="12", Default="7", Translation="uiR2EDProp_Count"},
238 {Name="HerbivoreRace", Type="Number", Category="uiR2EDRollout_Herbivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Race",
239 Enum= init("Herbivore")
241 {Name="HerbivoreEcosystem", Type="Number", Category="uiR2EDRollout_Herbivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Ecosystem",
242 Enum={"Desert", "Forest", "Jungle", "Lakes", "PrimeRoots", "Goo"},
243 onChange = updateHerbivores
245 {Name="HerbivoreLevel", Type="Number", Category="uiR2EDRollout_Herbivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Level",
246 Enum={"1-50", "51-100", "101-150", "151-200", "201-250"},
247 onChange = updateHerbivores
254 -- **************
255 -- * COMPONENTS *
256 -- **************
258 local FaunaRegionRadius = 5
261 -----------------------------------------------------------------------------------------------
262 -- CREATURE COMPONENT
264 feature.Components.Creature =
266 BaseClass="LogicEntity",
267 Name="Creature",
268 Menu="ui:interface:r2ed_feature_menu",
270 DisplayerUI = "R2::CDisplayerLua",
271 DisplayerUIParams = "defaultUIDisplayer",
272 DisplayerVisual = "R2::CDisplayerVisualEntity",
273 -----------------------------------------------------------------------------------------------
274 Parameters = {},
276 ApplicableActions = {},
278 Events = {},
280 Conditions = {},
282 TextContexts = {},
284 TextParameters = {},
286 LiveParameters = {},
287 -----------------------------------------------------------------------------------------------
288 Prop =
290 {Name="InstanceId", Type="String", WidgetStyle="StaticText", Visible = false},
291 {Name="Components", Type="Table", Visible= false},
292 {Name="Ghosts", Type = "Table", Visible = false },
293 {Name="Name", Type="String", MaxNumChar="32"},
294 {Name="CrittersCount", Type="String", WidgetStyle="StaticText", Translation="uiR2EDProp_CrittersCount"},
295 {Name="RaceBase", Type="String", WidgetStyle="StaticText", Visible=false},
296 {Name="RaceName", Type="String", WidgetStyle="StaticText", Translation="uiR2EDProp_Race"},
297 {Name="SleepZone", Type="RefId", PickFuntion = "r2:canPickZone", SetRefIdFunction = "r2:setZoneRefIdTarget", Translation="uiR2EDProp_SleepZone"},
298 {Name="FoodZone", Type="RefId", PickFuntion = "r2:canPickZone", SetRefIdFunction = "r2:setZoneRefIdTarget", Translation="uiR2EDProp_FoodZone"},
299 {Name="FoodDuration", Type="Number", Category="uiR2EDRollout_LifeCyclesInSeconds", Min="1", Max="40000", Default="30", Translation="uiR2EDProp_FoodDuration"},
300 {Name="SleepDuration", Type="Number", Category="uiR2EDRollout_LifeCyclesInSeconds", Min="1", Max="40000", Default="30", Translation="uiR2EDProp_SleepDuration"},
304 getAvailableCommands = function(this, dest)
305 r2.Classes.LogicEntity.getAvailableCommands(this, dest) -- fill by ancestor
306 this:getAvailableDisplayModeCommands(dest)
307 end,
309 appendInstancesByType = function(this, destTable, kind)
310 assert(type(kind) == "string")
311 r2.Classes.LogicEntity.appendInstancesByType(this, destTable, kind)
312 for k, component in specPairs(this.Components) do
313 component:appendInstancesByType(destTable, kind)
315 end,
317 getSelectBarSons = function(this)
318 return Components
319 end,
321 canHaveSelectBarSons = function(this)
322 return false;
323 end,
325 onPostCreate = function(this)
326 this:createGhostComponents()
327 end,
329 translate = function(this, context)
330 --local rtNpcGrp = r2.Translator.getRtGroup(context, context.Feature.InstanceId)
331 --local aiState = r2.newComponent("RtAiState")
332 --aiState.AiActivity = "normal"
333 --table.insert(context.RtAct.AiStates, aiState)
334 --table.insert(aiState.Children, rtNpcGrp.Id)
335 --local rtNpcGrp = r2.Translator.getRtGroup(context, this.InstanceId)
336 --r2.Translator.translateEventHandlers( context, this, this.Behavior.Actions, rtNpcGrp)
337 r2.Translator.translateAiGroup(this, context)
339 end,
341 pretranslate = function(this, context)
342 --local instance = r2:getInstanceFromId(context.Feature.InstanceId);
343 --r2.Translator.registerManager(context, context.Feature)
345 r2.Translator.createAiGroup(this, context)
349 local component = feature.Components.Creature
351 component.getLogicAction = function(entity, context, action)
352 return nil, nil
355 component.getLogicCondition = function(this, context, condition)
356 return nil,nil
359 component.getLogicEvent = function(this, context, event)
360 return nil, nil, nil
363 function component:getLogicTranslations()
365 local logicTranslations = {
366 ["ApplicableActions"] = {},
367 ["Events"] = {}
369 return nil--logicTranslations
372 component.createGhostComponents= function(this, act)
373 local comp = this
374 local leader = nil
375 local herd = nil
376 local isHerbivore
378 if act then
379 herd = r2.newComponent("NpcGrpFeature")
382 if comp._Seed then math.randomseed(comp._Seed) end
385 local x = comp.Position.x
386 local y = comp.Position.y
387 local n = comp._CrittersCount
388 local pas = (2 * math.pi)/n
389 local r = (n/(2*math.pi))+2
390 for i = 1, n do
391 local npc = r2.newComponent("Npc")
392 npc.Name = comp.RaceName
393 npc.Base = comp.RaceBase --"palette.entities.creatures.cbadc1"
396 local rr = FaunaRegionRadius - 1--r + math.random() * 5
397 npc.Position.x = (rr-1) * math.cos((i-1)*pas)
398 npc.Position.y = (rr-1) * math.sin((i-1)*pas)
399 npc.Position.z = 0
400 npc.Angle = 2 * math.pi * math.random(0, 100)/100.0
402 if i == 1 then
403 local manager = r2:getInstanceFromId(comp.ManagerId)
404 assert(manager)
405 if manager.Active == 1 then npc.AutoSpawn = 1 else npc.AutoSpawn = 0 end
406 leader = npc
407 r2.requestSetGhostNode(comp.InstanceId, "_LeaderId",npc.InstanceId)
408 isHerbivore = r2.getPropertyValue(npc, "IsHerbivore")
411 if act then -- TestMode --
412 table.insert(herd.Components, npc)
413 else
414 r2.requestInsertGhostNode(this.InstanceId, "Ghosts", -1, "", npc)
415 r2:getInstanceFromId(npc.InstanceId).Selectable = false
416 end
420 -- 2 wander sequences corresponding to the activities in both life zones attached to the herd
422 local sequence = r2.newComponent("ActivitySequence")
425 table.insert(leader.Behavior.Activities, sequence)
427 sequence.Name = "Life Cycle"
428 sequence.Repeating = 1
430 -- Wander in sleep zone
431 local step = r2.newComponent("ActivityStep")
432 table.insert(sequence.Components, step)
433 step.Type = "None"
434 step.Name = "Rest In Zone"
435 step.Activity = "Rest In Zone"
436 step.ActivityZoneId = r2.RefId(comp.SleepZone)
438 step.TimeLimit = "Few Sec"
439 step.TimeLimitValue = tostring(comp.SleepDuration)
441 -- Wander in food zone
442 local step = r2.newComponent("ActivityStep")
443 table.insert(sequence.Components, step)
444 step.Type = "None"
446 if isHerbivore == 1 then
447 step.Name = "Feed In Zone"
448 step.Activity = "Feed In Zone"
449 else
450 step.Name = "Hunt In Zone"
451 step.Activity = "Hunt In Zone"
453 step.ActivityZoneId = r2.RefId(comp.FoodZone)
455 step.TimeLimit = "Few Sec"
456 step.TimeLimitValue = tostring(comp.FoodDuration)
458 end
460 if act then
461 comp.User._Herd = herd.InstanceId
462 --herd.Name = r2:genInstanceName(i18n.get("uiR2EdFaunaFeature")):toUtf8()
463 herd.InheritPos = 0
464 herd.Position.x = comp.Position.x
465 herd.Position.y = comp.Position.y
466 r2.requestInsertGhostNode(act.InstanceId, "Features", -1, "", herd)
471 component.createComponent = function(x, y, nbcritters, raceBase, raceName,
472 sleepZoneId, foodZoneId)
475 local comp = r2.newComponent("Creature")
476 assert(comp)
478 --comp.Base = "palette.entities.botobjects.user_event"
479 comp.Base = r2.Translator.getDebugBase("palette.entities.botobjects.user_event")
481 comp.Name = r2:genInstanceName(i18n.get("uiR2EdCreatureComponent")):toUtf8()
483 comp.Position.x = x
484 comp.Position.y = y
485 comp.Position.z = r2:snapZToGround(x, y)
487 comp._CrittersCount= nbcritters
488 comp.CrittersCount = tostring(nbcritters)
489 comp.RaceBase = raceBase
490 comp.RaceName = raceName
492 comp.SleepDuration = 30
493 comp.FoodDuration = 30
495 comp._Seed = os.time()
497 comp.SleepZone = sleepZoneId
498 comp.FoodZone = foodZoneId
500 return comp
503 -----------------------------------------------------------------------------------------------
504 -- FAUNA SYSTEM COMPONENT
505 -- Fauna system containing 2 Creature components (herbivores & carnivores) and 3 life zones.
506 feature.Components.Fauna =
508 BaseClass="LogicEntity",
509 Name="Fauna",
510 Menu="ui:interface:r2ed_feature_menu",
511 InEventUI = true,
513 DisplayerUI = "R2::CDisplayerLua",
514 DisplayerUIParams = "defaultUIDisplayer",
515 DisplayerVisual = "R2::CDisplayerVisualEntity",
516 -----------------------------------------------------------------------------------------------
517 Parameters = {},
519 ApplicableActions = {"activate", "deactivate"},
521 Events = {"deactivation", "activation"},
523 Conditions = {"is active", "is inactive"},
525 TextContexts = {},
527 TextParameters = {},
529 LiveParameters = {},
530 -----------------------------------------------------------------------------------------------
531 Prop =
533 {Name="InstanceId", Type="String", WidgetStyle="StaticText", Visible = false},
534 {Name="Components", Type="Table", Visible = false},
535 {Name="Ghosts", Type = "Table", Visible = false },
536 {Name="Name", Type="String", MaxNumChar="32"},
537 {Name="Active", Type = "Number", WidgetStyle="Boolean", DefaultValue="1" },
538 {Name="CarnivoresCount", Type="String", Category="uiR2EDRollout_Carnivores", WidgetStyle="StaticText", Translation="uiR2EDProp_Count"},
539 {Name="CarnivoreBase", Type="String", Category="uiR2EDRollout_Carnivores", WidgetStyle="StaticText", Visible = false},
540 {Name="CarnivoreRace", Type="String", Category="uiR2EDRollout_Carnivores", WidgetStyle="StaticText", Translation="uiR2EDProp_Race"},
541 {Name="HerbivoresCount", Type="String", Category="uiR2EDRollout_Herbivores", WidgetStyle="StaticText",Translation="uiR2EDProp_Count"},
542 {Name="HerbivoreBase", Type="String", Category="uiR2EDRollout_Herbivores", WidgetStyle="StaticText", Visible = false},
543 {Name="HerbivoreRace", Type="String", Category="uiR2EDRollout_Herbivores", WidgetStyle="StaticText", Translation="uiR2EDProp_Race"},
546 getParentTreeNode = function(this)
547 return this:getFeatureParentTreeNode()
548 end,
550 getAvailableCommands = function(this, dest)
551 r2.Classes.LogicEntity.getAvailableCommands(this, dest) -- fill by ancestor
552 this:getAvailableDisplayModeCommands(dest)
553 end,
555 appendInstancesByType = function(this, destTable, kind)
556 assert(type(kind) == "string")
557 r2.Classes.LogicEntity.appendInstancesByType(this, destTable, kind)
558 for k, component in specPairs(this.Components) do
559 component:appendInstancesByType(destTable, kind)
561 end,
563 getSelectBarSons = function(this)
564 return Components
565 end,
567 canHaveSelectBarSons = function(this)
568 return false;
569 end,
571 onPostCreate = function(this)
572 --this:createGhostComponents()
573 if this.User.DisplayProp and this.User.DisplayProp == 1 then
574 r2:setSelectedInstanceId(this.InstanceId)
575 r2:showProperties(this)
576 this.User.DisplayProp = nil
578 end,
580 translate = function(this, context)
581 r2.Translator.translateAiGroup(this, context)
582 r2.Translator.translateFeatureActivation(this, context)
583 end,
585 pretranslate = function(this, context)
586 r2.Translator.createAiGroup(this, context)
590 component = feature.Components.Fauna
593 local FaunaRegionNumCorners = 6
594 --local FaunaRegionRadius = 5
595 local FaunaRegionOffsets = { { x = 10, y = 0 }, { x = -7, y = -7}, { x = 0, y = 10} }
598 component.create = function()
599 if not r2:checkAiQuota() then return end
601 local function paramsOk(resultTable, form)
604 local carnivoreBase, carnivoreName = getBase("Carnivore", form)
605 local herbivoreBase, herbivoreName = getBase("Herbivore", form)
607 local x = tonumber( resultTable["X"] )
608 local y = tonumber( resultTable["Y"] )
610 local carnCount = tonumber(resultTable["CarnivoresCount"])
611 local herbCount = tonumber(resultTable["HerbivoresCount"])
614 if not r2:checkAiQuota(carnCount + herbCount + 1) then return end
617 if not x or not y or not carnivoreBase or not carnivoreName or not carnCount or not herbivoreBase
618 or not herbivoreName or not herbCount
619 then
620 r2:doForm("Fauna_Form", resultTable , paramsOk, paramsCancel)
621 resetForm()
623 printMsg("FaunaSystem: Failed to create component either because your scenario is full or because you don't yet have access to creatures of the level and ecosystem that you have selected")
625 return
627 r2.requestNewAction(i18n.get("uiR2EDNewFaunaFeatureAction"))
628 local component = feature.Components.Fauna.createComponent(x, y, carnCount, carnivoreBase, carnivoreName,
629 herbCount, herbivoreBase, herbivoreName)
630 r2:setCookie(component.InstanceId, "DisplayProp", 1)
631 r2.requestInsertNode(r2:getCurrentAct().InstanceId, "Features", -1, "", component)
632 resetForm()
635 local function paramsCancel(data, form)
636 resetForm()
638 local function posOk(x, y, z)
639 debugInfo(string.format("Validate creation of 'FaunaFeature' at pos (%d, %d, %d)", x, y, z))
640 if r2.mustDisplayInfo("Fauna") == 1 then
641 r2.displayFeatureHelp("Fauna")
643 r2:doForm("Fauna_Form", {X=x, Y=y}, paramsOk, paramsCancel)
644 resetForm()
646 local function posCancel()
647 debugInfo("Cancel choice 'FaunaFeature' position")
648 end
649 --r2:choosePos("object_component_user_event.creature", posOk, posCancel, "createFeatureFauna")
650 local creature = r2.Translator.getDebugCreature("object_component_user_event.creature")
651 --r2:choosePos(creature, posOk, posCancel, "createFeatureFauna")
653 local polys = {}
654 for p = 1, table.getn(FaunaRegionOffsets) do
655 local poly = {}
656 local step = 2 * math.pi / FaunaRegionNumCorners
657 for k = 0, FaunaRegionNumCorners - 1 do
658 table.insert(poly, CVector2f(FaunaRegionOffsets[p].x + FaunaRegionRadius * math.cos(k * step),
659 FaunaRegionOffsets[p].y + FaunaRegionRadius * math.sin(k * step)))
661 table.insert(polys, poly)
663 r2:choosePos(creature, posOk, posCancel, "createFeatureFauna",
664 "curs_create.tga",
665 "curs_stop.tga",
666 polys, r2.PrimRender.ComponentRegionLook, r2.PrimRender.ComponentRegionInvalidLook)
669 function component.getAiCost(this)
670 if this.User.GhostDuplicate then return 0 end
671 return r2.getAiCost(this) - 2
678 -- create the fauna system component by creating and inserting zones and creature component into its own components table.
679 -- Generates a sleep zone and a food zone for the herbivores, and a sleep zone for the carnivores. The carnivore hunt zone is
680 -- one of the herbivore zones (default is herbivore sleep zone).
682 component.createComponent = function(x, y, carnCount, carnivoreBase, carnivoresName,
683 herbCount, herbivoreBase, herbivoresName)
685 local comp = r2.newComponent("Fauna")
686 assert(comp)
688 --TODO: replace this milestone base by some default feature base
689 comp.Base = "palette.entities.botobjects.user_event"
691 comp.Name = r2:genInstanceName(i18n.get("uiR2EdFaunaFeature")):toUtf8()
693 comp.Position.x = x
694 comp.Position.y = y
695 comp.Position.z = r2:snapZToGround(x, y)
697 comp._CarnCount= carnCount
698 comp.CarnivoresCount = tostring(carnCount)
699 comp.CarnivoreBase = carnivoreBase
700 comp.CarnivoreRace = tostring(carnivoresName)
702 comp._HerbCount= herbCount
703 comp.HerbivoresCount = tostring(herbCount)
704 comp.HerbivoreBase = herbivoreBase
705 comp.HerbivoresName = herbivoresName
706 comp.HerbivoreRace = tostring(herbivoresName)
708 comp._Seed = os.time()
710 -- Herbivore sleep zone
711 local zoneSleep1 = r2.newComponent("Region")
712 r2.Utils.createRegion(zoneSleep1, 0, 0, FaunaRegionRadius, FaunaRegionNumCorners)
713 zoneSleep1.Deletable = 1
714 zoneSleep1.Position.x = comp.Position.x + FaunaRegionOffsets[1].x
715 zoneSleep1.Position.y = comp.Position.y + FaunaRegionOffsets[1].y
716 zoneSleep1.Position.z = comp.Position.z
717 zoneSleep1.InheritPos = 0
718 zoneSleep1.Name = r2:genInstanceName(i18n.get("uiR2EDNameSleepRegion")):toUtf8()
719 table.insert(comp.Components, zoneSleep1)
721 -- Carnivore sleep zone
722 local zoneSleep2 = r2.newComponent("Region")
723 r2.Utils.createRegion(zoneSleep2, 0, 0, FaunaRegionRadius, FaunaRegionNumCorners)
724 zoneSleep2.Deletable = 1
725 zoneSleep2.Position.x = comp.Position.x + FaunaRegionOffsets[2].x
726 zoneSleep2.Position.y = comp.Position.y + FaunaRegionOffsets[2].y
727 zoneSleep2.Position.z = comp.Position.z
728 zoneSleep2.InheritPos = 0
729 zoneSleep2.Name = r2:genInstanceName(i18n.get("uiR2EDNameSleepRegion")):toUtf8()
730 table.insert(comp.Components, zoneSleep2)
732 --Herbivore sleep zone
733 local zoneFood = r2.newComponent("Region")
734 r2.Utils.createRegion(zoneFood, 0, 0, FaunaRegionRadius, FaunaRegionNumCorners)
735 zoneFood.Deletable = 1
736 zoneFood.Position.x = comp.Position.x + FaunaRegionOffsets[3].x
737 zoneFood.Position.y = comp.Position.y + FaunaRegionOffsets[3].y
738 zoneFood.Position.z = comp.Position.z
739 zoneFood.InheritPos = 0
740 zoneFood.Name = r2:genInstanceName(i18n.get("uiR2EDNameFoodRegion")):toUtf8()
741 table.insert(comp.Components, zoneFood)
743 -- Herd of herbivores
744 local herbivores = feature.Components.Creature.createComponent(zoneSleep1.Position.x, zoneSleep1.Position.y, herbCount, herbivoreBase,
745 herbivoresName, zoneSleep1.InstanceId, zoneFood.InstanceId)
746 herbivores.Name = i18n.get("uiR2EdHerbivores"):toUtf8()
747 --herbivores.Position.x = zoneSleep1.Position.x--comp.Position.x + 10
748 --herbivores.Position.y = zoneSleep1.Position.y--comp.Position.y + 10
749 herbivores.InheritPos = 0
750 --herbivores.Active = comp.Active
751 herbivores.ManagerId = comp.InstanceId
752 table.insert(comp.Components, herbivores)
753 comp._HerbId = herbivores.InstanceId
755 -- Pack of carnivores
756 local carnivores = feature.Components.Creature.createComponent(zoneSleep2.Position.x, zoneSleep2.Position.y, carnCount, carnivoreBase,
757 carnivoresName, zoneSleep2.InstanceId, zoneSleep1.InstanceId)
758 carnivores.Name = i18n.get("uiR2EdCarnivores"):toUtf8()
759 carnivores.InheritPos = 0
760 carnivores.ManagerId = comp.InstanceId
761 table.insert(comp.Components, carnivores)
762 comp._CarnId = carnivores.InstanceId
764 return comp
767 component.getLogicAction = function(entity, context, action)
768 assert( action.Class == "ActionStep")
769 local component = r2:getInstanceFromId(action.Entity)
770 assert(component)
771 local rtNpcGrp = r2.Translator.getRtGroup(context, component.InstanceId)
772 assert(rtNpcGrp)
774 local herbi = r2:getInstanceFromId(component._HerbId)
775 assert(herbi)
776 local herbivores = r2:getInstanceFromId(herbi.User._Herd)
777 assert(herbivores)
778 local rtHerbiGrp = r2.Translator.getRtGroup(context, herbivores.InstanceId)
779 assert(rtHerbiGrp)
781 local carni = r2:getInstanceFromId(component._CarnId)
782 assert(carni)
783 local carnivores = r2:getInstanceFromId(carni.User._Herd)
784 assert(carnivores)
785 local rtCarniGrp = r2.Translator.getRtGroup(context, carnivores.InstanceId)
786 assert(rtCarniGrp)
789 if action.Action.Type == "deactivate" then
790 local action1 = r2.Translator.createAction("set_value", rtNpcGrp.Id, "Active", 0)
791 local action2 = r2.Translator.getNpcLogicActionDeactivate(herbivores, context, action, rtHerbiGrp)
792 local action3 = r2.Translator.getNpcLogicActionDeactivate(carnivores, context, action, rtCarniGrp)
793 local action4 = r2.Translator.createAction("user_event_trigger", rtNpcGrp.Id, 5)
794 local multiaction = r2.Translator.createAction("multi_actions", {action1, action2, action3, action4})
795 return multiaction, multiaction
796 elseif (action.Action.Type == "activate") then
797 local action1 = r2.Translator.createAction("set_value", rtNpcGrp.Id, "Active", 1)
798 local action2 = r2.Translator.getNpcLogicActionActivate(herbivores, context, action, rtHerbiGrp)
799 local action3 = r2.Translator.getNpcLogicActionActivate(carnivores, context, action, rtCarniGrp)
800 local action4 = r2.Translator.createAction("user_event_trigger", rtNpcGrp.Id, 4)
801 local multiaction = r2.Translator.createAction("multi_actions", {action1, action2, action3, action4})
802 return multiaction, multiaction
805 return r2.Translator.getFeatureActivationLogicAction(rtNpcGrp, action)
808 component.getLogicEvent = function(this, context, event)
809 assert( event.Class == "LogicEntityAction")
810 local component = this
811 assert(component)
812 local rtNpcGrp = r2.Translator.getRtGroup(context, component.InstanceId)
813 assert(rtNpcGrp)
815 return r2.Translator.getFeatureActivationLogicEvent(rtNpcGrp, event)
818 component.getLogicCondition = function(this, context, condition)
819 assert( condition.Class == "ConditionStep")
820 local component = r2:getInstanceFromId(condition.Entity)
821 assert(component)
822 local rtNpcGrp = r2.Translator.getRtGroup(context, component.InstanceId)
823 assert(rtNpcGrp)
825 return r2.Translator.getFeatureActivationCondition(condition, rtNpcGrp)
828 function component:getLogicTranslations()
829 local logicTranslations = {}
830 r2.Translator.addActivationToTranslations(logicTranslations)
831 return logicTranslations
834 function component:registerMenu(logicEntityMenu)
835 local name = i18n.get("uiR2EdFaunaFeature")
836 logicEntityMenu:addLine(ucstring(name), "lua", "", "FaunaFeature")
839 r2.Features["FaunaFeature"] = feature