-- LUA Script - precede every function and global member with lowercase name of script + '_main' -- DESCRIPTION: smallg's motion tracker script -- DESCRIPTION: (default use key is Q) -- DESCRIPTION: [DISPLAYRANGE=3000] (how far the display can detect) -- DESCRIPTION: [DISPLAYANGLE=45(0,180)] (the view angle) -- DESCRIPTION: [UPDATEDELAY=150] (how quickly the tracker updates) -- DESCRIPTION: [MOVEDIST=1] (how far the entity needs to move to register on the tracker) -- DESCRIPTION: [FADETIME=1001] (how long before the blip is removed when entity stops moving) -- DESCRIPTION: [TRACKERX=0] (x pos of the tracker) -- DESCRIPTION: [TRACKERY=0] (y pos of the tracker) -- DESCRIPTION: [TRACKERSIZEX=100] (width of the tracker image) -- DESCRIPTION: [TRACKERSIZEY=100] (height of the tracker image) -- DESCRIPTION: [USEOVERLAY!=1] (use an image to show on top of the motion tracker display?) -- DESCRIPTION: [PLAYERX=25] (x offset of the player on the display) -- DESCRIPTION: [PLAYERY=45] (y offset of the player on the display) -- DESCRIPTION: [SHOWOFFSET!=0] (to help find the offset) -- DESCRIPTION: [MOTIONSIZEX=1] (width of the motion sprite) -- DESCRIPTION: [MOTIONSIZEY=1] (height of the motion sprite) -- DESCRIPTION: [TOGGLE!=1] (hold Q or press Q to show/hide the tracker) -- DESCRIPTION: [ANIMATED!=1] (is the tracker animated or a single image) -- DESCRIPTION: [ANIMATIONSPEED=1(0,100)] (how quick the animation plays) -- DESCRIPTION: (requires images in "scriptbank\\smallg\\images\\motiontracker\\") -- DESCRIPTION: ("display.png" & "motion.png" & ("overlay.png" or "motiontracker_000.png")) -- DESCRIPTION: (if animated use "motiontracker_000.png" to "motiontracker_099.png") -- DESCRIPTION: (sounds: 0 = take out tracker, 1 = put away tracker, 2 = motion detected) local displayimg = nil local overlayimg = {} local displayspr = nil local overlayspr = nil local motionimg = nil local motionspr = {} local timer = {} local oldx,oldy,oldz = {},{},{} local dot_posx, dot_posy = {},{} local currentframe = 0 local blips = 0 local showtracker = 0 local pressq = 0 local loadanimation = 0 U = U or require "scriptbank\\utillib" g_motiontracker = {} function motiontracker_properties(e, displayrange, displayangle, updatedelay, movedist, fadetime, trackerx, trackery, trackersizex, trackersizey, useoverlay, playerx, playery, showoffset, motionsizex, motionsizey, toggle, animated, animationspeed) local mt = g_motiontracker[e] mt.displayrange = displayrange mt.displayangle = displayangle mt.updatedelay = updatedelay mt.movedist = movedist mt.fadetime = fadetime mt.trackerx = trackerx mt.trackery = trackery mt.trackersizex = trackersizex mt.trackersizey = trackersizey mt.useoverlay = useoverlay mt.playerx = playerx mt.playery = playery mt.showoffset = showoffset mt.motionsizex = motionsizex mt.motionsizey = motionsizey mt.toggle = toggle mt.animated = animated mt.animationspeed = animationspeed end function motiontracker_init(e) g_motiontracker[e] = {} local mt = g_motiontracker[e] mt.displayrange = 3000 mt.displayangle = 45 mt.updatedelay = 150 mt.movedist = 1 mt.fadetime = 1001 mt.trackerx = 0 mt.trackery = 0 mt.trackersizex = 100 mt.trackersizey = 100 mt.useoverlay = 1 mt.playerx = 25 mt.playery = 45 mt.showoffset = 0 mt.motionsizex = 1 mt.motionsizey = 1 mt.toggle = 1 mt.animated = 1 mt.animationspeed = 1 timer[e] = {} timer[e][2] = 0 overlayimg[0] = nil end function motiontracker_main(e) local function GetDistanceToPos(x1,y1,z1,x2,y2,z2) local dx, dy, dz = x1 - x2, y1 - y2, z1 - z2 return dx*dx+dy*dy+dz*dz end local function pointAtPlayer (i) local x = g_PlayerPosX - g_Entity[i]['x']; local z = g_PlayerPosZ - g_Entity[i]['z']; local angle = math.atan2( z , x ); angle = angle + (-90.0*0.0174533); return angle; end local function file_exists(name) local f=io.open(name,"r") if f~=nil then io.close(f) return true else return false end end --move the entity just above the player at all times so the sound plays at the correct volumes Hide(e) CollisionOff(e) SetPosition(e,g_PlayerPosX, g_PlayerPosY + 300, g_PlayerPosZ) local mt = g_motiontracker[e] Text(2000,3000,3," ") -- to fix the max clear screen bug --check if the tracker is taken out or put away (pressing Q) if mt.toggle == 1 then if g_PlrKeyQ == 1 then if pressq == 0 then pressq = 1 if showtracker == 0 then showtracker = 1 currentframe = 0 PlaySound(e,0) SetSoundVolume(100) else showtracker = 0 PlaySound(e,1) SetSoundVolume(100) end end else pressq = 0 end --not in toggle mode so we need to hold Q else showtracker = g_PlrKeyQ if displayimg == nil then currentframe = 0 PlaySound(e,0) SetSoundVolume(100) end end --tracker is active if showtracker == 1 then --get the basic tracker image (i.e. the radar BG) if displayimg == nil then displayimg = LoadImage("scriptbank\\smallg\\images\\motiontracker\\display.png") end if displayspr == nil then displayspr = CreateSprite(displayimg) SetSpriteSize(displayspr, mt.trackersizex, mt.trackersizey) SetSpritePosition(displayspr, 2000, 2000) end PasteSpritePosition(displayspr, mt.trackerx, mt.trackery) --get the blip image to show when movement is detected if motionimg == nil then motionimg = LoadImage("scriptbank\\smallg\\images\\motiontracker\\motion.png") end if timer[e][1] == nil then timer[e][1] = g_Time end --this will detect motion if g_Time > timer[e][1] then blips = 0 local maxvol = 0 --loops through all entities on the map --might be a bit much for busy levels so might want to break it up into smaller loops? for a = 1, g_EntityElementMax do if a ~= nil then if g_Entity[a] ~= nil then local ent = g_Entity[a] if ent.obj ~= nil then if oldx[a] == nil or oldy[a] == nil or oldz[a] == nil then oldx[a] = ent.x oldy[a] = ent.y oldz[a] = ent.z else --check the entity has moved enough if GetDistanceToPos(ent.x, ent.y, ent.z, oldx[a], oldy[a], oldz[a]) > mt.movedist * mt.movedist then blips = blips + 1 --check it is within the tracker ranges we set if U.PlayerLookingNear(a, mt.displayrange, mt.displayangle) == true then oldx[a] = ent.x oldy[a] = ent.y oldz[a] = ent.z --create a blip sprite for this movement if it doesn't exist if motionspr[a] == nil then motionspr[a] = CreateSprite(motionimg) SetSpritePosition(motionspr[a], 2000, 2000) SetSpriteSize(motionspr[a], mt.motionsizex, mt.motionsizey) end --work out the blip placement on the tracker local angle = pointAtPlayer(a) + math.rad(g_PlayerAngY) local dist = GetPlayerDistance(a) local modifier = mt.displayrange / 16 dot_posx[a] = mt.trackerx + mt.playerx + (( math.sin(angle) * ( dist / modifier ) * (GetDeviceHeight()/GetDeviceWidth()) )) dot_posy[a] = mt.trackery + mt.playery + ( math.cos(angle) * ( dist / modifier ) ) timer[e][a+5] = g_Time + mt.fadetime --work out if the sound is louder than any other blip sounds (as we will only play the loudest) local vol = 105 - (dist / 80) if vol > 100 then vol = 100 elseif vol < 0 then vol = 0 end if vol > maxvol then maxvol = vol end end end end end end end end --if we have movement try to play the sound effect if maxvol > 0 then PlaySoundIfSilent(e,2) SetSoundVolume(maxvol) end timer[e][1] = g_Time + mt.updatedelay end --Prompt(blips) --update any movement blips and remove them out if timer is reached if g_Time > timer[e][2] then timer[e][2] = g_Time+15 for a = 1, g_EntityElementMax do if a ~= nil then if g_Entity[a] ~= nil then local ent = g_Entity[a] if ent.obj ~= nil then if timer[e][a+5] ~= nil then if g_Time < timer[e][a+5] then if motionspr[a] ~= nil then --TextCenterOnX(50,70,3,dot_posx[a].." "..dot_posy[a]) PasteSpritePosition(motionspr[a], dot_posx[a], dot_posy[a]) end else timer[e][a+5] = nil if motionspr[a] ~= nil then DeleteSprite(motionspr[a]) motionspr[a] = nil end end end end end end end end -- the idea is that the overlay will be on top of the blips and display so you can use it to try hide the edges if mt.useoverlay == 1 then if mt.animated == 0 then if overlayimg[0] == nil then overlayimg[0] = LoadImage("scriptbank\\smallg\\images\\motiontracker\\overlay.png") end else --if overlay is animated go through and load all the images (we do this in groups cos it takes a while) if loadanimation < 100 then if timer[e][4] == nil then timer[e][4] = 0 end if g_Time > timer[e][4] then for a = 0, 9 do local fn = "" local b = loadanimation+a fn = "scriptbank\\smallg\\images\\motiontracker\\motiontracker_0" if b < 10 then fn = fn.."0" end fn = fn..b..".png" if file_exists(fn) == true then overlayimg[b] = LoadImage(fn) timer[e][4] = g_Time+120 end end loadanimation = loadanimation + 10 end --TextCenterOnX(50,65,3,loadanimation.."%") end end --create the overlay sprite if overlayspr == nil then overlayspr = CreateSprite(overlayimg[0]) SetSpriteSize(overlayspr, mt.trackersizex, mt.trackersizey) SetSpritePosition(overlayspr, 2000, 2000) end --if the overlay is animated update the animation if mt.animated == 1 then if overlayimg[currentframe] ~= nil then SetSpriteImage(overlayspr, overlayimg[currentframe]) end if timer[e][3] == nil then timer[e][3] = g_Time + 15 end if g_Time > timer[e][3] then timer[e][3] = g_Time + 15 currentframe = currentframe + mt.animationspeed if currentframe >= 100 then currentframe = currentframe - 100 end local temp = 0 for a = 0, 99, mt.animationspeed do if a <= currentframe and overlayimg[a] ~= nil then temp = a else break end end currentframe = temp end --Text(50,60,3,currentframe) end PasteSpritePosition(overlayspr, mt.trackerx, mt.trackery) end if mt.showoffset == 1 then Text(mt.trackerx + mt.playerx, mt.trackery + mt.playery, 3, "^") end --if the tracker is not active we should remove all sprites and images from it else if displayspr ~= nil then DeleteSprite(displayspr) displayspr = nil end if displayimg ~= nil then DeleteImage(displayimg) displayimg = nil PlaySound(e,1) SetSoundVolume(100) end if overlayspr ~= nil then DeleteSprite(overlayspr) overlayspr = nil end if mt.animated == 1 then loadanimation = 0 timer[e][4] = nil for a = 0, 99 do if overlayimg[a] ~= nil then DeleteImage(overlayimg[a]) overlayimg[a] = nil end end end timer[e][1] = nil end end