diff --git a/TagTool/Commands/Porting/PortTagCommand.Scenario.cs b/TagTool/Commands/Porting/PortTagCommand.Scenario.cs index d5fd1386..fe10a57d 100644 --- a/TagTool/Commands/Porting/PortTagCommand.Scenario.cs +++ b/TagTool/Commands/Porting/PortTagCommand.Scenario.cs @@ -875,6 +875,7 @@ public void AddGametypeObjects(Scenario scnr) }); ProcessMegaloLabels(scnr.CratePalette, scnr.Crates); + scnr.Crates = scnr.Crates.Where(e => e.PaletteIndex != -1).ToList(); // Teleporters must be neutral. @@ -907,6 +908,11 @@ public void AddGametypeObjects(Scenario scnr) if (scnr.SceneryPalette.Count > 0) { + var invisible_spawn = scnr.SceneryPalette.FindIndex(e => e.Object?.Name == "objects\\multi\\spawning\\respawn_point_invisible"); + if (invisible_spawn != -1) + foreach (var entry in scnr.Scenery.Where(e => e.PaletteIndex == invisible_spawn).Skip(1)) + entry.PaletteIndex = -1; + scnr.SceneryPalette.AddRange(new List { new Scenario.ScenarioPaletteEntry { Object = CacheContext.TagCache.GetTag(@"objects\multi\assault\assault_respawn_zone", "scen") }, @@ -928,17 +934,23 @@ public void AddGametypeObjects(Scenario scnr) }); ProcessMegaloLabels(scnr.SceneryPalette, scnr.Scenery); + scnr.Scenery = scnr.Scenery.Where(e => e.PaletteIndex != -1).ToList(); } } private void ProcessMegaloLabels(List palette, List instanceList) { + List stripped = new List(); foreach (var instance in instanceList) { var mpProperties = (Scenario.MultiplayerObjectProperties)(instance.GetType().GetField("Multiplayer").GetValue(instance)); + if (mpProperties == null) + return; + var permutationInstance = (instance as Scenario.PermutationInstance); var newPaletteIndex = permutationInstance.PaletteIndex; var ctfReturnIndex = GetPaletteIndex(palette, @"objects\multi\ctf\ctf_flag_return_area"); + switch (mpProperties.MegaloLabel) { case "ctf_res_zone_away": @@ -975,9 +987,6 @@ private void ProcessMegaloLabels(List palette, case "inf_spawn": newPaletteIndex = GetPaletteIndex(palette, @"objects\multi\infection\infection_initial_spawn_point"); break; - case "ffa_only": - newPaletteIndex = -1; - break; case "inf_haven": newPaletteIndex = GetPaletteIndex(palette, @"objects\multi\infection\infection_respawn_zone"); break; @@ -989,21 +998,32 @@ private void ProcessMegaloLabels(List palette, break; case "oddball_ball": case "koth_hill": - case "team_only": - case "hh_drop_point": + case "slayer": + case "lift": case "none": break; - case "inv_objective": - case "inv_obj_flag": - case "invasion": - newPaletteIndex = -1; - break; + //case "team_only": + //case "hh_drop_point": + //case "inv_objective": + //case "inv_obj_flag": + //case "invasion": + // newPaletteIndex = -1; + // break; default: - //if (!string.IsNullOrEmpty(mpProperties.MegaloLabel)) - // new TagToolWarning($"unknown megalo label: {mpProperties.MegaloLabel}"); + if (!string.IsNullOrEmpty(mpProperties.MegaloLabel)) + { + newPaletteIndex = -1; + if(!stripped.Contains(mpProperties.MegaloLabel)) + { + stripped.Add(mpProperties.MegaloLabel); + Console.WriteLine($"Placements with label \"{mpProperties.MegaloLabel}\" stripped"); + } + } break; } + mpProperties.SpawnFlags &= ~MultiplayerObjectPlacementSpawnFlags.HideUnlessRequired; + permutationInstance.PaletteIndex = newPaletteIndex; } } diff --git a/TagTool/Commands/Porting/PortTagCommand.cs b/TagTool/Commands/Porting/PortTagCommand.cs index d80c651c..ea1b3ddf 100644 --- a/TagTool/Commands/Porting/PortTagCommand.cs +++ b/TagTool/Commands/Porting/PortTagCommand.cs @@ -464,15 +464,27 @@ private void PreConvertReachDefinition(object definition, Stream blamCacheStream {"objects\\equipment\\active_camouflage\\active_camouflage", "objects\\equipment\\invisibility_equipment\\invisibility_equipment"} }; + Dictionary reachWeapons = new Dictionary() + { + {"objects\\weapons\\melee\\energy_sword\\energy_sword", "objects\\weapons\\melee\\energy_blade\\energy_blade"} + }; + ReplaceObjects(scenario.SceneryPalette, reachObjectives); ReplaceObjects(scenario.CratePalette, reachObjectives); ReplaceObjects(scenario.VehiclePalette, reachVehicles); ReplaceObjects(scenario.EquipmentPalette, reachEquipment); + ReplaceObjects(scenario.WeaponPalette, reachWeapons); + + foreach (var entry in scenario.Weapons) + { + if (entry.Multiplayer.MegaloLabel == "inv_weapon") + entry.PaletteIndex = -1; + } - if (!FlagIsSet(PortingFlags.ReachMisc)) + foreach (var entry in scenario.Vehicles) { - CullNewObjects(scenario.SceneryPalette, scenario.Scenery, reachObjectives); - CullNewObjects(scenario.CratePalette, scenario.Crates, reachObjectives); + if (entry.Multiplayer.MegaloLabel == "inv_vehicle") + entry.PaletteIndex = -1; } CullNewObjects(scenario.VehiclePalette, scenario.Vehicles, reachObjectives); @@ -481,6 +493,16 @@ private void PreConvertReachDefinition(object definition, Stream blamCacheStream RemoveNullPlacements(scenario.SceneryPalette, scenario.Scenery); RemoveNullPlacements(scenario.CratePalette, scenario.Crates); + + // remove unsupported healthpack controls + if (BlamCache.TagCache.TryGetCachedTag("objects\\levels\\shared\\device_controls\\health_station\\health_station.ctrl", out CachedTag healthCtrl)) + { + short index = (short)scenario.ControlPalette.FindIndex(e => e.Object == healthCtrl); + if (index != -1) + scenario.ControlPalette[index].Object = null; + + RemoveNullPlacements(scenario.ControlPalette, scenario.Controls); + } } //if (definition is SkyAtmParameters skya) @@ -605,8 +627,22 @@ public void ReplaceObjects(List palette, Dictiona string name = block.Object.Name; if (replacements.TryGetValue(name, out string result)) block.Object.Name = result; - else if (name.EndsWith("weak_anti_respawn_zone") || name.EndsWith("weak_respawn_zone") || name.EndsWith("danger_zone")) + + if (name.Contains("spawning\\fireteam")) block.Object = null; + + switch(name) + { + case "objects\\multi\\boundaries\\soft_kill_volume": + BlamCache.TagCache.TryGetCachedTag("objects\\multi\\boundaries\\kill_volume.scen", out block.Object); + break; + case "objects\\multi\\boundaries\\safe_volume": + case "objects\\multi\\boundaries\\soft_safe_volume": + case "objects\\multi\\named_location_area\\named_location_area": + case "objects\\multi\\spawning\\danger_zone": + block.Object = null; + break; + } } } } @@ -617,13 +653,13 @@ public void RemoveNullPlacements(List palette, { List indices = new List(); - foreach (Scenario.ScenarioPaletteEntry block in palette) - if (block.Object == null) - foreach (var instance in instanceList) - { - if (!(instance is Scenario.EquipmentInstance) && (instance as Scenario.PermutationInstance).PaletteIndex == palette.IndexOf(block)) - indices.Add(instanceList.IndexOf(instance)); - } + for (int i = 0; i < instanceList.Count; i++) + { + var paletteIndex = (instanceList[i] as Scenario.ScenarioInstance).PaletteIndex; + if (paletteIndex == -1 || palette[paletteIndex].Object == null) + indices.Add(i); + } + indices.Sort(); indices.Reverse(); @@ -1747,19 +1783,17 @@ public object ConvertData(Stream cacheStream, Stream blamCacheStream, Dictionary case "stockpile": scnrObj.EngineFlags |= GameEngineSubTypeFlags.Vip; break; - case "ffa_only": - case "team_only": - case "hh_drop_point": - case "rally": - case "rally_flag": - case "race_flag": - case "race_spawn": - case "as_spawn": - case "none": - break; + //case "ffa_only": + //case "team_only": + //case "hh_drop_point": + //case "rally": + //case "rally_flag": + //case "race_flag": + //case "race_spawn": + //case "as_spawn": + //case "none": + // break; default: - //if (!string.IsNullOrEmpty(scnrObj.MegaloLabel)) - // new TagToolWarning($"unknown megalo label: {scnrObj.MegaloLabel}"); break; } diff --git a/TagTool/Geometry/BspCollisionGeometry/InstancedGeometry.cs b/TagTool/Geometry/BspCollisionGeometry/InstancedGeometry.cs index 7f59a6e1..55a011a7 100644 --- a/TagTool/Geometry/BspCollisionGeometry/InstancedGeometry.cs +++ b/TagTool/Geometry/BspCollisionGeometry/InstancedGeometry.cs @@ -119,9 +119,16 @@ public class InstancedGeometryInstance : TagStructure [TagField(MinVersion = CacheVersion.HaloReach)] public InstancedGeometryFlagsReach FlagsReach; + [TagField(MaxVersion = CacheVersion.HaloOnline700123)] public short LightmapTexcoordBlockIndex; - [TagField(Flags = TagFieldFlags.Padding, Length = 2)] + [TagField(Flags = TagFieldFlags.Padding, Length = 2, MaxVersion = CacheVersion.HaloOnline700123)] public byte[] Padding = new byte[2]; + + [TagField(MinVersion = CacheVersion.HaloReach)] + public short MeshIndex; + [TagField(MinVersion = CacheVersion.HaloReach)] + public short CompressionIndex; + [TagField(Length = 1, MaxVersion = CacheVersion.HaloOnline700123)] [TagField(Length = 4, MinVersion = CacheVersion.HaloReach)] public uint[] SeamBitVector; diff --git a/TagTool/Tags/Definitions/GameObject.cs b/TagTool/Tags/Definitions/GameObject.cs index c219ba55..9d7c94cd 100644 --- a/TagTool/Tags/Definitions/GameObject.cs +++ b/TagTool/Tags/Definitions/GameObject.cs @@ -465,7 +465,6 @@ public enum MultiplayerObjectFlagsReach : ushort ValidInitialPlayerSpawn = 1 << 2, FixedBoundaryOrientation = 1 << 3, CandyMonitorShouldIgnore = 1 << 4, - Bit4 = 1 << 4, Bit5 = 1 << 5, Bit6 = 1 << 6, Bit7 = 1 << 7,