public void CompareWithNullArguments()
        {
            ISortDefinition definition = new MutableSortDefinition("Nails", false, true);

            Funk one = new Funk(1, "long");
            PropertyComparator cmp = new PropertyComparator(definition);

            Assert.AreEqual(0, cmp.Compare(null, null));
            // nulls are always last (i.e. greater than)
            Assert.AreEqual(1, cmp.Compare(null, one));
            // any non-null instance comes before null (i.e. less than).
            Assert.AreEqual(-1, cmp.Compare(one, null));
        }
Пример #2
0
        /// <summary>
        /// записывает данные функции в файла на промежутке от a до b с шагом h
        /// </summary>
        /// <param name="fileName">Имя файла</param>
        /// <param name="F">Ф-ция</param>
        /// <param name="a">нижняя граница промежутка</param>
        /// <param name="b">верхняя граница промежутка</param>
        /// <param name="h">шаг</param>
        static void SaveFunc(string fileName, Funk F, double a, double b, double h)
        {
            FileStream   fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
            BinaryWriter bw = new BinaryWriter(fs);
            double       x  = a;

            while (x <= b)
            {
                bw.Write(F(x));
                x += h;
            }
            bw.Close();
            fs.Close();
        }
Пример #3
0
        /// <summary>
        /// Меню выбора функции к заданию 2
        /// </summary>
        static void Menu()
        {
            int    ans;
            double a, b, h, min;
            string filename = "data.txt";

            Console.WriteLine("Выберите ф-цию для нахождения минимума(введите номер): \n1)х^2\n2)sin(x)\n3)x^3\n4)2x-x^4");
            do
            {
                Console.WriteLine("Введите номер от 1 до 4");
                ans = My_methods.GetValueInt("Введите номер числом");
            } while (ans > 4 || ans < 1);
            GetParam(out a, out b, out h);
            Funk[] f = new Funk[4];
            f[0] = delegate(double x) { return(x * x); };
            f[1] = delegate(double x) { return(Math.Sin(x)); };
            f[2] = delegate(double x) { return(x * x * x); };
            f[3] = delegate(double x) { return(2 * x - x * x * x * x); };

            switch (ans)
            {
            case 1:
                SaveFunc(filename, f[0], a, b, h);
                break;

            case 2:
                SaveFunc(filename, f[1], a, b, h);
                break;

            case 3:
                SaveFunc(filename, f[2], a, b, h);
                break;

            case 4:
                SaveFunc(filename, f[3], a, b, h);
                break;
            }
            ArrayList list = new ArrayList();

            list = Load(filename, out min);
            foreach (var v in list)
            {
                Console.WriteLine(v);
            }
            Console.WriteLine("Минимальное значение: " + min);
        }
Пример #4
0
        /// <summary>
        /// Creates an eventhandler for the specified event info
        /// </summary>
        /// <param name="delegateType">the event information for the subscribed event</param>
        /// <returns>a delegate that raises a generic event providing all required information used to distribute the event to clients</returns>
        public Delegate CreateDelegate(Type delegateType)
        {
            Funk       d      = Invoke;
            Type       method = delegateType;
            MethodInfo minf   = method.GetMethod("Invoke");

            ParameterInfo[] methodParameters = minf.GetParameters();
            List <string>   names            = new List <string>();
            int             a = 0;

            ParameterExpression[] parameters =
                methodParameters.Select(n => Expression.Parameter(n.ParameterType, string.Format("arg{0}", a++)))
                .ToArray();
            names.AddRange(parameters.Select(n => n.Name));
            NewArrayExpression array = Expression.NewArrayInit(typeof(object), parameters.Select(n => Expression.Convert(n, typeof(object))));
            List <Expression>  xps   = new List <Expression>();
            var callExp = Expression.Call(Expression.Constant(d), d.GetType().GetMethod("Invoke"), array);

            //xps.Add(lambda);
            if (minf.ReturnType == typeof(void))
            {
                xps.Add(callExp);
                xps.Add(Expression.Empty());
            }
            else
            {
                xps.Add(Expression.Convert(callExp, minf.ReturnType));
            }

            BlockExpression  block  = Expression.Block(xps);
            LambdaExpression lambda =
                Expression.Lambda(block, parameters);
            Delegate tmp = lambda.Compile();

            return(Delegate.CreateDelegate(method, tmp, "Invoke", false));
        }
        public void CompareWithNullArguments()
        {
            ISortDefinition definition = new MutableSortDefinition("Nails", false, true);

            Funk one = new Funk(1, "long");
            PropertyComparator cmp = new PropertyComparator(definition);
            Assert.AreEqual(0, cmp.Compare(null, null));
            // nulls are always last (i.e. greater than)
            Assert.AreEqual(1, cmp.Compare(null, one));
            // any non-null instance comes before null (i.e. less than).
            Assert.AreEqual(-1, cmp.Compare(one, null));
        }
