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);
}
}
}
}
}