g_cutscene_sequence = {"h","s0;y500","s5;x-1000;z-600;y-200","x-1300;y-50","s0;p-40;t10","s3;x-800;z500;y250","w5","h"} g_cutscene_default_spd = 5 -- seconds per sequence g_cutscene_vars = nil g_cutscene_initial_cam = {pan = -90, tilt = 0, fov = 50} g_cutscene_active = false g_cutscene_key_pressed = false g_cutscene_player_orig = {x = 0, y = 0, z = 0, xa = 0, ya = 0, za = 0, fov = 0} function cutscene_parse_sequence (cs, m, a) if m == nil then return end local Mode = string.sub(string.lower(m),1,1) if Mode == 's' then cs.spd = math.abs(a or g_cutscene_default_spd) if cs.spd < 200 then cs.spd = cs.spd * 1000 end cs.seq_in_progress = true elseif Mode == 'f' then if a ~= nil then cs.TargFOV = a cs.seq_in_progress = true cs.sequence_time = g_Time + cs.spd end elseif Mode == 'x' then if a ~= nil then cs.TargX = cs.x + a cs.seq_in_progress = true cs.sequence_time = g_Time + cs.spd end elseif Mode == 'y' then if a ~= nil then cs.TargY = cs.y + a cs.seq_in_progress = true cs.sequence_time = g_Time + cs.spd end elseif Mode == 'z' then if a ~= nil then cs.TargZ = cs.z + a cs.seq_in_progress = true cs.sequence_time = g_Time + cs.spd end elseif Mode == 'p' then if a ~= nil then cs.TargPan = cs.pan + a cs.seq_in_progress = true cs.sequence_time = g_Time + cs.spd end elseif Mode == 't' then if a ~= nil then cs.TargTilt = cs.tilt + a cs.seq_in_progress = true cs.sequence_time = g_Time + cs.spd end -- Pause elseif Mode == 'w' then local pause_time = math.abs(a or g_default_spd) if pause_time < 200 then pause_time = pause_time * 1000 end cs.sequence_time = g_Time + pause_time cs.seq_in_progress = true end end ------------------------------------------------------------ function cutscene_init(e) g_cutscene_vars = nil g_cutscene_key_pressed = false end ------------------------------------------------------------ function cutscene_main(e) local Ent = g_Entity[e] local defs = g_cutscene_initial_cam if g_cutscene_vars == nil then if Ent ~= nil then g_cutscene_vars = {x = Ent.x, y = Ent.y, z = Ent.z, pan = defs.pan, tilt = defs.tilt, fov = defs.fov, spd = g_cutscene_default_spd * 1000, seq = 1, seq_in_progress = false, sequence_time = 0, TargX = nil, TargY = nil, TargZ = nil, TargPan = nil, TargTilt = nil, TargFOV = nil}; Hide(e); return end return end scheduler(e) local cs = g_cutscene_vars if g_KeyPressC == 1 and g_KeyPressSHIFT == 1 then if not g_cutscene_key_pressed then g_cutscene_key_pressed = true if not g_cutscene_active then g_cutscene_active = true cs.seq = cs.seq + 1 HideHuds() FreezeAI() ChangePlayerWeaponID(0) g_cutscene_player_orig = {x = g_PlayerPosX, y = g_PlayerPosY, z = g_PlayerPosZ, xa = g_PlayerAngX, ya = g_PlayerAngY, za = g_PlayerAngZ, fov = g_PlayerFOV}; end end else g_cutscene_key_pressed = false end if not g_cutscene_active then return end local cutscene_seq = g_cutscene_sequence[cs.seq] -- if we've reached the end of the sequence start back at the start if cutscene_seq == nil then cs.seq = 1 cs.x = Ent.x cs.y = Ent.y cs.z = Ent.z cs.pan = defs.pan cs.tilt = defs.tilt cs.spd = g_cutscene_default_spd * 1000 cutscene_seq = g_cutscene_sequence[cs.seq] g_cutscene_active = false end if not cs.seq_in_progress and string.lower(string.sub(cutscene_seq,1,1)) ~= 'h' then local m1, a1 = string.match(cutscene_seq, "(%a+)([+-]?%d+)(;?)") local m2, a2 = string.match(cutscene_seq, ";(%a+)([+-]?%d+)") local m3, a3 = string.match(cutscene_seq, ";%a+[+-]?%d+;(%a+)([+-]?%d+)") local m4, a4 = string.match(cutscene_seq, ";%a+[+-]?%d+;%a+[+-]?%d+;(%a+)([+-]?%d+)") local m5, a5 = string.match(cutscene_seq, ";%a+[+-]?%d+;%a+[+-]?%d+;%a+[+-]?%d+;(%a+)([+-]?%d+)") cutscene_parse_sequence (cs, m1, a1) cutscene_parse_sequence (cs, m2, a2) cutscene_parse_sequence (cs, m3, a3) cutscene_parse_sequence (cs, m4, a4) cutscene_parse_sequence (cs, m5, a5) elseif string.lower(string.sub(cutscene_seq,1,1)) == 'h' then cs.seq_in_progress = false g_cutscene_active = false ShowHuds() SetFreezePosition (g_cutscene_player_orig.x, g_cutscene_player_orig.y, g_cutscene_player_orig.z); SetFreezeAngle (g_cutscene_player_orig.xa, g_cutscene_player_orig.ya, g_cutscene_player_orig.za); TransportToFreezePosition() UnFreezeAI() SetPlayerFOV(g_cutscene_player_orig.fov) end if cs.seq_in_progress then local time_left = cs.sequence_time - g_Time local num_steps = g_scheduler[e].frames_per_second * time_left / 1000 if cs.TargFOV ~= nil then if num_steps < 1 then cs.fov = cs.TargFOV cs.TargFOV = nil if cs.seq_in_progress then cs.seq_in_progress = false cs.seq = cs.seq + 1 end else cs.fov = cs.fov + ((cs.TargFOV - cs.fov) / num_steps) end end if cs.TargX ~= nil then if num_steps < 1 then cs.x = cs.TargX cs.TargX = nil if cs.seq_in_progress then cs.seq_in_progress = false cs.seq = cs.seq + 1 end else cs.x = cs.x + ((cs.TargX - cs.x) / num_steps) end end if cs.TargY ~= nil then if num_steps < 1 then cs.y = cs.TargY cs.TargY = nil if cs.seq_in_progress then cs.seq_in_progress = false cs.seq = cs.seq + 1 end else cs.y = cs.y + ((cs.TargY - cs.y) / num_steps) end end if cs.TargZ ~= nil then if num_steps < 1 then cs.z = cs.TargZ cs.TargZ = nil if cs.seq_in_progress then cs.seq_in_progress = false cs.seq = cs.seq + 1 end else cs.z = cs.z + ((cs.TargZ - cs.z) / num_steps) end end if cs.TargPan ~= nil then if num_steps < 1 then cs.pan = cs.TargPan cs.TargPan = nil if cs.seq_in_progress then cs.seq_in_progress = false cs.seq = cs.seq + 1 end else cs.pan = cs.pan + ((cs.TargPan - cs.pan) / num_steps) -- Make sure platform angle in 'normal' range cs.pan, cs.TargPan = canonical_angle(cs.pan, cs.TargPan) end end if cs.TargTilt ~= nil then if num_steps < 1 then cs.tilt = cs.TargTilt cs.TargTilt = nil if cs.seq_in_progress then cs.seq_in_progress = false cs.seq = cs.seq + 1 end else cs.tilt = cs.tilt + ((cs.TargTilt - cs.tilt) / num_steps) -- Make sure angles in 'normal' range cs.tilt, cs.TargTilt = canonical_angle(cs.tilt, cs.TargTilt) end end if g_Time > cs.sequence_time then cs.seq_in_progress = false cs.seq = cs.seq + 1 end SetFreezePosition (cs.x, cs.y, cs.z) SetFreezeAngle(cs.tilt, cs.pan, 0) TransportToFreezePosition() SetPlayerFOV(cs.fov) end end ------------------------------------------------------------ function canonical_angle (ang1, ang2) if ang1 < -180 then if ang2 == nil then return (ang1 + 360), nil else return (ang1 + 360), (ang2 + 360) end elseif ang1 > 180 then if ang2 == nil then return (ang1 - 360), nil else return (ang1 - 360), (ang2 - 360) end end return ang1, ang2 end ---------------------------------------------------------------- -- Scheduler, this nifty little function keeps track of time. -- -- The main routine should be called every frame and returns -- -- a flag indicating whether the passed in time has expired -- -- since the last time it was called. -- -- If no time period is specified 100ms is used by default, -- -- i.e. 1/10th of a second. -- -- The caller can either ignore the return flag or use it to -- -- trigger time sensitive functionality. -- -- A global value giving the frames per second count is also -- -- generated, this can be used in script to make animations -- -- independent of frames. -- -- The reason this function is tied to an entity rather than -- -- being global is so that each entity can be triggered at a -- -- different time rather than all being triggered in the same -- -- frame. ---------------------------------------------------------------- g_scheduler = {} function scheduler(e, period) period = period or 100 -- defaults to tenths of a second (100ms) if g_Time == nil then return false end if g_scheduler[e] == nil then g_scheduler[e] = {frames_per_second = 60, period_accumulated = math.random(0, period), accumulated_time = 0, timer_value_last_frame = g_Time, frame_counter = 0}; -- 'test' mode sometimes doesn't clear Lua globals so if -- this appears to be the case initialise everything elseif g_scheduler[e].accumulated_time > 2000 then g_scheduler[e].frames_per_second = 60 g_scheduler[e].period_accumulated = math.random(0, period) g_scheduler[e].accumulated_time = 0 g_scheduler[e].timer_value_last_frame = g_Time g_scheduler[e].frame_counter = 0 end local entry = g_scheduler[e] local do_this_frame_flag = false entry.frame_counter = entry.frame_counter + 1 local time_since_last_frame = g_Time - entry.timer_value_last_frame if (entry.period_accumulated + time_since_last_frame) > period then entry.period_accumulated = (entry.period_accumulated + time_since_last_frame) - period; do_this_frame_flag = true else entry.period_accumulated = entry.period_accumulated + time_since_last_frame end if (entry.accumulated_time + time_since_last_frame) > 1000 then -- more than a second passed? entry.accumulated_time = (entry.accumulated_time + time_since_last_frame) - 1000; entry.frames_per_second = entry.frame_counter entry.frame_counter = 0 else entry.accumulated_time = entry.accumulated_time + time_since_last_frame end entry.timer_value_last_frame = entry.timer_value_last_frame + time_since_last_frame return do_this_frame_flag end