Пример #6
0
        public void Save(string path)
        {
            using (DocumentWriter dw = new DocumentWriter(path))
            {
                dw.WriteLine($"VERSION {Version}");
                dw.WriteLine("//	Version 1 :		New crush data");
                if (Version > 1)
                {
                    dw.WriteLine("//		2 :		New windscreen spec");
                }
                dw.WriteLine($"{(FemaleDriver ? "GIRL" : "")}");
                dw.WriteLine($"{Name}", "Name of car");

                dw.WriteLine();

                dw.WriteLine($"{SoftnessFactor}", "softness_factor");

                dw.WriteLine();

                dw.WriteLine("START OF DRIVABLE STUFF");
                dw.WriteLine();
                dw.WriteLine($"{DriversHeadOffset.X},{DriversHeadOffset.Y},{DriversHeadOffset.Z}", "Offset of driver's head in 3D space");
                dw.WriteLine($"{DriversHeadTurnAngles.X},{DriversHeadTurnAngles.Y}", "Angles to turn to make head go left and right");
                dw.WriteLine($"{MirrorCamera.X},{MirrorCamera.Y},{MirrorCamera.Z},{MirrorCamera.W}", "Offset of 'mirror camera' in 3D space, viewing angle of mirror");
                dw.WriteLine($"{string.Join(",", PratcamBorders)}", "Pratcam border names (left, top, right, bottom)");
                dw.WriteLine();
                dw.WriteLine("END OF DRIVABLE STUFF");

                dw.WriteLine();

                dw.WriteLine($"{string.Join(",",EngineNoises)}", "Engine noise (normal, enclosed space, underwater)");

                dw.WriteLine();

                dw.WriteLine($"{(Stealworthy ? "stealworthy" : "")}", "Can be stolen");

                dw.WriteLine();

                foreach (ImpactSpec impactSpec in new List <ImpactSpec> {
                    ImpactTop, ImpactBottom, ImpactLeft, ImpactRight, ImpactFront, ImpactBack
                })
                {
                    dw.WriteLine($"// Damage info for {impactSpec.Description} impacts");
                    dw.WriteLine($"{impactSpec.Clauses.Count}", "Number of clauses");
                    dw.IncreaseIndent();
                    foreach (ImpactSpecClause clause in impactSpec.Clauses)
                    {
                        dw.WriteLine($"{clause.Clause}", "Condition");
                        dw.WriteLine($"{clause.Systems.Count}", "Systems count");

                        dw.IncreaseIndent();
                        foreach (ImpactSpecClauseSystem system in clause.Systems)
                        {
                            dw.WriteLine($"{system.Part},{system.Damage:F1}", "Damage");
                        }
                        dw.DecreaseIndent();
                    }
                    dw.DecreaseIndent();
                }

                dw.WriteLine();

                dw.WriteLine($"{string.Join(",", GridImages)}", "Grid image (opponent, frank, annie)");

                dw.WriteLine();

                dw.WriteLine($"{ExtraLevelsOfDetail.Count}", "Number of extra levels of detail");
                foreach (int extraLevelOfDetail in ExtraLevelsOfDetail)
                {
                    dw.WriteLine($"{extraLevelOfDetail}", "min_dist_squared");
                }

                dw.WriteLine();

                dw.WriteLine($"{WAM}", "crush data file (will be incorporated into this file)");

                dw.WriteLine();

                dw.WriteLine($"{ReflectiveScreenMaterial}", "Name of reflective screen material (or none if non-reflective)");
                dw.WriteLine($"{TransparencyOfWindscreen}", "Percentage transparency of windscreen");

                dw.WriteLine();

                dw.WriteLine($"{SteerableWheels.Count}", "Number of steerable wheels");
                foreach (int steerableWheel in SteerableWheels)
                {
                    dw.WriteLine($"{steerableWheel}", "GroovyFunkRef of nth steerable wheel");
                }

                dw.WriteLine();

                dw.WriteLine($"{string.Join(",", LeftFrontSuspension)}", "Left-front suspension parts GroovyFunkRef");
                dw.WriteLine($"{string.Join(",", RightFrontSuspension)}", "Right-front suspension parts GroovyFunkRef");
                dw.WriteLine($"{string.Join(",", LeftRearSuspension)}", "Left-rear suspension parts GroovyFunkRef");
                dw.WriteLine($"{string.Join(",", RightRearSuspension)}", "Right-rear suspension parts GroovyFunkRef");

                dw.WriteLine();

                dw.WriteLine($"{string.Join(",", DrivenWheels)}", "Driven wheels GroovyFunkRefs (for spinning) - MUST BE 4 ITEMS");
                dw.WriteLine($"{string.Join(",", NonDrivenWheels)}", "Non-driven wheels GroovyFunkRefs (for spinning) - MUST BE 4 ITEMS");

                dw.WriteLine();

                dw.WriteLine($"{DrivenWheelDiameter}", "Driven wheels diameter");
                dw.WriteLine($"{NonDrivenWheelDiameter}", "Non-driven wheels diameter");

                dw.WriteLine();
                dw.WriteLine("START OF FUNK");
                dw.WriteLine();

                for (int i = 0; i < Funks.Count; i++)
                {
                    Funk funk = Funks[i];

                    dw.WriteLine($"{funk.Material}");
                    dw.WriteLine($"{funk.Mode}");
                    dw.WriteLine($"{funk.MatrixModType}");
                    if (funk.MatrixModType != FunkMatrixMode.None)
                    {
                        dw.WriteLine($"{funk.MatrixModMode}");
                    }

                    switch (funk.MatrixModType)
                    {
                    case FunkMatrixMode.roll:
                        dw.WriteLine($"{funk.RollPeriods.X},{funk.RollPeriods.Y}");
                        break;

                    case FunkMatrixMode.slither:
                        dw.WriteLine($"{funk.SlitherSpeed.X},{funk.SlitherSpeed.Y}");
                        dw.WriteLine($"{funk.SlitherAmount.X},{funk.SlitherAmount.Y}");
                        break;

                    case FunkMatrixMode.spin:
                        dw.WriteLine($"{funk.SpinPeriod}");
                        break;
                    }

                    dw.WriteLine($"{funk.LightingMode}");
                    dw.WriteLine($"{funk.AnimationType}");

                    switch (funk.AnimationType)
                    {
                    case FunkAnimationType.frames:
                        dw.WriteLine($"{funk.Framerate}");
                        dw.WriteLine($"{funk.FrameMode}");

                        switch (funk.FrameMode)
                        {
                        case FrameType.texturebits:
                            dw.WriteLine($"{funk.TextureBitMode}");
                            break;

                        case FrameType.continuous:
                            dw.WriteLine($"{funk.FrameSpeed}");
                            break;
                        }

                        dw.WriteLine($"{funk.Frames.Count}");
                        foreach (string frame in funk.Frames)
                        {
                            dw.WriteLine($"{frame}");
                        }
                        break;
                    }

                    if (i + 1 != Funks.Count)
                    {
                        dw.WriteLine();
                        dw.WriteLine("NEXT FUNK");
                        dw.WriteLine();
                    }
                }

                dw.WriteLine();
                dw.WriteLine("END OF FUNK");
                dw.WriteLine();

                dw.WriteLine();
                dw.WriteLine("START OF GROOVE");
                dw.WriteLine();

                for (int i = 0; i < Grooves.Count; i++)
                {
                    Groove groove = Grooves[i];

                    dw.WriteLine($"{groove.Part}");
                    dw.WriteLine($"{groove.LollipopMode}");
                    dw.WriteLine($"{groove.Mode}");
                    dw.WriteLine($"{groove.PathType}");
                    if (groove.PathType != GroovePathNames.None)
                    {
                        dw.WriteLine($"{groove.PathMode}");
                    }

                    switch (groove.PathType)
                    {
                    case GroovePathNames.straight:
                        dw.WriteLine($"{groove.PathCentre.X},{groove.PathCentre.Y},{groove.PathCentre.Z}");
                        dw.WriteLine($"{groove.PathPeriod}");
                        dw.WriteLine($"{groove.PathDelta.X},{groove.PathDelta.Y},{groove.PathDelta.Z}");
                        break;
                    }

                    dw.WriteLine($"{groove.AnimationType}");
                    if (groove.AnimationType != GrooveAnimation.None)
                    {
                        dw.WriteLine($"{groove.AnimationMode}");
                    }

                    switch (groove.AnimationType)
                    {
                    case GrooveAnimation.rock:
                        dw.WriteLine($"{groove.AnimationPeriod}");
                        dw.WriteLine($"{groove.AnimationCentre.X},{groove.AnimationCentre.Y},{groove.AnimationCentre.Z}");
                        dw.WriteLine($"{groove.AnimationAxis}");
                        dw.WriteLine($"{groove.RockMaxAngle}");
                        break;

                    case GrooveAnimation.shear:
                        dw.WriteLine($"{groove.ShearPeriod.X},{groove.ShearPeriod.Y},{groove.ShearPeriod.Z}");
                        dw.WriteLine($"{groove.AnimationCentre.X},{groove.AnimationCentre.Y},{groove.AnimationCentre.Z}");
                        dw.WriteLine($"{groove.ShearMagnitude.X},{groove.ShearMagnitude.Y},{groove.ShearMagnitude.Z}");
                        break;

                    case GrooveAnimation.spin:
                        dw.WriteLine($"{groove.AnimationPeriod}");
                        dw.WriteLine($"{groove.AnimationCentre.X},{groove.AnimationCentre.Y},{groove.AnimationCentre.Z}");
                        dw.WriteLine($"{groove.AnimationAxis}");
                        break;
                    }

                    if (i + 1 != Grooves.Count)
                    {
                        dw.WriteLine();
                        dw.WriteLine("NEXT GROOVE");
                        dw.WriteLine();
                    }
                }

                dw.WriteLine();
                dw.WriteLine("END OF GROOVE");
                dw.WriteLine();

                dw.WriteLine("// END OF CRUSH DATA");

                dw.WriteLine();
                dw.WriteLine("START OF MECHANICS STUFF version 1");
                dw.WriteLine();

                dw.WriteLine($"{MinimumTurningCircle:F6}", "Minimum turning circle.");
                dw.WriteLine($"{BrakeMultiplier:F6}", "Brake multiplier.");
                dw.WriteLine($"{BrakingStrengthMultiplier:F6}", "Braking strength multiplier.");
                dw.WriteLine($"{NumberOfGears}", "Number of gears.");
                dw.WriteLine($"{TopGearRedlineSpeed:F4}", "Speed at red line in highest gear.");
                dw.WriteLine($"{TopGearAcceleration:F6}", "Acceleration in highest gear (m/s^2) i.e. engine strength.");

                dw.WriteLine();

                dw.WriteLine("// Sub member: Root part");
                dw.WriteLine($"{RootPartType}", "Type");
                dw.WriteLine($"{RootPartIdentifier}", "Identifier");
                dw.WriteLine($"{RootPartActor}", "Actor");
                dw.WriteLine("// Sub member: Joint data");
                dw.WriteLine($"{SubPartType}", "Type");
                dw.WriteLine($"{CentreOfMass.X:F6},{CentreOfMass.Y:F6},{CentreOfMass.Z:F6}", "Centre of mass");
                dw.WriteLine($"{Mass}", "Mass");
                dw.WriteLine($"{AngularMomentumProportions.X:F6},{AngularMomentumProportions.Y:F6},{AngularMomentumProportions.Z:F6}", "Angular momentum proportions");
                dw.WriteLine($"{DownforceToWeightBalanceSpeed:F6}", "Downforce-to-weight balance speed");
                dw.WriteLine($"{Wheels.Count}", "Number of 'Wheels' entries.");

                for (int i = 0; i < Wheels.Count; i++)
                {
                    Wheel wheel = Wheels[i];

                    dw.WriteLine($"// Wheels entry #{i + 1}");
                    dw.WriteLine($"{(int)wheel.Type}", "Type");
                    dw.WriteLine($"{wheel.Identifier}", "Identifier");
                    dw.WriteLine($"{wheel.Actor}", "Actor");
                    dw.WriteLine($"{wheel.Position.X},{wheel.Position.Y},{wheel.Position.Z}", "Position");
                    dw.WriteLine($"{wheel.SteerableFlags}", "Steerable flags");
                    dw.WriteLine($"{wheel.DrivenFlags}", "Driven flags");
                    dw.WriteLine($"{wheel.SuspensionGive:F6}", "Suspension give");
                    dw.WriteLine($"{wheel.DampingFactor:F6}", "Damping factor");
                    dw.WriteLine($"{wheel.SlipFrictionReductionFraction:F6}", "Fractional reduction in friction when slipping");
                    dw.WriteLine($"{wheel.FrictionAngles.X:F6},{wheel.FrictionAngles.Y:F6}", "Friction angles");
                    dw.WriteLine($"{wheel.TractionFractionalMultiplier:F6}", "Traction fractional multiplier");
                    dw.WriteLine($"{wheel.RollingResistance:F6}", "Rolling resistance");
                }

                dw.WriteLine();

                dw.WriteLine($"{BoundingShapes.Count}", "Number of 'Bounding shapes' entries.");

                for (int i = 0; i < BoundingShapes.Count; i++)
                {
                    BoundingShape shape = BoundingShapes[i];

                    dw.WriteLine($"// Bounding shapes entry #{i + 1}");
                    dw.WriteLine($"{shape.Type}", "Type");
                    dw.WriteLine($"{shape.Points.Count}");
                    foreach (Vector3 point in shape.Points)
                    {
                        dw.WriteLine($"{point.X:F2},{point.Y:F2},{point.Z:F2}");
                    }
                }

                dw.WriteLine();
                dw.WriteLine($"{SubParts.Count}", "Number of sub-parts.");
                dw.WriteLine();

                dw.WriteLine();
                dw.WriteLine("END OF MECHANICS STUFF");
                dw.WriteLine();

                dw.WriteLine("// Materials for shrapnel");
                dw.WriteLine($"{Shrapnel.Count}", "number of materials");
                foreach (string shrapnel in Shrapnel)
                {
                    dw.WriteLine($"{shrapnel}");
                }

                dw.WriteLine();

                dw.WriteLine("//damage vertices fire points");
                foreach (int point in FirePoints)
                {
                    dw.WriteLine($"{point}");
                }

                dw.WriteLine();

                dw.WriteLine("// start of keyword stuff");
                foreach (Keyword keyword in Keywords)
                {
                    keyword.Write(dw);
                }

                dw.WriteLine("// End of keyword stuff");
                dw.WriteLine("END");
            }
        }
