public static WAM Load(string path) { DocumentParser file = new DocumentParser(path); WAM wam = new WAM(); string version = file.ReadLine(); if (!version.StartsWith("VERSION")) { Logger.LogToFile(Logger.LogLevel.Error, "Not a valid Carmageddon 2 .wam file"); return(null); } wam.Version = version.Replace("VERSION ", "").ToInt(); int xMinCount = file.ReadInt(); for (int i = 0; i < xMinCount; i++) { wam.XMins.Add(file.ReadSingle()); } int xMaxCount = file.ReadInt(); for (int i = 0; i < xMaxCount; i++) { wam.XMaxs.Add(file.ReadSingle()); } int yMinCount = file.ReadInt(); for (int i = 0; i < yMinCount; i++) { wam.YMins.Add(file.ReadSingle()); } int yMaxCount = file.ReadInt(); for (int i = 0; i < yMaxCount; i++) { wam.YMaxs.Add(file.ReadSingle()); } int zMinCount = file.ReadInt(); for (int i = 0; i < zMinCount; i++) { wam.ZMins.Add(file.ReadSingle()); } int zMaxCount = file.ReadInt(); for (int i = 0; i < zMaxCount; i++) { wam.ZMaxs.Add(file.ReadSingle()); } wam.BendabilityFactor = file.ReadSingle(); wam.BendPointZMin = file.ReadSingle(); wam.BendPointZMax = file.ReadSingle(); wam.SnappabilityFactor = file.ReadSingle(); wam.YSplitPosition = file.ReadSingle(); wam.DriverPosition = file.ReadVector3(); int crushEntries = file.ReadInt(); for (int i = 0; i < crushEntries; i++) { CrushData crush = new CrushData { Actor = file.ReadLine() }; crush.Softness = file.ReadEnum <CrushData.CrushSoftness>(); crush.Type = file.ReadEnum <CrushData.CrushType>(); switch (crush.Type) { case CrushData.CrushType.detach: crush.EaseOfDetach = file.ReadEnum <CrushData.Ease>(); crush.DetachmentType = file.ReadEnum <CrushData.DetachType>(); crush.CrushShape = file.ReadEnum <CrushData.BoxShape>(); break; case CrushData.CrushType.flap: crush.HingePoints.Add(file.ReadInt()); crush.HingePoints.Add(file.ReadInt()); crush.HingePoints.Add(file.ReadInt()); crush.KevOFlap = file.ReadInt() == 1; crush.EaseOfFlap = file.ReadEnum <CrushData.Ease>(); crush.CrushShape = file.ReadEnum <CrushData.BoxShape>(); break; } if (crush.CrushShape == CrushData.BoxShape.poly) { int polyPoints = file.ReadInt(); for (int j = 0; j < polyPoints; j++) { crush.ShapePoints.Add(file.ReadInt());; } } int smashEntries = file.ReadInt(); for (int j = 0; j < smashEntries; j++) { SmashData smash = new SmashData { Trigger = file.ReadLine(), TriggerMode = SmashData.SmashTriggerMode.texturechange }; smash.IntactMaterial = file.ReadLine(); int textureLevels = file.ReadInt(); for (int k = 0; k < textureLevels; k++) { SmashDataTextureLevel textureLevel = new SmashDataTextureLevel() { TriggerThreshold = file.ReadSingle(), Flags = file.ReadInt() }; textureLevel.Connotations.Load(file); int pixelmaps = file.ReadInt(); for (int l = 0; l < pixelmaps; l++) { textureLevel.Pixelmaps.Add(file.ReadLine()); } smash.Levels.Add(textureLevel); } crush.SmashEntries.Add(smash); } wam.CrushEntries.Add(crush); } return(wam); }
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); }