---------------------------------------------------------------------------------------------------- -- -- All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -- its licensors. -- -- For complete copyright and license terms please see the LICENSE at the root of this -- distribution (the "License"). All use of this software is governed by the License, -- or, if provided, by the license below or the license accompanying this file. Do not -- remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- -- ---------------------------------------------------------------------------------------------------- EntityCommon = { TempPhysParams = { mass=0,density=0 }, TempPhysicsFlags = { flags_mask=0, flags=0 }; TempSimulationParams = { max_time_step=0.02 }; } ---------------------------------------------------------- -- Creates a new table that is derived class of parent entity. ---------------------------------------------------------- function MakeDerivedEntity( _DerivedClass,_Parent ) local derivedProperties = _DerivedClass.Properties; _DerivedClass.Properties = {}; mergef(_DerivedClass,_Parent,1); -- Add derived class properties. mergef(_DerivedClass.Properties,derivedProperties,1); _DerivedClass.__super = BasicEntity; return _DerivedClass; end ---------------------------------------------------------- -- Creates a new table that is derived class of parent entity. -- The Child's Properties will override the ones from the parent ---------------------------------------------------------- function MakeDerivedEntityOverride( _DerivedClass,_Parent ) --local derivedProperties = _Parent.Properties; --_Parent.Properties = {}; mergef(_DerivedClass,_Parent,1); -- Add derived class properties. --mergef(_DerivedClass.Properties,derivedProperties,1); _DerivedClass.__super = _Parent; return _DerivedClass; end ---------------------------------- function BroadcastEvent( sender,Event ) -- Check if Event Target for this input event exists. sender:ProcessBroadcastEvent( Event ); if (sender.Events) then --System.Log( "Events found" ); local eventTargets = sender.Events[Event]; if (eventTargets) then --System.Log( "Events Targets found" ); for i, target in pairs(eventTargets) do local TargetId = target[1]; local TargetEvent = target[2]; --System.Log( "Target: "..TargetId.."/"..TargetEvent ); --System.Log( "Target: "..TargetEvent ); if (TargetId == 0) then -- If TargetId refer to global Mission table. if Mission then local func = Mission["Event_"..TargetEvent]; if (func ~= nil) then func( sender ) else System.Log( "Mission does not support event "..TargetEvent ); end end else -- If TargetId refer to Entity. local entity = System.GetEntity(TargetId); if (entity ~= nil) then local TargetName=entity:GetName(); --System.Log( "Entity Named "..TargetName.." Found." ); --System.Log( "Calling method: "..TargetName..":Event_"..TargetEvent ); local func = entity["Event_"..TargetEvent]; if (func ~= nil) then func( entity,sender ) -- else -- System.Log( "Entity "..TargetName.." does not support event "..TargetEvent ); end -- else -- System.Log( "Entity Named "..TargetName.." Not Found." ); end end end end end end function DumpEntities() local ents=System.GetEntities(); System.Log("Entities dump"); for idx,e in pairs(ents) do local pos=e:GetPos(); local ang=e:GetAngles(); System.Log("["..tostring(e.id).."]..name="..e:GetName().." clsid="..e.class..format(" pos=%.03f,%.03f,%.03f",pos.x,pos.y,pos.z)..format(" ang=%.03f,%.03f,%.03f",ang.x,ang.y,ang.z)); end end function MakeTargetableByAI( entity ) if (not entity.Properties) then entity.Properties = {} end if (not entity.Properties.esFaction) then entity.Properties.esFaction = ""; end function entity:RegisterWithAI() if (self.Properties.esFaction ~= "") then CryAction.RegisterWithAI(self.id, AIOBJECT_TARGET); AI.ChangeParameter(self.id, AIPARAM_FACTION, self.Properties.esFaction); end end local _onReset = entity.OnReset; function entity:OnReset(...) if (_onReset) then _onReset(self, ...); end self:RegisterWithAI(); end local _onSpawn = entity.OnSpawn; function entity:OnSpawn(...) if (_onSpawn) then _onSpawn(self, ...); end self:RegisterWithAI(); end end function MakeAICoverEntity(entity) if (not entity.Properties) then entity.Properties = {} end if (not entity.Properties.bProvideAICover) then entity.Properties.bProvideAICover = 1 end local tbl = entity.Server and entity.Server or entity local _onStartGame = tbl.OnStartGame tbl.OnStartGame = function(self) if (self.PropertiesInstance.bProvideAICover ~= 0) and (AI ~= nil) then AI.AddCoverEntity(self.id) end if (_onStartGame) then _onStartGame(self) end end end function MakeKillable( entity ) if (not entity.Properties) then entity.Properties = {} end if (not entity.Properties.Health) then entity.Properties.Health = {} end local Health = entity.Properties.Health; Health.MaxHealth = 500; Health.bInvulnerable = 0; Health.bOnlyEnemyFire = 1; function entity:IsDead() return self.dead; end function entity:SetupHealthProperties() self.dead = nil; self.health = self.Properties.Health.MaxHealth; self.invulnerable = self.Properties.Health.bInvulnerable ~= 0; self.friendlyFire = self.Properties.Health.bOnlyEnemyFire == 0; end if (not entity.Server) then entity.Server = {} end if (not entity.Client) then entity.Client = {} end function entity:GetHealthRatio() local healthR = 1; local maxHealth = self.Properties.Health.MaxHealth; if (maxHealth > 0) then healthR = self.health / maxHealth; end return healthR; end function entity:IsInvulnerable() return self.invulnerable end function entity:GetMaxHealth() return self.Properties.Health.MaxHealth; end local _onHit = entity.Server.OnHit; function entity.Server:OnHit(hit) if ((not self.health) or (self.IsInvulnerable == nil)) then Log("$4%s:%s Health not initialized!", self.class, self:GetName()); self:SetupHealthProperties(); end local result = false; if (_onHit) then result = _onHit(self, hit); end if (not result) then if (self:IsInvulnerable()) then self:ActivateOutput("Health", self:GetHealthRatio() * 100); self:Event_Hit(); return false; end if (not self.friendlyFire) then if (System.GetEntity(hit.shooterId) ~= nil) then local reaction = AI.GetReactionOf(self.id, hit.shooterId); if (reaction == Friendly) then self:ActivateOutput("Health", self:GetHealthRatio() * 100); self:Event_Hit(); return false; end end end self.health = self.health - hit.damage; end self:ActivateOutput("Health", self:GetHealthRatio() * 100); self:Event_Hit(); if (self.health <= 0) then self.dead = true; self:Event_Dead(); return true; end end local _onReset = entity.OnReset; function entity:OnReset(...) if (_onReset) then _onReset(self, ...); end self:SetupHealthProperties(); end local _onSpawn = entity.OnSpawn; function entity:OnSpawn(...) if (_onSpawn) then _onSpawn(self, ...); end self:SetupHealthProperties(); end function entity:Event_ResetHealth() self.dead = nil; self.health = self.Properties.Health.MaxHealth; end function entity:SetInvulnerability(invulnerable) self.invulnerable = invulnerable; if(not self.overrode_saveload) then local _onSave = self.OnSave; function self:OnSave(table) if(_onSave) then _onSave(self, table); end if(self.invulnerable) then table.invulnerable = self.invulnerable; end if(self.dead) then table.dead = self.dead; end if(self.health) then table.health = self.health; end end local _onLoad = self.OnLoad; function self:OnLoad(table) if(_onLoad) then _onLoad(self, table); end if(table.invulnerable) then self.invulnerable = table.invulnerable; else self.invulnerable = false; end if(table.dead) then self.dead = table.dead; else self.dead = false; end if(table.health) then self.health = table.health; else self.health = self.Properties.Health.MaxHealth; end end self.overrode_saveload = true; end end function entity:Event_MakeVulnerable() self:SetInvulnerability(false); end function entity:Event_MakeInvulnerable() self:SetInvulnerability(true); end function entity:Event_Dead() self:TriggerEvent(AIEVENT_DISABLE); BroadcastEvent(self, "Dead"); end function entity:Event_Hit() BroadcastEvent(self, "Hit"); end if not entity.FlowEvents then entity.FlowEvents = {} end local fe = entity.FlowEvents fe.Inputs = fe.Inputs or {} fe.Outputs = fe.Outputs or {} fe.Inputs["ResetHealth"] = { entity.Event_ResetHealth, "any" }; fe.Inputs["MakeVulnerable"] = { entity.Event_MakeVulnerable, "any" }; fe.Inputs["MakeInvulnerable"] = { entity.Event_MakeInvulnerable, "any" }; fe.Outputs["Dead"] = "bool"; fe.Outputs["Hit"] = "bool"; fe.Outputs["Health"] = "float"; end function MakeRenderProxyOptions( entity ) if (not entity.Properties) then entity.Properties = {} end if (not entity.Properties.RenderProxyOptions) then entity.Properties.RenderProxyOptions = {} end entity.Properties.RenderProxyOptions.bAnimateOffScreenShadow = 0; function entity:SetRenderProxyOptions() self.bAnimateOffScreenShadow = self.Properties.RenderProxyOptions.bAnimateOffScreenShadow ~= 0; if (self.bAnimateOffScreenShadow) then self:CreateRenderProxy(); end self:SetAnimateOffScreenShadow(self.bAnimateOffScreenShadow); end local _onReset = entity.OnReset; function entity:OnReset(...) if (_onReset) then _onReset(self, ...); end self:SetRenderProxyOptions(); end local _onSpawn = entity.OnSpawn; function entity:OnSpawn(...) if (_onSpawn) then _onSpawn(self, ...); end self:SetRenderProxyOptions(); end end -- makes an OnUsed event for designers on an entity... -- usage: -- MyEntity = { ... whatever you usually put here ... } -- MakeUsable(MyEntity) -- function MyEntity:OnSpawn() ... -- function MyEntity:OnReset() -- self:ResetOnUsed() -- ... -- end function MakeUsable( entity ) if not entity.Properties then entity.Properties = {} end entity.Properties.UseMessage = ""; entity.Properties.bUsable = 0; function entity:IsUsable() if not self.__usable then self.__origUsable = self.Properties.bUsable; self.__origPickable = self.Properties.bPickable; if (self.Properties.bUsable==1 or self.Properties.bPickable==1) then self.__usable = 1; else self.__usable = 0; end end return self.__usable; end function entity:ResetOnUsed() self.__usable = nil; end function entity:GetUsableMessage() return self.Properties.UseMessage; end function entity:OnUsed(user, idx) BroadcastEvent(self, "Used"); if (self.Base_OnUsed) then self:Base_OnUsed(user, idx); end end function entity:Event_Used() BroadcastEvent(self, "Used"); end function entity:Event_EnableUsable() self.__usable = 1; BroadcastEvent(self, "EnableUsable"); end function entity:Event_DisableUsable() self.__usable = 0; BroadcastEvent(self, "DisableUsable"); end end function MakePickable( entity ) if not entity.Properties then entity.Properties = {} end; entity.Properties.bPickable = 0; end function AddHeavyObjectProperty(entity) if (not entity.Properties) then entity.Properties = {}; end; entity.Properties.bHeavyObject = 0; end; function MakeThrownObjectTargetable( entity ) -- Add property if not entity.Properties then entity.Properties = {}; end if not entity.Properties.AutoAimTarget then entity.Properties.AutoAimTarget = {}; end entity.Properties.AutoAimTarget.bMakeTargetableOnThrown = 0; entity.Properties.AutoAimTarget.InnerRadiusVolumeFactor = 0.35; entity.Properties.AutoAimTarget.OuterRadiusVolumeFactor = 0.6; entity.Properties.AutoAimTarget.SnapRadiusVolumeFactor = 1.25; entity.Properties.AutoAimTarget.AfterThrownTargetableTime = 3.0; -- Add callback functions function entity:OnThrown() if ((self.Properties.AutoAimTarget.bMakeTargetableOnThrown ~= 0) and (self:CanBeMadeTargetable())) then Game.RegisterWithAutoAimManager(self.id, self.Properties.AutoAimTarget.InnerRadiusVolumeFactor, self.Properties.AutoAimTarget.OuterRadiusVolumeFactor, self.Properties.AutoAimTarget.SnapRadiusVolumeFactor); Script.SetTimer(self.Properties.AutoAimTarget.AfterThrownTargetableTime * 1000, function() self:AfterThrownTimer(); end) self.isTargetable = 1; end end function entity:AfterThrownTimer() if (self.isTargetable) then Game.UnregisterFromAutoAimManager(self.id); self.isTargetable = nil; end end local _CanBeMadeTargetable = entity.CanBeMadeTargetable; function entity:CanBeMadeTargetable(...) if (_CanBeMadeTargetable) then return _CanBeMadeTargetable(self, ...); end return true; end -- Override shutdown/reset local _OnShutDown = entity.OnShutDown; function entity:OnShutDown(...) if _OnShutDown then _OnShutDown(self, ...); end if (self.isTargetable) then Game.UnregisterFromAutoAimManager(self.id); self.isTargetable = nil; end end local _OnReset = entity.OnReset; function entity:OnReset(...) if _OnReset then _OnReset(self, ...); end if (self.isTargetable) then Game.UnregisterFromAutoAimManager(self.id); self.isTargetable = nil; end end end function AddInteractLargeObjectProperty(entity) if (not entity.Properties) then entity.Properties = {}; end; entity.Properties.bInteractLargeObject = 0; end; function MakeSpawnable( entity ) entity.spawnedEntity = nil -- setup some basic properties if not entity.Properties then entity.Properties = {} end local p = entity.Properties; p.bSpawner = false; p.SpawnedEntityName = ""; local _OnDestroy = entity.OnDestroy; function entity:OnDestroy(...) -- System.Log("OnDestroy"..tostring(self.id)); if self.whoSpawnedMe then -- inform that I'm dead self.whoSpawnedMe:NotifyRemoval(self.id); end if _OnDestroy then _OnDestroy(self, ...); end end function entity:NotifyRemoval(spawnedEntityId) -- System.Log("NotifyRemoval"..tostring(self.id).." spawned="..tostring(spawnedEntityId)); -- clear spawnedEntity on original if (self.spawnedEntity and self.spawnedEntity == spawnedEntityId) then --System.Log("...Cleared"); self.spawnedEntity = nil; self.lastSpawnedEntity = nil; end end -- override some functions to have our code called also local _OnReset = entity.OnReset; function entity:OnReset(...) --System.Log("reset"); self.lastSpawnedEntity = nil; if self.spawnedEntity then System.RemoveEntity(self.spawnedEntity); self.spawnedEntity = nil; end if self.whoSpawnedMe then System.RemoveEntity( self.id ); return end _OnReset(self, ...); end local _OnEditorSetGameMode = entity.OnEditorSetGameMode; function entity:OnEditorSetGameMode(...) self.lastSpawnedEntity = nil; if self.spawnedEntity then self.spawnedEntity = nil; end if (_OnEditorSetGameMode) then _OnEditorSetGameMode(self, ...); end end -- allow flowgraph forwarding function entity:GetFlowgraphForwardingEntity() if (self.spawnedEntity) then return self.spawnedEntity; else return self.lastSpawnedEntity; end end -- OnSpawned event function entity:Event_Spawned() BroadcastEvent(self, "Spawned") end if not entity.FlowEvents then entity.FlowEvents = {} end local fe = entity.FlowEvents -- normalize events fe.Inputs = fe.Inputs or {} fe.Outputs = fe.Outputs or {} -- collate events local allEvents = {} local name, data for name, data in pairs(fe.Outputs) do allEvents[name] = data end for name, data in pairs(fe.Inputs) do allEvents[name] = data end -- event rebinding for name, data in pairs(allEvents) do local isInput = fe.Inputs[name] local isOutput = fe.Outputs[name] local isDeath = (name=="Dead") local _event = data if type(_event) == "table" then _event = _event[1] else _event = nil end entity["Event_"..name] = function(self, sender, param) -- auto broadcast received things for outputs if isOutput and (sender and sender.id == self.spawnedEntity or sender==self) then -- AI.LogEvent( ">>broadcasting output event "..name ); BroadcastEvent(self, name) end -- forward events where necessary if isInput and (self.spawnedEntity and ((not sender) or (self.spawnedEntity ~= sender.id))) then local ent = System.GetEntity(self.spawnedEntity) if _event and ent and ent ~= sender then _event(ent, sender, param) end elseif _event and not self.spawnedEntity then -- and pass through where not _event(self, sender, param) end -- handle death events if isDeath and (sender and sender.id == self.spawnedEntity) then self.spawnedEntity = nil end end end -- spawn event function entity:Event_Spawn() local entityIdDone = self:Event_Spawn_Internal(); -- the entity needs the output being activated, is not enough to just activate the output on the entity that spawnedMe, -- because the flowgraph could be already forwarded to the newly spawned entity (if the entity does not have the flowgraph associated, the output event will be just ignored) if (entityIdDone ~= self.id) then self:ActivateOutput("Spawned", self.id); end end function entity:Event_Spawn_Internal() if self.whoSpawnedMe then -- we were spawned (and not placed on a level)... -- GetForwardingEntity will make sure that this event -- is sent here first, but this event *MUST* be handled -- by our spawner return self.whoSpawnedMe:Event_Spawn_Internal() else if self.spawnedEntity then return nil end local params = { class = self.class; position = self:GetPos(), orientation = self:GetDirectionVector(1), scale = self:GetScale(), archetype = self:GetArchetype(), properties = self.Properties, propertiesInstance = self.PropertiesInstance, } if (self.InitialPosition) then params.position = self.InitialPosition; end if self.Properties.SpawnedEntityName ~= "" then params.name = self.Properties.SpawnedEntityName else params.name = self:GetName().."_s" end local ent = System.SpawnEntity(params, self.id) if ent then self.spawnedEntity = ent.id self.lastSpawnedEntity = ent.id; if not ent.Events then ent.Events = {} end local evts = ent.Events for name, data in pairs(self.FlowEvents.Outputs) do if not evts[name] then evts[name] = {} end table.insert(evts[name], {self.id, name}) end ent.whoSpawnedMe = self; ent:SetupTerritoryAndWave(); --self:Event_Spawned(); self:ActivateOutput("Spawned", ent.id); return self.id; end end end -- spawn event keep function entity:Event_SpawnKeep() local params = { class = self.class; position = self:GetPos(), orientation = self:GetDirectionVector(1), scale = self:GetScale(), archetype = self:GetArchetype(), properties = self.Properties, propertiesInstance = self.PropertiesInstance, } local rndOffset = 1; params.position.x = params.position.x + random(0,rndOffset*2)-rndOffset; params.position.y = params.position.y + random(0,rndOffset*2)-rndOffset; params.name = self:GetName() local ent = System.SpawnEntity(params, self.id) if ent then self.spawnedEntity = ent.id self.lastSpawnedEntity = ent.id; if not ent.Events then ent.Events = {} end local evts = ent.Events for name, data in pairs(self.FlowEvents.Outputs) do if not evts[name] then evts[name] = {} end table.insert(evts[name], {self.id, name}) end -- ent.whoSpawnedMe = self; --self:Event_Spawned(); self:ActivateOutput("Spawned", ent.id); end end -- hidhing/unhiding should be done inside disable/enable -- function entity:Event_Hide() -- self:Hide(1) -- end fe.Inputs["Spawn"] = {entity.Event_Spawn, "bool"} -- fe.Inputs["Hide"] = {entity.Event_Hide, "bool"} fe.Outputs["Spawned"] = "entity"; end ----------------------------------------------------------------------------------------- -- Setup the collision filtering for the entity ----------------------------------------------------------------------------------------- function SetupCollisionFiltering( entity ) -- Have we got an entity and a physics collision filtering table if (entity == nil) then return end if (entity.Properties == nil) then entity.Properties = {} end if (entity.Properties.Physics == nil) then entity.Properties.Physics = {} end -- Populate the table with the basic collision classes -- These are enumurated in the global g_PhysicsCollisionClass -- which is created by the game code entity.Properties.Physics.CollisionFiltering = {}; local c = entity.Properties.Physics.CollisionFiltering; c.collisionType = {} c.collisionIgnore = {} if (g_PhysicsCollisionClass == nil) then return end for i, v in pairs(g_PhysicsCollisionClass) do c.collisionType[i] = 0; c.collisionIgnore[i] = 0; end end function GetCollisionFiltering( entity ) local output = {} output.collisionClass = 0; output.collisionClassIgnore = 0; if (entity.Properties.Physics==nil) then return output; end if (entity.Properties.Physics.CollisionFiltering==nil) then return output; end local c = entity.Properties.Physics.CollisionFiltering; for i,v in pairs(c.collisionType) do local gameSideFlag = g_PhysicsCollisionClass[i]; if (gameSideFlag ~= nil and v==1) then output.collisionClass = output.collisionClass + gameSideFlag; end end for i,v in pairs(c.collisionIgnore) do local gameSideFlag = g_PhysicsCollisionClass[i]; if (gameSideFlag ~= nil and v==1) then output.collisionClassIgnore = output.collisionClassIgnore + gameSideFlag; end end return output; end function ApplyCollisionFiltering(entity, filtering) if (filtering.collisionClass ~= 0 or filtering.collisionClassIgnore ~= 0) then entity:SetPhysicParams(PHYSICPARAM_COLLISION_CLASS, filtering ); end end --------------------------------------------------------------------------------------------------- -- Physicalize rigid body. --------------------------------------------------------------------------------------------------- --GlobalPhysicsSimParams = { max_logged_collisions = 1 }; EntityCommon.PhysicalizeRigid = function( entity,nSlot,Properties,bActive ) local Mass = Properties.Mass; local Density = Properties.Density; if bActive and bActive==0 then Mass = 0.0; Density = 0.0; end local physType; if (Properties.bArticulated == 1) then physType = PE_ARTICULATED; else if (Properties.bRigidBody == 1) then physType = PE_RIGID; else physType = PE_STATIC; end end local TempPhysParams = EntityCommon.TempPhysParams; TempPhysParams.density = Density; TempPhysParams.mass = Mass; TempPhysParams.flags = 0; if (Properties.CGFPropsOverride) then TempPhysParams.CGFprops = ""; for key,value in pairs(Properties.CGFPropsOverride) do if (type(value)=="table") then for key1,value1 in pairs(value) do if (value1~="") then TempPhysParams.CGFprops = TempPhysParams.CGFprops..key1.."="..value1.."\n"; end end else if (value~="") then TempPhysParams.CGFprops = TempPhysParams.CGFprops..key.."="..value.."\n"; end end end end entity:Physicalize( nSlot, physType, TempPhysParams ); --entity:SetPhysicParams(PHYSICPARAM_SIMULATION, GlobalPhysicsSimParams ); if (Mass>0 or Density>0) then ApplyCollisionFiltering(entity, { collisionClass=gcc_rigid; } ); end if(Properties.bInteractLargeObject==1) then ApplyCollisionFiltering(entity, { collisionClass=gcc_large_kickable; } ); end ApplyCollisionFiltering(entity, GetCollisionFiltering(entity)); if (Properties.Simulation) then local SimulationSrc = Properties.Simulation; local SimulationDst = EntityCommon.TempSimulationParams; for key,value in next,SimulationDst,nil do SimulationDst[key] = nil; end for key,value in next,SimulationSrc,nil do if (key~="max_time_step" or value<0.0199 or value>0.0201) and (key~="sleep_speed" or value<0.0399 or value>0.0401) then SimulationDst[key] = value; end end entity:SetPhysicParams(PHYSICPARAM_SIMULATION, SimulationDst); end local Buoyancy = Properties.Buoyancy; if (Buoyancy) then entity:SetPhysicParams(PHYSICPARAM_BUOYANCY, Buoyancy); end local ForeignData = Properties.ForeignData; if(ForeignData and ForeignData.bMovingPlatform == 1) then entity:SetPhysicParams(PHYSICPARAM_FOREIGNDATA, { foreignFlags=FOREIGNFLAGS_MOVING_PLATFORM } ); end ----------------------------------------------------------------------------- -- Set physical flags. ----------------------------------------------------------------------------- local PhysFlags = EntityCommon.TempPhysicsFlags; PhysFlags.flags = 0; if (Properties.bPushableByPlayers == 1) then PhysFlags.flags = pef_pushable_by_players; end if (Simulation and Simulation.bFixedDamping and Simulation.bFixedDamping==1) then PhysFlags.flags = PhysFlags.flags+pef_fixed_damping; end if (Simulation and Simulation.bUseSimpleSolver and Simulation.bUseSimpleSolver==1) then PhysFlags.flags = PhysFlags.flags+ref_use_simple_solver; end if (Properties.bCanBreakOthers==nil or Properties.bCanBreakOthers==0) then PhysFlags.flags = PhysFlags.flags+pef_never_break; end if (Properties.MP and Properties.MP.bClientOnly) then -- allow breaking on the client PhysFlags.flags = PhysFlags.flags+pef_override_impulse_scale; end PhysFlags.flags_mask = pef_fixed_damping + ref_use_simple_solver + pef_pushable_by_players + pef_never_break + pef_override_impulse_scale; entity:SetPhysicParams( PHYSICPARAM_FLAGS,PhysFlags ); ----------------------------------------------------------------------------- if (Properties.bResting == 0) then entity:AwakePhysics(1); else entity:AwakePhysics(0); end end ------------------------------------------------------------------------------- -- Compare entities by name (for table.sort) ------------------------------------------------------------------------------- function CompareEntitiesByName( ent1, ent2 ) return ent1:GetName() < ent2:GetName() end function MakeCompareEntitiesByDistanceFromPoint( point ) function CompareEntitiesByDistanceFromPoint( ent1, ent2 ) distance1 = DistanceSqVectors( ent1:GetWorldPos(), point ) distance2 = DistanceSqVectors( ent2:GetWorldPos(), point ) return distance1 > distance2 end return CompareEntitiesByDistanceFromPoint end ------------------------------------------------------------------------------- -- Called by Pool System when an Entity is bookmarked for pool usage -- - Gives us its EntityId and PropertiesInstance tables for logic-driven utilities ------------------------------------------------------------------------------- function OnEntityBookmarkCreated( entityId, propertiesInstance ) local waveName = nil; if (propertiesInstance and propertiesInstance.AITerritoryAndWave) then waveName = propertiesInstance.AITerritoryAndWave.aiwave_Wave; end if (waveName and waveName ~= "") then -- Notify territory and wave AddBookmarkedToWave(entityId, waveName); return false; end return true; end