Пример #7
0
        public static Car Load(string path)
        {
            DocumentParser file = new DocumentParser(path);
            Car            car  = new Car();

            string version = file.ReadLine();

            if (!version.StartsWith("VERSION"))
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Not a valid Carmageddon 2 car .txt file");
                return(null);
            }

            car.Version = version.Replace("VERSION ", "").ToInt();

            if (file.PeekLine() == "GIRL")
            {
                car.FemaleDriver = true;
                file.ReadLine();
            }

            car.Name           = file.ReadLine();
            car.SoftnessFactor = file.ReadSingle();

            if (file.ReadLine() != "START OF DRIVABLE STUFF")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Car.TXT file?", "START OF DRIVABLE STUFF");
                return(null);
            }

            car.DriversHeadOffset     = file.ReadVector3();
            car.DriversHeadTurnAngles = file.ReadVector2();
            car.MirrorCamera          = file.ReadVector4();
            car.PratcamBorders        = file.ReadStrings();

            if (file.ReadLine() != "END OF DRIVABLE STUFF")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Car.TXT file?", "END OF DRIVABLE STUFF");
                return(null);
            }

            car.EngineNoises = file.ReadInts();
            car.Stealworthy  = file.ReadLine().ToLower() == "stealworthy";

            car.ImpactTop    = ImpactSpec.Load("top", file);
            car.ImpactBottom = ImpactSpec.Load("bottom", file);
            car.ImpactLeft   = ImpactSpec.Load("left", file);
            car.ImpactRight  = ImpactSpec.Load("right", file);
            car.ImpactFront  = ImpactSpec.Load("front", file);
            car.ImpactBack   = ImpactSpec.Load("rear", file);

            car.GridImages = file.ReadStrings();

            int extraLevelsOfDetail = file.ReadInt();

            for (int j = 0; j < extraLevelsOfDetail; j++)
            {
                car.ExtraLevelsOfDetail.Add(file.ReadInt());
            }

            car.WAM = file.ReadLine();

            car.ReflectiveScreenMaterial = file.ReadLine();
            car.TransparencyOfWindscreen = file.ReadSingle();

            int steerableWheelsCount = file.ReadInt();

            for (int j = 0; j < steerableWheelsCount; j++)
            {
                car.SteerableWheels.Add(file.ReadInt());
            }

            car.LeftFrontSuspension  = file.ReadInts();
            car.RightFrontSuspension = file.ReadInts();
            car.LeftRearSuspension   = file.ReadInts();
            car.RightRearSuspension  = file.ReadInts();
            car.DrivenWheels         = file.ReadInts();
            car.NonDrivenWheels      = file.ReadInts();

            car.DrivenWheelDiameter    = file.ReadSingle();
            car.NonDrivenWheelDiameter = file.ReadSingle();

            if (file.ReadLine() != "START OF FUNK")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Car.TXT file?", "START OF FUNK");
                return(null);
            }

            while (file.PeekLine() != "END OF FUNK")
            {
                car.Funks.Add(Funk.Load(file));
                if (file.PeekLine() == "NEXT FUNK")
                {
                    file.ReadLine();
                }
            }
            file.ReadLine();

            if (file.ReadLine() != "START OF GROOVE")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Car.TXT file?", "START OF GROOVE");
                return(null);
            }

            while (file.PeekLine() != "END OF GROOVE")
            {
                car.Grooves.Add(Groove.Load(file));
                if (file.PeekLine() == "NEXT GROOVE")
                {
                    file.ReadLine();
                }
            }
            file.ReadLine();

            int _ = file.ReadLine().Replace("START OF MECHANICS STUFF version ", "", StringComparison.InvariantCultureIgnoreCase).ToInt();

            car.MinimumTurningCircle      = file.ReadSingle();
            car.BrakeMultiplier           = file.ReadSingle();
            car.BrakingStrengthMultiplier = file.ReadSingle();
            car.NumberOfGears             = file.ReadSingle();
            car.TopGearRedlineSpeed       = file.ReadSingle();
            car.TopGearAcceleration       = file.ReadSingle();

            car.RootPartType       = file.ReadEnum <PartType>();
            car.RootPartIdentifier = file.ReadLine();
            car.RootPartActor      = file.ReadLine();

            car.SubPartType = file.ReadEnum <PartType>();

            car.CentreOfMass = file.ReadVector3();
            car.Mass         = file.ReadSingle();
            car.AngularMomentumProportions    = file.ReadVector3();
            car.DownforceToWeightBalanceSpeed = file.ReadSingle();

            int numberOfWheels = file.ReadInt();

            for (int j = 0; j < numberOfWheels; j++)
            {
                Wheel wheel = new Wheel
                {
                    Type           = file.ReadEnum <Wheel.WheelType>(),
                    Identifier     = file.ReadLine(),
                    Actor          = file.ReadLine(),
                    Position       = file.ReadVector3(),
                    SteerableFlags = file.ReadInt(),
                    DrivenFlags    = file.ReadInt(),
                    SuspensionGive = file.ReadSingle(),
                    DampingFactor  = file.ReadSingle(),
                    SlipFrictionReductionFraction = file.ReadSingle(),
                    FrictionAngles = file.ReadVector2(),
                    TractionFractionalMultiplier = file.ReadSingle(),
                    RollingResistance            = file.ReadSingle()
                };

                car.Wheels.Add(wheel);
            }

            int boundingShapes = file.ReadInt();

            for (int j = 0; j < boundingShapes; j++)
            {
                BoundingShape shape = new BoundingShape
                {
                    Type = file.ReadEnum <BoundingShape.BoundingShapeType>()
                };

                int shapePoints = file.ReadInt();

                for (int k = 0; k < shapePoints; k++)
                {
                    shape.Points.Add(file.ReadVector3());
                }

                car.BoundingShapes.Add(shape);
            }

            int subParts = file.ReadInt();

            for (int j = 0; j < subParts; j++)
            {
                throw new NotImplementedException("subparts?!");
            }

            if (file.ReadLine() != "END OF MECHANICS STUFF")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Car.TXT file?", "END OF MECHANICS STUFF");
                return(null);
            }

            int shrapnelCount = file.ReadInt();

            for (int i = 0; i < shrapnelCount; i++)
            {
                car.Shrapnel.Add(file.ReadLine());
            }

            for (int i = 0; i < 12; i++)
            {
                car.FirePoints.Add(file.ReadInt());
            }

            while (file.PeekLine() != "END")
            {
                string keyWord = file.ReadLine();

                switch (keyWord)
                {
                case "CAMERA_POSITIONS":
                    car.Keywords.Add(new CameraPosition
                    {
                        BumperPosition  = file.ReadVector3(),
                        CockpitPosition = file.ReadVector3()
                    });
                    break;

                case "CAMERA_TURN_OFF_MATERIALS":
                {
                    CameraTurnOffMaterials ctom = new CameraTurnOffMaterials();

                    int materialCount = file.ReadInt();

                    for (int i = 0; i < materialCount; i++)
                    {
                        CameraTurnOffMaterialEntry ctomEntry = new CameraTurnOffMaterialEntry
                        {
                            MaterialName = file.ReadLine()
                        };

                        int entryCount = file.ReadInt();

                        for (int j = 0; j < entryCount; j++)
                        {
                            ctomEntry.Materials.Add(file.ReadLine());
                        }

                        ctom.Entries.Add(ctomEntry);
                    }

                    car.Keywords.Add(ctom);
                }
                break;

                default:
                    throw new NotImplementedException($"{keyWord} not supported!");
                }
            }

            return(car);
        }
