-- Alarm box will blink periodically when alarm is not triggered and -- faster when alarm is triggered. Alarm is triggered if ay of: -- 1) Box is broken -- 2) Box is tampered with (multiple modes, depending on how the box is attached) -- 3) Any rope connected to this box is detached JOINTED_STATIC = 1 JOINTED_DYNAMIC = 2 FIXED_STATIC = 3 FIXED_DYNAMIC = 4 #include "common/utils.lua" local smokePos = nil function init() box = FindShape("alarmbox") dynamic = IsBodyDynamic(GetShapeBody(box)) boxTransform = GetShapeWorldTransform(box) local min, max = GetShapeBounds(box) smokePos = VecLerp(min, max, 0.5) smokeTimer = 0.5 triggerAlarm = false idleSmokeTimer = 0.0 waitSmokeTimer = 0.0 AlarmActive = LoadSound("MOD/sound/alarm-activation.ogg") AlarmLoop = LoadLoop("MOD/sound/alarm-loop.ogg") SoundDoOnce = false local joints = GetShapeJoints(box) wires = {} wireVehicle = {} for i=1,#joints do if GetJointType(joints[i]) == "rope" then wires[#wires+1] = joints[i] local otherShape = GetJointOtherShape(joints[i],box) wireVehicle[#wireVehicle+1] = GetBodyVehicle(GetShapeBody(otherShape)) else joint = joints[i] end end if joint then local s = GetJointOtherShape(joint, box) if IsBodyDynamic(GetShapeBody(s)) then type = JOINTED_DYNAMIC initialMass = GetBodyMass(GetShapeBody(s)) else type = JOINTED_STATIC end else if IsBodyDynamic(GetShapeBody(box)) then type = FIXED_DYNAMIC initialMass = GetBodyMass(GetShapeBody(box)) else type = FIXED_STATIC end end SetShapeEmissiveScale(box, 0) blinkTimer = 0 light = FindLight() SetLightColor(light, 1.0, 0.15, 0.0) end function tick(dt) if GetBool("level.alarmdisabled") then SetShapeEmissiveScale(box, 0) return end blinkTimer = blinkTimer + dt local t = math.mod(blinkTimer, 2.0) local alarm = GetBool("level.alarm") if alarm then --Alarm blink if blinkTimer < 1.5 then SetShapeEmissiveScale(box, 10) else SetShapeEmissiveScale(box, 0) end else --Regular blink if t > 1.5 then SetShapeEmissiveScale(box, 0.5) else SetShapeEmissiveScale(box, 0) end end --Check if alarm should be triggered if not triggerAlarm then PlayLoop(AlarmLoop, boxTransform.pos, 0.5) -- Trigger alarm if any wire is broken for i = 1, #wires do if IsJointBroken(wires[i]) then triggerAlarm = true else if wireVehicle[i] ~= 0 then local otherShape = GetJointOtherShape(wires[i],box) if wireVehicle[i] ~= GetBodyVehicle(GetShapeBody(otherShape)) then triggerAlarm = true end end end end -- Trigger alarm if box is broken if IsShapeBroken(box) then triggerAlarm = true end if type == FIXED_STATIC then if IsBodyDynamic(GetShapeBody(box)) then triggerAlarm = true end elseif type == FIXED_DYNAMIC then local currentMass = GetBodyMass(GetShapeBody(box)) if currentMass < 0.5 * initialMass then triggerAlarm = true end elseif type == JOINTED_STATIC then if IsJointBroken(joint) then triggerAlarm = true else local s = GetJointOtherShape(joint, box) if IsBodyDynamic(GetShapeBody(s)) then triggerAlarm = true end end elseif type == JOINTED_DYNAMIC then if IsJointBroken(joint) then triggerAlarm = true else local s = GetJointOtherShape(joint, box) local currentMass = GetBodyMass(GetShapeBody(s)) if currentMass < 0.5 * initialMass then triggerAlarm = true end end end if triggerAlarm then if not SoundDoOnce then PlaySound(AlarmActive, boxTransform.pos) SoundDoOnce = true end local challengeState = GetString("challenge.state", "unavailable") if challengeState == "unavailable" then SetBool("level.alarm", true) end if GetString("challenge.state") ~= "done" then SetBool("level.alarm", true) end blinkTimer = 0 end idleSmokeTimer = idleSmokeTimer + dt if idleSmokeTimer >= 1.5 then ParticleReset() ParticleType("smoke") ParticleColor(0.9, 0.9, 0.9) ParticleRadius(0.038, 0.093, "easeout") ParticleCollide(1) ParticleAlpha(0.43, 0, "smooth", "fadein") ParticleRotation(1, 7, "easeout") ParticleStretch(1) ParticleTile(3) ParticleDrag(0.3) SpawnParticle(smokePos, TransformToParentVec(boxTransform, Vec(rnd(-0.5, 0.5), 2, 2)), 3) end if idleSmokeTimer >= 2.0 then idleSmokeTimer = 0.0 end else if waitSmokeTimer < 0.5 then waitSmokeTimer = waitSmokeTimer + dt else if smokeTimer > 0 then smokeTimer = smokeTimer - dt ParticleReset() ParticleType("smoke") ParticleColor(0.9, 0.9, 0.9) ParticleRadius(0.6, 3, "easeout") ParticleCollide(1) ParticleGravity(-1) ParticleAlpha(0.37, 0.01, "smooth", "fadein") ParticleRotation(1, 2.5, "easeout") ParticleStretch(1) ParticleTile(3) ParticleDrag(0.3) ParticleSticky(0.3) for i = 1, 2 do SpawnParticle(smokePos, Vec(rnd(-20, 20), -20, rnd(-20, 20)), 10) end end end end end function handleCommand(cmd) if cmd == "quickload" then --from scene init box = FindShape("alarmbox") dynamic = IsBodyDynamic(GetShapeBody(box)) boxTransform = GetShapeWorldTransform(box) local min, max = GetShapeBounds(box) smokePos = VecLerp(min, max, 0.5) smokeTimer = 0.5 triggerAlarm = false idleSmokeTimer = 0.0 waitSmokeTimer = 0.0 AlarmActive = LoadSound("MOD/sound/alarm-activation.ogg") AlarmLoop = LoadLoop("MOD/sound/alarm-loop.ogg") SoundDoOnce = false local joints = GetShapeJoints(box) wires = {} wireVehicle = {} for i=1,#joints do if GetJointType(joints[i]) == "rope" then wires[#wires+1] = joints[i] local otherShape = GetJointOtherShape(joints[i],box) wireVehicle[#wireVehicle+1] = GetBodyVehicle(GetShapeBody(otherShape)) else joint = joints[i] end end if joint then local s = GetJointOtherShape(joint, box) if IsBodyDynamic(GetShapeBody(s)) then type = JOINTED_DYNAMIC initialMass = GetBodyMass(GetShapeBody(s)) else type = JOINTED_STATIC end else if IsBodyDynamic(GetShapeBody(box)) then type = FIXED_DYNAMIC initialMass = GetBodyMass(GetShapeBody(box)) else type = FIXED_STATIC end end SetShapeEmissiveScale(box, 0) blinkTimer = 0 light = FindLight() SetLightColor(light, 1.0, 0.15, 0.0) end end