841 lines
28 KiB
Lua
841 lines
28 KiB
Lua
|
--
|
||
|
-- *****************
|
||
|
-- * FAUNA FEATURE *
|
||
|
-- *****************
|
||
|
--
|
||
|
-- The fauna feature contains 2 herds of creatures (herbivores and carnivores) that wander between 2 life zones (sleep zone and
|
||
|
-- food zone).There are 2 differents kinds of components in this feature: fauna system and creature.
|
||
|
-- The fauna system component is some kind of manager for the feature. It creates the creatures and their life zones, and then
|
||
|
-- store them in its components table, so that their createChostComponents call and translation are automatically done by
|
||
|
-- the translator.
|
||
|
-- The created life zones are affected to each of the creature components. But the properties panel of the creature components allows
|
||
|
-- the DM to choose other zones in the scenario through RefId picking.
|
||
|
|
||
|
|
||
|
r2.Features.FaunaFeature = {}
|
||
|
|
||
|
local feature = r2.Features.FaunaFeature
|
||
|
|
||
|
feature.Name="FaunaFeature"
|
||
|
|
||
|
feature.Description="Generates a pack of carnivores and a herd of herbivores that will wander between two life zones (sleep zone, food zone) each."
|
||
|
|
||
|
feature.Components = {}
|
||
|
|
||
|
|
||
|
-- *********************
|
||
|
-- * FEATURE FUNCTIONS *
|
||
|
-- *********************
|
||
|
|
||
|
|
||
|
--Form functions
|
||
|
|
||
|
-- Reinit makes sure the enums are reinitialized, ie contain all creatures (respectively herbivores or carnivores) from
|
||
|
-- the desert ecosystem and with a level between 1 and 50.
|
||
|
local function reinit(form, creature)
|
||
|
if form == nil then
|
||
|
debugInfo("Reinit impossible: nil form")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local creatureEnum = form:find(creature.."Race")
|
||
|
if creatureEnum == nil then
|
||
|
debugInfo("Reinit impossible: can't find "..creature.."Race enum")
|
||
|
return
|
||
|
end
|
||
|
creatureEnum:resetTexts()
|
||
|
|
||
|
local creaturePalette = {}
|
||
|
if creature == "Carnivore" then
|
||
|
creaturePalette = r2.Palette.Entries.creature.creatures_predators.instances
|
||
|
else
|
||
|
creaturePalette = r2.Palette.Entries.creature.creatures_passive.instances
|
||
|
end
|
||
|
|
||
|
local k, v = next(creaturePalette, nil)
|
||
|
while k do
|
||
|
if r2.isInPalette(v.Id) then
|
||
|
local paletteElt = r2.getPaletteElement(v.Id)
|
||
|
if paletteElt and paletteElt.RingAccess and
|
||
|
r2.RingAccess.testAccess(paletteElt.RingAccess) then
|
||
|
|
||
|
if paletteElt.Ecosystem == "Desert" and paletteElt.Level >= 1 and paletteElt.Level <= 50 then
|
||
|
creatureEnum:addText(ucstring(i18n.get(v.Translation)))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
k, v = next(creaturePalette, k)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Returns the chosen bases from the form before creating the components.
|
||
|
local function getBase(creature, form)
|
||
|
if (form == nil) then
|
||
|
debugInfo("getBase: form is nil")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local creaturePalette = {}
|
||
|
if creature == "Carnivore" then
|
||
|
creaturePalette = r2.Palette.Entries.creature.creatures_predators.instances
|
||
|
else
|
||
|
creaturePalette = r2.Palette.Entries.creature.creatures_passive.instances
|
||
|
end
|
||
|
|
||
|
local creatureEnum = form:find(creature.."Race")
|
||
|
local race = creatureEnum.selection_text
|
||
|
|
||
|
local k, v = next(creaturePalette, nil)
|
||
|
while k do
|
||
|
local name = i18n.get(v.Translation):toUtf8()
|
||
|
if name == race then
|
||
|
return v.Id, name
|
||
|
end
|
||
|
k, v = next(creaturePalette, k)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- When the selected ecosystem or level changes, the corresponding creature combobox is updated.
|
||
|
local function updateEnum(creature)
|
||
|
local currentForm = r2.CurrentForm
|
||
|
if (currentForm == nil) then
|
||
|
debugInfo("UpdatePredators: r2.CurrentForm is nil")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local creatureEnum = currentForm:find(creature.."Race")
|
||
|
local ecoEnum = currentForm:find(creature.."Ecosystem")
|
||
|
local currentEco = ecoEnum.selection_text
|
||
|
if currentEco == "Lakes" then
|
||
|
currentEco = "Lacustre"
|
||
|
end
|
||
|
|
||
|
local levelEnum = currentForm:find(creature.."Level")
|
||
|
local levelRange = levelEnum.selection + 1
|
||
|
local levelMin
|
||
|
local levelMax
|
||
|
if levelRange == 0 then
|
||
|
levelMin = 1
|
||
|
levelMax = 250
|
||
|
else
|
||
|
levelMin = (levelRange - 1) * 50 + 1
|
||
|
levelMax = levelMin + 49
|
||
|
end
|
||
|
|
||
|
creatureEnum:resetTexts()
|
||
|
|
||
|
local creaturePalette = {}
|
||
|
if creature == "Carnivore" then
|
||
|
creaturePalette = r2.Palette.Entries.creature.creatures_predators.instances
|
||
|
else
|
||
|
creaturePalette = r2.Palette.Entries.creature.creatures_passive.instances
|
||
|
end
|
||
|
|
||
|
local k, v = next(creaturePalette, nil)
|
||
|
while k do
|
||
|
if r2.isInPalette(v.Id) then
|
||
|
local paletteElt = r2.getPaletteElement(v.Id)
|
||
|
if paletteElt and paletteElt.RingAccess and
|
||
|
r2.RingAccess.testAccess(paletteElt.RingAccess) then
|
||
|
if paletteElt.Ecosystem == currentEco and paletteElt.Level >= levelMin and paletteElt.Level <= levelMax then
|
||
|
creatureEnum:addText(ucstring(i18n.get(v.Translation)))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
k, v = next(creaturePalette, k)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Calls update function for the carnivores combobox.
|
||
|
local function updateCarnivores(form)
|
||
|
updateEnum("Carnivore")
|
||
|
end
|
||
|
|
||
|
-- Calls update function for the herbivores combobox.
|
||
|
local function updateHerbivores(form)
|
||
|
updateEnum("Herbivore")
|
||
|
end
|
||
|
|
||
|
local function resetForm()
|
||
|
|
||
|
local currentForm = r2:getForm("Fauna_Form")
|
||
|
assert(currentForm)
|
||
|
|
||
|
do
|
||
|
local creature = "Carnivore"
|
||
|
local ecoEnum = currentForm:find(creature.."Ecosystem")
|
||
|
ecoEnum.selection_text= "Desert"
|
||
|
local levelEnum = currentForm:find(creature.."Level")
|
||
|
levelEnum.selection = 0
|
||
|
updateCarnivores(form)
|
||
|
end
|
||
|
do
|
||
|
local creature = "Herbivore"
|
||
|
local ecoEnum = currentForm:find(creature.."Ecosystem")
|
||
|
ecoEnum.selection_text= "Desert"
|
||
|
local levelEnum = currentForm:find(creature.."Level")
|
||
|
levelEnum.selection = 0
|
||
|
updateHerbivores(form)
|
||
|
end
|
||
|
|
||
|
end
|
||
|
--
|
||
|
-- The creation form lets the DM choose the type of creatures and their number.
|
||
|
-- Like the palette tree, the available creatures are filtered by their ecosystems and level.
|
||
|
-- Each life cycle duration is defined in the properties panel of the creature component.
|
||
|
-- The creation form will return the chosen creature base when ok button is pressed.
|
||
|
-- The form is reinitialized each time the ok or cancel button is pressed.
|
||
|
--
|
||
|
feature.registerForms = function()
|
||
|
|
||
|
-- Initializes the creature comboboxes. Default ecosystem is desert and default level range is 1-50.
|
||
|
local function init(creature)
|
||
|
local initEnum = {}
|
||
|
|
||
|
local creaturePalette = {}
|
||
|
if not r2.Palette.Entries.creature then
|
||
|
return -- special case for the 'light' palette
|
||
|
end
|
||
|
if creature == "Carnivore" then
|
||
|
creaturePalette = r2.Palette.Entries.creature.creatures_predators.instances
|
||
|
else
|
||
|
creaturePalette = r2.Palette.Entries.creature.creatures_passive.instances
|
||
|
end
|
||
|
local k, v = next(creaturePalette, nil)
|
||
|
while k do
|
||
|
if r2.isInPalette(v.Id) then
|
||
|
local paletteElt = r2.getPaletteElement(v.Id)
|
||
|
if paletteElt then
|
||
|
if paletteElt.Ecosystem == "Desert" and paletteElt.Level >= 1 and paletteElt.Level <= 50 then
|
||
|
table.insert(initEnum, i18n.get(v.Translation))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
k, v = next(creaturePalette, k)
|
||
|
end
|
||
|
|
||
|
return initEnum
|
||
|
end
|
||
|
|
||
|
r2.Forms.Fauna_Form =
|
||
|
{
|
||
|
Caption = "uiR2EdFauna",
|
||
|
Prop =
|
||
|
{
|
||
|
{Name="CarnivoresCount", Type="Number", Category="uiR2EDRollout_Carnivores", Min="1", Max="12", Default="3", Translation="uiR2EDProp_Count"},
|
||
|
{Name="CarnivoreRace", Type="Number", Category="uiR2EDRollout_Carnivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Race",
|
||
|
Enum= init("Carnivore")
|
||
|
},
|
||
|
{Name="CarnivoreEcosystem", Type="Number", Category="uiR2EDRollout_Carnivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Ecosystem",
|
||
|
Enum={"Desert", "Forest", "Jungle", "Lakes", "PrimeRoots", "Goo"},
|
||
|
onChange = updateCarnivores
|
||
|
},
|
||
|
{Name="CarnivoreLevel", Type="Number", Category="uiR2EDRollout_Carnivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Level",
|
||
|
Enum={"1-50", "51-100", "101-150", "151-200", "201-250"},
|
||
|
onChange = updateCarnivores
|
||
|
},
|
||
|
{Name="HerbivoresCount", Type="Number", Category="uiR2EDRollout_Herbivores", Min="1", Max="12", Default="7", Translation="uiR2EDProp_Count"},
|
||
|
{Name="HerbivoreRace", Type="Number", Category="uiR2EDRollout_Herbivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Race",
|
||
|
Enum= init("Herbivore")
|
||
|
},
|
||
|
{Name="HerbivoreEcosystem", Type="Number", Category="uiR2EDRollout_Herbivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Ecosystem",
|
||
|
Enum={"Desert", "Forest", "Jungle", "Lakes", "PrimeRoots", "Goo"},
|
||
|
onChange = updateHerbivores
|
||
|
},
|
||
|
{Name="HerbivoreLevel", Type="Number", Category="uiR2EDRollout_Herbivores", WidgetStyle="EnumDropDown", Translation="uiR2EDProp_Level",
|
||
|
Enum={"1-50", "51-100", "101-150", "151-200", "201-250"},
|
||
|
onChange = updateHerbivores
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
end
|
||
|
|
||
|
-- **************
|
||
|
-- * COMPONENTS *
|
||
|
-- **************
|
||
|
|
||
|
local FaunaRegionRadius = 5
|
||
|
|
||
|
|
||
|
-----------------------------------------------------------------------------------------------
|
||
|
-- CREATURE COMPONENT
|
||
|
|
||
|
feature.Components.Creature =
|
||
|
{
|
||
|
BaseClass="LogicEntity",
|
||
|
Name="Creature",
|
||
|
Menu="ui:interface:r2ed_feature_menu",
|
||
|
|
||
|
DisplayerUI = "R2::CDisplayerLua",
|
||
|
DisplayerUIParams = "defaultUIDisplayer",
|
||
|
DisplayerVisual = "R2::CDisplayerVisualEntity",
|
||
|
-----------------------------------------------------------------------------------------------
|
||
|
Parameters = {},
|
||
|
|
||
|
ApplicableActions = {},
|
||
|
|
||
|
Events = {},
|
||
|
|
||
|
Conditions = {},
|
||
|
|
||
|
TextContexts = {},
|
||
|
|
||
|
TextParameters = {},
|
||
|
|
||
|
LiveParameters = {},
|
||
|
-----------------------------------------------------------------------------------------------
|
||
|
Prop =
|
||
|
{
|
||
|
{Name="InstanceId", Type="String", WidgetStyle="StaticText", Visible = false},
|
||
|
{Name="Components", Type="Table", Visible= false},
|
||
|
{Name="Ghosts", Type = "Table", Visible = false },
|
||
|
{Name="Name", Type="String", MaxNumChar="32"},
|
||
|
{Name="CrittersCount", Type="String", WidgetStyle="StaticText", Translation="uiR2EDProp_CrittersCount"},
|
||
|
{Name="RaceBase", Type="String", WidgetStyle="StaticText", Visible=false},
|
||
|
{Name="RaceName", Type="String", WidgetStyle="StaticText", Translation="uiR2EDProp_Race"},
|
||
|
{Name="SleepZone", Type="RefId", PickFuntion = "r2:canPickZone", SetRefIdFunction = "r2:setZoneRefIdTarget", Translation="uiR2EDProp_SleepZone"},
|
||
|
{Name="FoodZone", Type="RefId", PickFuntion = "r2:canPickZone", SetRefIdFunction = "r2:setZoneRefIdTarget", Translation="uiR2EDProp_FoodZone"},
|
||
|
{Name="FoodDuration", Type="Number", Category="uiR2EDRollout_LifeCyclesInSeconds", Min="1", Max="40000", Default="30", Translation="uiR2EDProp_FoodDuration"},
|
||
|
{Name="SleepDuration", Type="Number", Category="uiR2EDRollout_LifeCyclesInSeconds", Min="1", Max="40000", Default="30", Translation="uiR2EDProp_SleepDuration"},
|
||
|
},
|
||
|
|
||
|
|
||
|
getAvailableCommands = function(this, dest)
|
||
|
r2.Classes.LogicEntity.getAvailableCommands(this, dest) -- fill by ancestor
|
||
|
this:getAvailableDisplayModeCommands(dest)
|
||
|
end,
|
||
|
|
||
|
appendInstancesByType = function(this, destTable, kind)
|
||
|
assert(type(kind) == "string")
|
||
|
r2.Classes.LogicEntity.appendInstancesByType(this, destTable, kind)
|
||
|
for k, component in specPairs(this.Components) do
|
||
|
component:appendInstancesByType(destTable, kind)
|
||
|
end
|
||
|
end,
|
||
|
|
||
|
getSelectBarSons = function(this)
|
||
|
return Components
|
||
|
end,
|
||
|
|
||
|
canHaveSelectBarSons = function(this)
|
||
|
return false;
|
||
|
end,
|
||
|
|
||
|
onPostCreate = function(this)
|
||
|
this:createGhostComponents()
|
||
|
end,
|
||
|
|
||
|
translate = function(this, context)
|
||
|
--local rtNpcGrp = r2.Translator.getRtGroup(context, context.Feature.InstanceId)
|
||
|
--local aiState = r2.newComponent("RtAiState")
|
||
|
--aiState.AiActivity = "normal"
|
||
|
--table.insert(context.RtAct.AiStates, aiState)
|
||
|
--table.insert(aiState.Children, rtNpcGrp.Id)
|
||
|
--local rtNpcGrp = r2.Translator.getRtGroup(context, this.InstanceId)
|
||
|
--r2.Translator.translateEventHandlers( context, this, this.Behavior.Actions, rtNpcGrp)
|
||
|
r2.Translator.translateAiGroup(this, context)
|
||
|
|
||
|
end,
|
||
|
|
||
|
pretranslate = function(this, context)
|
||
|
--local instance = r2:getInstanceFromId(context.Feature.InstanceId);
|
||
|
--r2.Translator.registerManager(context, context.Feature)
|
||
|
|
||
|
r2.Translator.createAiGroup(this, context)
|
||
|
end
|
||
|
}
|
||
|
|
||
|
local component = feature.Components.Creature
|
||
|
|
||
|
component.getLogicAction = function(entity, context, action)
|
||
|
return nil, nil
|
||
|
end
|
||
|
|
||
|
component.getLogicCondition = function(this, context, condition)
|
||
|
return nil,nil
|
||
|
end
|
||
|
|
||
|
component.getLogicEvent = function(this, context, event)
|
||
|
return nil, nil, nil
|
||
|
end
|
||
|
|
||
|
function component:getLogicTranslations()
|
||
|
|
||
|
local logicTranslations = {
|
||
|
["ApplicableActions"] = {},
|
||
|
["Events"] = {}
|
||
|
}
|
||
|
return nil--logicTranslations
|
||
|
end
|
||
|
|
||
|
component.createGhostComponents= function(this, act)
|
||
|
local comp = this
|
||
|
local leader = nil
|
||
|
local herd = nil
|
||
|
local isHerbivore
|
||
|
|
||
|
if act then
|
||
|
herd = r2.newComponent("NpcGrpFeature")
|
||
|
end
|
||
|
|
||
|
if comp._Seed then math.randomseed(comp._Seed) end
|
||
|
|
||
|
do
|
||
|
local x = comp.Position.x
|
||
|
local y = comp.Position.y
|
||
|
local n = comp._CrittersCount
|
||
|
local pas = (2 * math.pi)/n
|
||
|
local r = (n/(2*math.pi))+2
|
||
|
for i = 1, n do
|
||
|
local npc = r2.newComponent("Npc")
|
||
|
npc.Name = comp.RaceName
|
||
|
npc.Base = comp.RaceBase --"palette.entities.creatures.cbadc1"
|
||
|
|
||
|
|
||
|
local rr = FaunaRegionRadius - 1--r + math.random() * 5
|
||
|
npc.Position.x = (rr-1) * math.cos((i-1)*pas)
|
||
|
npc.Position.y = (rr-1) * math.sin((i-1)*pas)
|
||
|
npc.Position.z = 0
|
||
|
npc.Angle = 2 * math.pi * math.random(0, 100)/100.0
|
||
|
|
||
|
if i == 1 then
|
||
|
local manager = r2:getInstanceFromId(comp.ManagerId)
|
||
|
assert(manager)
|
||
|
if manager.Active == 1 then npc.AutoSpawn = 1 else npc.AutoSpawn = 0 end
|
||
|
leader = npc
|
||
|
r2.requestSetGhostNode(comp.InstanceId, "_LeaderId",npc.InstanceId)
|
||
|
isHerbivore = r2.getPropertyValue(npc, "IsHerbivore")
|
||
|
end
|
||
|
|
||
|
if act then -- TestMode --
|
||
|
table.insert(herd.Components, npc)
|
||
|
else
|
||
|
r2.requestInsertGhostNode(this.InstanceId, "Ghosts", -1, "", npc)
|
||
|
r2:getInstanceFromId(npc.InstanceId).Selectable = false
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- 2 wander sequences corresponding to the activities in both life zones attached to the herd
|
||
|
do
|
||
|
local sequence = r2.newComponent("ActivitySequence")
|
||
|
|
||
|
|
||
|
table.insert(leader.Behavior.Activities, sequence)
|
||
|
|
||
|
sequence.Name = "Life Cycle"
|
||
|
sequence.Repeating = 1
|
||
|
|
||
|
-- Wander in sleep zone
|
||
|
local step = r2.newComponent("ActivityStep")
|
||
|
table.insert(sequence.Components, step)
|
||
|
step.Type = "None"
|
||
|
step.Name = "Rest In Zone"
|
||
|
step.Activity = "Rest In Zone"
|
||
|
step.ActivityZoneId = r2.RefId(comp.SleepZone)
|
||
|
|
||
|
step.TimeLimit = "Few Sec"
|
||
|
step.TimeLimitValue = tostring(comp.SleepDuration)
|
||
|
|
||
|
-- Wander in food zone
|
||
|
local step = r2.newComponent("ActivityStep")
|
||
|
table.insert(sequence.Components, step)
|
||
|
step.Type = "None"
|
||
|
|
||
|
if isHerbivore == 1 then
|
||
|
step.Name = "Feed In Zone"
|
||
|
step.Activity = "Feed In Zone"
|
||
|
else
|
||
|
step.Name = "Hunt In Zone"
|
||
|
step.Activity = "Hunt In Zone"
|
||
|
end
|
||
|
step.ActivityZoneId = r2.RefId(comp.FoodZone)
|
||
|
|
||
|
step.TimeLimit = "Few Sec"
|
||
|
step.TimeLimitValue = tostring(comp.FoodDuration)
|
||
|
|
||
|
end
|
||
|
|
||
|
if act then
|
||
|
comp.User._Herd = herd.InstanceId
|
||
|
--herd.Name = r2:genInstanceName(i18n.get("uiR2EdFaunaFeature")):toUtf8()
|
||
|
herd.InheritPos = 0
|
||
|
herd.Position.x = comp.Position.x
|
||
|
herd.Position.y = comp.Position.y
|
||
|
r2.requestInsertGhostNode(act.InstanceId, "Features", -1, "", herd)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
component.createComponent = function(x, y, nbcritters, raceBase, raceName,
|
||
|
sleepZoneId, foodZoneId)
|
||
|
|
||
|
|
||
|
local comp = r2.newComponent("Creature")
|
||
|
assert(comp)
|
||
|
|
||
|
--comp.Base = "palette.entities.botobjects.user_event"
|
||
|
comp.Base = r2.Translator.getDebugBase("palette.entities.botobjects.user_event")
|
||
|
|
||
|
comp.Name = r2:genInstanceName(i18n.get("uiR2EdCreatureComponent")):toUtf8()
|
||
|
|
||
|
comp.Position.x = x
|
||
|
comp.Position.y = y
|
||
|
comp.Position.z = r2:snapZToGround(x, y)
|
||
|
|
||
|
comp._CrittersCount= nbcritters
|
||
|
comp.CrittersCount = tostring(nbcritters)
|
||
|
comp.RaceBase = raceBase
|
||
|
comp.RaceName = raceName
|
||
|
|
||
|
comp.SleepDuration = 30
|
||
|
comp.FoodDuration = 30
|
||
|
|
||
|
comp._Seed = os.time()
|
||
|
|
||
|
comp.SleepZone = sleepZoneId
|
||
|
comp.FoodZone = foodZoneId
|
||
|
|
||
|
return comp
|
||
|
end
|
||
|
|
||
|
-----------------------------------------------------------------------------------------------
|
||
|
-- FAUNA SYSTEM COMPONENT
|
||
|
-- Fauna system containing 2 Creature components (herbivores & carnivores) and 3 life zones.
|
||
|
feature.Components.Fauna =
|
||
|
{
|
||
|
BaseClass="LogicEntity",
|
||
|
Name="Fauna",
|
||
|
Menu="ui:interface:r2ed_feature_menu",
|
||
|
InEventUI = true,
|
||
|
|
||
|
DisplayerUI = "R2::CDisplayerLua",
|
||
|
DisplayerUIParams = "defaultUIDisplayer",
|
||
|
DisplayerVisual = "R2::CDisplayerVisualEntity",
|
||
|
-----------------------------------------------------------------------------------------------
|
||
|
Parameters = {},
|
||
|
|
||
|
ApplicableActions = {"activate", "deactivate"},
|
||
|
|
||
|
Events = {"deactivation", "activation"},
|
||
|
|
||
|
Conditions = {"is active", "is inactive"},
|
||
|
|
||
|
TextContexts = {},
|
||
|
|
||
|
TextParameters = {},
|
||
|
|
||
|
LiveParameters = {},
|
||
|
-----------------------------------------------------------------------------------------------
|
||
|
Prop =
|
||
|
{
|
||
|
{Name="InstanceId", Type="String", WidgetStyle="StaticText", Visible = false},
|
||
|
{Name="Components", Type="Table", Visible = false},
|
||
|
{Name="Ghosts", Type = "Table", Visible = false },
|
||
|
{Name="Name", Type="String", MaxNumChar="32"},
|
||
|
{Name="Active", Type = "Number", WidgetStyle="Boolean", DefaultValue="1" },
|
||
|
{Name="CarnivoresCount", Type="String", Category="uiR2EDRollout_Carnivores", WidgetStyle="StaticText", Translation="uiR2EDProp_Count"},
|
||
|
{Name="CarnivoreBase", Type="String", Category="uiR2EDRollout_Carnivores", WidgetStyle="StaticText", Visible = false},
|
||
|
{Name="CarnivoreRace", Type="String", Category="uiR2EDRollout_Carnivores", WidgetStyle="StaticText", Translation="uiR2EDProp_Race"},
|
||
|
{Name="HerbivoresCount", Type="String", Category="uiR2EDRollout_Herbivores", WidgetStyle="StaticText",Translation="uiR2EDProp_Count"},
|
||
|
{Name="HerbivoreBase", Type="String", Category="uiR2EDRollout_Herbivores", WidgetStyle="StaticText", Visible = false},
|
||
|
{Name="HerbivoreRace", Type="String", Category="uiR2EDRollout_Herbivores", WidgetStyle="StaticText", Translation="uiR2EDProp_Race"},
|
||
|
},
|
||
|
|
||
|
getParentTreeNode = function(this)
|
||
|
return this:getFeatureParentTreeNode()
|
||
|
end,
|
||
|
|
||
|
getAvailableCommands = function(this, dest)
|
||
|
r2.Classes.LogicEntity.getAvailableCommands(this, dest) -- fill by ancestor
|
||
|
this:getAvailableDisplayModeCommands(dest)
|
||
|
end,
|
||
|
|
||
|
appendInstancesByType = function(this, destTable, kind)
|
||
|
assert(type(kind) == "string")
|
||
|
r2.Classes.LogicEntity.appendInstancesByType(this, destTable, kind)
|
||
|
for k, component in specPairs(this.Components) do
|
||
|
component:appendInstancesByType(destTable, kind)
|
||
|
end
|
||
|
end,
|
||
|
|
||
|
getSelectBarSons = function(this)
|
||
|
return Components
|
||
|
end,
|
||
|
|
||
|
canHaveSelectBarSons = function(this)
|
||
|
return false;
|
||
|
end,
|
||
|
|
||
|
onPostCreate = function(this)
|
||
|
--this:createGhostComponents()
|
||
|
if this.User.DisplayProp and this.User.DisplayProp == 1 then
|
||
|
r2:setSelectedInstanceId(this.InstanceId)
|
||
|
r2:showProperties(this)
|
||
|
this.User.DisplayProp = nil
|
||
|
end
|
||
|
end,
|
||
|
|
||
|
translate = function(this, context)
|
||
|
r2.Translator.translateAiGroup(this, context)
|
||
|
r2.Translator.translateFeatureActivation(this, context)
|
||
|
end,
|
||
|
|
||
|
pretranslate = function(this, context)
|
||
|
r2.Translator.createAiGroup(this, context)
|
||
|
end
|
||
|
}
|
||
|
|
||
|
component = feature.Components.Fauna
|
||
|
|
||
|
|
||
|
local FaunaRegionNumCorners = 6
|
||
|
--local FaunaRegionRadius = 5
|
||
|
local FaunaRegionOffsets = { { x = 10, y = 0 }, { x = -7, y = -7}, { x = 0, y = 10} }
|
||
|
|
||
|
|
||
|
component.create = function()
|
||
|
if not r2:checkAiQuota() then return end
|
||
|
|
||
|
local function paramsOk(resultTable, form)
|
||
|
|
||
|
|
||
|
local carnivoreBase, carnivoreName = getBase("Carnivore", form)
|
||
|
local herbivoreBase, herbivoreName = getBase("Herbivore", form)
|
||
|
|
||
|
local x = tonumber( resultTable["X"] )
|
||
|
local y = tonumber( resultTable["Y"] )
|
||
|
|
||
|
local carnCount = tonumber(resultTable["CarnivoresCount"])
|
||
|
local herbCount = tonumber(resultTable["HerbivoresCount"])
|
||
|
|
||
|
|
||
|
if not r2:checkAiQuota(carnCount + herbCount + 1) then return end
|
||
|
|
||
|
|
||
|
if not x or not y or not carnivoreBase or not carnivoreName or not carnCount or not herbivoreBase
|
||
|
or not herbivoreName or not herbCount
|
||
|
then
|
||
|
r2:doForm("Fauna_Form", resultTable , paramsOk, paramsCancel)
|
||
|
resetForm()
|
||
|
|
||
|
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")
|
||
|
|
||
|
return
|
||
|
end
|
||
|
r2.requestNewAction(i18n.get("uiR2EDNewFaunaFeatureAction"))
|
||
|
local component = feature.Components.Fauna.createComponent(x, y, carnCount, carnivoreBase, carnivoreName,
|
||
|
herbCount, herbivoreBase, herbivoreName)
|
||
|
r2:setCookie(component.InstanceId, "DisplayProp", 1)
|
||
|
r2.requestInsertNode(r2:getCurrentAct().InstanceId, "Features", -1, "", component)
|
||
|
resetForm()
|
||
|
end
|
||
|
|
||
|
local function paramsCancel(data, form)
|
||
|
resetForm()
|
||
|
end
|
||
|
local function posOk(x, y, z)
|
||
|
debugInfo(string.format("Validate creation of 'FaunaFeature' at pos (%d, %d, %d)", x, y, z))
|
||
|
if r2.mustDisplayInfo("Fauna") == 1 then
|
||
|
r2.displayFeatureHelp("Fauna")
|
||
|
end
|
||
|
r2:doForm("Fauna_Form", {X=x, Y=y}, paramsOk, paramsCancel)
|
||
|
resetForm()
|
||
|
end
|
||
|
local function posCancel()
|
||
|
debugInfo("Cancel choice 'FaunaFeature' position")
|
||
|
end
|
||
|
--r2:choosePos("object_component_user_event.creature", posOk, posCancel, "createFeatureFauna")
|
||
|
local creature = r2.Translator.getDebugCreature("object_component_user_event.creature")
|
||
|
--r2:choosePos(creature, posOk, posCancel, "createFeatureFauna")
|
||
|
|
||
|
local polys = {}
|
||
|
for p = 1, table.getn(FaunaRegionOffsets) do
|
||
|
local poly = {}
|
||
|
local step = 2 * math.pi / FaunaRegionNumCorners
|
||
|
for k = 0, FaunaRegionNumCorners - 1 do
|
||
|
table.insert(poly, CVector2f(FaunaRegionOffsets[p].x + FaunaRegionRadius * math.cos(k * step),
|
||
|
FaunaRegionOffsets[p].y + FaunaRegionRadius * math.sin(k * step)))
|
||
|
end
|
||
|
table.insert(polys, poly)
|
||
|
end
|
||
|
r2:choosePos(creature, posOk, posCancel, "createFeatureFauna",
|
||
|
"curs_create.tga",
|
||
|
"curs_stop.tga",
|
||
|
polys, r2.PrimRender.ComponentRegionLook, r2.PrimRender.ComponentRegionInvalidLook)
|
||
|
end
|
||
|
|
||
|
function component.getAiCost(this)
|
||
|
if this.User.GhostDuplicate then return 0 end
|
||
|
return r2.getAiCost(this) - 2
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
--
|
||
|
-- create the fauna system component by creating and inserting zones and creature component into its own components table.
|
||
|
-- Generates a sleep zone and a food zone for the herbivores, and a sleep zone for the carnivores. The carnivore hunt zone is
|
||
|
-- one of the herbivore zones (default is herbivore sleep zone).
|
||
|
--
|
||
|
component.createComponent = function(x, y, carnCount, carnivoreBase, carnivoresName,
|
||
|
herbCount, herbivoreBase, herbivoresName)
|
||
|
|
||
|
local comp = r2.newComponent("Fauna")
|
||
|
assert(comp)
|
||
|
|
||
|
--TODO: replace this milestone base by some default feature base
|
||
|
comp.Base = "palette.entities.botobjects.user_event"
|
||
|
|
||
|
comp.Name = r2:genInstanceName(i18n.get("uiR2EdFaunaFeature")):toUtf8()
|
||
|
|
||
|
comp.Position.x = x
|
||
|
comp.Position.y = y
|
||
|
comp.Position.z = r2:snapZToGround(x, y)
|
||
|
|
||
|
comp._CarnCount= carnCount
|
||
|
comp.CarnivoresCount = tostring(carnCount)
|
||
|
comp.CarnivoreBase = carnivoreBase
|
||
|
comp.CarnivoreRace = tostring(carnivoresName)
|
||
|
|
||
|
comp._HerbCount= herbCount
|
||
|
comp.HerbivoresCount = tostring(herbCount)
|
||
|
comp.HerbivoreBase = herbivoreBase
|
||
|
comp.HerbivoresName = herbivoresName
|
||
|
comp.HerbivoreRace = tostring(herbivoresName)
|
||
|
|
||
|
comp._Seed = os.time()
|
||
|
|
||
|
-- Herbivore sleep zone
|
||
|
local zoneSleep1 = r2.newComponent("Region")
|
||
|
r2.Utils.createRegion(zoneSleep1, 0, 0, FaunaRegionRadius, FaunaRegionNumCorners)
|
||
|
zoneSleep1.Deletable = 1
|
||
|
zoneSleep1.Position.x = comp.Position.x + FaunaRegionOffsets[1].x
|
||
|
zoneSleep1.Position.y = comp.Position.y + FaunaRegionOffsets[1].y
|
||
|
zoneSleep1.Position.z = comp.Position.z
|
||
|
zoneSleep1.InheritPos = 0
|
||
|
zoneSleep1.Name = r2:genInstanceName(i18n.get("uiR2EDNameSleepRegion")):toUtf8()
|
||
|
table.insert(comp.Components, zoneSleep1)
|
||
|
|
||
|
-- Carnivore sleep zone
|
||
|
local zoneSleep2 = r2.newComponent("Region")
|
||
|
r2.Utils.createRegion(zoneSleep2, 0, 0, FaunaRegionRadius, FaunaRegionNumCorners)
|
||
|
zoneSleep2.Deletable = 1
|
||
|
zoneSleep2.Position.x = comp.Position.x + FaunaRegionOffsets[2].x
|
||
|
zoneSleep2.Position.y = comp.Position.y + FaunaRegionOffsets[2].y
|
||
|
zoneSleep2.Position.z = comp.Position.z
|
||
|
zoneSleep2.InheritPos = 0
|
||
|
zoneSleep2.Name = r2:genInstanceName(i18n.get("uiR2EDNameSleepRegion")):toUtf8()
|
||
|
table.insert(comp.Components, zoneSleep2)
|
||
|
|
||
|
--Herbivore sleep zone
|
||
|
local zoneFood = r2.newComponent("Region")
|
||
|
r2.Utils.createRegion(zoneFood, 0, 0, FaunaRegionRadius, FaunaRegionNumCorners)
|
||
|
zoneFood.Deletable = 1
|
||
|
zoneFood.Position.x = comp.Position.x + FaunaRegionOffsets[3].x
|
||
|
zoneFood.Position.y = comp.Position.y + FaunaRegionOffsets[3].y
|
||
|
zoneFood.Position.z = comp.Position.z
|
||
|
zoneFood.InheritPos = 0
|
||
|
zoneFood.Name = r2:genInstanceName(i18n.get("uiR2EDNameFoodRegion")):toUtf8()
|
||
|
table.insert(comp.Components, zoneFood)
|
||
|
|
||
|
-- Herd of herbivores
|
||
|
local herbivores = feature.Components.Creature.createComponent(zoneSleep1.Position.x, zoneSleep1.Position.y, herbCount, herbivoreBase,
|
||
|
herbivoresName, zoneSleep1.InstanceId, zoneFood.InstanceId)
|
||
|
herbivores.Name = i18n.get("uiR2EdHerbivores"):toUtf8()
|
||
|
--herbivores.Position.x = zoneSleep1.Position.x--comp.Position.x + 10
|
||
|
--herbivores.Position.y = zoneSleep1.Position.y--comp.Position.y + 10
|
||
|
herbivores.InheritPos = 0
|
||
|
--herbivores.Active = comp.Active
|
||
|
herbivores.ManagerId = comp.InstanceId
|
||
|
table.insert(comp.Components, herbivores)
|
||
|
comp._HerbId = herbivores.InstanceId
|
||
|
|
||
|
-- Pack of carnivores
|
||
|
local carnivores = feature.Components.Creature.createComponent(zoneSleep2.Position.x, zoneSleep2.Position.y, carnCount, carnivoreBase,
|
||
|
carnivoresName, zoneSleep2.InstanceId, zoneSleep1.InstanceId)
|
||
|
carnivores.Name = i18n.get("uiR2EdCarnivores"):toUtf8()
|
||
|
carnivores.InheritPos = 0
|
||
|
carnivores.ManagerId = comp.InstanceId
|
||
|
table.insert(comp.Components, carnivores)
|
||
|
comp._CarnId = carnivores.InstanceId
|
||
|
|
||
|
return comp
|
||
|
end
|
||
|
|
||
|
component.getLogicAction = function(entity, context, action)
|
||
|
assert( action.Class == "ActionStep")
|
||
|
local component = r2:getInstanceFromId(action.Entity)
|
||
|
assert(component)
|
||
|
local rtNpcGrp = r2.Translator.getRtGroup(context, component.InstanceId)
|
||
|
assert(rtNpcGrp)
|
||
|
|
||
|
local herbi = r2:getInstanceFromId(component._HerbId)
|
||
|
assert(herbi)
|
||
|
local herbivores = r2:getInstanceFromId(herbi.User._Herd)
|
||
|
assert(herbivores)
|
||
|
local rtHerbiGrp = r2.Translator.getRtGroup(context, herbivores.InstanceId)
|
||
|
assert(rtHerbiGrp)
|
||
|
|
||
|
local carni = r2:getInstanceFromId(component._CarnId)
|
||
|
assert(carni)
|
||
|
local carnivores = r2:getInstanceFromId(carni.User._Herd)
|
||
|
assert(carnivores)
|
||
|
local rtCarniGrp = r2.Translator.getRtGroup(context, carnivores.InstanceId)
|
||
|
assert(rtCarniGrp)
|
||
|
|
||
|
|
||
|
if action.Action.Type == "deactivate" then
|
||
|
local action1 = r2.Translator.createAction("set_value", rtNpcGrp.Id, "Active", 0)
|
||
|
local action2 = r2.Translator.getNpcLogicActionDeactivate(herbivores, context, action, rtHerbiGrp)
|
||
|
local action3 = r2.Translator.getNpcLogicActionDeactivate(carnivores, context, action, rtCarniGrp)
|
||
|
local action4 = r2.Translator.createAction("user_event_trigger", rtNpcGrp.Id, 5)
|
||
|
local multiaction = r2.Translator.createAction("multi_actions", {action1, action2, action3, action4})
|
||
|
return multiaction, multiaction
|
||
|
elseif (action.Action.Type == "activate") then
|
||
|
local action1 = r2.Translator.createAction("set_value", rtNpcGrp.Id, "Active", 1)
|
||
|
local action2 = r2.Translator.getNpcLogicActionActivate(herbivores, context, action, rtHerbiGrp)
|
||
|
local action3 = r2.Translator.getNpcLogicActionActivate(carnivores, context, action, rtCarniGrp)
|
||
|
local action4 = r2.Translator.createAction("user_event_trigger", rtNpcGrp.Id, 4)
|
||
|
local multiaction = r2.Translator.createAction("multi_actions", {action1, action2, action3, action4})
|
||
|
return multiaction, multiaction
|
||
|
end
|
||
|
|
||
|
return r2.Translator.getFeatureActivationLogicAction(rtNpcGrp, action)
|
||
|
end
|
||
|
|
||
|
component.getLogicEvent = function(this, context, event)
|
||
|
assert( event.Class == "LogicEntityAction")
|
||
|
local component = this
|
||
|
assert(component)
|
||
|
local rtNpcGrp = r2.Translator.getRtGroup(context, component.InstanceId)
|
||
|
assert(rtNpcGrp)
|
||
|
|
||
|
return r2.Translator.getFeatureActivationLogicEvent(rtNpcGrp, event)
|
||
|
end
|
||
|
|
||
|
component.getLogicCondition = function(this, context, condition)
|
||
|
assert( condition.Class == "ConditionStep")
|
||
|
local component = r2:getInstanceFromId(condition.Entity)
|
||
|
assert(component)
|
||
|
local rtNpcGrp = r2.Translator.getRtGroup(context, component.InstanceId)
|
||
|
assert(rtNpcGrp)
|
||
|
|
||
|
return r2.Translator.getFeatureActivationCondition(condition, rtNpcGrp)
|
||
|
end
|
||
|
|
||
|
function component:getLogicTranslations()
|
||
|
local logicTranslations = {}
|
||
|
r2.Translator.addActivationToTranslations(logicTranslations)
|
||
|
return logicTranslations
|
||
|
end
|
||
|
|
||
|
function component:registerMenu(logicEntityMenu)
|
||
|
local name = i18n.get("uiR2EdFaunaFeature")
|
||
|
logicEntityMenu:addLine(ucstring(name), "lua", "", "FaunaFeature")
|
||
|
end
|
||
|
|
||
|
r2.Features["FaunaFeature"] = feature
|
||
|
|