Beispiel #1
0
        private static int GetSaveIndex(Track track)
        {
            var dir = GetTrackDirectory(track);

            if (track.Name.Equals("<untitled>"))
            {
                dir = Utils.Constants.TracksDirectory + "Unnamed Track" + Path.DirectorySeparatorChar;
            }

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            var trackfiles =
                TrackIO.EnumerateTrackFiles(dir);
            int saveindex = 0;

            for (var i = 0; i < trackfiles.Length; i++)
            {
                var s     = Path.GetFileNameWithoutExtension(trackfiles[i]);
                var index = s.IndexOf(" ", StringComparison.Ordinal);
                if (index != -1)
                {
                    s = s.Remove(index);
                }
                if (int.TryParse(s, out saveindex))
                {
                    break;
                }
            }
            saveindex++;
            return(saveindex);
        }
Beispiel #2
0
        public static string SaveTrack(Track track, string savename)
        {
            var dir = TrackIO.GetTrackDirectory(track);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            var             filename = dir + savename + ".sol";
            BigEndianWriter bw       = new BigEndianWriter();

            bw.WriteShort(0x00BF); //sol version
            bw.WriteInt(0);        //length, placeholder
            bw.WriteString("TCSO");
            bw.WriteBytes(new byte[] { 0, 4, 0, 0, 0, 0 });
            bw.WriteMapleString("savedLines");
            bw.WriteInt(0);//padding
            Amf0Object rootobj = new Amf0Object();

            rootobj.name = "trackList";
            rootobj.type = Amf0Object.Amf0Type.AMF0_ECMA_ARRAY;
            var tracks = new List <Amf0Object>();

            rootobj.data = tracks;
            WriteTrack(tracks, track);
            Amf0 amf = new Amf0(bw);

            amf.WriteAmf0Object(rootobj);
            bw.WriteByte(0);
            bw.Reset(2);
            bw.WriteInt(bw.Length - 6);
            File.WriteAllBytes(filename, bw.ToArray());
            return(filename);
        }
Beispiel #3
0
        private static int GetSaveIndex(Track track)
        {
            var dir = GetTrackDirectory(track);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            var trackfiles =
                TrackIO.EnumerateTrackFiles(dir);
            int saveindex = 0;

            for (var i = 0; i < trackfiles.Length; i++)
            {
                var s     = Path.GetFileNameWithoutExtension(trackfiles[i]);
                var index = s.IndexOf(" ", StringComparison.Ordinal);
                if (index != -1)
                {
                    s = s.Remove(index);
                }
                if (int.TryParse(s, out saveindex))
                {
                    break;
                }
            }
            saveindex++;
            return(saveindex);
        }
        public static string SaveTrackToFile(Track track, string savename, string songdata = null)
        {
            var dir = GetTrackDirectory(track);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            var trackfiles =
                TrackIO.EnumerateTrackFiles(dir);
            int saveindex = 0;

            for (var i = 0; i < trackfiles.Length; i++)
            {
                var s     = Path.GetFileNameWithoutExtension(trackfiles[i]);
                var index = s.IndexOf(" ", StringComparison.Ordinal);
                if (index != -1)
                {
                    s = s.Remove(index);
                }
                if (int.TryParse(s, out saveindex))
                {
                    break;
                }
            }
            saveindex++;

            var filename = TRKWriter.SaveTrack(track, saveindex + " " + savename, songdata);

            track.Filename = filename;
            return(filename);
        }