Пример #8
0
        public void Save(string path)
        {
            using (DocumentWriter dw = new DocumentWriter(path))
            {
                dw.WriteLine($"{Name}", "Name of car");

                dw.WriteLine();

                dw.WriteLine("START OF DRIVABLE STUFF");
                dw.WriteLine($"{DriversHeadOffset.X},{DriversHeadOffset.Y},{DriversHeadOffset.Z}", "Offset of driver's head in 3D space");
                dw.WriteLine($"{DriversHeadTurnAngles.X},{DriversHeadTurnAngles.Y}", "Angles to turn to make head go left and right");
                dw.WriteLine($"{MirrorCamera.X},{MirrorCamera.Y},{MirrorCamera.Z},{MirrorCamera.W}", "Offset of 'mirror camera' in 3D space, viewing angle of mirror");
                dw.WriteLine($"{string.Join(",", PratcamBorders)}", "Pratcam border names (left, top, right, bottom)");
                dw.WriteLine("END OF DRIVABLE STUFF");

                dw.WriteLine();

                dw.WriteLine($"{string.Join(",", EngineNoises)}", "Engine noise (normal, enclosed space, underwater)");
                dw.WriteLine($"{(Stealworthy ? "stealworthy" : "")}", "Can be stolen");

                dw.WriteLine();

                foreach (ImpactSpec impactSpec in new List <ImpactSpec> {
                    ImpactTop, ImpactBottom, ImpactLeft, ImpactRight, ImpactFront, ImpactBack
                })
                {
                    dw.WriteLine($"// Damage info for {impactSpec.Description} impacts");
                    dw.WriteLine($"{impactSpec.Clauses.Count}", "Number of clauses");

                    foreach (ImpactSpecClause clause in impactSpec.Clauses)
                    {
                        dw.WriteLine($"{clause.Clause}", "Condition");
                        dw.WriteLine($"{clause.Systems.Count}", "Systems count");

                        foreach (ImpactSpecClauseSystem system in clause.Systems)
                        {
                            dw.WriteLine($"{system.Part},{system.Damage:F1}", "Damage");
                        }
                    }
                }

                dw.WriteLine();

                dw.WriteLine($"{string.Join(",", GridImages)}", "Grid image (opponent, frank, annie)");

                dw.WriteLine();

                dw.WriteLine($"{PixelmapsLoMem.Count}", "Number of pixelmap files for this car");
                foreach (string pixelmap in PixelmapsLoMem)
                {
                    dw.WriteLine($"{pixelmap}");
                }
                dw.WriteLine($"{PixelmapsLoRes.Count}", "Number of pixelmap files for this car");
                foreach (string pixelmap in PixelmapsLoRes)
                {
                    dw.WriteLine($"{pixelmap}");
                }
                dw.WriteLine($"{PixelmapsHiRes.Count}", "Number of pixelmap files for this car");
                foreach (string pixelmap in PixelmapsHiRes)
                {
                    dw.WriteLine($"{pixelmap}");
                }

                dw.WriteLine($"{ShadeTables.Count}", "Number of shadetable files for this car");
                foreach (string shadetable in ShadeTables)
                {
                    dw.WriteLine($"{shadetable}");
                }

                dw.WriteLine($"{MaterialsLoMem.Count}", "Number of material files for this car");
                foreach (string material in MaterialsLoMem)
                {
                    dw.WriteLine($"{material}");
                }
                dw.WriteLine($"{MaterialsLoRes.Count}", "Number of material files for this car");
                foreach (string material in MaterialsLoRes)
                {
                    dw.WriteLine($"{material}");
                }
                dw.WriteLine($"{MaterialsHiRes.Count}", "Number of material files for this car");
                foreach (string material in MaterialsHiRes)
                {
                    dw.WriteLine($"{material}");
                }

                dw.WriteLine($"{Models.Count}", "Number of model files for this car");
                foreach (string model in Models)
                {
                    dw.WriteLine($"{model}");
                }

                dw.WriteLine($"{Actors.Count}", "Number of alternative actors");
                for (int i = 0; i < Actors.Count; i++)
                {
                    dw.WriteLine($"{ActorLODs[i]},{Actors[i]}", "Minimum distance away, actor name");
                }

                dw.WriteLine();

                dw.WriteLine($"{ReflectiveScreenMaterial}", "Name of reflective screen material (or none if non-reflective)");

                dw.WriteLine();

                dw.WriteLine($"{SteerableWheels.Count}", "Number of steerable wheels");
                foreach (int steerableWheel in SteerableWheels)
                {
                    dw.WriteLine($"{steerableWheel}", "GroovyFunkRef of nth steerable wheel");
                }

                dw.WriteLine();

                dw.WriteLine($"{string.Join(",", LeftFrontSuspension)}", "Left-front suspension parts GroovyFunkRef");
                dw.WriteLine($"{string.Join(",", RightFrontSuspension)}", "Right-front suspension parts GroovyFunkRef");
                dw.WriteLine($"{string.Join(",", LeftRearSuspension)}", "Left-rear suspension parts GroovyFunkRef");
                dw.WriteLine($"{string.Join(",", RightRearSuspension)}", "Right-rear suspension parts GroovyFunkRef");

                dw.WriteLine();

                dw.WriteLine($"{string.Join(",", DrivenWheels)}", "Driven wheels GroovyFunkRefs (for spinning) - MUST BE 4 ITEMS");
                dw.WriteLine($"{string.Join(",", NonDrivenWheels)}", "Non-driven wheels GroovyFunkRefs (for spinning) - MUST BE 4 ITEMS");

                dw.WriteLine();

                dw.WriteLine($"{DrivenWheelDiameter}", "Driven wheels diameter");
                dw.WriteLine($"{NonDrivenWheelDiameter}", "Non-driven wheels diameter");

                dw.WriteLine();

                dw.WriteLine("START OF FUNK");

                for (int i = 0; i < Funks.Count; i++)
                {
                    Funk funk = Funks[i];

                    dw.WriteLine($"{funk.Material}");
                    dw.WriteLine($"{funk.Mode}");
                    dw.WriteLine($"{funk.MatrixModType}");
                    if (funk.MatrixModType != FunkMatrixMode.None)
                    {
                        dw.WriteLine($"{funk.MatrixModMode}");
                    }

                    switch (funk.MatrixModType)
                    {
                    case FunkMatrixMode.roll:
                        dw.WriteLine($"{funk.RollPeriods.X},{funk.RollPeriods.Y}");
                        break;

                    case FunkMatrixMode.slither:
                        dw.WriteLine($"{funk.SlitherSpeed.X},{funk.SlitherSpeed.Y}");
                        dw.WriteLine($"{funk.SlitherAmount.X},{funk.SlitherAmount.Y}");
                        break;

                    case FunkMatrixMode.spin:
                        dw.WriteLine($"{funk.SpinPeriod}");
                        break;
                    }

                    dw.WriteLine($"{funk.LightingMode}");
                    dw.WriteLine($"{funk.AnimationType}");

                    switch (funk.AnimationType)
                    {
                    case FunkAnimationType.frames:
                        dw.WriteLine($"{funk.Framerate}");
                        dw.WriteLine($"{funk.FrameMode}");

                        switch (funk.FrameMode)
                        {
                        case FrameType.texturebits:
                            dw.WriteLine($"{funk.TextureBitMode}");
                            break;

                        case FrameType.continuous:
                            dw.WriteLine($"{funk.FrameSpeed}");
                            break;
                        }

                        dw.WriteLine($"{funk.Frames.Count}");
                        foreach (string frame in funk.Frames)
                        {
                            dw.WriteLine($"{frame}");
                        }
                        break;
                    }

                    if (i + 1 != Funks.Count)
                    {
                        dw.WriteLine("NEXT FUNK");
                    }
                }

                dw.WriteLine("END OF FUNK");

                dw.WriteLine();

                dw.WriteLine("START OF GROOVE");

                for (int i = 0; i < Grooves.Count; i++)
                {
                    Groove groove = Grooves[i];

                    dw.WriteLine($"{groove.Part}");
                    dw.WriteLine($"{groove.LollipopMode}");
                    dw.WriteLine($"{groove.Mode}");
                    dw.WriteLine($"{groove.PathType}");
                    if (groove.PathType != GroovePathNames.None)
                    {
                        dw.WriteLine($"{groove.PathMode}");
                    }

                    switch (groove.PathType)
                    {
                    case GroovePathNames.straight:
                        dw.WriteLine($"{groove.PathCentre.X},{groove.PathCentre.Y},{groove.PathCentre.Z}");
                        dw.WriteLine($"{groove.PathPeriod}");
                        dw.WriteLine($"{groove.PathDelta.X},{groove.PathDelta.Y},{groove.PathDelta.Z}");
                        break;
                    }

                    dw.WriteLine($"{groove.AnimationType}");
                    if (groove.AnimationType != GrooveAnimation.None)
                    {
                        dw.WriteLine($"{groove.AnimationMode}");
                    }

                    switch (groove.AnimationType)
                    {
                    case GrooveAnimation.rock:
                        dw.WriteLine($"{groove.AnimationPeriod}");
                        dw.WriteLine($"{groove.AnimationCentre.X},{groove.AnimationCentre.Y},{groove.AnimationCentre.Z}");
                        dw.WriteLine($"{groove.AnimationAxis}");
                        dw.WriteLine($"{groove.RockMaxAngle}");
                        break;

                    case GrooveAnimation.shear:
                        dw.WriteLine($"{groove.ShearPeriod.X},{groove.ShearPeriod.Y},{groove.ShearPeriod.Z}");
                        dw.WriteLine($"{groove.AnimationCentre.X},{groove.AnimationCentre.Y},{groove.AnimationCentre.Z}");
                        dw.WriteLine($"{groove.ShearMagnitude.X},{groove.ShearMagnitude.Y},{groove.ShearMagnitude.Z}");
                        break;

                    case GrooveAnimation.spin:
                        dw.WriteLine($"{groove.AnimationPeriod}");
                        dw.WriteLine($"{groove.AnimationCentre.X},{groove.AnimationCentre.Y},{groove.AnimationCentre.Z}");
                        dw.WriteLine($"{groove.AnimationAxis}");
                        break;
                    }

                    if (i + 1 != Grooves.Count)
                    {
                        dw.WriteLine("NEXT GROOVE");
                    }
                }

                dw.WriteLine("END OF GROOVE");

                dw.WriteLine();

                for (int i = 0; i < Actors.Count; i++)
                {
                    Crushes[i].Write(dw);
                }

                dw.WriteLine();

                dw.WriteLine($"START OF MECHANICS STUFF version {MechanicsVersion}");

                dw.WriteLine($"{LRWheelPos.X:F3}, {LRWheelPos.Y:F3}, {LRWheelPos.Z:F3}", "left rear wheel position");
                dw.WriteLine($"{RRWheelPos.X:F3}, {RRWheelPos.Y:F3}, {RRWheelPos.Z:F3}", "right rear");
                dw.WriteLine($"{LFWheelPos.X:F3}, {LFWheelPos.Y:F3}, {LFWheelPos.Z:F3}", "left front wheel position");
                dw.WriteLine($"{RFWheelPos.X:F3}, {RFWheelPos.Y:F3}, {RFWheelPos.Z:F3}", "right front");

                dw.WriteLine($"{CentreOfMass.X}, {CentreOfMass.Y}, {CentreOfMass.Z}", "centre of mass position");

                dw.WriteLine();

                switch (MechanicsVersion)
                {
                case 2:
                    dw.WriteLine($"{BoundingBoxes.Count}", "number of bounding boxes");
                    foreach (BoundingBox box in BoundingBoxes)
                    {
                        box.Write(dw);
                    }
                    break;

                case 3:
                case 4:
                    foreach (BoundingBox box in BoundingBoxes)
                    {
                        box.Write(dw);
                    }

                    dw.WriteLine($"{AdditionalPoints.Count}", "number of extra points  	v. 3");
                    foreach (Vector3 point in AdditionalPoints)
                    {
                        dw.WriteLine($"{point.X},{point.Y},{point.Z}");
                    }
                    break;
                }

                dw.WriteLine();

                dw.WriteLine($"{MinimumTurningCircle}", "min turning circle radius");
                dw.WriteLine($"{SuspensionGive.X:F3}, {SuspensionGive.Y:F3}", "suspension give (forward, back)");
                dw.WriteLine($"{RideHeight}", "ride height (must be more than miny in bounding box )");
                dw.WriteLine($"{DampingFactor}", "damping factor");
                dw.WriteLine($"{Mass}", "mass in tonnes");
                dw.WriteLine($"{SlipFrictionReductionFraction}", "fractional reduction in friction when slipping");
                dw.WriteLine($"{FrictionAngle.X}, {FrictionAngle.Y}{(MechanicsVersion == 4 ? $", {FrictionAngle.Z}" : null)}", "friction angle ( front and rear )");
                dw.WriteLine($"{AngularMomentumProportions.X}, {AngularMomentumProportions.Y}, {AngularMomentumProportions.Z}", "width, height, length for angular momentum calculation");
                dw.WriteLine($"{TractionFractionalMultiplier:F1}", "traction fractional multiplier v. 2");
                dw.WriteLine($"{DownforceToWeightBalanceSpeed}", "speed at which down force = weight v. 2");
                dw.WriteLine($"{BrakeMultiplier:F1}", "brake multiplier, 1 = nomral brakes v. 2");
                dw.WriteLine($"{BrakingStrengthMultiplier:F1}", "increase in brakes per second 1 = normal v. 2");
                dw.WriteLine($"{RollingResistance.X}, {RollingResistance.Y}", "rolling resistance front and back");
                dw.WriteLine($"{NumberOfGears}", "number of gears");
                dw.WriteLine($"{TopGearRedlineSpeed}", "speed at red line in highest gear");
                dw.WriteLine($"{TopGearAcceleration}", "acceleration in highest gear m/s^2 (i.e. engine strength)");

                dw.WriteLine("END OF MECHANICS STUFF");

                dw.WriteLine();

                dw.WriteLine("// Materials for shrapnel");
                dw.WriteLine($"{Shrapnel.Count}", "number of materials");
                foreach (string shrapnel in Shrapnel)
                {
                    dw.WriteLine($"{shrapnel}");
                }

                if (FirePoints.Count > 0)
                {
                    dw.WriteLine();
                    dw.WriteLine("// damage vertices fire point");
                    foreach (int firepoint in FirePoints)
                    {
                        dw.WriteLine($"{firepoint}");
                    }
                }
            }
        }
