/// <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];
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        /// <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));
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
 public bool GetInvetoryBool(InventoryThings thing)
 {
     return(DataChunk.CreateDataChunk(DataChunk.DataFormatType.Byte, "", gameStateByteArray, (int)thing, sizeof(byte)).GetChunkAsByte() > 0);
 }