using FSO.Files.Utils; using System.Collections.Generic; using System.IO; using System.Linq; namespace FSO.Files.Formats.IFF.Chunks { /// /// This chunk defines all neighbours in a neighbourhood. /// A neighbour is a specific version of a sim object with associated relationships and person data. (skills, person type) /// /// These can be read within SimAntics without the avatar actually present. This is used to find and spawn suitable sims on /// ped portals as visitors, and also drive phone calls to other sims in the neighbourhood. /// When neighbours are spawned, they assume the attributes saved here. A TS1 global call allows the game to save these attributes. /// public class NBRS : IffChunk { public List Entries = new List(); public Dictionary NeighbourByID = new Dictionary(); public Dictionary DefaultNeighbourByGUID = new Dictionary(); public uint Version; /// /// Reads a NBRS chunk from a stream. /// /// An Iff instance. /// A Stream object holding a NBRS chunk. public override void Read(IffFile iff, Stream stream) { using (var io = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN)) { io.ReadUInt32(); //pad Version = io.ReadUInt32(); //0x49 for latest game string magic = io.ReadCString(4); //SRBN var count = io.ReadUInt32(); for (int i=0; i 0) { NeighbourByID.Add(neigh.NeighbourID, neigh); DefaultNeighbourByGUID[neigh.GUID] = neigh.NeighbourID; } } } Entries = Entries.OrderBy(x => x.NeighbourID).ToList(); foreach (var entry in Entries) entry.RuntimeIndex = Entries.IndexOf(entry); } /// /// Writes a NBRS chunk to a stream. /// /// An Iff instance. /// A destination stream. public override bool Write(IffFile iff, Stream stream) { using (var io = IoWriter.FromStream(stream, ByteOrder.LITTLE_ENDIAN)) { io.WriteUInt32(0); io.WriteUInt32(0x49); io.WriteCString("SRBN", 4); io.WriteInt32(Entries.Count); foreach (var n in NeighbourByID.Values) { n.Save(io); } } return true; } public void AddNeighbor(Neighbour nb) { Entries.Add(nb); Entries = Entries.OrderBy(x => x.NeighbourID).ToList(); foreach (var entry in Entries) entry.RuntimeIndex = Entries.IndexOf(entry); NeighbourByID.Add(nb.NeighbourID, nb); DefaultNeighbourByGUID[nb.GUID] = nb.NeighbourID; } public short GetFreeID() { //find the lowest id that is free short newID = 1; for (int i = 0; i < Entries.Count; i++) { if (Entries[i].NeighbourID == newID) newID++; else if (Entries[i].NeighbourID < newID) continue; else break; } return newID; } } public class Neighbour { public int Unknown1 = 1; //1 public int Version = 0xA; //0x4, 0xA //if 0xA, unknown3 follows //0x4 indicates person data size of 0xa0.. (160 bytes, or 80 entries) public int Unknown3 = 9; //9 public string Name; public int MysteryZero = 0; public int PersonMode; //0/5/9 public short[] PersonData; //can be null public short NeighbourID; public uint GUID; public int UnknownNegOne = -1; //negative 1 usually public Dictionary> Relationships; public int RuntimeIndex; //used for fast continuation of Set to Next public Neighbour() { } public Neighbour(IoBuffer io) { Unknown1 = io.ReadInt32(); if (Unknown1 != 1) { return; } Version = io.ReadInt32(); if (Version == 0xA) { //TODO: what version does this truly start? Unknown3 = io.ReadInt32(); if (Unknown3 != 9) { } } Name = io.ReadNullTerminatedString(); if (Name.Length % 2 == 0) io.ReadByte(); MysteryZero = io.ReadInt32(); if (MysteryZero != 0) { } PersonMode = io.ReadInt32(); if (PersonMode > 0) { var size = (Version == 0x4) ? 0xa0 : 0x200; PersonData = new short[88]; int pdi = 0; for (int i=0; i= 88) { io.ReadBytes(size - i); break; } PersonData[pdi++] = io.ReadInt16(); } } NeighbourID = io.ReadInt16(); GUID = io.ReadUInt32(); UnknownNegOne = io.ReadInt32(); if (UnknownNegOne != -1) { } var entries = io.ReadInt32(); Relationships = new Dictionary>(); for (int i=0; i(); var valueCount = io.ReadInt32(); for (int j=0; j 0) { var size = (Version == 0x4) ? 0xa0 : 0x200; int pdi = 0; for (int i = 0; i < size; i += 2) { if (pdi >= 88) { io.WriteInt16(0); } else { io.WriteInt16(PersonData[pdi++]); } } } io.WriteInt16(NeighbourID); io.WriteUInt32(GUID); io.WriteInt32(UnknownNegOne); io.WriteInt32(Relationships.Count); foreach (var rel in Relationships) { io.WriteInt32(1); //keycount (1) io.WriteInt32(rel.Key); io.WriteInt32(rel.Value.Count); foreach (var val in rel.Value) { io.WriteInt32(val); } } } } }