void ProcessStartSpatialPropAnim(ThnEvent ev) { var obj = Objects[(string)ev.Targets[0]]; var props = (LuaTable)ev.Properties["spatialprops"]; Matrix4?orient = null; object tmp; if (ev.Properties.TryGetValue("orient", out tmp)) { orient = ThnScript.GetMatrix((LuaTable)tmp); } if (obj.Camera != null) { if (orient != null) { obj.Camera.Orientation = orient.Value; } if (ev.Duration > 0) { FLLog.Error("Thn", "spatialpropanim.duration > 0 - unimplemented"); //return; } } if (obj.Camera == null) { FLLog.Error("Thn", "StartSpatialPropAnim unimplemented"); } }
void PlayScript(StoryCutsceneIni ct, CutsceneState state) { ui.Visible = false; cState = CutsceneState.Regular; string scName = ct.Encounters[0].Action; if (!string.IsNullOrEmpty(ct.Encounters[0].Offer)) { scName = ct.Encounters[0].Offer; cState = CutsceneState.Offer; } switch (state) { case CutsceneState.Decision: scName = ct.Encounters[0].Decision; cState = state; break; case CutsceneState.Accept: scName = ct.Encounters[0].Accept; cState = state; break; case CutsceneState.Reject: scName = ct.Encounters[0].Reject; cState = state; break; } var script = new ThnScript(session.Game.GameData.ResolveDataPath(scName)); currentCutscene = ct; RoomDoSceneScript(script, ScriptState.Cutscene); }
public void RunScript(ThnScript thn, Action onFinish = null) { AddEntities(thn); var evArr = events.ToArray(); var evsNew = new List <ThnEvent>(evArr); foreach (var ev in thn.Events) { totalDuration = Math.Max(totalDuration, thn.Duration); ev.TimeOffset = currentTime; evsNew.Add(ev); } if (onFinish != null) { evsNew.Add(new ThnEvent() { TimeOffset = thn.Duration, CustomAction = onFinish }); } evsNew.Sort((x, y) => x.Time.CompareTo(y.Time)); events = new Queue <ThnEvent>(); foreach (var item in evsNew) { events.Enqueue(item); } }
public ThnScriptInstance(Cutscene cs, ThnScript script) { this.thn = script; Duration = script.Duration; Cutscene = cs; foreach (var ev in script.Events) { events.Enqueue(ev); } }
private bool firstFrame = false; //Stops a desync in scene starting void RoomDoSceneScript(ThnScript sc, ScriptState state) { hotspots = new List <RTCHotspot>(); firstFrame = true; currentState = state; if (sc == null) { currentState = ScriptState.None; } waitingForFinish = sc; scene.BeginScene(Scripts(sceneScripts, new[] { sc })); string[] ships = Array.Empty <string>(); if (session.Ships != null) { ships = session.Ships.Select(x => Game.GameData.GetShip(x.ShipCRC).Nickname).ToArray(); } for (int i = 0; (i < ships.Length && i < currentRoom.ForSaleShipPlacements.Count); i++) { ThnObject marker = scene.GetObject(currentRoom.ForSaleShipPlacements[i]); if (marker == null) { FLLog.Error("Base", "Couldn't display " + ships[i] + " on " + currentRoom.ForSaleShipPlacements[i]); continue; } var toSellShip = Game.GameData.GetShip(ships[i]); //Set up object var obj = new GameObject(toSellShip.ModelFile.LoadFile(Game.ResourceManager), Game.ResourceManager) { Parent = marker.Object }; obj.PhysicsComponent = null; marker.Object.Children.Add(obj); if (obj.HardpointExists("HpMount")) { Matrix4x4.Invert(obj.GetHardpoint("HpMount").Transform, out var tr); obj.SetLocalTransform(tr); } } if (sc == null) { SetRoomCameraAndShip(); letterboxAmount = -1; ui.Visible = true; } else { ui.Visible = false; letterboxAmount = 1; } if (cState == CutsceneState.Decision) { letterboxAmount = -1; } }
private void SceneOnScriptFinished(ThnScript obj) { if (waitingForFinish != null && obj == waitingForFinish) { if (currentCutscene != null) { if (cState == CutsceneState.Decision) { return; } FadeOut(0.25, () => { RoomDoSceneScript(null, ScriptState.None); ui.Visible = true; FLLog.Info("Thn", "Finished cutscene"); if (cState == CutsceneState.Regular) { session.FinishCutscene(currentCutscene); currentCutscene = null; if (toPlay.Count > 0) { ProcessNextCutscene(); } } else if (cState == CutsceneState.Offer) { PlayScript(currentCutscene, CutsceneState.Decision); ui.Event("MissionOffer", currentCutscene.Encounters[0].MissionTextId); } FadeIn(0.2, 0.25); }); } else if (currentState == ScriptState.Launch) { SendLaunch(); } else { currentState = ScriptState.None; SetRoomCameraAndShip(); animatingLetterbox = true; } } }
public void HandlePacket(IPacket pkt) { if (!(pkt is ObjectUpdatePacket)) { FLLog.Debug("Client", "Got packet of type " + pkt.GetType()); } switch (pkt) { case CallThornPacket ct: AddGameplayAction(gp => { var thn = new ThnScript(Game.GameData.ResolveDataPath(ct.Thorn)); gp.Thn = new Cutscene(new ThnScript[] { thn }, gp); }); break; case AddRTCPacket rtc: AddRTC(rtc.RTC); break; case MsnDialogPacket msndlg: AddGameplayAction(gp => { RunDialog(msndlg.Lines); }); break; case PlaySoundPacket psnd: PlaySound(psnd.Sound); break; case PlayMusicPacket mus: PlayMusic(mus.Music); break; case SpawnPlayerPacket p: PlayerBase = null; PlayerSystem = p.System; PlayerPosition = p.Position; PlayerOrientation = Matrix4x4.CreateFromQuaternion(p.Orientation); SetSelfLoadout(p.Ship); SceneChangeRequired(); break; case BaseEnterPacket b: PlayerBase = b.Base; SetSelfLoadout(b.Ship); SceneChangeRequired(); break; case SpawnObjectPacket p: var shp = Game.GameData.GetShip((int)p.Loadout.ShipCRC); //Set up player object + camera var newobj = new GameObject(shp, Game.ResourceManager); newobj.Name = "NetPlayer " + p.ID; newobj.Transform = Matrix4x4.CreateFromQuaternion(p.Orientation) * Matrix4x4.CreateTranslation(p.Position); objects.Add(p.ID, newobj); if (worldReady) { gp.world.Objects.Add(newobj); } else { toAdd.Add(newobj); } break; case ObjectUpdatePacket p: foreach (var update in p.Updates) { UpdateObject(update); } break; case DespawnObjectPacket p: var despawn = objects[p.ID]; if (worldReady) { gp.world.Objects.Remove(despawn); } else { toAdd.Remove(despawn); } objects.Remove(p.ID); break; default: if (ExtraPackets != null) { ExtraPackets(pkt); } else { FLLog.Error("Network", "Unknown packet type " + pkt.GetType().ToString()); } break; } }
void DoTrigger(int i, SpaceGameplay gameplay) { active[i] = true; var tr = msn.Triggers[i]; if (!CheckConditions(tr)) { return; } FLLog.Debug("Mission", "Running trigger " + tr.Nickname); if (timers.ContainsKey(tr.Nickname)) { timers.Remove(tr.Nickname); } triggered[i] = true; foreach (var act in tr.Actions) { switch (act.Type) { case TriggerActions.Act_ActTrig: var trname = act.Entry[0].ToString(); for (int j = 0; j < msn.Triggers.Count; j++) { if (trname.Equals(msn.Triggers[j].Nickname, StringComparison.OrdinalIgnoreCase)) { DoTrigger(j, gameplay); break; } } break; case TriggerActions.Act_PlaySoundEffect: session.Game.Sound.PlaySound(act.Entry[0].ToString()); break; case TriggerActions.Act_ForceLand: session.ForceLand(act.Entry[0].ToString()); break; case TriggerActions.Act_AdjAcct: session.Credits += act.Entry[0].ToInt32(); break; case TriggerActions.Act_SpawnSolar: SpawnSolar(act.Entry[0].ToString(), gameplay.world); break; case TriggerActions.Act_StartDialog: RunDialog(msn.Dialogs.First((x) => x.Nickname.Equals(act.Entry[0].ToString(), StringComparison.OrdinalIgnoreCase))); break; case TriggerActions.Act_MovePlayer: gameplay.player.Transform = Matrix4.CreateTranslation(act.Entry[0].ToSingle(), act.Entry[1].ToSingle(), act.Entry[2].ToSingle()); //last param seems to always be one? break; case TriggerActions.Act_LightFuse: var fuse = session.Game.GameData.GetFuse(act.Entry[1].ToString()); var gameObj = gameplay.world.GetObject(act.Entry[0].ToString()); var fzr = new FuseRunnerComponent(gameObj) { Fuse = fuse }; gameObj.Components.Add(fzr); fzr.Run(); break; case TriggerActions.Act_PlayMusic: session.Game.Sound.PlayMusic(act.Entry[3].ToString()); break; case TriggerActions.Act_CallThorn: var thn = new ThnScript(gameplay.FlGame.GameData.ResolveDataPath(act.Entry[0].ToString())); gameplay.Thn = new Cutscene(new ThnScript[] { thn }, gameplay); break; case TriggerActions.Act_SetShipAndLoadout: if (!act.Entry[0].ToString().Equals("none", StringComparison.OrdinalIgnoreCase)) { var loadout = session.Game.GameData.Ini.Loadouts.FindLoadout(act.Entry[1].ToString()); if (loadout != null) { session.PlayerShip = act.Entry[0].ToString(); session.Mounts = new List <EquipMount>(); foreach (var equip in loadout.Equip) { if (equip.Value == null) { continue; } var hp = equip.Key.StartsWith("__noHardpoint") ? null : equip.Key; session.Mounts.Add(new EquipMount(hp, equip.Value)); } } } break; } } }
void AddEntities(ThnScript thn) { foreach (var kv in thn.Entities) { if (Objects.ContainsKey(kv.Key)) { continue; } if ((kv.Value.ObjectFlags & ThnObjectFlags.Reference) == ThnObjectFlags.Reference) { continue; } var obj = new ThnObject(); obj.Name = kv.Key; obj.Translate = kv.Value.Position ?? Vector3.Zero; obj.Rotate = kv.Value.RotationMatrix ?? Matrix4.Identity; //PlayerShip object if (spawnObjects && scriptContext.PlayerShip != null && kv.Value.Type == EntityTypes.Compound && kv.Value.Template.Equals("playership", StringComparison.InvariantCultureIgnoreCase)) { obj.Object = scriptContext.PlayerShip; obj.Object.RenderComponent.LitDynamic = (kv.Value.ObjectFlags & ThnObjectFlags.LitDynamic) == ThnObjectFlags.LitDynamic; obj.Object.RenderComponent.LitAmbient = (kv.Value.ObjectFlags & ThnObjectFlags.LitAmbient) == ThnObjectFlags.LitAmbient; obj.Object.RenderComponent.NoFog = kv.Value.NoFog; ((ModelRenderer)obj.Object.RenderComponent).LightGroup = kv.Value.LightGroup; obj.Entity = kv.Value; Vector3 transform = kv.Value.Position ?? Vector3.Zero; obj.Object.Transform = (kv.Value.RotationMatrix ?? Matrix4.Identity) * Matrix4.CreateTranslation(transform); obj.HpMount = scriptContext.PlayerShip.GetHardpoint("HpMount"); World.Objects.Add(obj.Object); Objects.Add(kv.Key, obj); continue; } var template = kv.Value.Template; string replacement; if (scriptContext != null && scriptContext.Substitutions.TryGetValue(kv.Value.Template, out replacement)) { template = replacement; } if (spawnObjects && kv.Value.Type == EntityTypes.Compound) { bool getHpMount = false; //Fetch model IDrawable drawable; switch (kv.Value.MeshCategory.ToLowerInvariant()) { case "solar": drawable = gameData.GetSolar(template); break; case "ship": case "spaceship": getHpMount = true; var sh = gameData.GetShip(template); sh.LoadResources(); drawable = sh.Drawable; break; case "prop": drawable = gameData.GetProp(template); break; case "room": drawable = gameData.GetRoom(template); break; case "equipment cart": drawable = gameData.GetCart(template); break; case "equipment": var eq = gameData.GetEquipment(template); eq.LoadResources(); drawable = eq.GetDrawable(); break; case "asteroid": drawable = gameData.GetAsteroid(kv.Value.Template); break; default: throw new NotImplementedException("Mesh Category " + kv.Value.MeshCategory); } if (kv.Value.UserFlag != 0) { //This is a starsphere var transform = (kv.Value.RotationMatrix ?? Matrix4.Identity) * Matrix4.CreateTranslation(kv.Value.Position ?? Vector3.Zero); layers.Add(new Tuple <IDrawable, Matrix4, int>(drawable, transform, kv.Value.SortGroup)); } else { obj.Object = new GameObject(drawable, game.GetService <ResourceManager>(), true, false); obj.Object.Name = kv.Value.Name; obj.Object.PhysicsComponent = null; //Jitter seems to interfere with directly setting orientation if (getHpMount) { obj.HpMount = obj.Object.GetHardpoint("HpMount"); } var r = (ModelRenderer)obj.Object.RenderComponent; r.LightGroup = kv.Value.LightGroup; r.LitDynamic = (kv.Value.ObjectFlags & ThnObjectFlags.LitDynamic) == ThnObjectFlags.LitDynamic; r.LitAmbient = (kv.Value.ObjectFlags & ThnObjectFlags.LitAmbient) == ThnObjectFlags.LitAmbient; //HIDDEN just seems to be an editor flag? //r.Hidden = (kv.Value.ObjectFlags & ThnObjectFlags.Hidden) == ThnObjectFlags.Hidden; r.NoFog = kv.Value.NoFog; } } else if (kv.Value.Type == EntityTypes.PSys) { var fx = gameData.GetEffect(kv.Value.Template); obj.Object = new GameObject(); obj.Object.RenderComponent = new ParticleEffectRenderer(fx) { Active = false }; } else if (kv.Value.Type == EntityTypes.Scene) { if (hasScene) { //throw new Exception("Thn can only have one scene"); //TODO: This needs to be handled better continue; } var amb = kv.Value.Ambient.Value; if (amb.X == 0 && amb.Y == 0 && amb.Z == 0) { continue; } hasScene = true; Renderer.SystemLighting.Ambient = new Color4(amb.X / 255f, amb.Y / 255f, amb.Z / 255f, 1); } else if (kv.Value.Type == EntityTypes.Light) { var lt = new DynamicLight(); lt.LightGroup = kv.Value.LightGroup; lt.Active = kv.Value.LightProps.On; lt.Light = kv.Value.LightProps.Render; obj.Light = lt; obj.LightDir = lt.Light.Direction; if (kv.Value.RotationMatrix.HasValue) { var m = kv.Value.RotationMatrix.Value; lt.Light.Direction = (new Vector4(lt.Light.Direction.Normalized(), 0) * m).Xyz.Normalized(); } if (Renderer != null) { Renderer.SystemLighting.Lights.Add(lt); } } else if (kv.Value.Type == EntityTypes.Camera) { obj.Camera = new ThnCameraTransform(); obj.Camera.Position = kv.Value.Position.Value; obj.Camera.Orientation = kv.Value.RotationMatrix ?? Matrix4.Identity; obj.Camera.FovH = kv.Value.FovH ?? obj.Camera.FovH; obj.Camera.AspectRatio = kv.Value.HVAspect ?? obj.Camera.AspectRatio; } else if (kv.Value.Type == EntityTypes.Marker) { obj.Object = new GameObject(); obj.Object.Name = "Marker"; obj.Object.Nickname = ""; } else if (kv.Value.Type == EntityTypes.Sound) { obj.Sound = new ThnSound(kv.Value.Template, game.GetService <SoundManager>(), kv.Value.AudioProps, obj); obj.Sound.Spatial = (kv.Value.ObjectFlags & ThnObjectFlags.Spatial) == ThnObjectFlags.Spatial; } if (obj.Object != null) { Vector3 transform = kv.Value.Position ?? Vector3.Zero; obj.Object.Transform = (kv.Value.RotationMatrix ?? Matrix4.Identity) * Matrix4.CreateTranslation(transform); World.Objects.Add(obj.Object); } obj.Entity = kv.Value; Objects[kv.Key] = obj; } }
public void Process(ThnEvent ev, Cutscene cs) { if (ev.Targets.Capacity == 0) { return; } ThnObject objA; if (!cs.Objects.TryGetValue((string)ev.Targets[0], out objA)) { FLLog.Error("Thn", "Object does not exist " + (string)ev.Targets[0]); return; } bool hasPos = false; Quaternion?q_orient = null; if (ev.Targets.Capacity >= 1) { var props = (LuaTable)ev.Properties["spatialprops"]; Vector3 pos; object tmp; if (props.TryGetValue("q_orient", out tmp)) { var tb = (LuaTable)tmp; q_orient = new Quaternion((float)tb[1], (float)tb[2], (float)tb[3], (float)tb[0]); } if (props.TryGetValue("orient", out tmp)) { var orient = ThnScript.GetMatrix((LuaTable)tmp); q_orient = orient.ExtractRotation(); } AxisRotation axisRotation = null; if (props.TryGetValue("axisrot", out tmp)) { var axisRot_Table = (LuaTable)tmp; axisRotation = new AxisRotation(); if (!axisRot_Table.TryGetVector3(1, out axisRotation.Axis)) { FLLog.Error("Thn", "invalid axisrot"); return; } axisRotation.Axis = Vector3.TransformNormal(axisRotation.Axis, objA.Rotate); axisRotation.Degrees = (float)axisRot_Table[0]; axisRotation.OriginalRotate = objA.Rotate; } hasPos = props.TryGetVector3("pos", out pos); if (ev.Targets.Capacity > 1) { ThnObject objB; if (!cs.Objects.TryGetValue((string)ev.Targets[1], out objB)) { FLLog.Error("Thn", "Object does not exist " + (string)ev.Targets[1]); return; } if (ev.Duration < float.Epsilon) { objA.Translate = objB.Translate; objA.Rotate = objB.Rotate; } else { cs.Coroutines.Add(new FollowSpatialRoutine() { Duration = ev.Duration, HasPos = hasPos, HasQuat = q_orient != null, This = objA, Follow = objB }); } } else { if (ev.Duration < float.Epsilon) { if (hasPos) { objA.Translate = pos; } if (q_orient != null) { objA.Rotate = Matrix4x4.CreateFromQuaternion(q_orient.Value); } } else { cs.Coroutines.Add(new StaticSpatialRoutine() { Duration = ev.Duration, HasPos = hasPos, HasQuat = q_orient != null, EndPos = pos, EndQuat = q_orient ?? Quaternion.Identity, This = objA, AxisRot = axisRotation }); } } } }
public ThnScriptContext(ThnScript set) { SetScript = set; }
public void FidgetScript(ThnScript scene) { SceneSetup(new[] { scene }, false); }
public void OnScriptFinished(ThnScript thn) => ScriptFinished?.Invoke(thn);
public void Process(ThnEvent ev, Cutscene cs) { if (ev.Targets.Capacity == 0) { return; } ThnObject objA; if (!cs.Objects.TryGetValue((string)ev.Targets[0], out objA)) { FLLog.Error("Thn", "Object does not exist " + (string)ev.Targets[0]); return; } if (ev.Targets.Capacity == 1) { var props = (LuaTable)ev.Properties["spatialprops"]; Quaternion?q_orient = null; Vector3 pos; object tmp; if (props.TryGetValue("q_orient", out tmp)) { var tb = (LuaTable)tmp; q_orient = new Quaternion((float)tb[1], (float)tb[2], (float)tb[3], (float)tb[0]); } if (props.TryGetValue("orient", out tmp)) { var orient = ThnScript.GetMatrix((LuaTable)tmp); q_orient = orient.ExtractRotation(); } bool hasPos = props.TryGetVector3("pos", out pos); if (ev.Duration < float.Epsilon) { if (hasPos) { objA.Translate = pos; } if (q_orient != null) { objA.Rotate = Matrix4.CreateFromQuaternion(q_orient.Value); } } else { cs.Coroutines.Add(new StaticSpatialRoutine() { Duration = ev.Duration, HasPos = hasPos, HasQuat = q_orient != null, EndPos = pos, EndQuat = q_orient ?? Quaternion.Identity, This = objA }); } } else { ThnObject objB; if (!cs.Objects.TryGetValue((string)ev.Targets[1], out objB)) { FLLog.Error("Thn", "Object does not exist " + (string)ev.Targets[1]); return; } if (ev.Duration < float.Epsilon) { objA.Translate = objB.Translate; objA.Rotate = objB.Rotate; } else { cs.Coroutines.Add(new FollowSpatialRoutine() { Duration = ev.Duration, HasPos = true, HasQuat = true, This = objA, Follow = objB }); } } }
public void HandlePacket(IPacket pkt) { if (!(pkt is ObjectUpdatePacket)) { FLLog.Debug("Client", "Got packet of type " + pkt.GetType()); } switch (pkt) { case CallThornPacket ct: RunSync(() => { var thn = new ThnScript(Game.GameData.ResolveDataPath(ct.Thorn)); gp.Thn = new Cutscene(new ThnScript[] { thn }, gp); }); break; case UpdateRTCPacket rtc: AddRTC(rtc.RTCs); break; case MsnDialogPacket msndlg: RunSync(() => { RunDialog(msndlg.Lines); }); break; case PlaySoundPacket psnd: PlaySound(psnd.Sound); break; case PlayMusicPacket mus: PlayMusic(mus.Music); break; case SpawnPlayerPacket p: PlayerBase = null; PlayerSystem = p.System; PlayerPosition = p.Position; PlayerOrientation = Matrix4x4.CreateFromQuaternion(p.Orientation); SetSelfLoadout(p.Ship); SceneChangeRequired(); break; case BaseEnterPacket b: PlayerBase = b.Base; SetSelfLoadout(b.Ship); SceneChangeRequired(); AddRTC(b.RTCs); break; case SpawnSolarPacket solar: RunSync(() => { foreach (var si in solar.Solars) { if (!objects.ContainsKey(si.ID)) { var arch = Game.GameData.GetSolarArchetype(si.Archetype); var go = new GameObject(arch, Game.ResourceManager, true); go.StaticPosition = si.Position; go.Transform = Matrix4x4.CreateFromQuaternion(si.Orientation) * Matrix4x4.CreateTranslation(si.Position); go.Nickname = $"$Solar{si.ID}"; go.World = gp.world; go.Register(go.World.Physics); go.CollisionGroups = arch.CollisionGroups; FLLog.Debug("Client", $"Spawning object {si.ID}"); gp.world.Objects.Add(go); objects.Add(si.ID, go); } } }); break; case DestroyPartPacket p: RunSync(() => { objects[p.ID].DisableCmpPart(p.PartName); }); break; case SpawnDebrisPacket p: RunSync(() => { var arch = Game.GameData.GetSolarArchetype(p.Archetype); var mdl = ((IRigidModelFile)arch.ModelFile.LoadFile(Game.ResourceManager)).CreateRigidModel(true); var newpart = mdl.Parts[p.Part].Clone(); var newmodel = new RigidModel() { Root = newpart, AllParts = new[] { newpart }, MaterialAnims = mdl.MaterialAnims, Path = mdl.Path, }; var go = new GameObject($"debris{p.ID}", newmodel, Game.ResourceManager, p.Part, p.Mass, true); go.Transform = Matrix4x4.CreateFromQuaternion(p.Orientation) * Matrix4x4.CreateTranslation(p.Position); go.World = gp.world; go.Register(go.World.Physics); gp.world.Objects.Add(go); objects.Add(p.ID, go); }); break; case SpawnObjectPacket p: RunSync(() => { var shp = Game.GameData.GetShip((int)p.Loadout.ShipCRC); //Set up player object + camera var newobj = new GameObject(shp, Game.ResourceManager); newobj.Name = "NetPlayer " + p.ID; newobj.Transform = Matrix4x4.CreateFromQuaternion(p.Orientation) * Matrix4x4.CreateTranslation(p.Position); if (connection is GameNetClient) { newobj.Components.Add(new CNetPositionComponent(newobj)); } objects.Add(p.ID, newobj); gp.world.Objects.Add(newobj); }); break; case ObjectUpdatePacket p: RunSync(() => { foreach (var update in p.Updates) { UpdateObject(p.Tick, update); } }); break; case DespawnObjectPacket p: RunSync(() => { var despawn = objects[p.ID]; gp.world.Objects.Remove(despawn); objects.Remove(p.ID); }); break; default: if (ExtraPackets != null) { ExtraPackets(pkt); } else { FLLog.Error("Network", "Unknown packet type " + pkt.GetType().ToString()); } break; } }