/// <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]; }
/// <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 speed 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 essentially 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 bool GetInventoryBool(InventoryThings thing) { return(DataChunk.CreateDataChunk(DataChunk.DataFormatType.Byte, "", _gameStateByteArray, (int)thing, sizeof(byte)).GetChunkAsByte() > 0); }