using System;
using System.Linq;
using System.IO;
using FSO.Files.Utils;
namespace FSO.Files.Formats.IFF.Chunks
{
///
/// Type of OBJD.
///
[Serializable()]
public enum OBJDType
{
Unknown = 0,
//Character or NPC
Person = 2,
//Buyable objects
Normal = 4,
//Roaches, Stoves2, TrClownGen, AnimTester, HelpSystem, JobFinder, NPCController, Stoves,
//Tutorial, VisitGenerator, phonecall, unsnacker, CCPhonePlugin, EStove
SimType = 7,
//Stairs, doors, pool diving board & ladder, windows(?)
Portal = 8,
Cursor = 9,
PrizeToken = 10,
//Temporary location for drop or shoo
Internal = 11,
//these are mysteriously set as global sometimes.
GiftToken = 12,
Food = 34
}
///
/// This is an object definition, the main chunk for an object and the first loaded by the VM.
/// There can be multiple master OBJDs in an IFF, meaning that one IFF file can define multiple objects.
///
public class OBJD : IffChunk
{
public uint Version;
public static string[] VERSION_142_Fields = new string[]
{
"StackSize",
"BaseGraphicID",
"NumGraphics",
"BHAV_MainID",
"BHAV_GardeningID",
"TreeTableID",
"InteractionGroupID",
"ObjectType",
"MasterID",
"SubIndex",
"BHAV_WashHandsID",
"AnimationTableID",
"GUID1",
"GUID2",
"Disabled",
"BHAV_Portal",
"Price",
"BodyStringID",
"SlotID",
"BHAV_AllowIntersectionID",
"UsesFnTable",
"BitField1",
"BHAV_PrepareFoodID",
"BHAV_CookFoodID",
"BHAV_PlaceSurfaceID",
"BHAV_DisposeID",
"BHAV_EatID",
"BHAV_PickupFromSlotID",
"BHAV_WashDishID",
"BHAV_EatSurfaceID",
"BHAV_SitID",
"BHAV_StandID",
"SalePrice",
"InitialDepreciation",
"DailyDepreciation",
"SelfDepreciating",
"DepreciationLimit",
"RoomFlags",
"FunctionFlags",
"CatalogStringsID",
"Global",
"BHAV_Init",
"BHAV_Place",
"BHAV_UserPickup",
"WallStyle",
"BHAV_Load",
"BHAV_UserPlace",
"ObjectVersion",
"BHAV_RoomChange",
"MotiveEffectsID",
"BHAV_Cleanup",
"BHAV_LevelInfo",
"CatalogID",
"BHAV_ServingSurface",
"LevelOffset",
"Shadow",
"NumAttributes",
"BHAV_Clean",
"BHAV_QueueSkipped",
"FrontDirection",
"BHAV_WallAdjacencyChanged",
"MyLeadObject",
"DynamicSpriteBaseId",
"NumDynamicSprites",
"ChairEntryFlags",
"TileWidth",
"LotCategories",
"BuildModeType",
"OriginalGUID1",
"OriginalGUID2",
"SuitGUID1",
"SuitGUID2",
"BHAV_Pickup",
"ThumbnailGraphic",
"ShadowFlags",
"FootprintMask",
"BHAV_DynamicMultiTileUpdate",
"ShadowBrightness",
"BHAV_Repair",
"WallStyleSpriteID",
"RatingHunger",
"RatingComfort",
"RatingHygiene",
"RatingBladder",
"RatingEnergy",
"RatingFun",
"RatingRoom",
"RatingSkillFlags",
"NumTypeAttributes",
"MiscFlags",
"TypeAttrGUID1",
"TypeAttrGUID2"
};
public static string[] VERSION_138b_Extra_Fields = new string[]
{
"FunctionSubsort",
"DTSubsort",
"KeepBuying",
"VacationSubsort",
"ResetLotAction",
"CommunitySubsort",
"DreamFlags",
"RenderFlags",
"VitaboyFlags",
"STSubsort",
"MTSubsort"
};
public ushort GUID1
{
get { return (ushort)(GUID); }
set { GUID = (GUID & 0xFFFF0000) | value; }
}
public ushort GUID2
{
get { return (ushort)(GUID>>16); }
set { GUID = (GUID & 0x0000FFFF) | ((uint)value<<16); }
}
public ushort StackSize { get; set; }
public ushort BaseGraphicID { get; set; }
public ushort NumGraphics { get; set; }
public ushort TreeTableID { get; set; }
public short InteractionGroupID { get; set; }
public OBJDType ObjectType { get; set; }
public ushort MasterID { get; set; }
public short SubIndex { get; set; }
public ushort AnimationTableID { get; set; }
public uint GUID { get; set; }
public ushort Disabled { get; set; }
public ushort BHAV_Portal { get; set; }
public ushort Price { get; set; }
public ushort BodyStringID { get; set; }
public ushort SlotID { get; set; }
public ushort SalePrice { get; set; }
public ushort InitialDepreciation { get; set; }
public ushort DailyDepreciation { get; set; }
public ushort SelfDepreciating { get; set; }
public ushort DepreciationLimit { get; set; }
public ushort RoomFlags { get; set; }
public ushort FunctionFlags { get; set; }
public ushort CatalogStringsID { get; set; }
public ushort BHAV_MainID { get; set; }
public ushort BHAV_GardeningID { get; set; }
public ushort BHAV_WashHandsID { get; set; }
public ushort BHAV_AllowIntersectionID { get; set; }
public ushort UsesFnTable { get; set; }
public ushort BitField1 { get; set; }
public ushort BHAV_PrepareFoodID { get; set; }
public ushort BHAV_CookFoodID { get; set; }
public ushort BHAV_PlaceSurfaceID { get; set; }
public ushort BHAV_DisposeID { get; set; }
public ushort BHAV_EatID { get; set; }
public ushort BHAV_PickupFromSlotID { get; set; }
public ushort BHAV_WashDishID { get; set; }
public ushort BHAV_EatSurfaceID { get; set; }
public ushort BHAV_SitID { get; set; }
public ushort BHAV_StandID { get; set; }
public ushort Global { get; set; }
public ushort BHAV_Init { get; set; }
public ushort BHAV_Place { get; set; }
public ushort BHAV_UserPickup { get; set; }
public ushort WallStyle { get; set; }
public ushort BHAV_Load { get; set; }
public ushort BHAV_UserPlace { get; set; }
public ushort ObjectVersion { get; set; }
public ushort BHAV_RoomChange { get; set; }
public ushort MotiveEffectsID { get; set; }
public ushort BHAV_Cleanup { get; set; }
public ushort BHAV_LevelInfo { get; set; }
public ushort CatalogID { get; set; }
public ushort BHAV_ServingSurface { get; set; }
public ushort LevelOffset { get; set; }
public ushort Shadow { get; set; }
public ushort NumAttributes { get; set; }
public ushort BHAV_Clean { get; set; }
public ushort BHAV_QueueSkipped { get; set; }
public ushort FrontDirection { get; set; }
public ushort BHAV_WallAdjacencyChanged { get; set; }
public ushort MyLeadObject { get; set; }
public ushort DynamicSpriteBaseId { get; set; }
public ushort NumDynamicSprites { get; set; }
public ushort ChairEntryFlags { get; set; }
public ushort TileWidth { get; set; }
public ushort LotCategories { get; set; }
public ushort BuildModeType { get; set; }
public ushort OriginalGUID1 { get; set; }
public ushort OriginalGUID2 { get; set; }
public ushort SuitGUID1 { get; set; }
public ushort SuitGUID2 { get; set; }
public ushort BHAV_Pickup { get; set; }
public ushort ThumbnailGraphic { get; set; }
public ushort ShadowFlags { get; set; }
public ushort FootprintMask { get; set; }
public ushort BHAV_DynamicMultiTileUpdate { get; set; }
public ushort ShadowBrightness { get; set; }
public ushort BHAV_Repair { get; set; }
public ushort WallStyleSpriteID { get; set; }
public short RatingHunger { get; set; }
public short RatingComfort { get; set; }
public short RatingHygiene { get; set; }
public short RatingBladder { get; set; }
public short RatingEnergy { get; set; }
public short RatingFun { get; set; }
public short RatingRoom { get; set; }
public ushort RatingSkillFlags { get; set; }
public ushort[] RawData;
public ushort NumTypeAttributes { get; set; }
public ushort MiscFlags { get; set; }
public uint TypeAttrGUID;
public ushort FunctionSubsort { get; set; }
public ushort DTSubsort { get; set; }
public ushort KeepBuying { get; set; }
public ushort VacationSubsort { get; set; }
public ushort ResetLotAction { get; set; }
public ushort CommunitySubsort { get; set; }
public ushort DreamFlags { get; set; }
public ushort RenderFlags { get; set; }
public ushort VitaboyFlags { get; set; }
public ushort STSubsort { get; set; }
public ushort MTSubsort { get; set; }
public ushort FootprintNorth
{
get
{
return (ushort)(FootprintMask & 0xF);
}
set
{
FootprintMask &= 0xFFF0;
FootprintMask |= (ushort)(value & 0xF);
}
}
public ushort FootprintEast
{
get
{
return (ushort)((FootprintMask >> 4) & 0xF);
}
set
{
FootprintMask &= 0xFF0F;
FootprintMask |= (ushort)((value & 0xF) << 4);
}
}
public ushort FootprintSouth
{
get
{
return (ushort)((FootprintMask >> 8) & 0xF);
}
set
{
FootprintMask &= 0xF0FF;
FootprintMask |= (ushort)((value & 0xF) << 8);
}
}
public ushort FootprintWest
{
get
{
return (ushort)((FootprintMask >> 12) & 0xF);
}
set
{
FootprintMask &= 0x0FFF;
FootprintMask |= (ushort)((value & 0xF) << 12);
}
}
public ushort TypeAttrGUID1
{
get { return (ushort)(TypeAttrGUID); }
set { TypeAttrGUID = (TypeAttrGUID & 0xFFFF0000) | value; }
}
public ushort TypeAttrGUID2
{
get { return (ushort)(TypeAttrGUID >> 16); }
set { TypeAttrGUID = (TypeAttrGUID & 0x0000FFFF) | ((uint)value << 16); }
}
public bool IsMaster
{
get
{
return SubIndex == -1;
}
}
public bool IsMultiTile
{
get {
return MasterID != 0;
}
}
public T GetPropertyByName(string name)
{
Type me = typeof(OBJD);
var prop = me.GetProperty(name);
return (T)Convert.ChangeType(prop.GetValue(this, null), typeof(T));
}
public void SetPropertyByName(string name, object value)
{
Type me = typeof(OBJD);
var prop = me.GetProperty(name);
try
{
value = Convert.ChangeType(value, prop.PropertyType);
} catch {
value = Enum.Parse(prop.PropertyType, value.ToString());
}
prop.SetValue(this, value, null);
}
public override void Read(IffFile iff, Stream stream)
{
using (var io = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN))
{
this.Version = io.ReadUInt32();
/**136 (80 fields)
138a (95 fields) - Used for The Sims 1 base game objects?
138b (108 fields) - Used for The Sims 1 expansion objects?
139 (96 fields)
140 (97 fields)
141 (97 fields)
142 (105 fields)**/
var numFields = 80;
if (Version == 138)
{
numFields = 95;
}
else if (Version == 139)
{
numFields = 96;
}
else if (Version == 140)
{
numFields = 97;
}
else if (Version == 141)
{
numFields = 97;
}
else if (Version == 142)
{
numFields = 105;
}
numFields -= 2;
RawData = new ushort[numFields];
io.Mark();
for (var i = 0; i < numFields; i++)
{
RawData[i] = io.ReadUInt16();
}
io.SeekFromMark(0);
this.StackSize = io.ReadUInt16();
this.BaseGraphicID = io.ReadUInt16();
this.NumGraphics = io.ReadUInt16();
this.BHAV_MainID = io.ReadUInt16();
this.BHAV_GardeningID = io.ReadUInt16();
this.TreeTableID = io.ReadUInt16();
this.InteractionGroupID = io.ReadInt16();
this.ObjectType = (OBJDType)io.ReadUInt16();
this.MasterID = io.ReadUInt16();
this.SubIndex = io.ReadInt16();
this.BHAV_WashHandsID = io.ReadUInt16();
this.AnimationTableID = io.ReadUInt16();
this.GUID = io.ReadUInt32();
this.Disabled = io.ReadUInt16();
this.BHAV_Portal = io.ReadUInt16();
this.Price = io.ReadUInt16();
this.BodyStringID = io.ReadUInt16();
this.SlotID = io.ReadUInt16();
this.BHAV_AllowIntersectionID = io.ReadUInt16();
this.UsesFnTable = io.ReadUInt16();
this.BitField1 = io.ReadUInt16();
this.BHAV_PrepareFoodID = io.ReadUInt16();
this.BHAV_CookFoodID = io.ReadUInt16();
this.BHAV_PlaceSurfaceID = io.ReadUInt16();
this.BHAV_DisposeID = io.ReadUInt16();
this.BHAV_EatID = io.ReadUInt16();
this.BHAV_PickupFromSlotID = io.ReadUInt16();
this.BHAV_WashDishID = io.ReadUInt16();
this.BHAV_EatSurfaceID = io.ReadUInt16();
this.BHAV_SitID = io.ReadUInt16();
this.BHAV_StandID = io.ReadUInt16();
this.SalePrice = io.ReadUInt16();
this.InitialDepreciation = io.ReadUInt16();
this.DailyDepreciation = io.ReadUInt16();
this.SelfDepreciating = io.ReadUInt16();
this.DepreciationLimit = io.ReadUInt16();
this.RoomFlags = io.ReadUInt16();
this.FunctionFlags = io.ReadUInt16();
this.CatalogStringsID = io.ReadUInt16();
this.Global = io.ReadUInt16();
this.BHAV_Init = io.ReadUInt16();
this.BHAV_Place = io.ReadUInt16();
this.BHAV_UserPickup = io.ReadUInt16();
this.WallStyle = io.ReadUInt16();
this.BHAV_Load = io.ReadUInt16();
this.BHAV_UserPlace = io.ReadUInt16();
this.ObjectVersion = io.ReadUInt16();
this.BHAV_RoomChange = io.ReadUInt16();
this.MotiveEffectsID = io.ReadUInt16();
this.BHAV_Cleanup = io.ReadUInt16();
this.BHAV_LevelInfo = io.ReadUInt16();
this.CatalogID = io.ReadUInt16();
this.BHAV_ServingSurface = io.ReadUInt16();
this.LevelOffset = io.ReadUInt16();
this.Shadow = io.ReadUInt16();
this.NumAttributes = io.ReadUInt16();
this.BHAV_Clean = io.ReadUInt16();
this.BHAV_QueueSkipped = io.ReadUInt16();
this.FrontDirection = io.ReadUInt16();
this.BHAV_WallAdjacencyChanged = io.ReadUInt16();
this.MyLeadObject = io.ReadUInt16();
this.DynamicSpriteBaseId = io.ReadUInt16();
this.NumDynamicSprites = io.ReadUInt16();
this.ChairEntryFlags = io.ReadUInt16();
this.TileWidth = io.ReadUInt16();
this.LotCategories = io.ReadUInt16();
this.BuildModeType = io.ReadUInt16();
this.OriginalGUID1 = io.ReadUInt16();
this.OriginalGUID2 = io.ReadUInt16();
this.SuitGUID1 = io.ReadUInt16();
this.SuitGUID2 = io.ReadUInt16();
this.BHAV_Pickup = io.ReadUInt16();
this.ThumbnailGraphic = io.ReadUInt16();
this.ShadowFlags = io.ReadUInt16();
this.FootprintMask = io.ReadUInt16();
this.BHAV_DynamicMultiTileUpdate = io.ReadUInt16();
this.ShadowBrightness = io.ReadUInt16();
if (numFields > 78)
{
this.BHAV_Repair = io.ReadUInt16();
this.WallStyleSpriteID = io.ReadUInt16();
this.RatingHunger = io.ReadInt16();
this.RatingComfort = io.ReadInt16();
this.RatingHygiene = io.ReadInt16();
this.RatingBladder = io.ReadInt16();
this.RatingEnergy = io.ReadInt16();
this.RatingFun = io.ReadInt16();
this.RatingRoom = io.ReadInt16();
this.RatingSkillFlags = io.ReadUInt16();
if (numFields > 90)
{
this.NumTypeAttributes = io.ReadUInt16();
this.MiscFlags = io.ReadUInt16();
this.TypeAttrGUID = io.ReadUInt32();
try
{
this.FunctionSubsort = io.ReadUInt16();
this.DTSubsort = io.ReadUInt16();
this.KeepBuying = io.ReadUInt16();
this.VacationSubsort = io.ReadUInt16();
this.ResetLotAction = io.ReadUInt16();
this.CommunitySubsort = io.ReadUInt16();
this.DreamFlags = io.ReadUInt16();
this.RenderFlags = io.ReadUInt16();
this.VitaboyFlags = io.ReadUInt16();
this.STSubsort = io.ReadUInt16();
this.MTSubsort = io.ReadUInt16();
} catch (Exception)
{
//past this point if these fields are here is really a mystery
}
}
if (this.TypeAttrGUID == 0) this.TypeAttrGUID = GUID;
}
}
}
public override bool Write(IffFile iff, Stream stream)
{
using (var io = IoWriter.FromStream(stream, ByteOrder.LITTLE_ENDIAN))
{
if (IffFile.TargetTS1)
{
//version 138
io.WriteUInt32(138);
var fields = VERSION_142_Fields.Concat(VERSION_138b_Extra_Fields);
foreach (var prop in fields)
{
io.WriteUInt16((ushort)GetPropertyByName(prop));
}
for (int i = fields.Count(); i < 108; i++)
{
io.WriteUInt16(0);
}
}
else
{
//tso version 142
io.WriteUInt32(142);
foreach (var prop in VERSION_142_Fields)
{
io.WriteUInt16((ushort)GetPropertyByName(prop));
}
for (int i = VERSION_142_Fields.Length; i < 105; i++)
{
io.WriteUInt16(0);
}
}
}
return true;
}
}
}