--------------------------------------------- -- PROTOTYPE: script on the skullkin tower -- -- created by brandi... 10/13/10 -- updated brandi... 10/27/10 - account for not smashing all the legs so smashed ones respawn, and update the mission -- updated abeechler... 1/11/11 - updates mission/achievement status based on a defined local table of applicable mission ids. -- updated brandi.. 6/8/11 - made the script generic so it can be use on different assets --------------------------------------------- -- to set up in HF add the following config data -- missions 0:(list of missions separated by _) -- legLOT 1:(lot of the leg to spawn) -- enemyToSpawn 1:(lot of the 2 enemies that spawn as the tower is coming down) -- vert_offset 1:(amount the leg should be up higher than the pivot from the tower) -- hort_offset 1:(amount that each leg is away from the pivot of the tower) function onStartup(self,msg) -- set the proximity for the player to be taken out of the list if they leave the tower self:SetProximityRadius{radius = 20, collisionGroup = 1} end function onPhysicsComponentReady(self,msg) -- stop the base from pathing self:StopPathing() -- function to spawn the three legs of the tower spawnLegs(self,"Left") spawnLegs(self,"Right") spawnLegs(self,"Rear") end function spawnLegs(self,loc) -- get the position and direction of the tower to use to spawn the legs local oPos = { pos = "", rot = ""} local oDir = self:GetObjectDirectionVectors() -- get which tower the tower is and put it as a group on the legs ** this isnt used right now, but be later --local group = "tower"..self:GetVar("number") oPos.pos = self:GetPosition().pos oPos.rot = self:GetRotation() -- move the legs up a little, they are all shorter than the tower oPos.pos.y = oPos.pos.y + (self:GetVar("vert_offset") or 0) local newRot = oPos.rot --rotateVector(oPos.rot, oDir.backward) --off set of the is 12 units from the base local offset = self:GetVar("hort_offset") or 0 local legLOT = self:GetVar("legLOT") if not legLOT then return end if loc == "Right" then -- spawn right leg local config = { {"Leg", "Right"} } RESMGR:LoadObject { objectTemplate = legLOT, x= oPos.pos.x + (oDir.forward.x * offset) , y= oPos.pos.y, z= oPos.pos.z + (oDir.forward.z * offset), rw = newRot.w, rx = newRot.x, ry = newRot.y, rz = newRot.z, owner = self, configData = config} --rw = oPos.rot.w, rx = oPos.rot.x, ry = oPos.rot.y + 1, rz = oPos.rot.z, owner = self, configData = config} elseif loc == "Rear" then -- spawn rear leg local config = { {"Leg", "Rear"} } RESMGR:LoadObject { objectTemplate = legLOT, x= oPos.pos.x + (oDir.left.x * offset) , y= oPos.pos.y, z= oPos.pos.z + (oDir.left.z * offset), rw = newRot.w, rx = newRot.x, ry = newRot.y, rz = newRot.z, owner = self, configData = config} --rw = oPos.rot.w - 1, rx = oPos.rot.x, ry = oPos.rot.y + 1, rz = oPos.rot.z, owner = self, configData = config} elseif loc == "Left" then -- spawn left leg local config = { {"Leg", "Left"} } RESMGR:LoadObject { objectTemplate = legLOT, x= oPos.pos.x + (oDir.backward.x * offset), y= oPos.pos.y, z= oPos.pos.z + (oDir.backward.z * offset), rw = newRot.w, rx = newRot.x, ry = newRot.y, rz = newRot.z, owner = self, configData = config} --rw = oPos.rot.w - 1, rx = oPos.rot.x, ry = oPos.rot.y, rz = oPos.rot.z, owner = self, configData = config} end end -- when a leg is added function onChildLoaded( self, msg ) -- get the game object of the child local child = msg.childID local legLOT = self:GetVar("legLOT") --check to see if the child is a leg if child:GetLOT().objtemplate == legLOT then -- get the position of the tower local oPos = self:GetPosition().pos -- turn the legs to face the tower child:RotateToPoint{targetPos = oPos} -- get the table of legs local legtable = self:GetVar("legTable") --table containing players in the volume --create a table of the legs currently alive, by their ID if not legtable then -- if the table doesnt already exist (no one is in it), create it legtable = {} end for k,v in ipairs(legtable) do if v == child:GetID() then -- check to see if the leg is already in the table return end end -- the leg isnt already in the table, so put them there table.insert(legtable,child:GetID()) --set the table back to the set var self:SetVar("legTable",legtable) self:SendLuaNotificationRequest{requestTarget=child, messageName="Die"} self:PlayAnimation{ animationID = "idle"} self:ChangeIdleFlags {on = 1} end end -- when a leg dies function notifyDie(self,other,msg) -- find out who killed the leg local killer = msg.killerID -- get the table of players who have killed legs local players = self:GetVar("Players") --table containing players in the volume -- if the table doesnt already exist (no one is in it), create it if not players then players = {} else -- if the table exists, parse through it and see if the player is already in it for k,v in ipairs(players) do if v == killer:GetID() then -- if it is, jump out of the function return end end end -- the player isnt already in the table, so put them there table.insert(players,killer:GetID()) --set the table back to the set var self:SetVar("Players",players) end -- when a leg is removed function onChildRemoved(self,msg) local legLOT = self:GetVar("legLOT") if not msg.childID:GetLOT().objtemplate == legLOT then return end -- number of legs that still exist in the level local legsAlive = 0 -- number of legs left alive -- get the leg table if self:GetVar("legTable") then -- gmae object of the leg that was removed local leg = msg.childID -- get the leg table local legtable = self:GetVar("legTable") local removeLeg = 0 -- create variable for the Leg to be removed -- parse through all the legs in the table for k,v in ipairs(legtable) do -- if the leg in teh table matches the leg that was removed, set its key to be removed from the table if v == leg:GetID() then removeLeg = k break end end -- remove the leg from the table table.remove(legtable,removeLeg) -- if there's still legs in the table, set it back to set var, otherwise set it to nil if #legtable ~= 0 then self:SetVar("legTable",legtable) else self:SetVar("legTable",false) end -- when one leg is down, play minor wobble animation if #legtable == 2 then self:ChangeIdleFlags {off = 1} self:PlayAnimation{ animationID = "wobble-1" } -- when two legs are done, play more wobble animation elseif #legtable == 1 then self:PlayAnimation{ animationID = "wobble-2" } end -- if there are no legs left in the table if not self:GetVar("legTable") then -- get the time for the fall animation local animTime = self:GetAnimationTime{ animationID = "fall" }.time -- play the fall animation self:PlayAnimation{ animationID = "fall" } -- set the collision to not collide with anything so the skeletons wont get stuck on top self:SetCollisionGroup{colGroup = 25} -- start a timer to spawn the 2 skeletons that spawn on top GAMEOBJ:GetTimer():AddTimerWithCancel(animTime - 0.2, "spawnGuys", self ) -- start a timer to kill the tower GAMEOBJ:GetTimer():AddTimerWithCancel(animTime + 0.5, "killTower", self ) -- cancel any timers started by the legs dying GAMEOBJ:GetTimer():CancelTimer( "RespawnLeg", self ) if self:GetVar("missions") then local missionsToUpdate = split(self:GetVar("missions"),"_") -- get the list of all the players that have smashed a leg local players = self:GetVar("Players") if players then -- parse through them and make sure they exist for k,v in ipairs(players) do v = GAMEOBJ:GetObjectByID(v) if v:Exists() then for k,missionID in ipairs(missionsToUpdate) do -- if the player is on the currently iterated mission ID, then update the player mission status. v:UpdateMissionTask{taskType = "complete", value = missionID, value2 = 1, target = self} end end end end end -- no need to do the rest if the tower is done return end -- create a table to hold the location of legs that died local deadlegs = self:GetVar("DeadLegs") -- if a table already exists, check to see if the leg is already in the table, if so jump out, if not create a new table if deadlegs then for k,v in ipairs(deadlegs) do if v == removeLeg then return end end else deadlegs = {} end -- get the leg location off the config data on the leg local legLoc = leg:GetStoredConfigData{ optionalKey = "Leg" }.configData["Leg"] -- put the leg into the table table.insert(deadlegs,legLoc) self:SetVar("DeadLegs",deadlegs) -- cancel any previous leg timers GAMEOBJ:GetTimer():CancelTimer( "RespawnLeg", self ) -- start a new leg timer GAMEOBJ:GetTimer():AddTimerWithCancel( 20, "RespawnLeg", self ) end end -- find out when a player leaves the proximity of the tower function onProximityUpdate(self,msg) -- someone exited the towers's bubble if msg.status == "LEAVE" then -- get the player who left local exiter = msg.objId -- does the player really exist? if exiter:Exists() then -- get the players table local players = self:GetVar("Players") -- if there aren't any players in the table, then jump out of the function if not players then return end -- create variable for the player to be removed local removePlayer = 0 -- parse through all the players in the table for k,v in ipairs(players) do -- if teh player in teh table matches the player that was removed, set its key to be removed from the table if v == exiter:GetID() then removePlayer = k break end end -- remove the player from the table table.remove(players,removePlayer) -- if there's still players in the table, set it back to set var, otherwise set it to nil if #players ~= 0 then self:SetVar("Players",players) else self:SetVar("Players",{}) end end end end -- when the legs timer is done function onTimerDone(self, msg) if( msg.name == "RespawnLeg" ) then local legs = self:GetVar("DeadLegs") -- parse through all the legs in the table if legs then for k,v in ipairs(legs) do -- for every leg in the table, respawn that leg spawnLegs(self,v) end end -- clear the table out self:SetVar("DeadLegs",{}) -- timer to spawn the guys at the top of the tower elseif msg.name == "spawnGuys" then -- get the position of the tower again local oPos = { pos = "", rot = ""} oPos.pos = self:GetPosition().pos -- increase the y so the skullkin spawn on top of the tower oPos.pos.y = oPos.pos.y + 7 oPos.rot = self:GetRotation() local numEnemies = self:GetVar("numOfEnemies") or 2 -- spawn two skullkin on top of the tower for i = 1,numEnemies do RESMGR:LoadObject { objectTemplate = self:GetVar("enemyToSpawn"), x= oPos.pos.x, y= oPos.pos.y, z= oPos.pos.z, rw = oPos.rot.w, rx = oPos.rot.x, ry = oPos.rot.y, rz = oPos.rot.z, owner = self} end -- timer to kill the tower elseif msg.name == "killTower" then -- kill it violently so if it had an lxfml, it would play it self:RequestDie{ killerID = self, killtype = "VIOLENT" } end end function split(str, pat) local t = {} -- Creates a table of strings based on the passed in pattern string.gsub(str .. pat, "(.-)" .. pat, function(result) table.insert(t, result) end) return t end