Beispiel #5
0
        public static string SaveTrack(Track trk, string savename)
        {
            var        sw       = Stopwatch.StartNew();
            track_json trackobj = new track_json();

            trackobj.label         = trk.Name;
            trackobj.startPosition = new track_json.point_json()
            {
                x = trk.StartOffset.X,
                y = trk.StartOffset.Y
            };
            trackobj.startZoom = trk.StartZoom;
            trackobj.zeroStart = trk.ZeroStart;
            int ver = trk.GetVersion();

            switch (ver)
            {
            case 61:
                trackobj.version = "6.1";
                break;

            case 62:
                trackobj.version = "6.2";
                break;
            }
            var sort = trk.GetSortedLines();

            trackobj.linesArray = new object[sort.Length][];
            trackobj.triggers   = new List <track_json.zoomtrigger_json>();
            int idx = 0;

            foreach (var line in sort)
            {
                line_json jline = new line_json();
                switch (line.Type)
                {
                case LineType.Blue:
                    jline.type = 0;
                    break;

                case LineType.Red:
                    jline.type = 1;
                    break;

                case LineType.Scenery:
                    jline.type = 2;
                    break;
                }
                jline.id = line.ID;
                jline.x1 = line.Position.X;
                jline.y1 = line.Position.Y;
                jline.x2 = line.Position2.X;
                jline.y2 = line.Position2.Y;
                if (line is StandardLine stl)
                {
                    if (stl.Extension.HasFlag(StandardLine.Ext.Left))
                    {
                        jline.leftExtended = true;
                    }
                    if (stl.Extension.HasFlag(StandardLine.Ext.Right))
                    {
                        jline.rightExtended = true;
                    }
                    jline.extended = (int)stl.Extension;
                    jline.flipped  = stl.inv;
                    if (line is RedLine red)
                    {
                        jline.multiplier = red.Multiplier;
                    }
                    if (stl.Trigger != null && stl.Trigger.ZoomTrigger)
                    {
                        trackobj.triggers.Add(new track_json.zoomtrigger_json()
                        {
                            zoom   = true,
                            ID     = jline.id,
                            target = stl.Trigger.ZoomTarget,
                            frames = stl.Trigger.ZoomFrames
                        });
                    }
                }
                trackobj.linesArray[idx++] = line_to_linearrayline(jline);
            }
            var dir = TrackIO.GetTrackDirectory(trk);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            var filename = dir + savename + ".track.json";

            using (var file = File.Create(filename))
            {
                var bytes = JsonSerializer.Serialize <track_json>(trackobj);
                file.Write(bytes, 0, bytes.Length);
            }
            return(filename);
        }
        public static string SaveTrack(Track trk, string savename)
        {
            var dir = TrackIO.GetTrackDirectory(trk);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            var filename = dir + savename + ".trk";

            using (var file = File.Create(filename))
            {
                var bw = new BinaryWriter(file);
                bw.Write(new byte[] { (byte)'T', (byte)'R', (byte)'K', 0xF2 });
                bw.Write((byte)1);
                string featurestring = "";
                var    lines         = trk.GetLines();
                var    featurelist   = TrackIO.GetTrackFeatures(trk);
                featurelist.TryGetValue(TrackFeatures.songinfo, out bool songinfo);
                featurelist.TryGetValue(TrackFeatures.redmultiplier, out bool redmultiplier);
                featurelist.TryGetValue(TrackFeatures.zerostart, out bool zerostart);
                featurelist.TryGetValue(TrackFeatures.scenerywidth, out bool scenerywidth);
                featurelist.TryGetValue(TrackFeatures.six_one, out bool six_one);
                featurelist.TryGetValue(TrackFeatures.ignorable_trigger, out bool ignorable_trigger);
                foreach (var feature in featurelist)
                {
                    if (feature.Value)
                    {
                        featurestring += feature.Key + ";";
                    }
                }
                WriteString(bw, featurestring);
                if (songinfo)
                {
                    // unfotrunately this relies on .net to save and parse in
                    // its own way, and we're kind of stuck with it instead of
                    // the right way to write strings
                    bw.Write(trk.Song.ToString());
                }
                bw.Write(trk.StartOffset.X);
                bw.Write(trk.StartOffset.Y);
                bw.Write(lines.Length);
                foreach (var line in lines)
                {
                    byte type = (byte)line.Type;
                    if (line is StandardLine l)
                    {
                        if (l.inv)
                        {
                            type |= 1 << 7;
                        }
                        var ext = (byte)l.Extension;
                        type |= (byte)((ext & 0x03) << 5); //bits: 2
                        bw.Write(type);
                        if (redmultiplier)
                        {
                            if (line is RedLine red)
                            {
                                bw.Write((byte)red.Multiplier);
                            }
                        }
                        if (ignorable_trigger)
                        {
                            if (l.Trigger != null)
                            {
                                if (l.Trigger.ZoomTrigger) // check other triggers here for at least one
                                {
                                    bw.Write(l.Trigger.ZoomTrigger);
                                    if (l.Trigger.ZoomTrigger)
                                    {
                                        bw.Write(l.Trigger.ZoomTarget);
                                        bw.Write((short)l.Trigger.ZoomFrames);
                                    }
                                }
                                else
                                {
                                    bw.Write(false);
                                }
                            }
                            else
                            {
                                bw.Write(false);//zoomtrigger=false
                            }
                        }
                        bw.Write(l.ID);
                        if (l.Extension != StandardLine.Ext.None)
                        {
                            // this was extension writing
                            // but we no longer support this.
                            bw.Write(-1);
                            bw.Write(-1);
                        }
                    }
                    else
                    {
                        bw.Write(type);
                        if (scenerywidth)
                        {
                            if (line is SceneryLine scenery)
                            {
                                byte b = (byte)(Math.Round(scenery.Width, 1) * 10);
                                bw.Write(b);
                            }
                        }
                    }

                    bw.Write(line.Position.X);
                    bw.Write(line.Position.Y);
                    bw.Write(line.Position2.X);
                    bw.Write(line.Position2.Y);
                }
                bw.Write(new byte[] { (byte)'M', (byte)'E', (byte)'T', (byte)'A' });
                List <string> metadata = new List <string>();
                metadata.Add("STARTZOOM=" + trk.StartZoom.ToString(Program.Culture));

                bw.Write((short)metadata.Count);
                foreach (var str in metadata)
                {
                    WriteString(bw, str);
                }
            }
            return(filename);
        }
        public static string SaveTrack(Track trk, string savename)
        {
            var dir = TrackIO.GetTrackDirectory(trk);

            if (trk.Name.Equals("<untitled>"))
            {
                dir = Utils.Constants.TracksDirectory + "Unnamed Track" + Path.DirectorySeparatorChar;
            }
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            var filename = dir + savename + ".trk";

            using (var file = File.Create(filename))
            {
                var bw = new BinaryWriter(file);
                bw.Write(new byte[] { (byte)'T', (byte)'R', (byte)'K', 0xF2 }); //TRK
                bw.Write((byte)1);
                string featurestring = "";
                var    lines         = trk.GetLines();
                var    featurelist   = TrackIO.GetTrackFeatures(trk);
                featurelist.TryGetValue(TrackFeatures.songinfo, out bool songinfo);
                featurelist.TryGetValue(TrackFeatures.redmultiplier, out bool redmultiplier);
                featurelist.TryGetValue(TrackFeatures.zerostart, out bool zerostart);
                featurelist.TryGetValue(TrackFeatures.scenerywidth, out bool scenerywidth);
                featurelist.TryGetValue(TrackFeatures.six_one, out bool six_one);
                featurelist.TryGetValue(TrackFeatures.ignorable_trigger, out bool ignorable_trigger);
                featurelist.TryGetValue(TrackFeatures.remount, out bool remount);
                featurelist.TryGetValue(TrackFeatures.frictionless, out bool frictionless);
                foreach (var feature in featurelist)
                {
                    if (feature.Value)
                    {
                        featurestring += feature.Key + ";";
                    }
                }
                WriteString(bw, featurestring);
                if (songinfo)
                {
                    // unfotrunately this relies on .net to save and parse in
                    // its own way, and we're kind of stuck with it instead of
                    // the right way to write strings
                    bw.Write(trk.Song.ToString());
                }
                bw.Write(trk.StartOffset.X);
                bw.Write(trk.StartOffset.Y);
                bw.Write(lines.Length);
                foreach (var line in lines)
                {
                    byte type = (byte)line.Type;
                    if (line is StandardLine l)
                    {
                        if (l.inv)
                        {
                            type |= 1 << 7;
                        }
                        var ext = (byte)l.Extension;
                        type |= (byte)((ext & 0x03) << 5); //bits: 2
                        bw.Write(type);
                        if (redmultiplier)
                        {
                            if (line is RedLine red)
                            {
                                bw.Write((byte)red.Multiplier);
                            }
                        }
                        if (ignorable_trigger)
                        {
                            if (l.Trigger != null)
                            {
                                if (l.Trigger.ZoomTrigger) // check other triggers here for at least one
                                {
                                    bw.Write(l.Trigger.ZoomTrigger);
                                    if (l.Trigger.ZoomTrigger)
                                    {
                                        bw.Write(l.Trigger.ZoomTarget);
                                        bw.Write((short)l.Trigger.ZoomFrames);
                                    }
                                }
                                else
                                {
                                    bw.Write(false);
                                }
                            }
                            else
                            {
                                bw.Write(false);//zoomtrigger=false
                            }
                        }
                        bw.Write(l.ID);
                        if (l.Extension != StandardLine.Ext.None)
                        {
                            // this was extension writing
                            // but we no longer support this.
                            bw.Write(-1);
                            bw.Write(-1);
                        }
                    }
                    else
                    {
                        bw.Write(type);
                        if (scenerywidth)
                        {
                            if (line is SceneryLine scenery)
                            {
                                byte b = (byte)(Math.Round(scenery.Width, 1) * 10);
                                bw.Write(b);
                            }
                        }
                    }

                    bw.Write(line.Position.X);
                    bw.Write(line.Position.Y);
                    bw.Write(line.Position2.X);
                    bw.Write(line.Position2.Y);
                }
                bw.Write(new byte[] { (byte)'M', (byte)'E', (byte)'T', (byte)'A' });
                List <string> metadata = new List <string>();
                metadata.Add(TrackMetadata.startzoom + "=" + trk.StartZoom.ToString(Program.Culture));

                //Only add if the values are different from default
                if (trk.YGravity != 1)
                {
                    metadata.Add(TrackMetadata.ygravity + "=" + trk.YGravity.ToString(Program.Culture));
                }
                if (trk.XGravity != 0)
                {
                    metadata.Add(TrackMetadata.xgravity + "=" + trk.XGravity.ToString(Program.Culture));
                }
                if (trk.GravityWellSize != 10)
                {
                    metadata.Add(TrackMetadata.gravitywellsize + "=" + trk.GravityWellSize.ToString(Program.Culture));
                }

                if (trk.BGColorR != Color.FromArgb(Utils.Constants.ColorOffwhite.ToArgb()).R)
                {
                    metadata.Add(TrackMetadata.bgcolorR + "=" + trk.BGColorR.ToString(Program.Culture));
                }
                if (trk.BGColorG != Color.FromArgb(Utils.Constants.ColorOffwhite.ToArgb()).G)
                {
                    metadata.Add(TrackMetadata.bgcolorG + "=" + trk.BGColorG.ToString(Program.Culture));
                }
                if (trk.BGColorB != Color.FromArgb(Utils.Constants.ColorOffwhite.ToArgb()).B)
                {
                    metadata.Add(TrackMetadata.bgcolorB + "=" + trk.BGColorB.ToString(Program.Culture));
                }

                if (trk.LineColorR != Settings.Lines.DefaultLine.R)
                {
                    metadata.Add(TrackMetadata.linecolorR + "=" + trk.LineColorR.ToString(Program.Culture));
                }
                if (trk.LineColorG != Settings.Lines.DefaultLine.G)
                {
                    metadata.Add(TrackMetadata.linecolorG + "=" + trk.LineColorG.ToString(Program.Culture));
                }
                if (trk.LineColorB != Settings.Lines.DefaultLine.B)
                {
                    metadata.Add(TrackMetadata.linecolorB + "=" + trk.LineColorB.ToString(Program.Culture));
                }

                StringBuilder triggerstring = new StringBuilder();
                for (int i = 0; i < trk.Triggers.Count; i++)
                {
                    GameTrigger t = trk.Triggers[i];
                    if (i != 0)
                    {
                        triggerstring.Append("&");
                    }
                    switch (t.TriggerType)
                    {
                    case TriggerType.Zoom:
                        triggerstring.Append((int)TriggerType.Zoom);
                        triggerstring.Append(":");
                        triggerstring.Append(t.ZoomTarget.ToString(Program.Culture));
                        triggerstring.Append(":");
                        break;

                    case TriggerType.BGChange:
                        triggerstring.Append((int)TriggerType.BGChange);
                        triggerstring.Append(":");
                        triggerstring.Append(t.backgroundRed.ToString(Program.Culture));
                        triggerstring.Append(":");
                        triggerstring.Append(t.backgroundGreen.ToString(Program.Culture));
                        triggerstring.Append(":");
                        triggerstring.Append(t.backgroundBlue.ToString(Program.Culture));
                        triggerstring.Append(":");
                        break;

                    case TriggerType.LineColor:
                        triggerstring.Append((int)TriggerType.LineColor);
                        triggerstring.Append(":");
                        triggerstring.Append(t.lineRed.ToString(Program.Culture));
                        triggerstring.Append(":");
                        triggerstring.Append(t.lineGreen.ToString(Program.Culture));
                        triggerstring.Append(":");
                        triggerstring.Append(t.lineBlue.ToString(Program.Culture));
                        triggerstring.Append(":");
                        break;
                    }
                    triggerstring.Append(t.Start.ToString(Program.Culture));
                    triggerstring.Append(":");
                    triggerstring.Append(t.End.ToString(Program.Culture));
                }
                if (trk.Triggers.Count > 0) //If here are not trigger don't add triggers entry
                {
                    metadata.Add(TrackMetadata.triggers + "=" + triggerstring.ToString());
                }
                bw.Write((short)metadata.Count);
                foreach (var str in metadata)
                {
                    WriteString(bw, str);
                }
            }
            return(filename);
        }