Пример #9
0
        public static Car Load(string path, bool suppressFolderCheck)
        {
            DocumentParser file = new DocumentParser(path);
            Car            car  = new Car {
                Name = file.ReadLine()
            };

            if (!suppressFolderCheck)
            {
                if (string.Compare(Path.GetFileName(path).ToUpper(), car.Name) != 0)
                {
                    Logger.LogToFile(Logger.LogLevel.Error, "Not a valid Carmageddon car .txt file, expected {0} but found {1}", Path.GetFileName(path).ToUpper(), car.Name);
                    return(null);
                }
            }

            if (file.ReadLine() != "START OF DRIVABLE STUFF")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Car.TXT file?", "START OF DRIVABLE STUFF");
                return(null);
            }

            car.DriversHeadOffset     = file.ReadVector3();
            car.DriversHeadTurnAngles = file.ReadVector2();
            car.MirrorCamera          = file.ReadVector4();
            car.PratcamBorders        = file.ReadStrings();

            if (file.ReadLine() != "END OF DRIVABLE STUFF")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Car.TXT file?", "END OF DRIVABLE STUFF");
                return(null);
            }

            car.EngineNoises = file.ReadInts();
            car.Stealworthy  = file.ReadLine().ToLower() == "stealworthy";

            car.ImpactTop    = ImpactSpec.Load("top", file);
            car.ImpactBottom = ImpactSpec.Load("bottom", file);
            car.ImpactLeft   = ImpactSpec.Load("left", file);
            car.ImpactRight  = ImpactSpec.Load("right", file);
            car.ImpactFront  = ImpactSpec.Load("front", file);
            car.ImpactBack   = ImpactSpec.Load("rear", file);

            car.GridImages = file.ReadStrings();

            int pixCount = file.ReadInt();

            for (int i = 0; i < pixCount; i++)
            {
                car.PixelmapsLoMem.Add(file.ReadLine());
            }

            pixCount = file.ReadInt();
            for (int i = 0; i < pixCount; i++)
            {
                car.PixelmapsLoRes.Add(file.ReadLine());
            }

            pixCount = file.ReadInt();
            for (int i = 0; i < pixCount; i++)
            {
                car.PixelmapsHiRes.Add(file.ReadLine());
            }

            int shadeCount = file.ReadInt();

            for (int j = 0; j < shadeCount; j++)
            {
                car.ShadeTables.Add(file.ReadLine());
            }

            int matCount = file.ReadInt();

            for (int i = 0; i < matCount; i++)
            {
                car.MaterialsLoMem.Add(file.ReadLine());
            }

            matCount = file.ReadInt();
            for (int i = 0; i < matCount; i++)
            {
                car.MaterialsLoRes.Add(file.ReadLine());
            }

            matCount = file.ReadInt();
            for (int i = 0; i < matCount; i++)
            {
                car.MaterialsHiRes.Add(file.ReadLine());
            }

            int modelCount = file.ReadInt();

            for (int j = 0; j < modelCount; j++)
            {
                car.Models.Add(file.ReadLine());
            }

            int actorCount = file.ReadInt();

            for (int j = 0; j < actorCount; j++)
            {
                string[] s = file.ReadStrings();
                car.ActorLODs.Add(s[0].ToInt());
                car.Actors.Add(s[1]);
            }

            car.ReflectiveScreenMaterial = file.ReadLine();

            int steerableWheelsCount = file.ReadInt();

            for (int j = 0; j < steerableWheelsCount; j++)
            {
                car.SteerableWheels.Add(file.ReadInt());
            }

            car.LeftFrontSuspension  = file.ReadInts();
            car.RightFrontSuspension = file.ReadInts();
            car.LeftRearSuspension   = file.ReadInts();
            car.RightRearSuspension  = file.ReadInts();
            car.DrivenWheels         = file.ReadInts();
            car.NonDrivenWheels      = file.ReadInts();

            car.DrivenWheelDiameter    = file.ReadSingle();
            car.NonDrivenWheelDiameter = file.ReadSingle();

            if (file.ReadLine() != "START OF FUNK")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Car.TXT file?", "START OF FUNK");
                return(null);
            }

            while (file.PeekLine() != "END OF FUNK")
            {
                car.Funks.Add(Funk.Load(file));
                if (file.PeekLine() == "NEXT FUNK")
                {
                    file.ReadLine();
                }
            }
            file.ReadLine();

            if (file.ReadLine() != "START OF GROOVE")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Car.TXT file?", "START OF GROOVE");
                return(null);
            }

            while (file.PeekLine() != "END OF GROOVE")
            {
                car.Grooves.Add(Groove.Load(file));
                if (file.PeekLine() == "NEXT GROOVE")
                {
                    file.ReadLine();
                }
            }
            file.ReadLine();

            for (int i = 0; i < car.Actors.Count; i++)
            {
                car.Crushes.Add(Crush.Load(file));
            }

            car.MechanicsVersion = file.ReadLine().Replace("START OF MECHANICS STUFF version ", "", StringComparison.InvariantCultureIgnoreCase).ToInt();

            car.LRWheelPos   = file.ReadVector3();
            car.RRWheelPos   = file.ReadVector3();
            car.LFWheelPos   = file.ReadVector3();
            car.RFWheelPos   = file.ReadVector3();
            car.CentreOfMass = file.ReadVector3();

            switch (car.MechanicsVersion)
            {
            case 2:
                int boundingBoxCount = file.ReadInt();
                for (int i = 0; i < boundingBoxCount; i++)
                {
                    car.BoundingBoxes.Add(new BoundingBox {
                        Min = file.ReadVector3(), Max = file.ReadVector3()
                    });
                }
                break;

            case 3:
            case 4:
                car.BoundingBoxes.Add(new BoundingBox {
                    Min = file.ReadVector3(), Max = file.ReadVector3()
                });

                int additionalPointsCount = file.ReadInt();
                for (int i = 0; i < additionalPointsCount; i++)
                {
                    car.AdditionalPoints.Add(file.ReadVector3());
                }
                break;
            }

            car.MinimumTurningCircle = file.ReadSingle();
            car.SuspensionGive       = file.ReadVector2();
            car.RideHeight           = file.ReadSingle();
            car.DampingFactor        = file.ReadSingle();
            car.Mass = file.ReadSingle();
            car.SlipFrictionReductionFraction = file.ReadSingle();

            if (car.MechanicsVersion == 4)
            {
                car.FrictionAngle = file.ReadVector3();
            }
            else
            {
                car.FrictionAngle = (Vector3)file.ReadVector2();
            }

            car.AngularMomentumProportions    = file.ReadVector3();
            car.TractionFractionalMultiplier  = file.ReadSingle();
            car.DownforceToWeightBalanceSpeed = file.ReadSingle();
            car.BrakeMultiplier           = file.ReadSingle();
            car.BrakingStrengthMultiplier = file.ReadSingle();
            car.RollingResistance         = file.ReadVector2();
            car.NumberOfGears             = file.ReadInt();
            car.TopGearRedlineSpeed       = file.ReadInt();
            car.TopGearAcceleration       = file.ReadSingle();

            if (file.ReadLine() != "END OF MECHANICS STUFF")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Car.TXT file?", "END OF MECHANICS STUFF");
                return(null);
            }

            int shrapnelCount = file.ReadInt();

            for (int i = 0; i < shrapnelCount; i++)
            {
                car.Shrapnel.Add(file.ReadLine());
            }

            if (!file.EOF)
            {
                for (int i = 0; i < 12; i++)
                {
                    car.FirePoints.Add(file.ReadInt());
                }
            }

            if (!file.EOF)
            {
                Console.WriteLine("Still data to parse in {0}", path);
            }

            return(car);
        }
