#include "/script/common.lua" pSpeed = GetFloatParam("speed", 7) pActivationId = GetStringParam("id", "challenge.balloon1") function init() SetBool("level."..pActivationId,false) balloon = FindBody("balloon") balloonstart = FindLocation("balloonstart") balloonend = FindLocation("balloonend") balloonTransform = GetLocationTransform(balloonstart) balloonSound = LoadLoop("fire-out-loop.ogg") balloonChargeSound = LoadSound("chopper-charge.ogg") balloonShootSound = LoadSound("tools/shotgun0.ogg") balloonShootGunSound = LoadSound("tools/gun0.ogg") balloonStartSound = LoadSound("chopper-start.ogg") balloonEndSound = LoadSound("chopper-end.ogg") balloonSoundSound = LoadSound("chopper-sound.ogg") inSpawning = false angle = 0.0 targetPos = balloonTransform balloonHeight = GetLocationTransform(balloonend).pos[2] balloonVel = Vec() balloonVelScale = 0.5 balloonTargetPos = VecAdd(balloonTransform.pos, Vec(0,0,0)) balloonTargetRot = QuatEuler() searchLightTargetRot = QuatEuler() searchLightRot = QuatEuler() averageSurroundingHeight = 0 poiPos = Vec() poiTimer = 0.0 playerSeen = false timeSinceLastSeen = 0 shootCooldown = 3 shootTimer = 0.0 shootGunCooldown = 1.2 shootGunTimer = 0.0 end function spawnBaloon() if not active and (GetBool("challenge."..pActivationId) or InputPressed("X") or GetBool("level.alarm")) then --PlaySound(balloonStartSound) active = true --Spawn("MOD/prefabs/balloon.xml", balloonTransform) balloon = FindBody("balloon") basket = FindBody("basket") SetBodyDynamic(basket, true) inSpawning = true end end function getDistanceToPlayer() return VecLength(VecSub(GetPlayerPos(), balloonTransform.pos)) end function canSeePlayer() local playerPos = GetPlayerPos() --Direction to player local dir = VecSub(playerPos, balloonTransform.pos) local dist = VecLength(dir) dir = VecNormalize(dir) QueryRejectVehicle(GetPlayerVehicle()) QueryRejectBody(balloon) QueryRejectBody(GetPlayerGrabBody()) return not QueryRaycast(balloonTransform.pos, dir, dist, 0, true) end function getSoundVolume(pos) local d = VecLength(VecSub(pos, balloonTransform.pos)) local dir = VecNormalize(VecSub(pos, balloonTransform.pos)) local distanceLower = 20 local distanceUpper = 100 local distanceFactor = 1.0 - clamp(d-distanceLower, 0, distanceUpper-distanceLower)/(distanceUpper-distanceLower) local origin = balloonTransform.pos local dist = d - 2 local blockedFactor = 1.0 QueryRejectBody(balloon) if QueryRaycast(origin, dir, dist) then blockedFactor = 0.5 end return blockedFactor * distanceFactor end function shoot(dt) if shootTimer < shootCooldown then shootTimer = shootTimer + dt return end shootTimer = 0.0 local shotpos = GetBodyTransform(basket).pos PlaySound(balloonShootSound, shotpos, 8, false) local shotdirection = VecNormalize(VecSub(targetPos, shotpos)) local spread = 0.02 if GetPlayerVehicle() ~= 0 then spread = 0.01 end shotdirection[1] = shotdirection[1] + (math.random()-0.5) * spread shotdirection[2] = shotdirection[2] + (math.random()-0.5) * spread shotdirection[3] = shotdirection[3] + (math.random()-0.5) * spread shotdirection = VecNormalize(shotdirection) shotpos = VecAdd(shotpos, VecScale(shotdirection, 5)) Shoot(shotpos, shotdirection, "bullet", 1.5, 200) end function shootGun(dt) if shootGunTimer < shootGunCooldown then shootGunTimer = shootGunTimer + dt return end shootGunTimer = 0.0 local shotpos = GetBodyTransform(basket).pos PlaySound(balloonShootGunSound, shotpos, 5, false) local shotdirection = VecNormalize(VecSub(targetPos, shotpos)) local spread = 0.03 if GetPlayerVehicle() ~= 0 then spread = 0.1 end shotdirection[1] = shotdirection[1] + (math.random()-0.5) * spread shotdirection[2] = shotdirection[2] + (math.random()-0.5) * spread shotdirection[3] = shotdirection[3] + (math.random()-0.5) * spread shotdirection = VecNormalize(shotdirection) shotpos = VecAdd(shotpos, VecScale(shotdirection, 5)) Shoot(shotpos, shotdirection, "bullet", 1, 150) end function rejectAllHelicopters() for i=1,#balloons do QueryRejectBody(balloons[i]) end end function tick(dt) spawnBaloon() if GetBool("challenge.hardmode") then hardmode = true end if not active then return end if not complete and GetFloat("game.player.health") == 0.0 then complete = true --PlaySound(balloonEndSound) return end if inSpawning then balloonTargetPos = GetLocationTransform(balloonend).pos else balloonTargetPos = GetPlayerPos() end playerSpeed = VecLength(VecSub(GetPlayerPos(), lastPlayerPos)) / dt playerSeen = false if canSeePlayer() then targetPos = GetPlayerPos() playerSeen = true shoot(dt) shootGun(dt) end --PlayLoop(balloonSound, balloonTransform.pos, 8, false) DrawBodyOutline(balloon, 1.0) end function update(dt) if not active then return end --Move balloon towards target position smoothly local acc = VecNormalize(VecSub(balloonTargetPos, balloonTransform.pos)) balloonVel = VecAdd(balloonVel, VecScale(acc, 1)) balloonVel = VecScale(balloonVel, balloonVelScale) balloonTransform.pos = VecAdd(balloonTransform.pos, VecScale(balloonVel, 2 * dt)) if inSpawning then if balloonTransform.pos[2] >= balloonHeight then inSpawning = false balloonTransform.pos[2] = balloonHeight end else balloonTransform.pos[2] = balloonHeight end SetBodyTransform(balloon, balloonTransform) if not IsBodyActive(basket) then SetBodyActive(basket, true) end end