public static NPCXfer FromStream(Stream mstream, ThingDb.Thing tt, short ParsingRule) { NPCXfer result = new NPCXfer(); NoxBinaryReader br = new NoxBinaryReader(mstream); result.Direction = (MonsterXfer.DirectionEncoded) br.ReadUInt64(); result.ScriptEvents = new string[10]; // Читаем имена обработчиков скриптовых событий for (int i = 0; i < 10; i++) { if (i == 2) result.DetectEventTimeout = br.ReadUInt16(); result.ScriptEvents[i] = br.ReadScriptEventString(); } // Пропуск (0) br.ReadInt32(); // цвета result.NPCColors = new Color[6]; byte R, G, B; for (int i = 0; i < 6; i++) { R = br.ReadByte(); G = br.ReadByte(); B = br.ReadByte(); result.NPCColors[i] = Color.FromArgb(R, G, B); } // основной блок инфы if (ParsingRule >= 32) { result.ActionRoamPathFlag = br.ReadByte(); if (ParsingRule < 49) result.StatusFlags = (NoxEnums.MonsterStatus) br.ReadUInt16(); else result.StatusFlags = (NoxEnums.MonsterStatus) br.ReadUInt32(); result.HealthMultiplier = br.ReadSingle(); result.RetreatRatio = br.ReadSingle(); result.ResumeRatio = br.ReadSingle(); result.SightRange = br.ReadSingle(); result.Health = br.ReadInt16(); result.Aggressiveness = br.ReadSingle(); if (ParsingRule < 35) result.DefaultAction = br.ReadInt32(); result.EscortObjName = br.ReadString(); if (ParsingRule >= 34) { int spells = br.ReadInt32(); result.KnownSpells = new List<MonsterXfer.SpellEntry>(); string spellName = null; uint spellFlags = 0; for (int i = 0; i < spells; i++) { spellName = br.ReadString(); spellFlags = br.ReadUInt32(); if (ThingDb.thingdb.Spells.Keys.Contains(spellName)) result.KnownSpells.Add(new MonsterXfer.SpellEntry(spellName, spellFlags)); } } else br.BaseStream.Seek(0x224, SeekOrigin.Current); // Задержки между заклинаниями if (ParsingRule < 47) { result.ReactionCastingDelayMin = (ushort) br.ReadByte(); result.ReactionCastingDelayMax = (ushort) br.ReadByte(); if (ParsingRule <= 32) br.ReadInt32(); result.BuffCastingDelayMin = (ushort) br.ReadByte(); result.BuffCastingDelayMax = (ushort) br.ReadByte(); if (ParsingRule <= 32) br.ReadInt32(); result.DebuffCastingDelayMin = (ushort) br.ReadByte(); result.DebuffCastingDelayMax = (ushort) br.ReadByte(); if (ParsingRule <= 32) br.ReadInt32(); result.OffensiveCastingDelayMin = (ushort) br.ReadByte(); result.OffensiveCastingDelayMax = (ushort) br.ReadByte(); if (ParsingRule <= 32) br.ReadInt32(); result.BlinkCastingDelayMin = (ushort) br.ReadByte(); result.BlinkCastingDelayMax = (ushort) br.ReadByte(); if (ParsingRule <= 32) br.ReadInt32(); } else { result.ReactionCastingDelayMin = br.ReadUInt16(); result.ReactionCastingDelayMax = br.ReadUInt16(); result.BuffCastingDelayMin = br.ReadUInt16(); result.BuffCastingDelayMax = br.ReadUInt16(); result.DebuffCastingDelayMin = br.ReadUInt16(); result.DebuffCastingDelayMax = br.ReadUInt16(); result.OffensiveCastingDelayMin = br.ReadUInt16(); result.OffensiveCastingDelayMax = br.ReadUInt16(); result.BlinkCastingDelayMin = br.ReadUInt16(); result.BlinkCastingDelayMax = br.ReadUInt16(); } if (ParsingRule < 34) result.MagicNumber = br.ReadUInt32(); if (ParsingRule >= 33) result.LockPathDistance = br.ReadSingle(); if (ParsingRule >= 34) { result.SpellPowerLevel = br.ReadInt32(); result.NPCStrength = br.ReadByte(); result.NPCSpeed = br.ReadSingle(); result.AimSkillLevel = br.ReadSingle(); if (ParsingRule < 42) { if (br.ReadInt16() == 0) result.Immortal = true; } result.TrapSpell1 = br.ReadString(); result.TrapSpell2 = br.ReadString(); result.TrapSpell3 = br.ReadString(); } if (ParsingRule >= 35) { string action = br.ReadString(); result.DefaultAction = Array.IndexOf(NoxEnums.AIActionStrings, action); } if (ParsingRule >= 41) { // здесь придётся читать просто огромное кол-во инфы // однако она используется очень редко, обычно entryType = 4; forced = 0 short entryType = br.ReadInt16(); if (entryType <= 4) { byte forced = 1; if (entryType >= 2) forced = br.ReadByte(); if (forced == 1 || entryType < 2) { return result; // TODO для ПОЛНОЙ совместимости, придётся } } } if (ParsingRule >= 42) result.Immortal = br.ReadBoolean(); if (ParsingRule >= 44) result.MagicNumber = br.ReadUInt32(); if (ParsingRule >= 45) result.MaxHealth = (short) br.ReadInt32(); if (ParsingRule >= 46) result.AddedSubclass = br.ReadUInt32(); if (ParsingRule >= 48) result.Health = br.ReadInt16(); if (ParsingRule >= 51) result.Experience = br.ReadSingle(); if (ParsingRule >= 52) result.NPCVoiceSet = br.ReadString(); if (ParsingRule < 61) return result; // энчанты short buffsType = br.ReadInt16(); if (buffsType > 2 || buffsType <= 0) return result; byte count = br.ReadByte(); result.BuffList = new MonsterXfer.BuffEntry[count]; while (count > 0) { MonsterXfer.BuffEntry be = new MonsterXfer.BuffEntry(); be.Name = br.ReadString(); be.Power = br.ReadByte(); be.Duration = br.ReadInt32(); if (be.Name == ENCHANT_SHIELD && buffsType >= 2) be.ShieldHealth = br.ReadInt32(); result.BuffList[count] = be; count--; } Array.Reverse(result.BuffList); if (ParsingRule >= 62) result.PoisonLevel = br.ReadByte(); } return result; }
public static MonsterXfer FromStream(Stream mstream, ThingDb.Thing tt, short ParsingRule) { MonsterXfer result = new MonsterXfer(); NoxBinaryReader br = new NoxBinaryReader(mstream); result.Direction = (DirectionEncoded) br.ReadUInt64(); result.ScriptEvents = new string[10]; // Читаем имена обработчиков скриптовых событий for (int i = 0; i < 10; i++) { if (i == 2) result.DetectEventTimeout = br.ReadUInt16(); result.ScriptEvents[i] = br.ReadScriptEventString(); } // Пропуск (0) if (ParsingRule >= 11) br.ReadInt32(); if (ParsingRule >= 31) { result.ActionRoamPathFlag = br.ReadByte(); if (ParsingRule < 51) result.StatusFlags = (NoxEnums.MonsterStatus) br.ReadUInt16(); else result.StatusFlags = (NoxEnums.MonsterStatus) br.ReadUInt32(); result.HealthMultiplier = br.ReadSingle(); result.RetreatRatio = br.ReadSingle(); result.ResumeRatio = br.ReadSingle(); result.SightRange = br.ReadSingle(); if (ParsingRule < 33) br.BaseStream.Seek(2, SeekOrigin.Current); result.Aggressiveness = br.ReadSingle(); if (ParsingRule < 34) result.DefaultAction = br.ReadInt32(); result.EscortObjName = br.ReadString(); if (ParsingRule >= 34) { int spells = br.ReadInt32(); result.KnownSpells = new List<SpellEntry>(); string spellName = null; uint spellFlags = 0; for (int i = 0; i < spells; i++) { spellName = br.ReadString(); spellFlags = br.ReadUInt32(); if (ThingDb.thingdb.Spells.Keys.Contains(spellName)) result.KnownSpells.Add(new SpellEntry(spellName, spellFlags)); } } else br.BaseStream.Seek(0x224, SeekOrigin.Current); // Задержки между заклинаниями if (ParsingRule < 46) { result.ReactionCastingDelayMin = (ushort) br.ReadByte(); result.ReactionCastingDelayMax = (ushort) br.ReadByte(); if (ParsingRule <= 32) br.ReadInt32(); result.BuffCastingDelayMin = (ushort) br.ReadByte(); result.BuffCastingDelayMax = (ushort) br.ReadByte(); if (ParsingRule <= 32) br.ReadInt32(); result.DebuffCastingDelayMin = (ushort) br.ReadByte(); result.DebuffCastingDelayMax = (ushort) br.ReadByte(); if (ParsingRule <= 32) br.ReadInt32(); result.OffensiveCastingDelayMin = (ushort) br.ReadByte(); result.OffensiveCastingDelayMax = (ushort) br.ReadByte(); if (ParsingRule <= 32) br.ReadInt32(); result.BlinkCastingDelayMin = (ushort) br.ReadByte(); result.BlinkCastingDelayMax = (ushort) br.ReadByte(); if (ParsingRule <= 32) br.ReadInt32(); } else { result.ReactionCastingDelayMin = br.ReadUInt16(); result.ReactionCastingDelayMax = br.ReadUInt16(); result.BuffCastingDelayMin = br.ReadUInt16(); result.BuffCastingDelayMax = br.ReadUInt16(); result.DebuffCastingDelayMin = br.ReadUInt16(); result.DebuffCastingDelayMax = br.ReadUInt16(); result.OffensiveCastingDelayMin = br.ReadUInt16(); result.OffensiveCastingDelayMax = br.ReadUInt16(); result.BlinkCastingDelayMin = br.ReadUInt16(); result.BlinkCastingDelayMax = br.ReadUInt16(); } if (ParsingRule > 32) result.LockPathDistance = br.ReadSingle(); if (ParsingRule >= 33) { result.SpellPowerLevel = br.ReadInt32(); result.AimSkillLevel = br.ReadSingle(); if (ParsingRule < 42) { if (br.ReadInt16() == 0) result.Immortal = true; } if (ParsingRule < 53) { int spellIndex = br.ReadInt32(); result.TrapSpell1 = ThingDb.thingdb.Spells.Values[spellIndex].Name; spellIndex = br.ReadInt32(); result.TrapSpell2 = ThingDb.thingdb.Spells.Values[spellIndex].Name; spellIndex = br.ReadInt32(); result.TrapSpell3 = ThingDb.thingdb.Spells.Values[spellIndex].Name; } else { result.TrapSpell1 = br.ReadString(); result.TrapSpell2 = br.ReadString(); result.TrapSpell3 = br.ReadString(); } } if (ParsingRule >= 34) { string action = br.ReadString(); result.DefaultAction = Array.IndexOf(NoxEnums.AIActionStrings, action); } if (ParsingRule >= 41) { // здесь придётся читать просто огромное кол-во инфы // однако она используется очень редко, обычно entryType = 4; forced = 0 short entryType = br.ReadInt16(); if (entryType <= 4) { byte forced = 1; if (entryType >= 2) forced = br.ReadByte(); if (forced == 1 || entryType < 2) { return result; // TODO для ПОЛНОЙ совместимости, придётся } } } if (ParsingRule >= 42) { result.Immortal = br.ReadBoolean(); } if (ParsingRule >= 43 && tt.Subclass[(int) ThingDb.Thing.SubclassBitIndex.SHOPKEEPER]) { // Информация о содержании магазина ShopkeeperInfoStruct si = new ShopkeeperInfoStruct(); if (ParsingRule >= 50) si.BuyValueMultiplier = br.ReadSingle(); if (ParsingRule >= 61) si.SellValueMultiplier = br.ReadSingle(); if (ParsingRule >= 48) si.ShopkeeperGreetingText = br.ReadString(); byte items = br.ReadByte(); si.ShopItems = new ShopItemInfo[items]; for (int i = 0; i < items; i++) { ShopItemInfo item = new ShopItemInfo(); if (ParsingRule < 50) br.ReadInt32(); item.Count = br.ReadByte(); item.Name = br.ReadString(); if (ParsingRule >= 47) { item.SpellID = br.ReadString(); item.Ench1 = br.ReadString(); item.Ench2 = br.ReadString(); item.Ench3 = br.ReadString(); item.Ench4 = br.ReadString(); } si.ShopItems[i] = item; } result.ShopkeeperInfo = si; } if (ParsingRule >= 44) result.MagicNumber = br.ReadUInt32(); if (ParsingRule >= 45) result.AddedSubclass = br.ReadUInt32(); if (ParsingRule >= 49) result.Health = br.ReadInt16(); if (ParsingRule >= 51) { result.SetDefaultResumeRatio = br.ReadBoolean(); result.SetDefaultRetreatRatio = br.ReadBoolean(); result.SetDefaultMonsterStatus = br.ReadBoolean(); result.LearnDefaultSpells = br.ReadBoolean(); } if (ParsingRule >= 54 && tt.Subclass[(int) ThingDb.Thing.SubclassBitIndex.FEMALE_NPC]) { result.MaidenBodyColors = new Color[6]; byte R, G, B; for (int i = 0; i < 6; i++) { R = br.ReadByte(); G = br.ReadByte(); B = br.ReadByte(); result.MaidenBodyColors[i] = Color.FromArgb(R, G, B); } if (ParsingRule >= 55) result.MaidenVoiceSet = br.ReadString(); } if (ParsingRule >= 62) { short entryType = br.ReadInt16(); if (entryType > 2 || entryType <= 0) return result; byte count = br.ReadByte(); result.BuffList = new BuffEntry[count]; while (count > 0) { BuffEntry be = new BuffEntry(); be.Name = br.ReadString(); be.Power = br.ReadByte(); be.Duration = br.ReadInt32(); if (be.Name == ENCHANT_SHIELD && entryType >= 2) be.ShieldHealth = br.ReadInt32(); result.BuffList[count] = be; count--; } Array.Reverse(result.BuffList); } if (ParsingRule >= 63 && tt.Subclass[(int) ThingDb.Thing.SubclassBitIndex.WOUNDED_NPC]) result.WoundedNPCVoiceSet = br.ReadString(); if (ParsingRule >= 64) result.PoisonLevel = br.ReadByte(); } return result; }
public static ThingDb thingdb; //stupid hack public ThingDb() { thingdb = this; dbFile = "thing.bin"; NoxBinaryReader rdr = new NoxBinaryReader(GetStream(), CryptApi.NoxCryptFormat.THING); int floorId = 0, edgeId = 0, wallId = 0; for (ThingToken token = NextToken(rdr); Enum.IsDefined(typeof(ThingToken), token); token = NextToken(rdr)) { if (token == ThingToken.FLOR) { Tile tile = new Tile(rdr.BaseStream); tile.Id = floorId++; FloorTiles.Add(tile); } else if (token == ThingToken.EDGE) { Tile tile = new Tile(rdr.BaseStream); tile.Id = edgeId++; EdgeTiles.Add(tile); } else if (token == ThingToken.WALL) { Wall wall = new Wall(rdr.BaseStream); wall.Id = wallId++; Walls.Add(wall); } else if (token == ThingToken.AUD) ReadEntries(rdr); else if (token == ThingToken.AVNT) { Avnt avnt = new Avnt(rdr.BaseStream); Avnts.Add(avnt.Name, avnt); } else if (token == ThingToken.SPEL) ReadEntries(rdr); else if (token == ThingToken.ABIL) ReadEntries(rdr); else if (token == ThingToken.IMAG) ReadEntries(rdr); else if (token == ThingToken.THNG) { Thing thing = new Thing(rdr.BaseStream); if (!Things.ContainsKey(thing.Name))//there are a few duplicates, but they seem to be identical Things.Add(thing.Name, thing); } else Debug.Fail("Encountered unkown token while reading thing.bin"); } Debug.Assert(rdr.BaseStream.Length - rdr.BaseStream.Position < 8, "Error reading thing.bin", "Could not parse entire file"); }
static void Main(string[] args) { while (true) { Console.WriteLine("Export:"); Console.WriteLine("A - Export ThingDB"); Console.WriteLine("M - Export Maps"); Console.WriteLine("X - Export Tiles"); Console.WriteLine("P - Export TileEdges"); Console.WriteLine("Y - Export Walls"); Console.WriteLine("L - Export Sequences"); Console.WriteLine("U - Export Objects"); Console.WriteLine("B - Export OtherImages"); Console.WriteLine("I - Export Audio"); Console.WriteLine("S - Export Map Scripts"); Console.WriteLine("W - Export Soundset"); Console.WriteLine("T - Export StringDB"); Console.WriteLine("E - Export MonsterDB"); Console.WriteLine("O - ModDB"); Console.WriteLine("Q - Quit"); thingdb = new ThingDb(); moddb = new ModifierDb(); bag = new VideoBag(@"C:\GOG Games\Nox\video8.bag"); ssilist = new Lexicon<uint, VideoBag.SpriteSheetInfo>(); switch (Convert.ToChar(Console.Read())) { case 'T': { var stringdb = new StringDb(); var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength = int.MaxValue; var json = jsonserialize.Serialize(stringdb); System.IO.File.WriteAllText("StringDB.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("StringDB.json", json); } break; case 'A': { var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength *= 5; var json = jsonserialize.Serialize(thingdb); System.IO.File.WriteAllText("ThingDB.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("ThingDB.json", json); } break; case 'I': { AudioBag abag = new AudioBag(NoxDb.NoxPath + "Audio.bag"); abag.ExtractAll("audio"); var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength = int.MaxValue; var json = jsonserialize.Serialize(abag); System.IO.File.WriteAllText("Audio.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("Audio.json", json); } break; case 'M': { ExportMaps(); /* Map map = new Map(@"C:\Program Files (x86)\Nox\maps\BluDeath\BluDeath.map", thingdb); var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength *= 5; var json = jsonserialize.Serialize(map); System.IO.File.WriteAllText("BlueDeath.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("BlueDeath.json", json);J*/ } break; case 'S': { ExportMapScripts(); /* Map map = new Map(@"C:\Program Files (x86)\Nox\maps\BluDeath\BluDeath.map", thingdb); var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength *= 5; var json = jsonserialize.Serialize(map); System.IO.File.WriteAllText("BlueDeath.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("BlueDeath.json", json);J*/ } break; case 'O': { var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength *= 5; var json = jsonserialize.Serialize(moddb); System.IO.File.WriteAllText("ModDB.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("ModDB.json", json); } break; case 'X': { ExportTiles(); var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength *= 5; var json = jsonserialize.Serialize(ssilist); System.IO.File.WriteAllText("TileSprites.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("TileSprites.json", json); } break; case 'P': { ExportEdgeTiles(); var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength *= 5; var json = jsonserialize.Serialize(ssilist); System.IO.File.WriteAllText("TileEdgeSprites.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("TileEdgeSprites.json", json); } break; case 'Y': { ExportWalls(); var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength *= 5; var json = jsonserialize.Serialize(ssilist); System.IO.File.WriteAllText("WallSprites.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("WallSprites.json", json); } break; case 'B': { ExportOtherSprites(); var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength *= 5; var json = jsonserialize.Serialize(ssilist); System.IO.File.WriteAllText("OtherSprites.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("OtherSprites.json", json); } break; case 'L': { ExportSequences(); var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength = int.MaxValue; var json = jsonserialize.Serialize(ssilist); System.IO.File.WriteAllText("SequenceSprites.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("SequenceSprites.json", json); } break; case 'U': { var jsonserialize = new JavaScriptSerializer(); try { string cont = System.IO.File.ReadAllText("ObjectSprites.min.json"); ssilist = jsonserialize.Deserialize<Lexicon<uint, VideoBag.SpriteSheetInfo>>(cont); } catch {} ExportObjects(); jsonserialize.MaxJsonLength *= 5; var json = jsonserialize.Serialize(ssilist); System.IO.File.WriteAllText("ObjectSprites.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("ObjectSprites.json", json); } break; case 'E': { var mdb = new MonsterDb(); mdb.LoadMonsterInfo(); var jsonserialize = new JavaScriptSerializer(); jsonserialize.MaxJsonLength *= 5; var json = jsonserialize.Serialize(mdb); System.IO.File.WriteAllText("MonsterDB.min.json", json); json = JSON_PrettyPrinter.Process(json); System.IO.File.WriteAllText("MonsterDB.json", json); } break; case 'W': { new SoundsetDb(); new GamedataDb(); } break; case 'Q': return; } } }