Пример #10
0
        public void Save(string path)
        {
            using (DocumentWriter dw = new DocumentWriter(path))
            {
                dw.WriteLine($"VERSION {Version}", Version > 1 ? "V1 expects map checkpoint rectangles" : null);
                if (Version >= 2)
                {
                    dw.WriteLine(null, "V2 and above expect map checkpoint points");
                }
                if (Version >= 3)
                {
                    dw.WriteLine(null, "V3 and above expect splash file stuff at the end");
                }
                if (Version >= 4)
                {
                    dw.WriteLine(null, "V4 and above expect two sets of PIX and MAT and ped substitution entry");
                }
                dw.WriteLine();

                if (Version == 1)
                {
                    dw.WriteLine();
                    dw.WriteLine("//////////// GLOBAL LIGHTING DATA ///////////");
                    dw.WriteLine();
                    dw.WriteLine($"{LightColour.X},{LightColour.Y},{LightColour.Z}", "RGB for main directional light-source");
                    dw.WriteLine($"{DiffuseLight0.X:F1},{DiffuseLight0.Y:F1}", "Ambient/Diffuse light to be used when plaything ambient says 0				}--- Neither of these have smooth lighting effecs applied");
                    dw.WriteLine($"{DiffuseLight1.X:F1},{DiffuseLight1.Y:F1}", "Ambient/Diffuse light to be used when plaything ambient says 1				}");
                    dw.WriteLine($"{DiffuseLightOther.X:F1},{DiffuseLightOther.Y:F1}", "Ambient/Diffuse light to be used when plaything ambient says anything else");
                    dw.WriteLine();
                    dw.WriteLine("/////////////////////////////////////////////");
                    dw.WriteLine();
                }

                dw.WriteLine();

                dw.WriteLine($"{GridPosition.X},{GridPosition.Y},{GridPosition.Z}", "Position of centre of start of grid");
                dw.WriteLine($"{GridRotation}", "Direction that grid faces in");

                dw.WriteLine();
                dw.WriteLine("// Laps, checkpoints etc");
                dw.WriteLine();

                dw.WriteLine($"{Checkpoints.Count}", "# checkpoints");
                for (int i = 0; i < Checkpoints.Count; i++)
                {
                    Checkpoint checkpoint = Checkpoints[i];

                    dw.WriteLine($"// Checkpoint #{i + 1}");
                    dw.WriteLine($"{checkpoint.TimerIncrements.X},{checkpoint.TimerIncrements.Y},{checkpoint.TimerIncrements.Z}", "Timer increment for each skill level (ped mode)");
                    dw.WriteLine($"{checkpoint.Points.Count / 4}", "# quads for this checkpoint");

                    for (int j = 0; j < checkpoint.Points.Count; j++)
                    {
                        Vector3 point = checkpoint.Points[j];

                        dw.WriteLine($"{point.X},{point.Y},{point.Z}", $"Point #{j}");
                    }
                }

                dw.WriteLine();
                dw.WriteLine("// Smashable environment specs");
                dw.WriteLine();

                dw.WriteLine($"{Smashables.Count}", "Number of smash specs");
                dw.WriteLine();

                foreach (SmashData smash in Smashables)
                {
                    dw.WriteLine("// Start of smashable item");
                    dw.WriteLine($"{smash.Flags}", "Flags");
                    dw.WriteLine($"{smash.Trigger}", "Name of trigger material");
                    dw.WriteLine($"{smash.TriggerMode}", "Mode");

                    switch (smash.TriggerMode)
                    {
                    case SmashData.SmashTriggerMode.nochange:
                    case SmashData.SmashTriggerMode.remove:
                        dw.WriteLine($"{smash.RemovalThreshold}", "Removal threshold");
                        dw.IncreaseIndent();
                        smash.Connotations.Write(dw);
                        dw.DecreaseIndent();
                        break;

                    case SmashData.SmashTriggerMode.replacemodel:
                        dw.WriteLine($"{smash.RemovalThreshold}", "Removal threshold");
                        dw.WriteLine();
                        dw.IncreaseIndent();
                        smash.Connotations.Write(dw);
                        dw.DecreaseIndent();
                        dw.WriteLine($"{smash.NewModel}", "new model");
                        dw.WriteLine($"{smash.ChanceOfFire}", "%chance fire");

                        if (smash.ChanceOfFire > 0)
                        {
                            dw.WriteLine($"{smash.NumFires}");
                            dw.WriteLine($"{string.Join(",", smash.SmokeLevel)}");
                        }
                        break;

                    case SmashData.SmashTriggerMode.texturechange:
                        dw.WriteLine($"{smash.IntactMaterial}", "Intact pixelmap");
                        dw.WriteLine($"{smash.Levels.Count}", "Number of levels");

                        int j = 1;

                        foreach (SmashDataTextureLevel textureLevel in smash.Levels)
                        {
                            dw.WriteLine();
                            dw.WriteLine($"{textureLevel.TriggerThreshold}", "Trigger threshold");
                            dw.WriteLine($"{textureLevel.Flags}", "Flags");
                            dw.WriteLine($"{textureLevel.CollisionType}", "Collision type");
                            dw.IncreaseIndent();
                            textureLevel.Connotations.Write(dw);
                            dw.DecreaseIndent();
                            dw.WriteLine();
                            dw.WriteLine($"{textureLevel.Pixelmaps.Count}", "Number of pixelmap");
                            foreach (string pixelmap in textureLevel.Pixelmaps)
                            {
                                dw.WriteLine($"{pixelmap}", $"Pixelmap");
                            }

                            j++;
                        }
                        break;
                    }

                    dw.WriteLine($"{smash.Reserved1}", "reserved 1");
                    dw.WriteLine($"{smash.Reserved2}", "reserved 2");
                    dw.WriteLine($"{smash.Reserved3}", "reserved 3");
                    dw.WriteLine($"{smash.Reserved4}", "reserved 4");
                }

                dw.WriteLine();
                dw.WriteLine("// Ped specs");
                dw.WriteLine();

                dw.WriteLine($"{PedSpecs.Count}");

                foreach (PedSpec pedspec in PedSpecs)
                {
                    dw.WriteLine();
                    dw.WriteLine($"{pedspec.MaterialName}", "Material name");
                    dw.WriteLine($"{pedspec.MovementIndex}", "Movement index");
                    dw.WriteLine($"{pedspec.GroupIndex}", "Group index");
                    dw.WriteLine($"{pedspec.PedsPer100SquareMetres}", "Peds per 100 square metres");
                    dw.WriteLine($"{pedspec.ExclusionMaterials.Count}", "Number of exclusion materials");

                    foreach (PedExclusionMaterial pedExclusionMaterial in pedspec.ExclusionMaterials)
                    {
                        dw.WriteLine($"{pedExclusionMaterial.Flags}", "Exclusion flags (1 = OK when scared)");
                        dw.WriteLine($"{pedExclusionMaterial.Name}", "Exclusion material #1 name");
                    }

                    dw.WriteLine($"{pedspec.ExceptionMaterials.Count}", "Number of exception materials");
                }

                dw.WriteLine();

                dw.WriteLine($"{AdditionalActor}", "Additional actor");

                dw.WriteLine();
                dw.WriteLine("// HORIZON STUFF");
                dw.WriteLine();

                dw.WriteLine($"{SkyPixelmap}", @"Name of sky texture pixelmap (or ""none"")");
                dw.WriteLine($"{HorizontalRepetitions}", "Horizontal repetitions of sky texture");
                dw.WriteLine($"{VerticalSize}", "Vertical size of sky texture (degrees)");
                dw.WriteLine($"{PositionOfHorizon}", "Position of horizon (pixels below top)");
                dw.WriteLine($"{DepthCueMode}", @"Depth cue mode (""none"", ""dark"" or ""fog"")");
                dw.WriteLine($"{FogDarkness.X},{FogDarkness.Y}", "Degree of fog/darkness");
                dw.WriteLine($"{DepthCueColour.X},{DepthCueColour.Y},{DepthCueColour.Z}", "Depth cue colour (red, green, blue )");

                dw.WriteLine();
                dw.WriteLine("// DEFAULT ENGINE NOISE");
                dw.WriteLine();

                dw.WriteLine($"{DefaultEngineNoise}");

                dw.WriteLine();
                dw.WriteLine("// SPECIAL EFFECTS VOLUMES");
                dw.WriteLine();

                dw.WriteLine($"{SpecialVolumes.Count}", "# special effects volumes");

                foreach (SpecialEffectVolume volume in SpecialVolumes)
                {
                    dw.WriteLine();
                    dw.WriteLine($"{volume.Type}");

                    foreach (Vector3 corner in volume.Corners)
                    {
                        dw.WriteLine($"{corner.X:F3}, {corner.Y:F3}, {corner.Z:F3}");
                    }

                    dw.WriteLine($"{volume.GravityMultiplier:F2}", "gravity multiplier");
                    dw.WriteLine($"{volume.ViscosityMultiplier:F2}", "viscosity multiplier");
                    dw.WriteLine($"{volume.CarDamagePerMillisecond:F2}", "Car damage per millisecond");
                    dw.WriteLine($"{volume.PedDamagePerMillisecond:F2}", "Pedestrian damage per millisecond");
                    dw.WriteLine($"{volume.CameraEffectIndex}", "camera effect index");
                    dw.WriteLine($"{volume.SkyColour}", "sky colour");
                    dw.WriteLine($"{volume.WindscreenMaterial}", "Windscreen texture to use");
                    dw.WriteLine($"{volume.EntrySoundID}", "Sound ID of entry noise");
                    dw.WriteLine($"{volume.ExitSoundID}", "Sound ID of exit noise");
                    dw.WriteLine($"{volume.EngineNoiseIndex}", "Engine noise index");
                    dw.WriteLine($"{volume.MaterialIndex}", "material index");

                    if (volume.Type.ToUpper() == "BOX")
                    {
                        dw.WriteLine($"{volume.SoundType}", "Sound type");

                        if (volume.SoundType != SpecialEffectVolume.SpecVolSoundType.NONE)
                        {
                            volume.SoundSpec.Write(dw);
                        }
                    }
                }

                dw.WriteLine();
                dw.WriteLine("// SOUND GENERATORS");
                dw.WriteLine();

                dw.WriteLine($"{SoundGenerators.Count}", "Number of generators");

                dw.WriteLine();
                dw.WriteLine("// REFLECTIVE WINDSCREEN SPECIFICATIONS");
                dw.WriteLine();

                dw.WriteLine($"{MaterialDefault}", "Material to use for default screens");
                dw.WriteLine($"{MaterialDarkness}", "Material to use for default screens during darkness");
                dw.WriteLine($"{MaterialFog}", "Material to use for default screens during fog");

                dw.WriteLine();

                dw.WriteLine("0", "(ignore) # areas with different screens");

                dw.WriteLine();
                dw.WriteLine("// MAP DETAILS");
                dw.WriteLine();

                dw.WriteLine($"{MapPixelmap}", "Map pixelmap name");
                dw.WriteLine();
                dw.WriteLine($"{WorldMapTransform.M11,7:0.###},{WorldMapTransform.M12,11:0.###},{WorldMapTransform.M13,11:0.###}", "World->map transformation matrix");
                dw.WriteLine($"{WorldMapTransform.M21,7:0.###},{WorldMapTransform.M22,11:0.###},{WorldMapTransform.M23,11:0.###}");
                dw.WriteLine($"{WorldMapTransform.M31,7:0.###},{WorldMapTransform.M32,11:0.###},{WorldMapTransform.M33,11:0.###}");
                dw.WriteLine($"{WorldMapTransform.M41,7:0.###},{WorldMapTransform.M42,11:0.###},{WorldMapTransform.M43,11:0.###}");

                dw.WriteLine();
                dw.WriteLine("// ****** START OF FUNK AND GROOVE STUFF ******");
                dw.WriteLine();

                dw.WriteLine();
                dw.WriteLine("START OF FUNK");
                dw.WriteLine();

                for (int i = 0; i < Funks.Count; i++)
                {
                    Funk funk = Funks[i];

                    dw.WriteLine($"{funk.Material}");
                    dw.WriteLine($"{funk.Mode}");
                    dw.WriteLine($"{funk.MatrixModType}");
                    if (funk.MatrixModType != FunkMatrixMode.None)
                    {
                        dw.WriteLine($"{funk.MatrixModMode}");
                    }

                    switch (funk.MatrixModType)
                    {
                    case FunkMatrixMode.roll:
                        dw.WriteLine($"{funk.RollPeriods.X},{funk.RollPeriods.Y}");
                        break;

                    case FunkMatrixMode.slither:
                        dw.WriteLine($"{funk.SlitherSpeed.X},{funk.SlitherSpeed.Y}");
                        dw.WriteLine($"{funk.SlitherAmount.X},{funk.SlitherAmount.Y}");
                        break;

                    case FunkMatrixMode.spin:
                        dw.WriteLine($"{funk.SpinPeriod}");
                        break;
                    }

                    dw.WriteLine($"{funk.LightingMode}");
                    dw.WriteLine($"{funk.AnimationType}");

                    switch (funk.AnimationType)
                    {
                    case FunkAnimationType.frames:
                        dw.WriteLine($"{funk.Framerate}");
                        dw.WriteLine($"{funk.FrameMode}");

                        switch (funk.FrameMode)
                        {
                        case FrameType.texturebits:
                            dw.WriteLine($"{funk.TextureBitMode}");
                            break;

                        case FrameType.continuous:
                            dw.WriteLine($"{funk.FrameSpeed}");
                            break;
                        }

                        dw.WriteLine($"{funk.Frames.Count}");
                        foreach (string frame in funk.Frames)
                        {
                            dw.WriteLine($"{frame}");
                        }
                        break;
                    }

                    if (i + 1 != Funks.Count)
                    {
                        dw.WriteLine();
                        dw.WriteLine("NEXT FUNK");
                        dw.WriteLine();
                    }
                }

                dw.WriteLine();
                dw.WriteLine("END OF FUNK");
                dw.WriteLine();

                dw.WriteLine();
                dw.WriteLine("START OF GROOVE");
                dw.WriteLine();

                for (int i = 0; i < Grooves.Count; i++)
                {
                    Groove groove = Grooves[i];

                    dw.WriteLine($"{groove.Part}", "Actor name of moving part");
                    dw.WriteLine($"{groove.LollipopMode}");
                    dw.WriteLine($"{groove.Mode}");
                    dw.WriteLine($"{groove.PathType}");
                    if (groove.PathType != GroovePathNames.None)
                    {
                        dw.WriteLine($"{groove.PathMode}");
                    }

                    switch (groove.PathType)
                    {
                    case GroovePathNames.straight:
                        dw.WriteLine($"{groove.PathCentre.X},{groove.PathCentre.Y},{groove.PathCentre.Z}");
                        dw.WriteLine($"{groove.PathPeriod}");
                        dw.WriteLine($"{groove.PathDelta.X},{groove.PathDelta.Y},{groove.PathDelta.Z}");
                        break;
                    }

                    dw.WriteLine($"{groove.AnimationType}");
                    if (groove.AnimationType != GrooveAnimation.None)
                    {
                        dw.WriteLine($"{groove.AnimationMode}");
                    }

                    switch (groove.AnimationType)
                    {
                    case GrooveAnimation.rock:
                        dw.WriteLine($"{groove.AnimationPeriod}");
                        dw.WriteLine($"{groove.AnimationCentre.X},{groove.AnimationCentre.Y},{groove.AnimationCentre.Z}");
                        dw.WriteLine($"{groove.AnimationAxis}");
                        dw.WriteLine($"{groove.RockMaxAngle}");
                        break;

                    case GrooveAnimation.shear:
                        dw.WriteLine($"{groove.ShearPeriod.X},{groove.ShearPeriod.Y},{groove.ShearPeriod.Z}");
                        dw.WriteLine($"{groove.AnimationCentre.X},{groove.AnimationCentre.Y},{groove.AnimationCentre.Z}");
                        dw.WriteLine($"{groove.ShearMagnitude.X},{groove.ShearMagnitude.Y},{groove.ShearMagnitude.Z}");
                        break;

                    case GrooveAnimation.spin:
                        dw.WriteLine($"{groove.AnimationPeriod}");
                        dw.WriteLine($"{groove.AnimationCentre.X},{groove.AnimationCentre.Y},{groove.AnimationCentre.Z}");
                        dw.WriteLine($"{groove.AnimationAxis}");
                        break;
                    }

                    if (i + 1 != Grooves.Count)
                    {
                        dw.WriteLine();
                        dw.WriteLine("NEXT GROOVE");
                        dw.WriteLine();
                    }
                }

                dw.WriteLine();
                dw.WriteLine("END OF GROOVE");
                dw.WriteLine();
                dw.WriteLine("START OF OPPONENT PATHS");
                dw.WriteLine();

                dw.WriteLine($"{Nodes.Count}", "Number of path nodes");

                int n = 0;
                foreach (Vector3 node in Nodes)
                {
                    dw.WriteLine($"{node.X,9:F3},{node.Y,9:F3},{node.Z,9:F3}", $"Node #{n}");
                    n++;
                }

                dw.WriteLine();

                dw.WriteLine($"{Paths.Count}", "Number of path sections");

                n = 0;
                foreach (OpponentPathSection pathSection in Paths)
                {
                    dw.WriteLine($"{pathSection.StartNode,4},{pathSection.EndNode,4},{pathSection.Unknown1,4},{pathSection.Unknown2,4},{pathSection.Unknown3,4},{pathSection.Unknown4,4},{pathSection.Width,7:F1},{pathSection.SectionType,5}", $"Section #{n}");
                    n++;
                }

                dw.WriteLine();

                dw.WriteLine($"{CopStartPoints.Count}", "Number of cop start points");

                dw.WriteLine();
                dw.WriteLine("END OF OPPONENT PATHS");
                dw.WriteLine();

                dw.WriteLine();
                dw.WriteLine("START OF DRONE PATHS");
                dw.WriteLine();

                dw.WriteLine($"{DronePathVersion}", "version");
                dw.WriteLine($"{DronePaths.Count}", "n_nodes");

                for (int i = 0; i < DronePaths.Count; i++)
                {
                    DronePathNode node = DronePaths[i];

                    dw.WriteLine();
                    dw.WriteLine($"// {i}:");
                    dw.IncreaseIndent();
                    dw.WriteLine($"{node.Position.X:F3}, {node.Position.Y:F3}, {node.Position.Z:F3}");
                    dw.WriteLine($"{node.DroneName}");
                    dw.WriteLine($"{node.UnknownInt}");
                    dw.WriteLine($"{node.Destinations.Count}");
                    dw.IncreaseIndent();
                    foreach (string destination in node.Destinations)
                    {
                        dw.WriteLine($"{destination}");
                    }
                    dw.DecreaseIndent();
                    dw.DecreaseIndent();
                }

                dw.WriteLine();
                dw.WriteLine("END OF DRONE PATHS");
                dw.WriteLine();

                dw.WriteLine($"{MaterialModifiers.Count}", "number of material modifiers");

                for (int i = 0; i < MaterialModifiers.Count; i++)
                {
                    dw.WriteLine($"// {(i == 0 ? "default material" : $"material '{i - 1}'")}");

                    MaterialModifier materialModifier = MaterialModifiers[i];
                    dw.WriteLine($"{materialModifier.CarWallFriction:0.0##}", "car wall friction");
                    dw.WriteLine($"{materialModifier.TyreRoadFriction:0.0##}", "tyre road friction");
                    dw.WriteLine($"{materialModifier.DownForce:0.0##}", "down force");
                    dw.WriteLine($"{materialModifier.Bumpiness:0.0##}", "bumpiness");
                    dw.WriteLine($"{materialModifier.TyreSoundIndex}", "tyre sound index");
                    dw.WriteLine($"{materialModifier.CrashSoundIndex}", "crash sound index");
                    dw.WriteLine($"{materialModifier.ScrapeNoiseIndex}", "scrape noise index");
                    dw.WriteLine($"{materialModifier.Sparkiness:0.0##}", "sparkiness");
                    dw.WriteLine($"{materialModifier.RoomForExpansion}", "room for expansion");
                    dw.WriteLine($"{materialModifier.SkidmarkMaterial}", "skid mark material");
                }

                dw.WriteLine();
                dw.WriteLine("// Non CarObjects");
                dw.WriteLine($"{Noncars.Count}");
                foreach (string noncar in Noncars)
                {
                    dw.WriteLine($"{noncar}");
                }

                dw.WriteLine();

                dw.WriteLine($"{ShadeTables.Count}", "number of dust shade tables");
                foreach (ShadeTable shade in ShadeTables)
                {
                    dw.WriteLine($"{shade.RGB.X}, {shade.RGB.Y}, {shade.RGB.Z}", "r g b values");
                    dw.WriteLine($"{shade.Strengths.X}, {shade.Strengths.Y}, {shade.Strengths.Z}", @"quarter, half and three quarter ""strength""");
                }

                dw.WriteLine();

                dw.WriteLine($"{NetworkStarts.Count}", "Number of network start points");
                n = 0;
                foreach (NetworkStart start in NetworkStarts)
                {
                    dw.WriteLine();
                    dw.WriteLine($"{start.Position.X:F3}, {start.Position.Y:F3}, {start.Position.Z:F3}", $"{n}");
                    dw.WriteLine($"{start.Rotation}");
                    n++;
                }

                dw.WriteLine();

                dw.WriteLine($"{SplashFiles.Count}", "number of splash files");
                foreach (string splash in SplashFiles)
                {
                    dw.WriteLine($"{splash}", "name of pixelmapfile for splashes");
                }

                dw.WriteLine();

                dw.WriteLine($"{TxtFiles.Count}");
                foreach (string txt in TxtFiles)
                {
                    dw.WriteLine($"{txt}");
                }
            }
Пример #11
0
        public static Map Load(string path)
        {
            DocumentParser file = new DocumentParser(path);
            Map            map  = new Map();

            string version = file.ReadLine();

            if (!version.StartsWith("VERSION"))
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Not a valid Carmageddon 2 race .txt file");
                return(null);
            }

            map.Version = version.Replace("VERSION ", "").ToInt();

            if (map.Version == 1)
            {
                // V1 has global lighting data
                map.LightColour       = file.ReadVector3(); // RGB for main directional light-source
                map.DiffuseLight0     = file.ReadVector2(); // Ambient/Diffuse light to be used when plaything ambient says 0
                map.DiffuseLight1     = file.ReadVector2(); // Ambient/Diffuse light to be used when plaything ambient says 1
                map.DiffuseLightOther = file.ReadVector2(); // Ambient/Diffuse light to be used when plaything ambient says anything else
            }

            map.GridPosition = file.ReadVector3();          // Position of centre of start of grid
            map.GridRotation = file.ReadInt();              // Direction that grid faces in

            //string t = getNextLine(sr);

            //if (version == 8)
            //{
            //    // alpha and demo v8 files had an extra block here, we'll test if it
            //    if (t.Contains(","))
            //    {
            //        getNextLine(sr); // # laps
            //        getNextLine(sr); // Race completed bonus (all laps raced) for each skill level
            //        getNextLine(sr); // Race completed bonus (all peds killed) for each skill level
            //        getNextLine(sr); // Race completed bonus (all oppos wasted) for each skill level

            //        t = getNextLine(sr);
            //    }
            //}

            int checkpointCount = file.ReadInt();

            for (int i = 0; i < checkpointCount; i++)
            {
                Checkpoint cp = new Checkpoint()
                {
                    TimerIncrements = file.ReadVector3()
                };
                int quadCount = file.ReadInt();

                for (int j = 0; j < quadCount; j++)
                {
                    cp.Points.Add(file.ReadVector3());
                    cp.Points.Add(file.ReadVector3());
                    cp.Points.Add(file.ReadVector3());
                    cp.Points.Add(file.ReadVector3());
                }

                map.Checkpoints.Add(cp);
            }

            int smashSpecs = file.ReadInt();

            for (int i = 0; i < smashSpecs; i++)
            {
                SmashData smashable = new SmashData
                {
                    Flags   = file.ReadInt(),
                    Trigger = file.ReadLine()
                };

                if (smashable.Trigger.Length == 3 && smashable.Trigger.StartsWith("&"))
                {
                    smashable.TriggerFlags = file.ReadInt();
                }

                smashable.TriggerMode = file.ReadEnum <SmashData.SmashTriggerMode>();

                switch (smashable.TriggerMode)
                {
                case SmashData.SmashTriggerMode.nochange:
                case SmashData.SmashTriggerMode.remove:
                    smashable.RemovalThreshold = file.ReadSingle();
                    smashable.Connotations.Load(file);
                    break;

                case SmashData.SmashTriggerMode.replacemodel:
                    smashable.RemovalThreshold = file.ReadSingle();
                    smashable.Connotations.Load(file);
                    smashable.NewModel     = file.ReadLine();
                    smashable.ChanceOfFire = file.ReadInt();

                    if (smashable.ChanceOfFire > 0)
                    {
                        smashable.NumFires   = file.ReadInt();
                        smashable.SmokeLevel = file.ReadInts();
                    }
                    break;

                case SmashData.SmashTriggerMode.texturechange:
                    smashable.IntactMaterial = file.ReadLine();
                    int textureLevels = file.ReadInt();

                    for (int j = 0; j < textureLevels; j++)
                    {
                        SmashDataTextureLevel textureLevel = new SmashDataTextureLevel()
                        {
                            TriggerThreshold = file.ReadSingle(),
                            Flags            = file.ReadInt(),
                            CollisionType    = file.ReadEnum <SmashDataTextureLevel.TextureLevelCollisionType>()
                        };

                        textureLevel.Connotations.Load(file);

                        int pixelmaps = file.ReadInt();
                        for (int k = 0; k < pixelmaps; k++)
                        {
                            textureLevel.Pixelmaps.Add(file.ReadLine());
                        }

                        smashable.Levels.Add(textureLevel);
                    }
                    break;

                default:
                    throw new NotImplementedException($"Unknown TriggerMode '{smashable.TriggerMode}'");
                }

                smashable.Reserved1 = file.ReadInt();
                smashable.Reserved2 = file.ReadInt();
                smashable.Reserved3 = file.ReadInt();
                smashable.Reserved4 = file.ReadInt();

                map.Smashables.Add(smashable);
            }

            int pedSpecs = file.ReadInt();

            for (int i = 0; i < pedSpecs; i++)
            {
                PedSpec ps = new PedSpec()
                {
                    MaterialName           = file.ReadLine(),
                    MovementIndex          = file.ReadInt(),
                    GroupIndex             = file.ReadInt(),
                    PedsPer100SquareMetres = file.ReadSingle()
                };

                int exclusionCount = file.ReadInt();
                for (int j = 0; j < exclusionCount; j++)
                {
                    ps.ExclusionMaterials.Add(new PedExclusionMaterial
                    {
                        Flags = file.ReadInt(),
                        Name  = file.ReadLine()
                    });
                }

                int exceptionCount = file.ReadInt();
                for (int j = 0; j < exceptionCount; j++)
                {
                    ps.ExceptionMaterials.Add(file.ReadLine());
                }

                map.PedSpecs.Add(ps);
            }

            map.AdditionalActor = file.ReadLine();

            map.SkyPixelmap           = file.ReadLine();
            map.HorizontalRepetitions = file.ReadInt();
            map.VerticalSize          = file.ReadInt();
            map.PositionOfHorizon     = file.ReadInt();
            map.DepthCueMode          = file.ReadLine();
            map.FogDarkness           = file.ReadVector2();
            map.DepthCueColour        = file.ReadVector3();

            map.DefaultEngineNoise = file.ReadInt();

            int specialEffectVolumeCount = file.ReadInt();

            for (int i = 0; i < specialEffectVolumeCount; i++)
            {
                SpecialEffectVolume sev = new SpecialEffectVolume {
                    Type = file.ReadLine()
                };

                if (sev.Type.ToUpper() == "BOX")
                {
                    sev.Corners.Add(file.ReadVector3());
                    sev.Corners.Add(file.ReadVector3());
                    sev.Corners.Add(file.ReadVector3());
                    sev.Corners.Add(file.ReadVector3());
                }

                sev.GravityMultiplier       = file.ReadSingle();
                sev.ViscosityMultiplier     = file.ReadSingle();
                sev.CarDamagePerMillisecond = file.ReadSingle();
                sev.PedDamagePerMillisecond = file.ReadSingle();
                sev.CameraEffectIndex       = file.ReadInt();

                if (file.PeekLine().Contains(","))
                {
                    sev.SkyColourRGB = file.ReadVector3();
                }
                else
                {
                    sev.SkyColour = file.ReadInt();
                }

                sev.WindscreenMaterial = file.ReadLine();
                sev.EntrySoundID       = file.ReadInt();
                sev.ExitSoundID        = file.ReadInt();
                sev.EngineNoiseIndex   = file.ReadInt();
                sev.MaterialIndex      = file.ReadInt();

                if (sev.Type.ToUpper() == "BOX")
                {
                    sev.SoundType = file.ReadEnum <SpecialEffectVolume.SpecVolSoundType>();

                    if (sev.SoundType != SpecialEffectVolume.SpecVolSoundType.NONE)
                    {
                        sev.SoundSpec = SoundSpec.Load(file);
                    }
                }

                map.SpecialVolumes.Add(sev);
            }

            int soundGeneratorCount = file.ReadInt();

            if (soundGeneratorCount > 0)
            {
                throw new NotImplementedException("Can't handle sound generators yet!");
            }

            map.MaterialDefault  = file.ReadLine();
            map.MaterialDarkness = file.ReadLine();
            map.MaterialFog      = file.ReadLine();

            file.ReadLine();    // (ignore) # areas with different screens

            map.MapPixelmap       = file.ReadLine();
            map.WorldMapTransform = new Matrix3D(
                file.ReadVector3(),
                file.ReadVector3(),
                file.ReadVector3(),
                file.ReadVector3()
                );

            if (file.ReadLine() != "START OF FUNK")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Map.TXT file?", "START OF FUNK");
                return(null);
            }

            while (file.PeekLine() != "END OF FUNK")
            {
                map.Funks.Add(Funk.Load(file));
                if (file.PeekLine() == "NEXT FUNK")
                {
                    file.ReadLine();
                }
            }
            file.ReadLine();

            if (file.ReadLine() != "START OF GROOVE")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Expected \"{0}\", didn't get it.  Are you sure this is a Map.TXT file?", "START OF GROOVE");
                return(null);
            }

            while (file.PeekLine() != "END OF GROOVE")
            {
                map.Grooves.Add(Groove.Load(file));
                if (file.PeekLine() == "NEXT GROOVE")
                {
                    file.ReadLine();
                }
            }
            file.ReadLine();

            if (file.ReadLine() != "START OF OPPONENT PATHS")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Not a valid Carmageddon 2 race .txt file");
                return(null);
            }

            int nodeCount = file.ReadInt();

            for (int i = 0; i < nodeCount; i++)
            {
                map.Nodes.Add(file.ReadVector3());
            }

            int pathCount = file.ReadInt();

            for (int i = 0; i < pathCount; i++)
            {
                string[] parts = file.ReadLine().Split(',');

                map.Paths.Add(new OpponentPathSection
                {
                    StartNode   = parts[0].ToInt(),
                    EndNode     = parts[1].ToInt(),
                    Unknown1    = parts[2].ToInt(),
                    Unknown2    = parts[3].ToInt(),
                    Unknown3    = parts[4].ToInt(),
                    Unknown4    = parts[5].ToInt(),
                    Width       = parts[6].ToSingle(),
                    SectionType = parts[7].ToInt()
                });
            }

            int copStartPoints = file.ReadInt();

            if (copStartPoints > 0)
            {
                throw new NotImplementedException("Cop start points?  Really?");
            }

            if (file.ReadLine() != "END OF OPPONENT PATHS")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Not a valid Carmageddon 2 race .txt file");
                return(null);
            }

            if (file.ReadLine() != "START OF DRONE PATHS")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Not a valid Carmageddon 2 race .txt file");
                return(null);
            }

            map.DronePathVersion = file.ReadInt();

            int dronepathNodeCount = file.ReadInt();

            for (int i = 0; i < dronepathNodeCount; i++)
            {
                DronePathNode node = new DronePathNode
                {
                    Position  = file.ReadVector3(),
                    DroneName = file.ReadLine()
                };

                if (map.DronePathVersion == 0)
                {
                    node.UnknownVector = file.ReadVector3();
                }
                else
                {
                    node.UnknownInt = file.ReadInt();
                }

                int nextNodeCount = file.ReadInt();
                for (int j = 0; j < nextNodeCount; j++)
                {
                    node.Destinations.Add(file.ReadLine());
                }

                map.DronePaths.Add(node);
            }

            if (file.ReadLine() != "END OF DRONE PATHS")
            {
                Logger.LogToFile(Logger.LogLevel.Error, "Not a valid Carmageddon 2 race .txt file");
                return(null);
            }

            int materialModifierCount = file.ReadInt();

            for (int i = 0; i < materialModifierCount; i++)
            {
                map.MaterialModifiers.Add(new MaterialModifier
                {
                    CarWallFriction  = file.ReadSingle(),
                    TyreRoadFriction = file.ReadSingle(),
                    DownForce        = file.ReadSingle(),
                    Bumpiness        = file.ReadSingle(),
                    TyreSoundIndex   = file.ReadInt(),
                    CrashSoundIndex  = file.ReadInt(),
                    ScrapeNoiseIndex = file.ReadInt(),
                    Sparkiness       = file.ReadSingle(),
                    RoomForExpansion = file.ReadInt(),
                    SkidmarkMaterial = file.ReadLine()
                });
            }

            int noncarCount = file.ReadInt();

            for (int i = 0; i < noncarCount; i++)
            {
                map.Noncars.Add(file.ReadLine());
            }

            int shadetableCount = file.ReadInt();

            for (int i = 0; i < shadetableCount; i++)
            {
                map.ShadeTables.Add(new ShadeTable
                {
                    RGB       = file.ReadVector3(),
                    Strengths = file.ReadVector3()
                });
            }

            int networkStartCount = file.ReadInt();

            for (int i = 0; i < networkStartCount; i++)
            {
                map.NetworkStarts.Add(new NetworkStart
                {
                    Position = file.ReadVector3(),
                    Rotation = file.ReadInt()
                });
            }

            int splashfileCount = file.ReadInt();

            for (int i = 0; i < splashfileCount; i++)
            {
                map.SplashFiles.Add(file.ReadLine());
            }

            int txtfileCount = file.ReadInt();

            for (int i = 0; i < txtfileCount; i++)
            {
                map.TxtFiles.Add(file.ReadLine());
            }

            return(map);
        }