/// <summary> /// Creates a character record from a raw record that begins at offset 0 /// </summary> /// <param name="rawRecord"></param> public PlayerCharacterRecord(byte[] rawRecord) { Debug.Assert(rawRecord.Length == (int)CHARACTER_RECORD_BYTE_ARRAY_SIZE); List <byte> rawRecordByteList = new List <byte>(rawRecord); Name = DataChunk.CreateDataChunk(DataChunk.DataFormatType.SimpleString, "Character Name", rawRecordByteList, (int)CharacterRecordOffsets.Name, 9).GetChunkAsString(); Gender = (CharacterGender)rawRecordByteList[(int)CharacterRecordOffsets.Gender]; Class = (CharacterClass)rawRecordByteList[(int)CharacterRecordOffsets.Class]; Status = (CharacterStatus)rawRecordByteList[(int)CharacterRecordOffsets.Status]; Stats.Strength = rawRecordByteList[(int)CharacterRecordOffsets.Strength]; Stats.Dexterity = rawRecordByteList[(int)CharacterRecordOffsets.Dexterity]; Stats.Intelligence = rawRecordByteList[(int)CharacterRecordOffsets.Intelligence]; Stats.CurrentMP = rawRecordByteList[(int)CharacterRecordOffsets.CurrentMP]; Stats.CurrentHP = DataChunk.CreateDataChunk(DataChunk.DataFormatType.UINT16List, "Current hit points", rawRecordByteList, (int)CharacterRecordOffsets.CurrentHP, sizeof(UInt16)).GetChunkAsUINT16List()[0]; Stats.MaximumHP = DataChunk.CreateDataChunk(DataChunk.DataFormatType.UINT16List, "Maximum hit points", rawRecordByteList, (int)CharacterRecordOffsets.MaximimumHP, sizeof(UInt16)).GetChunkAsUINT16List()[0]; Stats.ExperiencePoints = DataChunk.CreateDataChunk(DataChunk.DataFormatType.UINT16List, "Maximum hit points", rawRecordByteList, (int)CharacterRecordOffsets.ExperiencePoints, sizeof(UInt16)).GetChunkAsUINT16List()[0]; Stats.Level = rawRecordByteList[(int)CharacterRecordOffsets.Level]; // this approach is necessary because I have found circumstances where shields and weapons were swapped in the save file // I couldn't guarantee that other items wouldn't do the same so instead we allow each of the equipment save // slots can be "whatever" in "whatever" order. When I save them back to disk, I will save them in the correct order // Also confirmed that Ultima 5 can handle these equipment saves out of order as well List <DataOvlReference.EQUIPMENT> allEquipment = new List <DataOvlReference.EQUIPMENT>(6); allEquipment.Add((DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Helmet]); allEquipment.Add((DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Armor]); allEquipment.Add((DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Weapon]); allEquipment.Add((DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Shield]); allEquipment.Add((DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Ring]); allEquipment.Add((DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Amulet]); Equipped.Helmet = (DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Helmet]; Equipped.Armor = (DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Armor]; Equipped.LeftHand = (DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Weapon]; Equipped.RightHand = (DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Shield]; Equipped.Ring = (DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Ring]; Equipped.Amulet = (DataOvlReference.EQUIPMENT)rawRecordByteList[(int)CharacterRecordOffsets.Amulet]; // sometimes U5 swaps the shield and weapon, so we are going to be careful and just swap them back if ((int)Equipped.LeftHand <= (int)DataOvlReference.EQUIPMENT.JewelShield && (int)Equipped.LeftHand >= (int)DataOvlReference.EQUIPMENT.Dagger) { DataOvlReference.EQUIPMENT shieldEquip = Equipped.RightHand; Equipped.RightHand = Equipped.LeftHand; Equipped.LeftHand = shieldEquip; } InnOrParty = rawRecordByteList[(int)CharacterRecordOffsets.InnParty]; Unknown1 = rawRecordByteList[(int)CharacterRecordOffsets.Unknown1]; Unknown2 = rawRecordByteList[(int)CharacterRecordOffsets.Unknown2]; }
static private List <string> GetAsStringListFromIndexes(List <ushort> indexList, List <byte> rawByteList) { List <string> strList = new List <string>(indexList.Count); const int MAX_STR_LENGTH = 20; foreach (ushort index in indexList) { // we grab the strings from the fullRawData because it is the entire file strList.Add(DataChunk.CreateDataChunk(DataFormatType.SimpleString, String.Empty, rawByteList, index, MAX_STR_LENGTH).GetChunkAsString()); } return(strList); }
/// <summary> /// Loads the "Look" descriptions /// </summary> /// <param name="u5directory">directory of data files</param> public Signs(string u5directory) { signsByteArray = Utils.GetFileAsByteList(Path.Combine(u5directory, FileConstants.SIGNS_DAT)); int nIndex = TOTAL_SIGNS * 2; // we are ignoring the "offsets" which are likely used to help optimize the lookup // on older hardware, instead we will just be lazy and search for them by cycling // through the whole list // TODO: optimize storage to improve lookup spped do { string rawSignTxt = Utils.BytesToStringNullTerm(signsByteArray, nIndex + 4, 0xFF); int nRawSignTxtLength = rawSignTxt.Length; // there are often two "warning signs" in the main virtue townes. Only one of the signs text is actually // populated - so if we see a "\n" as the only string, then we look ahead to the next signs text and use // it instead if (rawSignTxt.Trim() == String.Empty) { int nNextSignAdjust = rawSignTxt.Length + 1 + 4; rawSignTxt = Utils.BytesToStringNullTerm(signsByteArray, nIndex + 4 + nNextSignAdjust, 0xFF); } signList.Add(new Sign((SmallMapReferences.SingleMapReference.Location)signsByteArray[nIndex], signsByteArray[nIndex + 1], signsByteArray[nIndex + 2], signsByteArray[nIndex + 3], rawSignTxt, nIndex)); nIndex += nRawSignTxtLength + 1 + 4; // we hop over the string plus it's null byte plus the four bytes for definition // while we don't encounter four zero bytes in a row, which is eseentially the end of the file } while (!(signsByteArray[nIndex] == 0 && signsByteArray[nIndex + 1] == 0 && signsByteArray[nIndex + 2] == 0 && signsByteArray[nIndex + 3] == 0)); // there are some signs that are not included in the signs.dat file, so we manually pont to them and add them to our sign list List <byte> dataovlSignsByteArray = Utils.GetFileAsByteList(Path.Combine(u5directory, FileConstants.DATA_OVL)); List <byte> shSign = DataChunk.CreateDataChunk(DataChunk.DataFormatType.ByteList, "SH Sign of Eight Laws", dataovlSignsByteArray, 0x743a, 0x66).GetAsByteList(); signList.Add(new Sign(SmallMapReferences.SingleMapReference.Location.Serpents_Hold, 0, 15, 19, shSign.ToArray(), 0x743a)); }
public Inventory(List <byte> gameStateByteArray, DataOvlReference dataOvlRef) { this.gameStateByteArray = gameStateByteArray; DataChunk.CreateDataChunk(DataChunk.DataFormatType.Byte, "Grapple", gameStateByteArray, 0x209, sizeof(byte)); DataChunk.CreateDataChunk(DataChunk.DataFormatType.Byte, "Magic Carpet", gameStateByteArray, 0x20A, sizeof(byte)); ProtectiveArmour = new Armours(dataOvlRef, gameStateByteArray); AllItems.AddRange(ProtectiveArmour.GenericItemList); ReadyItems.AddRange(ProtectiveArmour.GenericItemList); TheWeapons = new Weapons(dataOvlRef, gameStateByteArray); ReadyItems.AddRange(TheWeapons.GenericItemList); MagicScrolls = new Scrolls(dataOvlRef, gameStateByteArray); UseItems.AddRange(MagicScrolls.GenericItemList); MagicPotions = new Potions(dataOvlRef, gameStateByteArray); UseItems.AddRange(MagicPotions.GenericItemList); SpecializedItems = new SpecialItems(dataOvlRef, gameStateByteArray); AllItems.AddRange(SpecializedItems.GenericItemList); UseItems.AddRange(SpecializedItems.GenericItemList); Artifacts = new LordBritishArtifacts(dataOvlRef, gameStateByteArray); AllItems.AddRange(Artifacts.GenericItemList); UseItems.AddRange(Artifacts.GenericItemList); Shards = new ShadowlordShards(dataOvlRef, gameStateByteArray); AllItems.AddRange(Shards.GenericItemList); UseItems.AddRange(Shards.GenericItemList); SpellReagents = new Reagents(dataOvlRef, gameStateByteArray); AllItems.AddRange(SpellReagents.GenericItemList); MagicSpells = new Spells(dataOvlRef, gameStateByteArray); AllItems.AddRange(MagicSpells.GenericItemList); }
public bool GetInvetoryBool(InventoryThings thing) { return(DataChunk.CreateDataChunk(DataChunk.DataFormatType.Byte, "", gameStateByteArray, (int)thing, sizeof(byte)).GetChunkAsByte() > 0); }