public Activation(STFReader stf) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("externalcam", () => { ExternalCam = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("cabcam", () => { CabCam = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("passengercam", () => { PassengerCam = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("distance", () => { Distance = stf.ReadFloatBlock(STFReader.UNITS.Distance, Distance); }), new STFReader.TokenProcessor("tracktype", () => { TrackType = stf.ReadIntBlock(null); }), }); }
public ScalabiltyGroup(STFReader stf) { stf.MustMatch("("); DetailLevel = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("activation", () => { Activation = new Activation(stf); }), new STFReader.TokenProcessor("deactivation", () => { Deactivation = new Deactivation(stf); }), new STFReader.TokenProcessor("streams", () => { Streams = new SMSStreams(stf); }), new STFReader.TokenProcessor("volume", () => { Volume = stf.ReadFloatBlock(STFReader.UNITS.None, null); }), new STFReader.TokenProcessor("stereo", () => { Stereo = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("ignore3d", () => { Ignore3D = stf.ReadBoolBlock(true); }), }); }
public float FullStaticCentreOfGravityM_Y = -9999; // get centre of gravity after adjusted for freight animation public FreightAnimationStatic(STFReader stf) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("subtype", () => { var typeString = stf.ReadStringBlock(null); switch (typeString) { default: SubType = FreightAnimationStatic.Type.DEFAULT; break; } }), new STFReader.TokenProcessor("shape", () => { ShapeFileName = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("freightweight", () => { FreightWeight = stf.ReadFloatBlock(STFReader.UNITS.Mass, 0); }), new STFReader.TokenProcessor("offset", () => { stf.MustMatch("("); XOffset = stf.ReadFloat(STFReader.UNITS.Distance, 0); YOffset = stf.ReadFloat(STFReader.UNITS.Distance, 0); ZOffset = stf.ReadFloat(STFReader.UNITS.Distance, 0); stf.MustMatch(")"); }), new STFReader.TokenProcessor("flip", () => { Flipped = stf.ReadBoolBlock(true); }), // additions to manage consequences of variable weight on friction and brake forces new STFReader.TokenProcessor("fullortsdavis_a", () => { FullStaticORTSDavis_A = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("fullortsdavis_b", () => { FullStaticORTSDavis_B = stf.ReadFloatBlock(STFReader.UNITS.Resistance, -1); }), new STFReader.TokenProcessor("fullortsdavis_c", () => { FullStaticORTSDavis_C = stf.ReadFloatBlock(STFReader.UNITS.ResistanceDavisC, -1); }), new STFReader.TokenProcessor("fullortswagonfrontalarea", () => { FullStaticORTSWagonFrontalAreaM2 = stf.ReadFloatBlock(STFReader.UNITS.AreaDefaultFT2, -1); }), new STFReader.TokenProcessor("fullortsdavisdragconstant", () => { FullStaticORTSDavisDragConstant = stf.ReadFloatBlock(STFReader.UNITS.Any, -1); }), new STFReader.TokenProcessor("fullmaxbrakeforce", () => { FullStaticMaxBrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("fullmaxhandbrakeforce", () => { FullStaticMaxHandbrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("fullcentreofgravity_y", () => { FullStaticCentreOfGravityM_Y = stf.ReadFloatBlock(STFReader.UNITS.Distance, -1); }) }); }
public FreightAnimationStatic(STFReader stf) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("subtype", () => { var typeString = stf.ReadStringBlock(null); switch (typeString) { default: SubType = FreightAnimationStatic.Type.DEFAULT; break; } }), new STFReader.TokenProcessor("shape", () => { ShapeFileName = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("freightweight", () => { FreightWeight = stf.ReadFloatBlock(STFReader.UNITS.Mass, 0); }), new STFReader.TokenProcessor("offset", () => { stf.MustMatch("("); XOffset = stf.ReadFloat(STFReader.UNITS.Distance, 0); YOffset = stf.ReadFloat(STFReader.UNITS.Distance, 0); ZOffset = stf.ReadFloat(STFReader.UNITS.Distance, 0); stf.MustMatch(")"); }), new STFReader.TokenProcessor("flip", () => { Flipped = stf.ReadBoolBlock(true); }), }); }
public float FullCentreOfGravityM_Y = -9999; // get centre of gravity after adjusted for freight animation public FreightAnimationContinuous(STFReader stf, MSTSWagon wagon) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("intakepoint", () => { wagon.IntakePointList.Add(new IntakePoint(stf)); wagon.IntakePointList.Last().LinkedFreightAnim = this; LinkedIntakePoint = wagon.IntakePointList.Last(); }), new STFReader.TokenProcessor("shape", () => { ShapeFileName = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("maxheight", () => { MaxHeight = stf.ReadFloatBlock(STFReader.UNITS.Distance, 0); }), new STFReader.TokenProcessor("minheight", () => { MinHeight = stf.ReadFloatBlock(STFReader.UNITS.Distance, 0); }), new STFReader.TokenProcessor("freightweightwhenfull", () => { FreightWeightWhenFull = stf.ReadFloatBlock(STFReader.UNITS.Mass, 0); }), new STFReader.TokenProcessor("fullatstart", () => { FullAtStart = stf.ReadBoolBlock(true); }), // additions to manage consequences of variable weight on friction and brake forces new STFReader.TokenProcessor("fullortsdavis_a", () => { FullORTSDavis_A = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("fullortsdavis_b", () => { FullORTSDavis_B = stf.ReadFloatBlock(STFReader.UNITS.Resistance, -1); }), new STFReader.TokenProcessor("fullortsdavis_c", () => { FullORTSDavis_C = stf.ReadFloatBlock(STFReader.UNITS.ResistanceDavisC, -1); }), new STFReader.TokenProcessor("fullortswagonfrontalarea", () => { FullORTSWagonFrontalAreaM2 = stf.ReadFloatBlock(STFReader.UNITS.AreaDefaultFT2, -1); }), new STFReader.TokenProcessor("fullortsdavisdragconstant", () => { FullORTSDavisDragConstant = stf.ReadFloatBlock(STFReader.UNITS.Any, -1); }), new STFReader.TokenProcessor("fullmaxbrakeforce", () => { FullMaxBrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("fullmaxhandbrakeforce", () => { FullMaxHandbrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("fullcentreofgravity_y", () => { FullCentreOfGravityM_Y = stf.ReadFloatBlock(STFReader.UNITS.Distance, -1); }) }); }
public virtual void Parse(string lowercasetoken, STFReader stf) { switch (lowercasetoken) { case "engine(ortsmasterkey(mode": string text = stf.ReadStringBlock("").ToLower(); if (text == "alwayson") { Mode = ModeType.AlwaysOn; } else if (text == "manual") { Mode = ModeType.Manual; } else { STFException.TraceWarning(stf, "Skipped invalid master key mode"); } break; case "engine(ortsmasterkey(delayoff": DelayS = stf.ReadFloatBlock(STFReader.UNITS.Time, 0f); break; case "engine(ortsmasterkey(headlightcontrol": HeadlightControl = stf.ReadBoolBlock(false); break; } }
public TrackShape(STFReader stf) { stf.MustMatchBlockStart(); ShapeIndex = stf.ReadUInt(null); int nextPath = 0; stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("filename", () => { FileName = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("numpaths", () => { SectionIndices = new SectionIndex[PathsNumber = stf.ReadUIntBlock(null)]; }), new STFReader.TokenProcessor("mainroute", () => { MainRoute = stf.ReadUIntBlock(null); }), new STFReader.TokenProcessor("clearancedist", () => { ClearanceDistance = stf.ReadFloatBlock(STFReader.Units.Distance, null); }), new STFReader.TokenProcessor("sectionidx", () => { SectionIndices[nextPath++] = new SectionIndex(stf); }), new STFReader.TokenProcessor("tunnelshape", () => { TunnelShape = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("roadshape", () => { RoadShape = stf.ReadBoolBlock(true); }), }); // TODO - this was removed since TrackShape( 183 ) is blank //if( FileName == null ) throw( new STFError( stf, "Missing FileName" ) ); //if( SectionIdxs == null ) throw( new STFError( stf, "Missing SectionIdxs" ) ); //if( NumPaths == 0 ) throw( new STFError( stf, "No Paths in TrackShape" ) ); }
public Tr_RouteFile(STFReader stf) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("routeid", () => { RouteID = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("name", () => { Name = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("filename", () => { FileName = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("description", () => { Description = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("maxlinevoltage", () => { MaxLineVoltage = stf.ReadFloatBlock(STFReader.UNITS.None, null); }), new STFReader.TokenProcessor("routestart", () => { if (RouteStart == null) { RouteStart = new RouteStart(stf); } }), new STFReader.TokenProcessor("environment", () => { Environment = new TRKEnvironment(stf); }), new STFReader.TokenProcessor("milepostunitskilometers", () => { MilepostUnitsMetric = true; }), new STFReader.TokenProcessor("electrified", () => { Electrified = stf.ReadBoolBlock(false); }), new STFReader.TokenProcessor("overheadwireheight", () => { OverheadWireHeight = stf.ReadFloatBlock(STFReader.UNITS.Distance, 6.0f); }), new STFReader.TokenProcessor("speedlimit", () => { SpeedLimit = stf.ReadFloatBlock(STFReader.UNITS.Speed, 500.0f); }), new STFReader.TokenProcessor("defaultcrossingsms", () => { DefaultCrossingSMS = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("defaultcoaltowersms", () => { DefaultCoalTowerSMS = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("defaultdieseltowersms", () => { DefaultDieselTowerSMS = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("defaultwatertowersms", () => { DefaultWaterTowerSMS = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("defaultsignalsms", () => { DefaultSignalSMS = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("temprestrictedspeed", () => { TempRestrictedSpeed = stf.ReadFloatBlock(STFReader.UNITS.Speed, -1f); }), // values for tunnel operation new STFReader.TokenProcessor("ortssingletunnelarea", () => { SingleTunnelAreaM2 = stf.ReadFloatBlock(STFReader.UNITS.AreaDefaultFT2, null); }), new STFReader.TokenProcessor("ortssingletunnelperimeter", () => { SingleTunnelPerimeterM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); }), new STFReader.TokenProcessor("ortsdoubletunnelarea", () => { DoubleTunnelAreaM2 = stf.ReadFloatBlock(STFReader.UNITS.AreaDefaultFT2, null); }), new STFReader.TokenProcessor("ortsdoubletunnelperimeter", () => { DoubleTunnelPerimeterM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); }), // if > 0 indicates distance from track without forest trees new STFReader.TokenProcessor("ortsuserpreferenceforestcleardistance", () => { ForestClearDistance = stf.ReadFloatBlock(STFReader.UNITS.Distance, 0); }), // values for superelevation new STFReader.TokenProcessor("ortstracksuperelevation", () => { SuperElevationHgtpRadiusM = new Interpolator(stf); }), }); //TODO This should be changed to STFException.TraceError() with defaults values created if (RouteID == null) { throw new STFException(stf, "Missing RouteID"); } if (Name == null) { throw new STFException(stf, "Missing Name"); } if (Description == null) { throw new STFException(stf, "Missing Description"); } if (RouteStart == null) { throw new STFException(stf, "Missing RouteStart"); } }
public FreightAnimationContinuous(STFReader stf, MSTSWagon wagon) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("intakepoint", () => { wagon.IntakePointList.Add(new IntakePoint(stf)); wagon.IntakePointList.Last().LinkedFreightAnim = this; LinkedIntakePoint = wagon.IntakePointList.Last(); }), new STFReader.TokenProcessor("shape", () => { ShapeFileName = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("maxheight", () => { MaxHeight = stf.ReadFloatBlock(STFReader.UNITS.Distance, 0); }), new STFReader.TokenProcessor("minheight", () => { MinHeight = stf.ReadFloatBlock(STFReader.UNITS.Distance, 0); }), new STFReader.TokenProcessor("freightweightwhenfull", () => { FreightWeightWhenFull = stf.ReadFloatBlock(STFReader.UNITS.Mass, 0); }), new STFReader.TokenProcessor("fullatstart", () => { FullAtStart = stf.ReadBoolBlock(true); }), }); }
public ShapeDescriptor(STFReader stf) { Name = stf.ReadString(); // Ignore the filename string. TODO: Check if it agrees with the SD file name? Is this important? stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("esd_detail_level", () => { EsdDetailLevel = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("esd_alternative_texture", () => { EsdAlternativeTexture = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("esd_no_visual_obstruction", () => { EsdNoVisualObstruction = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("esd_snapable", () => { EsdSnapable = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("esd_subobj", () => { EsdSubObject = true; stf.SkipBlock(); }), new STFReader.TokenProcessor("esd_bounding_box", () => { EsdBoundingBox = new EsdBoundingBox(stf); if (EsdBoundingBox.Min == null || EsdBoundingBox.Max == null) // ie quietly handle ESD_Bounding_Box() { EsdBoundingBox = null; } }), new STFReader.TokenProcessor("esd_ortssoundfilename", () => { EsdSoundFileName = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("esd_ortsbellanimationfps", () => { EsdBellAnimationFps = stf.ReadFloatBlock(STFReader.Units.Frequency, null); }), }); // TODO - some objects have no bounding box - ie JP2BillboardTree1.sd //if (ESD_Bounding_Box == null) throw new STFException(stf, "Missing ESD_Bound_Box statement"); }
public AttributeProcessor(object setWhom, FieldInfo fi, STFReader stf, object defaultValue) { _fi = fi; P = () => { switch (_fi.FieldType.Name.ToLower()) { case "int": case "int32": { int?i = defaultValue as int?; _fi.SetValue(setWhom, stf.ReadIntBlock(i)); break; } case "bool": case "boolean": { bool?b = defaultValue as bool?; _fi.SetValue(setWhom, stf.ReadBoolBlock(b.Value)); break; } case "string": { string s = defaultValue as string; _fi.SetValue(setWhom, stf.ReadStringBlock(s)); break; } case "float": case "single": { float?f = defaultValue as float?; _fi.SetValue(setWhom, stf.ReadFloatBlock(STFReader.Units.Any, f)); break; } case "double": { double?d = defaultValue as double?; _fi.SetValue(setWhom, stf.ReadDoubleBlock(d)); break; } case "vector3": { Vector3 v3 = (defaultValue as string).ParseVector3(); { _fi.SetValue(setWhom, stf.ReadVector3Block(STFReader.Units.Any, v3)); } break; } case "vector4": { Vector4 v4 = (defaultValue as string).ParseVector4(); { stf.ReadVector4Block(STFReader.Units.Any, ref v4); _fi.SetValue(setWhom, v4); } break; } case "color": { Color c = (defaultValue as string).ParseColor(); { Vector4 v4 = new Vector4(-1); stf.ReadVector4Block(STFReader.Units.Any, ref v4); if (v4.W == -1) { c.A = 255; c.R = v4.X == -1 ? c.R : (byte)v4.X; c.G = v4.Y == -1 ? c.G : (byte)v4.Y; c.B = v4.Z == -1 ? c.B : (byte)v4.Z; } else { c.A = v4.X == -1 ? c.A : (byte)v4.X; c.R = v4.Y == -1 ? c.R : (byte)v4.Y; c.G = v4.Z == -1 ? c.G : (byte)v4.Z; c.B = v4.W == -1 ? c.B : (byte)v4.W; } _fi.SetValue(setWhom, c); } break; } } }; }
public bool StaticFreightAnimationsPresent = false; // Flag to indicate that a continuous freight animation is present public FreightAnimations(STFReader stf, MSTSWagon wagon) { stf.MustMatch("("); bool empty = true; stf.ParseBlock(new[] { new STFReader.TokenProcessor("mstsfreightanimenabled", () => { MSTSFreightAnimEnabled = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("wagonemptyweight", () => { WagonEmptyWeight = stf.ReadFloatBlock(STFReader.UNITS.Mass, -1); }), new STFReader.TokenProcessor("loadingstartdelay", () => { UnloadingStartDelay = stf.ReadFloatBlock(STFReader.UNITS.None, 0); }), new STFReader.TokenProcessor("unloadingstartdelay", () => { UnloadingStartDelay = stf.ReadFloatBlock(STFReader.UNITS.None, 0); }), new STFReader.TokenProcessor("isgondola", () => { IsGondola = stf.ReadBoolBlock(false); }), // additions to manage consequences of variable weight on friction and brake forces new STFReader.TokenProcessor("emptyortsdavis_a", () => { EmptyORTSDavis_A = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("emptyortsdavis_b", () => { EmptyORTSDavis_B = stf.ReadFloatBlock(STFReader.UNITS.Resistance, -1); }), new STFReader.TokenProcessor("emptyortsdavis_c", () => { EmptyORTSDavis_C = stf.ReadFloatBlock(STFReader.UNITS.ResistanceDavisC, -1); }), new STFReader.TokenProcessor("emptyortswagonfrontalarea", () => { EmptyORTSWagonFrontalAreaM2 = stf.ReadFloatBlock(STFReader.UNITS.AreaDefaultFT2, -1); }), new STFReader.TokenProcessor("emptyortsdavisdragconstant", () => { EmptyORTSDavisDragConstant = stf.ReadFloatBlock(STFReader.UNITS.Any, -1); }), new STFReader.TokenProcessor("emptymaxbrakeforce", () => { EmptyMaxBrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("emptymaxhandbrakeforce", () => { EmptyMaxHandbrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("emptycentreofgravity_y", () => { EmptyCentreOfGravityM_Y = stf.ReadFloatBlock(STFReader.UNITS.Distance, -1); }), new STFReader.TokenProcessor("freightanimcontinuous", () => { Animations.Add(new FreightAnimationContinuous(stf, wagon)); FullPhysicsContinuousOne = Animations.Last() as FreightAnimationContinuous; if (wagon.WeightLoadController == null) { wagon.WeightLoadController = new MSTSNotchController(0, 1, 0.01f); } if ((Animations.Last() as FreightAnimationContinuous).FullAtStart) { if (empty) { empty = false; FreightType = wagon.IntakePointList.Last().Type; LoadedOne = Animations.Last() as FreightAnimationContinuous; FreightWeight += LoadedOne.FreightWeightWhenFull; LoadedOne.LoadPerCent = 100; } else { (Animations.Last() as FreightAnimationContinuous).FullAtStart = false; Trace.TraceWarning("The wagon can't be full with two different materials, only first is retained"); } } ContinuousFreightAnimationsPresent = true; }), new STFReader.TokenProcessor("freightanimstatic", () => { Animations.Add(new FreightAnimationStatic(stf)); StaticFreightWeight += (Animations.Last() as FreightAnimationStatic).FreightWeight; StaticFreightAnimationsPresent = true; FullPhysicsStaticOne = Animations.Last() as FreightAnimationStatic; }), /* new STFReader.TokenProcessor("freightanimdiscrete", ()=> * { * ORTSFreightAnims.Add(new FreightAnimDiscrete(stf)); * if ((ORTSFreightAnims.Last() as FreightAnimDiscrete).LoadedAtStart) * { * if (empty) * { * empty = false; * DiscreteLoadedOne = ORTSFreightAnims.Last() as FreightAnimDiscrete; * FreightWeight += DiscreteLoadedOne.LoadWeight; * } * else * { * (ORTSFreightAnims.Last() as FreightAnimContinuous).FullAtStart = false; * Trace.TraceWarning("The wagon can't be full with two different materials, only first is retained"); * } * } * }),*/ }); }
public float FullStaticCentreOfGravityM_Y = -9999; // get centre of gravity after adjusted for freight animation public FreightAnimationStatic(STFReader stf) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("subtype", () => { var typeString = stf.ReadStringBlock(null); switch (typeString) { default: SubType = FreightAnimationStatic.Type.DEFAULT; break; } }), new STFReader.TokenProcessor("shape", () => { ShapeFileName = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("freightweight", () => { FreightWeight = stf.ReadFloatBlock(STFReader.UNITS.Mass, 0); }), new STFReader.TokenProcessor("offset", () => { stf.MustMatch("("); XOffset = stf.ReadFloat(STFReader.UNITS.Distance, 0); YOffset = stf.ReadFloat(STFReader.UNITS.Distance, 0); ZOffset = stf.ReadFloat(STFReader.UNITS.Distance, 0); stf.MustMatch(")"); }), new STFReader.TokenProcessor("flip", () => { Flipped = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("visibility", () => { for (int index = 0; index < 3; index++) { Visibility[index] = false; } foreach (var visibilityPlace in stf.ReadStringBlock("").ToLower().Replace(" ", "").Split(',')) { switch (visibilityPlace) { case "outside": Visibility[(int)VisibleFrom.Outside] = true; break; case "cab2d": Visibility[(int)VisibleFrom.Cab2D] = true; break; case "cab3d": Visibility[(int)VisibleFrom.Cab3D] = true; break; default: break; } } }), // additions to manage consequences of variable weight on friction and brake forces new STFReader.TokenProcessor("fullortsdavis_a", () => { FullStaticORTSDavis_A = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("fullortsdavis_b", () => { FullStaticORTSDavis_B = stf.ReadFloatBlock(STFReader.UNITS.Resistance, -1); }), new STFReader.TokenProcessor("fullortsdavis_c", () => { FullStaticORTSDavis_C = stf.ReadFloatBlock(STFReader.UNITS.ResistanceDavisC, -1); }), new STFReader.TokenProcessor("fullortswagonfrontalarea", () => { FullStaticORTSWagonFrontalAreaM2 = stf.ReadFloatBlock(STFReader.UNITS.AreaDefaultFT2, -1); }), new STFReader.TokenProcessor("fullortsdavisdragconstant", () => { FullStaticORTSDavisDragConstant = stf.ReadFloatBlock(STFReader.UNITS.Any, -1); }), new STFReader.TokenProcessor("fullmaxbrakeforce", () => { FullStaticMaxBrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("fullmaxhandbrakeforce", () => { FullStaticMaxHandbrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, -1); }), new STFReader.TokenProcessor("fullcentreofgravity_y", () => { FullStaticCentreOfGravityM_Y = stf.ReadFloatBlock(STFReader.UNITS.Distance, -1); }) }); }
} // true for humans public CarSpawnerList(STFReader stf, string shapePath, string listName) { ListName = listName; var count = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("ignorexrotation", () => { IgnoreXRotation = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("carspawneritem", () => { if (--count < 0) { STFException.TraceWarning(stf, "Skipped extra CarSpawnerItem"); } else { CarSpawner dataItem = new CarSpawner(stf, shapePath); if (File.Exists(dataItem.Name)) { Add(dataItem); } else { STFException.TraceWarning(stf, $"Non-existent shape file {dataItem.Name} referenced"); } } }), }); if (count > 0) { STFException.TraceWarning(stf, count + " missing CarSpawnerItem(s)"); } }
internal Route(STFReader stf) { stf.MustMatchBlockStart(); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("routeid", () => { RouteID = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("name", () => { Name = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("filename", () => { FileName = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("description", () => { Description = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("maxlinevoltage", () => { MaxLineVoltage = stf.ReadFloatBlock(STFReader.Units.None, null); }), new STFReader.TokenProcessor("routestart", () => { RouteStart = new RouteStart(stf); }), new STFReader.TokenProcessor("environment", () => { Environment = new Environment(stf); }), new STFReader.TokenProcessor("milepostunitskilometers", () => { MilepostUnitsMetric = true; }), new STFReader.TokenProcessor("electrified", () => { Electrified = stf.ReadBoolBlock(false); }), new STFReader.TokenProcessor("overheadwireheight", () => { OverheadWireHeight = stf.ReadFloatBlock(STFReader.Units.Distance, 6.0f); }), new STFReader.TokenProcessor("speedlimit", () => { SpeedLimit = stf.ReadFloatBlock(STFReader.Units.Speed, 500.0f); }), new STFReader.TokenProcessor("defaultcrossingsms", () => { DefaultCrossingSMS = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("defaultcoaltowersms", () => { DefaultCoalTowerSMS = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("defaultdieseltowersms", () => { DefaultDieselTowerSMS = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("defaultwatertowersms", () => { DefaultWaterTowerSMS = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("defaultsignalsms", () => { DefaultSignalSMS = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("temprestrictedspeed", () => { TempRestrictedSpeed = stf.ReadFloatBlock(STFReader.Units.Speed, -1f); }), // values for tunnel operation new STFReader.TokenProcessor("ortssingletunnelarea", () => { SingleTunnelAreaM2 = stf.ReadFloatBlock(STFReader.Units.AreaDefaultFT2, null); }), new STFReader.TokenProcessor("ortssingletunnelperimeter", () => { SingleTunnelPerimeterM = stf.ReadFloatBlock(STFReader.Units.Distance, null); }), new STFReader.TokenProcessor("ortsdoubletunnelarea", () => { DoubleTunnelAreaM2 = stf.ReadFloatBlock(STFReader.Units.AreaDefaultFT2, null); }), new STFReader.TokenProcessor("ortsdoubletunnelperimeter", () => { DoubleTunnelPerimeterM = stf.ReadFloatBlock(STFReader.Units.Distance, null); }), // if > 0 indicates distance from track without forest trees new STFReader.TokenProcessor("ortsuserpreferenceforestcleardistance", () => { ForestClearDistance = stf.ReadFloatBlock(STFReader.Units.Distance, 0); }), // if true removes forest trees also from roads new STFReader.TokenProcessor("ortsuserpreferenceremoveforesttreesfromroads", () => { RemoveForestTreesFromRoads = stf.ReadBoolBlock(false); }), // values for superelevation new STFReader.TokenProcessor("ortstracksuperelevation", () => { SuperElevationHgtpRadiusM = stf.CreateInterpolator(); }), // images new STFReader.TokenProcessor("graphic", () => { Thumbnail = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("loadingscreen", () => { LoadingScreen = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("ortsloadingscreenwide", () => { LoadingScreenWide = stf.ReadStringBlock(null); }), // values for OHLE new STFReader.TokenProcessor("ortsdoublewireenabled", () => { DoubleWireEnabled = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("ortsdoublewireheight", () => { DoubleWireHeight = stf.ReadFloatBlock(STFReader.Units.Distance, null); }), new STFReader.TokenProcessor("ortstriphaseenabled", () => { TriphaseEnabled = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("ortstriphasewidth", () => { TriphaseWidth = stf.ReadFloatBlock(STFReader.Units.Distance, null); }), // default sms file for turntables and transfertables new STFReader.TokenProcessor("ortsdefaultturntablesms", () => { DefaultTurntableSMS = stf.ReadStringBlock(null); }), // sms file number in Ttype.dat when train over switch new STFReader.TokenProcessor("ortsswitchsmsnumber", () => { SwitchSMSNumber = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("ortscurvesmsnumber", () => { CurveSMSNumber = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("ortscurveswitchsmsnumber", () => { CurveSwitchSMSNumber = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("ortsopendoorsinaitrains", () => { OpenDoorsInAITrains = stf.ReadBoolBlock(false); }), }); //TODO This should be changed to STFException.TraceError() with defaults values created if (RouteID == null) { throw new STFException(stf, "Missing RouteID"); } if (Name == null) { throw new STFException(stf, "Missing Name"); } if (Description == null) { throw new STFException(stf, "Missing Description"); } if (RouteStart == null) { throw new STFException(stf, "Missing RouteStart"); } if (ForestClearDistance == 0 && RemoveForestTreesFromRoads) { Trace.TraceWarning("You must define also ORTSUserPreferenceForestClearDistance to avoid trees on roads"); } }
public AttributeProcessor(object setWhom, FieldInfo fi, STFReader stf, object defaultValue) { fieldInfo = fi; Processor = () => { switch (fieldInfo.FieldType.Name.ToUpperInvariant()) { case "INT": case "INT32": { int?i = defaultValue as int?; fieldInfo.SetValue(setWhom, stf.ReadIntBlock(i)); break; } case "BOOL": case "BOOLEAN": { bool?b = defaultValue as bool?; fieldInfo.SetValue(setWhom, stf.ReadBoolBlock(b.Value)); break; } case "STRING": { string s = defaultValue as string; fieldInfo.SetValue(setWhom, stf.ReadStringBlock(s)); break; } case "FLOAT": case "SINGLE": { float?f = defaultValue as float?; fieldInfo.SetValue(setWhom, stf.ReadFloatBlock(STFReader.Units.Any, f)); break; } case "DOUBLE": { double?d = defaultValue as double?; fieldInfo.SetValue(setWhom, stf.ReadDoubleBlock(d)); break; } case "VECTOR3": { Vector3 v3 = (defaultValue as string).ParseVector3(); { fieldInfo.SetValue(setWhom, stf.ReadVector3Block(STFReader.Units.Any, v3)); } break; } case "VECTOR4": { Vector4 v4 = (defaultValue as string).ParseVector4(); { stf.ReadVector4Block(STFReader.Units.Any, ref v4); fieldInfo.SetValue(setWhom, v4); } break; } case "COLOR": { Color c = (defaultValue as string).ParseColor(); { Vector4 v4 = new Vector4(-1); stf.ReadVector4Block(STFReader.Units.Any, ref v4); if (v4.W == -1) { c.A = 255; c.R = v4.X == -1 ? c.R : (byte)v4.X; c.G = v4.Y == -1 ? c.G : (byte)v4.Y; c.B = v4.Z == -1 ? c.B : (byte)v4.Z; } else { c.A = v4.X == -1 ? c.A : (byte)v4.X; c.R = v4.Y == -1 ? c.R : (byte)v4.Y; c.G = v4.Z == -1 ? c.G : (byte)v4.Z; c.B = v4.W == -1 ? c.B : (byte)v4.W; } fieldInfo.SetValue(setWhom, c); } break; } } }; }
private bool saveConnected = true; // Transfertable is connected to a track internal TransferTable(STFReader stf) { string animation; Matrix location = Matrix.Identity; location.M44 = 100_000_000; //WorlPosition not yet defined, will be loaded when loading related tile; stf.MustMatch("("); stf.ParseBlock(new[] { new STFReader.TokenProcessor("wfile", () => { WFile = stf.ReadStringBlock(null); position = new WorldPosition(int.Parse(WFile.Substring(1, 7), CultureInfo.InvariantCulture), int.Parse(WFile.Substring(8, 7), CultureInfo.InvariantCulture), location); }), new STFReader.TokenProcessor("uid", () => { UID = stf.ReadIntBlock(-1); }), new STFReader.TokenProcessor("animation", () => { animation = stf.ReadStringBlock(null); Animations.Add(animation); }), new STFReader.TokenProcessor("verticaltransfer", () => { verticalTransfer = stf.ReadBoolBlock(false); }), new STFReader.TokenProcessor("length", () => { Length = stf.ReadFloatBlock(STFReader.Units.None, null); }), new STFReader.TokenProcessor("xoffset", () => { offset.X = stf.ReadFloatBlock(STFReader.Units.None, null); }), new STFReader.TokenProcessor("zoffset", () => { offset.Z = -stf.ReadFloatBlock(STFReader.Units.None, null); }), new STFReader.TokenProcessor("yoffset", () => { offset.Y = stf.ReadFloatBlock(STFReader.Units.None, null); }), new STFReader.TokenProcessor("trackshapeindex", () => { TrackShapeIndex = stf.ReadIntBlock(-1); InitializeOffsetsAndTrackNodes(); }), }); }
public bool ResetOnResetButton; // OverspeedMonitor only public MonitoringDevice(STFReader stf) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("monitoringdevicemonitortimelimit", () => { MonitorTimeS = stf.ReadFloatBlock(STFReader.UNITS.Time, MonitorTimeS); }), new STFReader.TokenProcessor("monitoringdevicealarmtimelimit", () => { AlarmTimeS = stf.ReadFloatBlock(STFReader.UNITS.Time, AlarmTimeS); }), new STFReader.TokenProcessor("monitoringdevicepenaltytimelimit", () => { PenaltyTimeS = stf.ReadFloatBlock(STFReader.UNITS.Time, PenaltyTimeS); }), new STFReader.TokenProcessor("monitoringdevicecriticallevel", () => { CriticalLevelMpS = stf.ReadFloatBlock(STFReader.UNITS.Speed, CriticalLevelMpS); }), new STFReader.TokenProcessor("monitoringdeviceresetlevel", () => { ResetLevelMpS = stf.ReadFloatBlock(STFReader.UNITS.Speed, ResetLevelMpS); }), new STFReader.TokenProcessor("monitoringdeviceappliesfullbrake", () => { AppliesFullBrake = stf.ReadBoolBlock(AppliesFullBrake); }), new STFReader.TokenProcessor("monitoringdeviceappliesemergencybrake", () => { AppliesEmergencyBrake = stf.ReadBoolBlock(AppliesEmergencyBrake); }), new STFReader.TokenProcessor("monitoringdeviceappliescutspower", () => { EmergencyCutsPower = stf.ReadBoolBlock(EmergencyCutsPower); }), new STFReader.TokenProcessor("monitoringdeviceappliesshutsdownengine", () => { EmergencyShutsDownEngine = stf.ReadBoolBlock(EmergencyShutsDownEngine); }), new STFReader.TokenProcessor("monitoringdevicealarmtimebeforeoverspeed", () => { AlarmTimeBeforeOverspeedS = stf.ReadFloatBlock(STFReader.UNITS.Time, AlarmTimeBeforeOverspeedS); }), new STFReader.TokenProcessor("monitoringdevicetriggeronoverspeed", () => { TriggerOnOverspeedMpS = stf.ReadFloatBlock(STFReader.UNITS.Speed, TriggerOnOverspeedMpS); }), new STFReader.TokenProcessor("monitoringdevicetriggerontrackoverspeed", () => { TriggerOnTrackOverspeed = stf.ReadBoolBlock(TriggerOnTrackOverspeed); }), new STFReader.TokenProcessor("monitoringdevicetriggerontrackoverspeedmargin", () => { TriggerOnTrackOverspeedMarginMpS = stf.ReadFloatBlock(STFReader.UNITS.Speed, TriggerOnTrackOverspeedMarginMpS); }), new STFReader.TokenProcessor("monitoringdeviceresetondirectionneutral", () => { ResetOnDirectionNeutral = stf.ReadBoolBlock(ResetOnDirectionNeutral); }), new STFReader.TokenProcessor("monitoringdeviceresetonresetbutton", () => { ResetOnResetButton = stf.ReadBoolBlock(ResetOnResetButton); }), new STFReader.TokenProcessor("monitoringdeviceresetonzerospeed", () => { ResetOnZeroSpeed = stf.ReadBoolBlock(ResetOnZeroSpeed); }), }); }
public FreightAnimationDiscrete(STFReader stf) { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("subtype", () => { var typeString = stf.ReadStringBlock(null); switch (typeString) { default: SubType = FreightAnimationDiscrete.Type.DEFAULT; break; } }), new STFReader.TokenProcessor("shape", () => { ShapeFileName = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("offset", () => { stf.MustMatchBlockStart(); XOffset = stf.ReadFloat(STFReader.Units.Distance, 0); YOffset = stf.ReadFloat(STFReader.Units.Distance, 0); ZOffset = stf.ReadFloat(STFReader.Units.Distance, 0); stf.MustMatchBlockEnd(); }), new STFReader.TokenProcessor("loadweight", () => { LoadWeight = stf.ReadFloatBlock(STFReader.Units.Mass, 0); }), new STFReader.TokenProcessor("loadedatstart", () => { LoadedAtStart = stf.ReadBoolBlock(true); }), }); }
public SDShape(STFReader stf) { stf.ReadString(); // Ignore the filename string. TODO: Check if it agrees with the SD file name? Is this important? stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("esd_detail_level", () => { ESD_Detail_Level = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("esd_alternative_texture", () => { ESD_Alternative_Texture = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("esd_no_visual_obstruction", () => { ESD_No_Visual_Obstruction = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("esd_snapable", () => { ESD_Snapable = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("esd_subobj", () => { ESD_SubObj = true; stf.SkipBlock(); }), new STFReader.TokenProcessor("esd_bounding_box", () => { ESD_Bounding_Box = new ESD_Bounding_Box(stf); if (ESD_Bounding_Box.Min == null || ESD_Bounding_Box.Max == null) // ie quietly handle ESD_Bounding_Box() { ESD_Bounding_Box = null; } }), new STFReader.TokenProcessor("esd_ortssoundfilename", () => { ESD_SoundFileName = stf.ReadStringBlock(null); }), }); // TODO - some objects have no bounding box - ie JP2BillboardTree1.sd //if (ESD_Bounding_Box == null) throw new STFException(stf, "Missing ESD_Bound_Box statement"); }
public FreightAnimations(STFReader stf, MSTSWagon wagon) { stf.MustMatch("("); bool empty = true; stf.ParseBlock(new[] { new STFReader.TokenProcessor("mstsfreightanimenabled", () => { MSTSFreightAnimEnabled = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("wagonemptyweight", () => { WagonEmptyWeight = stf.ReadFloatBlock(STFReader.UNITS.Mass, -1); }), new STFReader.TokenProcessor("loadingstartdelay", () => { UnloadingStartDelay = stf.ReadFloatBlock(STFReader.UNITS.None, 0); }), new STFReader.TokenProcessor("unloadingstartdelay", () => { UnloadingStartDelay = stf.ReadFloatBlock(STFReader.UNITS.None, 0); }), new STFReader.TokenProcessor("isgondola", () => { IsGondola = stf.ReadBoolBlock(false); }), new STFReader.TokenProcessor("freightanimcontinuous", () => { Animations.Add(new FreightAnimationContinuous(stf, wagon)); if (wagon.WeightLoadController == null) { wagon.WeightLoadController = new MSTSNotchController(0, 1, 0.01f); } if ((Animations.Last() as FreightAnimationContinuous).FullAtStart) { if (empty) { empty = false; FreightType = wagon.IntakePointList.Last().Type; LoadedOne = Animations.Last() as FreightAnimationContinuous; FreightWeight += LoadedOne.FreightWeightWhenFull; LoadedOne.LoadPerCent = 100; } else { (Animations.Last() as FreightAnimationContinuous).FullAtStart = false; Trace.TraceWarning("The wagon can't be full with two different materials, only first is retained"); } } }), new STFReader.TokenProcessor("freightanimstatic", () => { Animations.Add(new FreightAnimationStatic(stf)); StaticFreightWeight += (Animations.Last() as FreightAnimationStatic).FreightWeight; }), /* new STFReader.TokenProcessor("freightanimdiscrete", ()=> * { * ORTSFreightAnims.Add(new FreightAnimDiscrete(stf)); * if ((ORTSFreightAnims.Last() as FreightAnimDiscrete).LoadedAtStart) * { * if (empty) * { * empty = false; * DiscreteLoadedOne = ORTSFreightAnims.Last() as FreightAnimDiscrete; * FreightWeight += DiscreteLoadedOne.LoadWeight; * } * else * { * (ORTSFreightAnims.Last() as FreightAnimContinuous).FullAtStart = false; * Trace.TraceWarning("The wagon can't be full with two different materials, only first is retained"); * } * } * }),*/ }); }
public CVCDiscrete(STFReader stf, string basepath) { // try { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("type", () => { ParseType(stf); }), new STFReader.TokenProcessor("position", () => { ParsePosition(stf); }), new STFReader.TokenProcessor("scalerange", () => { ParseScaleRange(stf); }), new STFReader.TokenProcessor("graphic", () => { ParseGraphic(stf, basepath); }), new STFReader.TokenProcessor("style", () => { ParseStyle(stf); }), new STFReader.TokenProcessor("units", () => { ParseUnits(stf); }), new STFReader.TokenProcessor("mousecontrol", () => { MouseControl = stf.ReadBoolBlock(false); }), new STFReader.TokenProcessor("orientation", () => { Orientation = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("dirincrease", () => { Direction = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("numframes", () => { stf.MustMatch("("); FramesCount = stf.ReadInt(null); FramesX = stf.ReadInt(null); FramesY = stf.ReadInt(null); stf.SkipRestOfBlock(); }), // <CJComment> Would like to revise this, as it is difficult to follow and debug. // Can't do that until interaction of ScaleRange, NumFrames, NumPositions and NumValues is more fully specified. // What is needed is samples of data that must be accommodated. // Some decisions appear unwise but they might be a pragmatic solution to a real problem. </CJComment> // // Code accommodates: // - NumValues before NumPositions or the other way round. // - More NumValues than NumPositions and the other way round - perhaps unwise. // - The count of NumFrames, NumValues and NumPositions is ignored - perhaps unwise. // - Abbreviated definitions so that values at intermediate unspecified positions can be omitted. // Strangely, these values are set to 0 and worked out later when drawing. // Max and min NumValues which don't match the ScaleRange are ignored - perhaps unwise. new STFReader.TokenProcessor("numpositions", () => { stf.MustMatch("("); // If Positions are not filled before by Values bool shouldFill = (Positions.Count == 0); numPositions = stf.ReadInt(null); // Number of Positions var minPosition = 0; var positionsRead = 0; while (!stf.EndOfBlock()) { int p = stf.ReadInt(null); minPosition = positionsRead == 0 ? p : Math.Min(minPosition, p); // used to get correct offset positionsRead++; // If Positions are not filled before by Values if (shouldFill) { Positions.Add(p); } } // If positions do not start at 0, add offset to shift them all so they do. // An example of this is RENFE 400 (from http://www.trensim.com/lib/msts/index.php?act=view&id=186) // which has a COMBINED_CONTROL with: // NumPositions ( 21 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 ) // Also handles definitions with position in reverse order, e.g. // NumPositions ( 5 8 7 2 1 0 ) positionsRead++; if (minPosition < 0) { for (int iPos = 0; iPos <= Positions.Count - 1; iPos++) { Positions[iPos] -= minPosition; } } // This is a hack for SLI locomotives which have the positions listed as "1056964608 0 0 0 ...". if (Positions.Any(p => p > 0xFFFF)) { STFException.TraceInformation(stf, "Renumbering cab control positions from zero due to value > 0xFFFF"); for (var i = 0; i < Positions.Count; i++) { Positions[i] = i; } } // Check if eligible for filling if (Positions.Count > 1 && Positions[0] != 0) { canFill = false; } else { for (var iPos = 1; iPos <= Positions.Count - 1; iPos++) { if (Positions[iPos] > Positions[iPos - 1]) { continue; } canFill = false; break; } } // This is a protection against GP40 locomotives that erroneously have positions pointing beyond frame count limit. if (Positions.Count > 1 && canFill && Positions.Count < FramesCount && Positions[Positions.Count - 1] >= FramesCount && Positions[0] == 0) { STFException.TraceInformation(stf, "Some NumPositions entries refer to non-exisiting frames, trying to renumber"); Positions[Positions.Count - 1] = FramesCount - 1; for (var iPos = Positions.Count - 2; iPos >= 1; iPos--) { if ((Positions[iPos] >= FramesCount || Positions[iPos] >= Positions[iPos + 1])) { Positions[iPos] = Positions[iPos + 1] - 1; } else { break; } } } }), new STFReader.TokenProcessor("numvalues", () => { stf.MustMatch("("); var numValues = stf.ReadDouble(null); // Number of Values while (!stf.EndOfBlock()) { double v = stf.ReadDouble(null); // If the Positions are less than expected add new Position(s) while (Positions.Count <= _ValuesRead) { Positions.Add(_ValuesRead); } // Avoid later repositioning, put every value to its Position // But before resize Values if needed if (numValues != numPositions) { while (Values.Count <= Positions[_ValuesRead]) { Values.Add(0); } // Avoid later repositioning, put every value to its Position Values[Positions[_ValuesRead]] = v; } Values.Add(v); _ValuesRead++; } }), }); // If no ACE, just don't need any fixup // Because Values are tied to the image Frame to be shown if (string.IsNullOrEmpty(ACEFile)) { return; } // Now, we have an ACE. // If read any Values, or the control requires Values to control // The twostate, tristate, signal displays are not in these // Need check the Values collection for validity if (_ValuesRead > 0 || ControlStyle == CABViewControlStyles.SPRUNG || ControlStyle == CABViewControlStyles.NOT_SPRUNG || FramesCount > 0 || (FramesX > 0 && FramesY > 0)) { // Check max number of Frames if (FramesCount == 0) { // Check valid Frame information if (FramesX == 0 || FramesY == 0) { // Give up, it won't work // Because later we won't know how to display frames from that Trace.TraceWarning("Invalid Frames information given for ACE {0} in {1}", ACEFile, stf.FileName); ACEFile = ""; return; } // Valid frames info, set FramesCount FramesCount = FramesX * FramesY; } // Now we have an ACE and Frames for it. // Only shuffle data in following cases if (Values.Count != Positions.Count || (Values.Count < FramesCount & canFill) || (Values.Count > 0 && Values[0] == Values[Values.Count - 1] && Values[0] == 0)) { // Fixup Positions and Values collections first // If the read Positions and Values are not match // Or we didn't read Values but have Frames to draw // Do not test if FramesCount equals Values count, we trust in the creator - // maybe did not want to display all Frames // (If there are more Values than Frames it will checked at draw time) // Need to fix the whole Values if (Positions.Count != _ValuesRead || (FramesCount > 0 && (Values.Count == 0 || Values.Count == 1))) { //This if clause covers among others following cases: // Case 1 (e.g. engine brake lever of Dash 9): //NumFrames ( 22 11 2 ) //NumPositions ( 1 0 ) //NumValues ( 1 0 ) //Orientation ( 1 ) //DirIncrease ( 1 ) //ScaleRange ( 0 1 ) // // Case 2 (e.g. throttle lever of Acela): //NumFrames ( 25 5 5 ) //NumPositions ( 0 ) //NumValues ( 0 ) //Orientation ( 1 ) //DirIncrease ( 1 ) //ScaleRange ( 0 1 ) // // Clear existing Positions.Clear(); Values.Clear(); // Add the two sure positions, the two ends Positions.Add(0); // We will need the FramesCount later! // We use Positions only here Positions.Add(FramesCount); // Fill empty Values for (int i = 0; i < FramesCount; i++) { Values.Add(0); } Values[0] = MinValue; Values.Add(MaxValue); } else if (Values.Count == 2 && Values[0] == 0 && Values[1] < MaxValue && Positions[0] == 0 && Positions[1] == 1 && Values.Count < FramesCount) { //This if clause covers among others following cases: // Case 1 (e.g. engine brake lever of gp38): //NumFrames ( 18 2 9 ) //NumPositions ( 2 0 1 ) //NumValues ( 2 0 0.3 ) //Orientation ( 0 ) //DirIncrease ( 0 ) //ScaleRange ( 0 1 ) Positions.Add(FramesCount); // Fill empty Values for (int i = Values.Count; i < FramesCount; i++) { Values.Add(Values[1]); } Values.Add(MaxValue); } else { //This if clause covers among others following cases: // Case 1 (e.g. train brake lever of Acela): //NumFrames ( 12 4 3 ) //NumPositions ( 5 0 1 9 10 11 ) //NumValues ( 5 0 0.2 0.85 0.9 0.95 ) //Orientation ( 1 ) //DirIncrease ( 1 ) //ScaleRange ( 0 1 ) // // Fill empty Values int iValues = 1; for (int i = 1; i < FramesCount && i <= Positions.Count - 1 && Values.Count < FramesCount; i++) { var deltaPos = Positions[i] - Positions[i - 1]; while (deltaPos > 1 && Values.Count < FramesCount) { Values.Insert(iValues, 0); iValues++; deltaPos--; } iValues++; } // Add the maximums to the end, the Value will be removed // We use Positions only here if (Values.Count > 0 && Values[0] <= Values[Values.Count - 1]) { Values.Add(MaxValue); } else if (Values.Count > 0 && Values[0] > Values[Values.Count - 1]) { Values.Add(MinValue); } } // OK, we have a valid size of Positions and Values // Now it is the time for checking holes in the given data if ((Positions.Count < FramesCount - 1 && Values[0] <= Values[Values.Count - 1]) || (Values.Count > 1 && Values[0] == Values[Values.Count - 2] && Values[0] == 0)) { int j = 1; int p = 0; // Skip the 0 element, that is the default MinValue for (int i = 1; i < Positions.Count; i++) { // Found a hole if (Positions[i] != p + 1) { // Iterate to the next valid data and fill the hole for (j = p + 1; j < Positions[i]; j++) { // Extrapolate into the hole Values[j] = MathHelper.Lerp((float)Values[p], (float)Values[Positions[i]], (float)j / (float)Positions[i]); } } p = Positions[i]; } } // Don't need the MaxValue added before, remove it Values.RemoveAt(Values.Count - 1); } } // MSTS ignores/overrides various settings by the following exceptional cases: if (ControlType == CABViewControlTypes.CP_HANDLE) { ControlStyle = CABViewControlStyles.NOT_SPRUNG; } if (ControlType == CABViewControlTypes.PANTOGRAPH || ControlType == CABViewControlTypes.PANTOGRAPH2) { ControlStyle = CABViewControlStyles.ONOFF; } if (ControlType == CABViewControlTypes.HORN || ControlType == CABViewControlTypes.SANDERS || ControlType == CABViewControlTypes.BELL || ControlType == CABViewControlTypes.RESET) { ControlStyle = CABViewControlStyles.WHILE_PRESSED; } if (ControlType == CABViewControlTypes.DIRECTION && Orientation == 0) { Direction = 1 - Direction; } } // catch (Exception error) // { // if (error is STFException) // Parsing error, so pass it on // throw; // else // Unexpected error, so provide a hint // throw new STFException(stf, "Problem with NumPositions/NumValues/NumFrames/ScaleRange"); // } // End of Need check the Values collection for validity } // End of Constructor
/// <summary> /// Default constructor used during file parsing. /// </summary> /// <param name="stf">The STFreader containing the file stream</param> /// <param name="orMode">Process SignalType for ORTS mode (always set NumClearAhead_ORTS only)</param> public SignalType(STFReader stf, bool orMode) : this() { stf.MustMatchBlockStart(); Name = stf.ReadString().ToLowerInvariant(); int numClearAhead = -2; int numdefs = 0; string ortsFunctionType = string.Empty; string ortsNormalSubType = string.Empty; stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("ortsscript", () => { Script = stf.ReadStringBlock("").ToLowerInvariant(); }), new STFReader.TokenProcessor("signalfntype", () => { if (orMode) { ortsFunctionType = ReadOrtsFunctionType(stf); } else { FunctionType = ReadFunctionType(stf); } }), new STFReader.TokenProcessor("signallighttex", () => { LightTextureName = stf.ReadStringBlock("").ToLowerInvariant(); }), new STFReader.TokenProcessor("signallights", () => { Lights = ReadLights(stf); }), new STFReader.TokenProcessor("signaldrawstates", () => { DrawStates = ReadDrawStates(stf); }), new STFReader.TokenProcessor("signalaspects", () => { Aspects = ReadAspects(stf); }), new STFReader.TokenProcessor("approachcontrolsettings", () => { ApproachControlDetails = ReadApproachControlDetails(stf); }), new STFReader.TokenProcessor("signalnumclearahead", () => { numClearAhead = numClearAhead >= -1 ? numClearAhead : stf.ReadIntBlock(null); numdefs++; }), new STFReader.TokenProcessor("semaphoreinfo", () => { SemaphoreInfo = stf.ReadFloatBlock(STFReader.Units.None, null); }), new STFReader.TokenProcessor("ortsdayglow", () => { DayGlow = stf.ReadFloatBlock(STFReader.Units.None, null); }), new STFReader.TokenProcessor("ortsnightglow", () => { NightGlow = stf.ReadFloatBlock(STFReader.Units.None, null); }), new STFReader.TokenProcessor("ortsdaylight", () => { DayLight = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("ortsnormalsubtype", () => { ortsNormalSubType = ReadOrtsNormalSubType(stf); }), new STFReader.TokenProcessor("ortsonofftime", () => { TransitionTime = stf.ReadFloatBlock(STFReader.Units.None, null); }), new STFReader.TokenProcessor("sigflashduration", () => { stf.MustMatchBlockStart(); FlashTimeOn = stf.ReadFloat(STFReader.Units.None, null); FlashTimeOff = stf.ReadFloat(STFReader.Units.None, null); stf.SkipRestOfBlock(); }), new STFReader.TokenProcessor("signalflags", () => { stf.MustMatchBlockStart(); while (!stf.EndOfBlock()) { switch (stf.ReadString().ToLower()) { case "abs": Abs = true; break; case "no_gantry": NoGantry = true; break; case "semaphore": Semaphore = true; break; default: stf.StepBackOneItem(); STFException.TraceInformation(stf, "Skipped unknown SignalType flag " + stf.ReadString()); break; } } }), }); if (orMode) { // set related MSTS function type OrtsFunctionTypeIndex = OrSignalTypes.Instance.FunctionTypes.FindIndex(i => StringComparer.OrdinalIgnoreCase.Equals(i, ortsFunctionType)); if (!EnumExtension.GetValue(ortsFunctionType, out SignalFunction functionType)) { FunctionType = SignalFunction.Info; } else { FunctionType = functionType; } // set index for Normal Subtype OrtsNormalSubTypeIndex = OrSignalTypes.Instance.NormalSubTypes.FindIndex(i => StringComparer.OrdinalIgnoreCase.Equals(i, ortsNormalSubType)); // set SNCA NumClearAhead_MSTS = -2; NumClearAhead_ORTS = numClearAhead; } else { // set defaulted OR function type OrtsFunctionTypeIndex = (int)FunctionType; // set SNCA NumClearAhead_MSTS = numdefs == 1 ? numClearAhead : -2; NumClearAhead_ORTS = numdefs == 2 ? numClearAhead : -2; } }
private protected void ParseDisabledIfCabPowerSupplyOff(STFReader stf) { DisabledIfCabPowerSupplyOff = stf.ReadBoolBlock(false); }
internal override void Update(STFReader stf) { stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("eventtypelocation", () => { stf.MustMatchBlockStart(); stf.MustMatchBlockEnd(); }), new STFReader.TokenProcessor("id", () => { ID = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("ortstriggeringtrain", () => { ParseTrain(stf); }), new STFReader.TokenProcessor("activation_level", () => { ActivationLevel = stf.ReadIntBlock(null); }), new STFReader.TokenProcessor("outcomes", () => { if (Outcomes == null) { Outcomes = new Outcomes(stf); } else { Outcomes.Update(stf); } }), new STFReader.TokenProcessor("name", () => { Name = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("texttodisplayoncompletioniftriggered", () => { TextToDisplayOnCompletionIfTriggered = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("texttodisplayoncompletionifnottriggered", () => { TextToDisplayOnCompletionIfNotTriggered = stf.ReadStringBlock(null); }), new STFReader.TokenProcessor("triggeronstop", () => { TriggerOnStop = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("location", () => { stf.MustMatchBlockStart(); location = new WorldLocation(stf.ReadInt(null), stf.ReadInt(null), stf.ReadFloat(STFReader.Units.None, null), 0f, stf.ReadFloat(STFReader.Units.None, null)); RadiusM = stf.ReadFloat(STFReader.Units.Distance, null); stf.MustMatchBlockEnd(); }), new STFReader.TokenProcessor("ortscontinue", () => { OrtsContinue = stf.ReadIntBlock(0); }), new STFReader.TokenProcessor("ortsactsoundfile", () => OrtsActivitySoundProcessor(stf)), new STFReader.TokenProcessor("ortsweatherchange", () => { WeatherChange = new OrtsWeatherChange(stf); }), }); }
public CarSpawnerBlock(STFReader stf, string shapePath, List <CarSpawnerList> carSpawnerLists, string listName) { var spawnerDataItems = new List <CarSpawnerItemData>(); { var count = stf.ReadInt(null); stf.ParseBlock(new STFReader.TokenProcessor[] { new STFReader.TokenProcessor("ignorexrotation", () => { IgnoreXRotation = stf.ReadBoolBlock(true); }), new STFReader.TokenProcessor("carspawneritem", () => { if (--count < 0) { STFException.TraceWarning(stf, "Skipped extra CarSpawnerItem"); } else { var dataItem = new CarSpawnerItemData(stf, shapePath); if (File.Exists(dataItem.name)) { spawnerDataItems.Add(dataItem); } else { STFException.TraceWarning(stf, String.Format("Non-existent shape file {0} referenced", dataItem.name)); } } }), }); if (count > 0) { STFException.TraceWarning(stf, count + " missing CarSpawnerItem(s)"); } } CarSpawnerList carSpawnerList = new CarSpawnerList(spawnerDataItems, listName, IgnoreXRotation); carSpawnerLists.Add(carSpawnerList); }