Beispiel #8
0
        public static string SaveTrack(Track trk, string savename)
        {
            var        sw       = Stopwatch.StartNew();
            track_json trackobj = new track_json();

            trackobj.label         = trk.Name;
            trackobj.startPosition = new track_json.point_json()
            {
                x = trk.StartOffset.X,
                y = trk.StartOffset.Y
            };
            trackobj.startZoom       = trk.StartZoom;
            trackobj.zeroStart       = trk.ZeroStart;
            trackobj.yGravity        = trk.YGravity;
            trackobj.xGravity        = trk.XGravity;
            trackobj.gravityWellSize = trk.GravityWellSize;
            trackobj.bgR             = trk.BGColorR;
            trackobj.bgG             = trk.BGColorG;
            trackobj.bgB             = trk.BGColorB;
            trackobj.lineR           = trk.LineColorR;
            trackobj.lineG           = trk.LineColorG;
            trackobj.lineB           = trk.LineColorB;

            int ver = trk.GetVersion();

            switch (ver)
            {
            case 61:
                trackobj.version = "6.1";
                break;

            case 62:
                trackobj.version = "6.2";
                break;
            }
            var sort = trk.GetSortedLines();

            trackobj.linesArray   = new object[sort.Length][];
            trackobj.gameTriggers = new List <track_json.gametrigger_json>();
            int idx = 0;

            foreach (var line in sort)
            {
                line_json jline = new line_json();
                switch (line.Type)
                {
                case LineType.Blue:
                    jline.type = 0;
                    break;

                case LineType.Red:
                    jline.type = 1;
                    break;

                case LineType.Scenery:
                    jline.type = 2;
                    break;
                }
                jline.id = line.ID;
                jline.x1 = line.Position.X;
                jline.y1 = line.Position.Y;
                jline.x2 = line.Position2.X;
                jline.y2 = line.Position2.Y;
                if (line is StandardLine stl)
                {
                    if (stl.Extension.HasFlag(StandardLine.Ext.Left))
                    {
                        jline.leftExtended = true;
                    }
                    if (stl.Extension.HasFlag(StandardLine.Ext.Right))
                    {
                        jline.rightExtended = true;
                    }
                    jline.extended = (int)stl.Extension;
                    jline.flipped  = stl.inv;
                    if (line is RedLine red)
                    {
                        jline.multiplier = red.Multiplier;
                    }
                }
                trackobj.linesArray[idx++] = line_to_linearrayline(jline);
            }
            foreach (var trigger in trk.Triggers)
            {
                switch (trigger.TriggerType)
                {
                case TriggerType.Zoom:
                    trackobj.gameTriggers.Add(new track_json.gametrigger_json()
                    {
                        triggerType = (int)trigger.TriggerType,
                        zoomTarget  = trigger.ZoomTarget,
                        start       = trigger.Start,
                        end         = trigger.End
                    });
                    break;

                case TriggerType.BGChange:
                    trackobj.gameTriggers.Add(new track_json.gametrigger_json()
                    {
                        triggerType     = (int)trigger.TriggerType,
                        backgroundred   = trigger.backgroundRed,
                        backgroundgreen = trigger.backgroundGreen,
                        backgroundblue  = trigger.backgroundBlue,
                        start           = trigger.Start,
                        end             = trigger.End
                    });
                    break;

                case TriggerType.LineColor:
                    trackobj.gameTriggers.Add(new track_json.gametrigger_json()
                    {
                        triggerType = (int)trigger.TriggerType,
                        lineRed     = trigger.lineRed,
                        lineGreen   = trigger.lineGreen,
                        lineBlue    = trigger.lineBlue,
                        start       = trigger.Start,
                        end         = trigger.End
                    });
                    break;
                }
            }
            var dir = TrackIO.GetTrackDirectory(trk);

            if (trk.Name.Equals("<untitled>"))
            {
                dir = Utils.Constants.TracksDirectory + "Unnamed Track" + Path.DirectorySeparatorChar;
            }
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            var filename = dir + savename + ".track.json";

            using (var file = File.Create(filename))
            {
                var bytes = JsonSerializer.Serialize <track_json>(trackobj);
                file.Write(bytes, 0, bytes.Length);
            }
            return(filename);
        }
        public static string SaveTrack(Track trk, string savename, string songdata = null)
        {
            var dir = TrackIO.GetTrackDirectory(trk);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            var filename = dir + savename + ".trk";

            using (var file = File.Create(filename))
            {
                var bw = new BinaryWriter(file);
                bw.Write(new byte[] { (byte)'T', (byte)'R', (byte)'K', 0xF2 });
                bw.Write((byte)1);
                string features       = "";
                bool[] saved_features = new bool[]
                {
                    false,
                    false,
                    false,
                    false,
                    false,
                    false
                };
                if (songdata != null)
                {
                    saved_features[SONGINFO_INDEX] = true;
                }
                if (trk.ZeroStart)
                {
                    saved_features[ZEROSTART_INDEX] = true;
                }
                var lines = trk.GetLines();
                foreach (GameLine l in lines)
                {
                    var scenery = l as SceneryLine;
                    if (scenery != null)
                    {
                        if (Math.Abs(scenery.Width - 1) > 0.0001f)
                        {
                            saved_features[SCENERYWIDTH_INDEX] = true;
                        }
                    }
                    var red = l as RedLine;
                    if (red != null)
                    {
                        if (red.Multiplier != 1)
                        {
                            saved_features[REDMULTIPLIER_INDEX] = true;
                        }
                    }
                    var stl = l as StandardLine;
                    if (stl != null)
                    {
                        if (stl.Trigger != null)
                        {
                            saved_features[IGNORABLE_TRIGGER_INDEX] = true;
                        }
                    }
                }

                if (trk.GetVersion() == 61)
                {
                    saved_features[SIX_ONE_INDEX] = true;
                }
                for (int i = 0; i < supported_features.Length; i++)
                {
                    if (saved_features[i])
                    {
                        features += supported_features[i] + ";";
                    }
                }
                bw.Write((short)features.Length);
                bw.Write(Encoding.ASCII.GetBytes(features));
                if (saved_features[SONGINFO_INDEX])
                {
                    bw.Write(songdata);
                }
                bw.Write(trk.StartOffset.X);
                bw.Write(trk.StartOffset.Y);
                bw.Write(lines.Length);
                foreach (var line in lines)
                {
                    byte type = (byte)line.Type;
                    if (line is StandardLine l)
                    {
                        if (l.inv)
                        {
                            type |= 1 << 7;
                        }
                        var ext = (byte)l.Extension;
                        type |= (byte)((ext & 0x03) << 5); //bits: 2
                        bw.Write(type);
                        if (saved_features[REDMULTIPLIER_INDEX])
                        {
                            if (line is RedLine red)
                            {
                                bw.Write((byte)red.Multiplier);
                            }
                        }
                        if (saved_features[IGNORABLE_TRIGGER_INDEX])
                        {
                            if (l.Trigger != null)
                            {
                                if (l.Trigger.Zoomtrigger) // check other triggers here for at least one
                                {
                                    bw.Write(l.Trigger.Zoomtrigger);
                                    if (l.Trigger.Zoomtrigger)
                                    {
                                        bw.Write(l.Trigger.ZoomTarget);
                                        bw.Write((short)l.Trigger.ZoomFrames);
                                    }
                                }
                                else
                                {
                                    bw.Write(false);
                                }
                            }
                            else
                            {
                                bw.Write(false);//zoomtrigger=false
                            }
                        }
                        bw.Write(l.ID);
                        if (l.Extension != StandardLine.Ext.None)
                        {
                            // this was extension writing
                            // but we no longer support this.
                            bw.Write(-1);
                            bw.Write(-1);
                        }
                    }
                    else
                    {
                        bw.Write(type);
                        if (saved_features[SCENERYWIDTH_INDEX])
                        {
                            if (line is SceneryLine scenery)
                            {
                                byte b = (byte)(Math.Round(scenery.Width, 1) * 10);
                                bw.Write(b);
                            }
                        }
                    }

                    bw.Write(line.Position.X);
                    bw.Write(line.Position.Y);
                    bw.Write(line.Position2.X);
                    bw.Write(line.Position2.Y);
                }
            }
            return(filename);
        }