#include "script/common.lua" #include "script/explosion.lua" #include "../../script/common/utils.lua" local train = nil local bridge = nil local railtrigger = nil local onbridge = nil local breakpoint = nil local mtarget = nil local wagonsjoint_01 = nil local wagonsjoint_02 = nil local wagon_01 = nil local wagon_02 = nil local railmotor = nil local second_target = nil local third_target = nil local tooearly_trigger = nil delay_01 = GetIntParam("Delay", 90) speed_01 = GetFloatParam("Speed", 4.5) local trainSmokeShape = nil function rndVec(t) return Vec(rnd(-t, t), rnd(-t, t), rnd(-t, t)) end function init() fade = false appeartime = delay_01 train_spawned = false loc_imp = speed_01 fadeToBlackAlpha = 0 fadeInAlpha = 0.05 fadetimer = 0 fall = false explode = false scene_launched = false ----from scene init bridge = FindBody("bridge", true) breakpoint = FindLocations("breakpoint", true) railtrigger = FindTrigger("railtrigger") onbridge = FindTrigger("onbridge") tooearly_trigger = FindTrigger("tooearly",true) trainsound = LoadSound("MOD/data/snd/train_tutu.ogg", 50) trainmovingsound = LoadLoop("MOD/data/snd/train_moves.ogg", 50) trainsound_step = 5 ----cutscene_train winTimer = 0 camera_target = nil eye = nil eye_end = FindLocation("eye_end") eye_end_02 = FindLocation("eye_end_02") trainspawn_win = FindLocation("trainspawn_win", true) cutscene = false eye_target_02 = FindLocation("eye_target_02", true) camera_transform = nil local wave_start = FindLocations("wave_start") local wave_start_02 = FindLocations("wave_start_02") firewave_pos = {} shockwave_pos = {} shockwave_02_pos = {} for i=1, #wave_start do firewave_pos[i] = GetLocationTransform(wave_start[i]).pos shockwave_pos[i] = GetLocationTransform(wave_start[i]).pos shockwave_02_pos[i] = GetLocationTransform(wave_start_02[i]).pos end gameover_trigger = FindTrigger("gameovertrigger", true) ----target main_target = FindBody("target", true) pArrowSize = 2 local arrow = FindLocation("arrow", true) if arrow ~= 0 then arrowSprite = LoadSprite("gfx/arrowdown.png") arrowPos = GetLocationTransform(arrow).pos arrowPos[2] = arrowPos[2] + pArrowSize/2 end show_finish_arrow = true ----time machine car time_machine = FindBody("time_machine", true) start_machine_transform = GetBodyTransform(time_machine) machine_up = false machine_pitch = false machine_punched = false machine_speed = -1 machine_speed_acceleration = 1 trigger_timetravel = FindTrigger("trigger_timetravel") machine_delay = nil rocket_light = FindLights("rocket_light", true) timetravel_shinig = FindLight("time_shining", true) machine_transform = nil wheels_lights = FindLights("shining", true) ---fire fire = TSharedUserdata.create("fire") fire.age = 0 fire.life = 10 fire.size = 1 ---debris fire debris_fire = TSharedUserdata.create("fire") debris_fire.age = 0 debris_fire.life = 5 debris_fire.size = 0.8 local debris_count = math.random(5,8) debris_fire_pos = {} for i = 1, debris_count do local randompos = math.random(1, #firewave_pos) debris_fire_pos[i] = firewave_pos[randompos] debris_fire_pos[i][2] = debris_fire_pos[i][2] + rnd(0.5, 1.5) end --Sounds sound_fireball = LoadLoop("MOD/sound/ravine_cutscenes/fireball.ogg") end function tick(dt) if GetBool("level.complete") and show_finish_arrow then local c = GetCameraTransform().pos c[2] = arrowPos[2] local p = VecCopy(arrowPos) p[2] = p[2] + math.sin(GetTime()*5)*0.3+0.3 local t = Transform(p, QuatLookAt(arrowPos, c)) DrawSprite(arrowSprite, t, pArrowSize, pArrowSize, 1, 1, 1, 1, true, false) end Train_Sounds(dt) SpawnTrainSmoke() machine_transform = GetBodyTransform(time_machine) Machine_Flies(dt) if not train_spawned and appeartime < GetTime() then ---Spawn train----------- Spawn_Train() end if GetPlayerInteractBody() == time_machine and InputPressed("interact") then if not GetBool("level.complete") then SetString("hud.notification","The Car is useless without explosion power!") else show_finish_arrow = false SetFloat("level.timelimit", -1) fade = true RemoveTag(time_machine, "interact") Train_WIN_Scene() end end if scene_launched then Final_Cut_Scene(dt) end if (explode and winTimer < 4.5) then SetTimeScale(0.6) end end function update(dt) if train_spawned then ---Move spawn train---------- Train_Moves() if IsShapeInTrigger(onbridge, train) and not fall and GetBool("level.complete") then Locomotive_Fall() end if not fall and not dead then if IsShapeInTrigger(gameover_trigger, train) then dead = true end local railmotors_count = 0 for i = 1, #railmotor do if IsJointBroken(railmotor[i]) and railmotor[i] ~= nil then for j = 1, #railmotor do Delete(railmotor[j]) end if (not GetBool("level.complete") or IsShapeInTrigger(tooearly_trigger, train)) then dead = true SetString("level.state", "fail") end end end end end if fall then if IsHandleValid(wagonsjoint_01) and IsPointInTrigger(railtrigger, GetShapeWorldTransform(wagon_01).pos) then Delete(wagonsjoint_01) end if IsHandleValid(wagonsjoint_02) and IsPointInTrigger(railtrigger, GetShapeWorldTransform(wagon_02).pos) then Delete(wagonsjoint_02) end if winTimer > 4 and not explode then RemoveTag(train, "unbreakable") local explosivetrainpos = TransformToParentPoint(GetShapeWorldTransform(train), Vec(6,1,2)) Explosion(explosivetrainpos, 8) explode = true dead = true for i = 1, #debris_fire_pos do FireDebris(debris_fire_pos[i]) end end end if (explode and winTimer < 4.7) then if HasTag(wagon_01, "unbreakable") and winTimer > 4.1 then RemoveTag(wagon_01, "unbreakable") Explosion( GetShapeWorldTransform(wagon_01).pos, 8) end if HasTag(wagon_02, "unbreakable") and winTimer > 4.2 then RemoveTag(wagon_02, "unbreakable") Explosion( GetShapeWorldTransform(wagon_02).pos, 8) end if winTimer > 4.2 then PlayLoop(sound_fireball) for i = 1, #firewave_pos do --smokeUpdateCPP(smoke, firewave_pos[i], dt) fireUpdateCPP(fire, firewave_pos[i], dt) explosionSparksCPP(firewave_pos[i], math.random(12,15), 1) firewave_pos[i][1] = firewave_pos[i][1] + rnd(-dt * 26,dt * 26) firewave_pos[i][2] = firewave_pos[i][2] + rnd(-dt * 10,dt * 10) firewave_pos[i][3] = firewave_pos[i][3] + rnd(dt * 23, dt * 26) fire.age = 0 end end for i = 1, #firewave_pos do ShockWave(shockwave_pos[i]) ShockWave(shockwave_02_pos[i]) shockwave_pos[i][3] = shockwave_pos[i][3] + dt * 30 shockwave_02_pos[i][3] = shockwave_02_pos[i][3] - dt * 30 end end if fade and fadetimer <= 3 then fadetimer = fadetimer + dt elseif fadetimer > 3 and fade then fade = false end if IsHandleValid(time_machine) then Floating_Dust() end end function handleCommand(cmd) if cmd == "quickload" then --from scene init train = FindShape("train") bridge = FindBody("bridge", true) railtrigger = FindTrigger("railtrigger") onbridge = FindTrigger("onbridge") breakpoint = FindLocations("breakpoint", true) mtarget = FindBody("main", true) second_target = FindBody("second", true) third_target = FindBody("third", true) wagonsjoint_01 = FindJoint("wagonsjoint_01", true) wagonsjoint_02 = FindJoint("wagonsjoint_02", true) wagon_01 = FindShape("wagon_01", true) wagon_02 = FindShape("wagon_02", true) railmotor = FindJoints("railmotor", true) end end function draw() if fade and fadetimer <= 1.5 then UiPush() fadeToBlackAlpha = fadeToBlackAlpha + fadeInAlpha UiColor(0, 0, 0, fadeToBlackAlpha) UiAlign("midlle") UiRect(UiWidth(), UiHeight()) UiPop() elseif fade and fadetimer > 1.5 and fadetimer <= 3 then if IsHandleValid(train) and not scene_launched then Delete_Train() end if fadetimer > 2 and cutscene and not scene_launched then scene_launched = true Spawn_Train() end UiPush() fadeToBlackAlpha = fadeToBlackAlpha - fadeInAlpha UiColor(0, 0, 0, fadeToBlackAlpha) UiAlign("midlle") UiRect(UiWidth(), UiHeight()) UiPop() end end function Locomotive_Fall() show_finish_arrow = false fall = true if not scene_launched and not cutscene then SetFloat("level.timelimit", -1) eye = GetLocationTransform(FindLocation("eye_start")).pos scene_launched = true end ---loc_imp = 80000 for i = 1, #breakpoint do MakeHole(GetLocationTransform(breakpoint[i]).pos, 2, 2, 2) end SetBodyDynamic(bridge, true) for i = 1, #railmotor do if IsHandleValid(railmotor[i]) then Delete(railmotor[i]) end end end function Train_Moves() if not dead and not explode then local vb = GetShapeBody(train) local com = TransformToParentPoint(GetBodyTransform(vb), Vec(0, 0, -3)) PlayLoop(trainmovingsound, com, 1) local fwd = Vec(1,0.15,0) if not fall then fwd[2] = 0 else fwd[2] = -1 end ConstrainVelocity(vb, 0, com, fwd , loc_imp) end end function Delete_Train() for i = 1, #railmotor do Delete(railmotor[i]) end Delete(wagonsjoint_01) Delete(wagonsjoint_02) local wagons = FindBodies("wagons", true) for i = 1, #wagons do Delete(wagons[i]) end local wheels = FindBodies("wheel", true) for i = 1, #wheels do Delete(wheels[i]) end Delete(FindBody("locomotive", true)) end function Train_WIN_Scene() eye = GetLocationTransform(FindLocation("eye_start")).pos cutscene = true end function Train_FAIL_Scene() end function Spawn_Train() local sppos = GetLocationTransform(FindLocation("trainspawn")) if cutscene then sppos = GetLocationTransform(trainspawn_win) end train_spawned = true local spawned = Spawn("MOD/runtime/prefabs/ravine/ravine_train.xml", sppos, true, true) for _, entity in pairs(spawned) do if HasTag(entity, "train_smoke") then trainSmokeShape = entity end end railmotor = FindJoints("railmotor", true) train = FindShape("train") wagonsjoint_01 = FindJoint("wagonsjoint_01", true) wagonsjoint_02 = FindJoint("wagonsjoint_02", true) wagon_01 = FindShape("wagon_01", true) wagon_02 = FindShape("wagon_02", true) end function Final_Cut_Scene(dt) if explode and winTimer < 4.5 then winTimer = winTimer + dt * 0.16 else winTimer = winTimer + dt * 0.8 end if winTimer <= 4.2 then camera_target = GetLocationTransform(eye_target_02).pos camera_transform = Transform(eye, QuatLookAt(eye, camera_target)) SetCameraTransform(camera_transform, 90) eye = VecLerp(eye, eye_end, dt * 0.045) elseif winTimer > 4.2 and winTimer <= 8 then if not cutscene and winTimer < 5 then camera_target = GetLocationTransform(eye_target_02).pos camera_transform = Transform(eye, QuatLookAt(eye, camera_target)) eye = VecLerp(VecAdd(Vec(-dt * 10, dt * 5, dt * 16),eye), eye_end_02, dt) elseif cutscene then if machine_transform.pos ~= nil then if not machine_punched then eye = VecLerp(camera_target, machine_transform.pos, dt * 0.6) elseif IsHandleValid(trigger_timetravel) then eye = VecLerp(camera_target, machine_transform.pos, dt * 1.8) end camera_transform.pos = VecAdd(camera_transform.pos, Vec(-dt * 1.8, dt * 0.32, dt * 2)) camera_transform = Transform(camera_transform.pos, QuatLookAt(camera_transform.pos, eye)) camera_target = eye end end if not machine_punched then if winTimer > 4.4 then machine_punched = true SetBodyDynamic(time_machine, true) end end SetCameraTransform(camera_transform, 90) elseif winTimer > 8 and winTimer <= 16 then if cutscene then camera_transform.pos = VecAdd(camera_transform.pos, Vec(-dt * 0.1,dt * 0.1,0)) end SetCameraTransform(camera_transform, 90) end end function Machine_Flies(dt) if not machine_punched then if machine_up then machine_transform.pos = VecAdd(machine_transform.pos,Vec(0,0.001,0)) else machine_transform.pos = VecAdd(machine_transform.pos,Vec(0,-0.001,0)) end if machine_pitch then machine_transform.rot = VecAdd(machine_transform.rot,Vec(0.0007,0,0,0)) else machine_transform.rot = VecAdd(machine_transform.rot,Vec(-0.0007,0,0,0)) end SetBodyTransform(time_machine, machine_transform) if machine_up and machine_transform.pos[2] > start_machine_transform.pos[2] + 0.1 then machine_up = false elseif not machine_up and machine_transform.pos[2] < start_machine_transform.pos[2] - 0.1 then machine_up = true end if machine_pitch and machine_transform.rot[1] > start_machine_transform.rot[1] + 0.02 then machine_pitch = false elseif not machine_pitch and machine_transform.rot[1] < start_machine_transform.rot[1] - 0.02 then machine_pitch = true end elseif machine_punched and cutscene then SetBodyVelocity(time_machine, Vec(0.6,4,machine_speed)) SetBodyAngularVelocity(time_machine, Vec(- dt * 6, dt * 1.2,0)) machine_speed = machine_speed + 0.3 * machine_speed_acceleration machine_speed_acceleration = machine_speed_acceleration + dt for i = 1, #rocket_light do SetLightIntensity(rocket_light[i], 1.2 * machine_speed_acceleration) ParticleColor(0.48, 0.33, 0.68) explosionSparksCPP(GetLightTransform(rocket_light[i]).pos, math.random(4,8), 1) end if IsPointInTrigger(trigger_timetravel, machine_transform.pos) then Delete(trigger_timetravel) machine_delay = 0.3 SetLightIntensity(timetravel_shinig, 9) end if machine_delay ~= nil then machine_delay = machine_delay - dt if machine_delay <= 0 then Explosion(machine_transform.pos, 4) explosionLarge(machine_transform.pos) Delete(time_machine) SetString("level.state", "win") machine_delay = nil end end elseif machine_punched and not cutscene and not GetString("level.state") ~= fail then if machine_delay == nil then ApplyBodyImpulse(time_machine, machine_transform.pos, Vec(40000,50000,80000)) machine_delay = 0 elseif machine_delay < 0.7 then machine_delay = machine_delay + dt elseif machine_delay >= 0.7 and IsHandleValid(timetravel_shinig) then RemoveTag(time_machine, "unbreakable") Explosion(GetLightTransform(timetravel_shinig).pos, 4) Delete(timetravel_shinig) SetString("level.state", "fail") end end end function Train_Sounds(dt) trainsound_step = trainsound_step - dt local sound_strength = 1 if appeartime > GetTime() and not train_spawned then if trainsound_step <= 0 then local sound_pos = GetLocationTransform(FindLocation("trainspawn")).pos sound_strength = GetTime()/delay_01 + 0.3 PlaySound(trainsound, sound_pos, sound_strength) trainsound_step = math.random(25,35) end elseif train_spawned and not fall then if trainsound_step <= 0 then PlaySound(trainsound, GetShapeWorldTransform(train).pos, sound_strength) trainsound_step = math.random(25,35) end end end function Floating_Dust() for i = 1, #wheels_lights do QueryRejectBody(time_machine) local wheelpos = GetLightTransform(wheels_lights[i]).pos local hit, dist = QueryRaycast(wheelpos, Vec(0, -1,0), 3) local pos = VecSub(wheelpos, VecScale(Vec(0,1,0), dist)) if hit then ParticleReset() ParticleColor(0.8, 0.75, 0.7) ParticleRadius(0.2, 0.6) ParticleAlpha(1, 0, "easeout") ParticleDrag(0.2) local x = rnd(-0.1, 0.1) local y = rnd(-0.1, 0.1) local z = rnd(-0.1, 0.1) local d = VecNormalize(Vec(x, y, z)) SpawnParticle(pos, VecScale(d, rnd(1,4)), rnd(0.3, 0.75)) end end end function ShockWave(particle_pos) ParticleReset() ParticleType("plain") ParticleRadius(rnd(0.5,1)) ParticleColor(0.9, 0.9, 0.9) ParticleAlpha(1, 1, "constant", 0.5, 0.5) ParticleCollide(0) ParticleTile(0) for i = 1, 3 do local life = 3 particle_pos[1] = particle_pos[1] + rnd(-0.5,0.5) SpawnParticle(particle_pos, Vec(0,0,0), life) end end function FireDebris(debrispos) local r = rnd(0, 1) local life = rnd(0.5, 3) r = (0.4 + 0.6*r*r*r) local velocity = VecAdd(Vec(0, r*0.5, 0), VecScale(rndVec(1), r)) local radius = rnd(0.03, 0.05) ParticleReset() ParticleColor(1, 0.6, 0.4, 1, 0.3, 0.2) ParticleAlpha(1) ParticleGravity(-10) ParticleRadius(radius, radius, "constant", 0, 0.2) ParticleSticky(0.2) ParticleStretch(0.0) ParticleTile(5) ParticleRotation(rnd(-20, 20), 0.0, "easeout") SpawnParticle(debrispos, velocity, life) local random_count = math.random(20,40) for i=1, random_count do local random_coef = rnd(0, 1) ^ 3 local life = 0.5 + random_coef * 3 random_coef = (0.4 + 0.6 * random_coef) local velocity = VecAdd(Vec(0, r * 10 * 0.5, 0), VecScale(rndVec(1), r * 10)) local radius = rnd(0.03, 0.05) local colour = rnd(0.2, 0.5) ParticleReset() ParticleColor(colour, colour, colour) ParticleAlpha(1) ParticleGravity(-10) ParticleRadius(radius, radius, "constant", 0, 0.2) ParticleSticky(0.2) ParticleStretch(0.0) ParticleTile(6) ParticleRotation(rnd(-20, 20), 0.0, "easeout") SpawnParticle(debrispos, velocity, life) end end function SpawnTrainSmoke() if fall or trainSmokeShape == nil then return end local trainSmokeTransform = GetShapeWorldTransform(trainSmokeShape) local trainSmoke = VecAdd(trainSmokeTransform.pos, Vec(0, 0.39, 0)) ParticleType("smoke") ParticleColor(0.7, 0.7, 0.7) ParticleRadius(0.3, 0.05, "easeout") ParticleCollide(1) ParticleGravity(0, 0.3, "smooth") ParticleAlpha(0.35, 0, "smooth", "fadeout") ParticleRotation(5, 10, "easein") ParticleStretch(1.2) ParticleTile(3) ParticleDrag(0.1) ParticleSticky(0.2) for i = 1, 7 do SpawnParticle(trainSmoke, TransformToParentVec(trainSmokeTransform, Vec(rnd(-1.1, 1.1), 3, rnd(-1, 1))), 12) end end