public NonPlayerCharacterMovement(int nDialogIndex, DataChunk movementInstructionDataChunk, DataChunk movementOffsetDataChunk) { // we totally ignore the first entry, since it's bad stuff if (nDialogIndex == 0) { return; } this.movementInstructionDataChunk = movementInstructionDataChunk; this.movementOffsetDataChunk = movementOffsetDataChunk; this.nDialogIndex = nDialogIndex; // todo: not a very efficient method of getting a UINT16 from the list -> it has to create a brand new list! nOffset = movementOffsetDataChunk.GetChunkAsUINT16List() [nDialogIndex]; // if it has the value of 0xFFFF then it indicates there are currently no instructions if (nOffset == 0xFFFF) { return; } // calculate the offset int nOffsetIndex = (nDialogIndex) * (MAX_COMMAND_LIST_ENTRIES * MAX_MOVEMENT_COMMAND_SIZE); // get a copy because the GetAsByteList is an expensive method call List <byte> rawData = movementInstructionDataChunk.GetAsByteList(); // gets a smaller version of it - much easier to keep track of loadedData = rawData.GetRange(nOffsetIndex, MAX_COMMAND_LIST_ENTRIES * 2); int nIndex = nOffset; for (int i = 0; i < MAX_COMMAND_LIST_ENTRIES; i++) { byte nIterations = loadedData[nIndex]; MovementCommandDirection direction = (MovementCommandDirection)loadedData[nIndex + 1]; // if we have hit 0xFF then there is nothing else in the list and we can just return if (nIterations == 0xFF || nIterations == 0) { return; } if (!(direction == MovementCommandDirection.East || direction == MovementCommandDirection.West || direction == MovementCommandDirection.North || direction == MovementCommandDirection.South)) { throw new Exception("a bad direction was set: " + direction.ToString()); } // we have a proper movement instruction so let's add it to the queue MovementCommand movementCommand = new MovementCommand(direction, nIterations); this.movementQueue.Enqueue(movementCommand); // we actually grab from the offset, but it is circular, so we need to mod it nIndex = (nIndex + 2) % (MAX_COMMAND_LIST_ENTRIES * 2); } }
public void Load(MapCharacterAnimationStatesFiles mapCharacterAnimationStatesType, bool bLoadFromDisk) { MapCharacterAnimationStatesType = mapCharacterAnimationStatesType; if (!bLoadFromDisk) { return; } List <byte> characterStateBytes = animationStatesDataChunk.GetAsByteList(); for (int i = 0; i < MAX_CHARACTER_STATES; i++) { characterStates.Add(new MapCharacterAnimationState(tileReferences, characterStateBytes.GetRange(i * MapCharacterAnimationState.NBYTES, MapCharacterAnimationState.NBYTES).ToArray())); } }
/// <summary> /// Construct the GameState /// </summary> /// <param name="u5Directory">Directory of the game State files</param> public GameState(string u5Directory, DataOvlReference dataOvlRef) { dataRef = dataOvlRef; string saveFileAndPath = Path.Combine(u5Directory, FileConstants.SAVED_GAM); dataChunks = new DataChunks <DataChunkName>(saveFileAndPath, DataChunkName.Unused); List <byte> gameStateByteArray; gameStateByteArray = Utils.GetFileAsByteList(saveFileAndPath); // import all character records dataChunks.AddDataChunk(DataChunk.DataFormatType.ByteList, "All Character Records (ie. name, stats)", 0x02, 0x20 * 16, 0x00, DataChunkName.CHARACTER_RECORDS); DataChunk rawCharacterRecords = dataChunks.GetDataChunk(DataChunkName.CHARACTER_RECORDS); CharacterRecords = new PlayerCharacterRecords(rawCharacterRecords.GetAsByteList()); // import the players invetry PlayerInventory = new Inventory(gameStateByteArray, dataRef); // player location dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "Current Party Location", 0x2ED, 0x01, 0x00, DataChunkName.PARTY_LOC); dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "Z Coordinate of Party [10]", 0x2EF, 0x01, 0x00, DataChunkName.Z_COORD); dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "X Coordinate of Party", 0x2F0, 0x01, 0x00, DataChunkName.X_COORD); dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "Y Coordinate of Party", 0x2F1, 0x01, 0x00, DataChunkName.Y_COORD); // quantities of standard items dataChunks.AddDataChunk(DataChunk.DataFormatType.UINT16, "Food Quantity", 0x202, 0x02, 0x00, DataChunkName.FOOD_QUANTITY); dataChunks.AddDataChunk(DataChunk.DataFormatType.UINT16, "Gold Quantity", 0x204, 0x02, 0x00, DataChunkName.GOLD_QUANTITY); dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "Keys Quantity", 0x206, 0x01, 0x00, DataChunkName.KEYS_QUANTITY); dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "Gems Quantity", 0x207, 0x01, 0x00, DataChunkName.GEMS_QUANTITY); dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "Torches Quantity", 0x208, 0x01, 0x00, DataChunkName.TORCHES_QUANTITY); // time and date dataChunks.AddDataChunk(DataChunk.DataFormatType.UINT16, "Current Year", 0x2CE, 0x02, 0x00, DataChunkName.CURRENT_YEAR); dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "Current Month", 0x2D7, 0x01, 0x00, DataChunkName.CURRENT_MONTH); dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "Current Day", 0x2D8, 0x01, 0x00, DataChunkName.CURRENT_DAY); dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "Current Hour", 0x2D9, 0x01, 0x00, DataChunkName.CURRENT_HOUR); // 0x2DA is copy of 2D9 for some reason dataChunks.AddDataChunk(DataChunk.DataFormatType.Byte, "Current Minute", 0x2DB, 0x01, 0x00, DataChunkName.CURRENT_MINUTE); //dataChunks.AddDataChunk() dataChunks.AddDataChunk(DataChunk.DataFormatType.Bitmap, "NPC Killed Bitmap", 0x5B4, 0x80, 0x00, DataChunkName.NPC_ISALIVE_TABLE); dataChunks.AddDataChunk(DataChunk.DataFormatType.Bitmap, "NPC Met Bitmap", 0x634, 0x80, 0x00, DataChunkName.NPC_ISMET_TABLE); dataChunks.AddDataChunk(DataChunk.DataFormatType.ByteList, "Number of Party Members", 0x2B5, 0x1, 0x00, DataChunkName.N_PEOPLE_PARTY); dataChunks.AddDataChunk(DataChunk.DataFormatType.ByteList, "NPC Type Map", 0x5B4, 0x20, 0x00, DataChunkName.NPC_TYPES); List <byte> chunks = dataChunks.GetDataChunk(DataChunkName.NPC_TYPES).GetAsByteList(); // get the NPCs movement list - 0x20 NPCs, with 0x10 movement commands each, consisting of 0x1 direction byte + 0x1 repetitions dataChunks.AddDataChunk(DataChunk.DataFormatType.ByteList, "NPC Movement List", 0xBB8, 0x20 * 0x10 * (sizeof(byte) * 2), 0x00, DataChunkName.NPC_MOVEMENT_LISTS); // bajh: Jan 12 2020, moved from BB8 to BBA to test a theory that it actually begins a few bytes after the original documentation indicates //dataChunks.AddDataChunk(DataChunk.DataFormatType.ByteList, "NPC Movement List", 0xBBA, 0x20 * 0x10 * (sizeof(byte) * 2), 0x00, DataChunkName.NPC_MOVEMENT_LISTS); // get the offsets to the current movement instructions of the NPCs dataChunks.AddDataChunk(DataChunk.DataFormatType.UINT16List, "NPC Movement Offset Lists", 0xFB8, 0x20 * (sizeof(byte) * 2), 0x00, DataChunkName.NPC_MOVEMENT_OFFSETS); // we will need to add 0x100 for now, but cannot because it's read in as a bytelist dataChunks.AddDataChunk(DataChunk.DataFormatType.ByteList, "NPC Sprite (by smallmap)", 0xFF8, 0x20, 0x00, DataChunkName.NPC_SPRITE_INDEXES); // Initialize the table to determine if an NPC is dead List <bool> npcAlive = dataChunks.GetDataChunk(DataChunkName.NPC_ISALIVE_TABLE).GetAsBitmapBoolList(); npcIsDeadArray = Utils.ListTo2DArray <bool>(npcAlive, NonPlayerCharacterReferences.NPCS_PER_TOWN, 0x00, NonPlayerCharacterReferences.NPCS_PER_TOWN * SmallMapReferences.SingleMapReference.TOTAL_SMALL_MAP_LOCATIONS); // Initialize a table to determine if an NPC has been met List <bool> npcMet = dataChunks.GetDataChunk(DataChunkName.NPC_ISMET_TABLE).GetAsBitmapBoolList(); // these will map directly to the towns and the NPC dialog # npcIsMetArray = Utils.ListTo2DArray <bool>(npcMet, NonPlayerCharacterReferences.NPCS_PER_TOWN, 0x00, NonPlayerCharacterReferences.NPCS_PER_TOWN * SmallMapReferences.SingleMapReference.TOTAL_SMALL_MAP_LOCATIONS); // this stores monsters, party, objects and NPC location info and other stuff too (apparently!?) dataChunks.AddDataChunk(DataChunk.DataFormatType.ByteList, "Character Animation States - including xyz", 0x6B4, 0x100, 0x00, DataChunkName.CHARACTER_ANIMATION_STATES); // this stores monsters, party, objects and NPC location info and other stuff too (apparently!?) dataChunks.AddDataChunk(DataChunk.DataFormatType.UINT16List, "Character States - including xyz", 0x9B8, 0x200, 0x00, DataChunkName.CHARACTER_STATES); // load the overworld and underworld overlays string overworldOverlayPath = Path.Combine(u5Directory, FileConstants.BRIT_OOL); string underworldOverlayPath = Path.Combine(u5Directory, FileConstants.UNDER_OOL); overworldOverlayDataChunks = new DataChunks <OverlayChunkName>(overworldOverlayPath, OverlayChunkName.Unused); underworldOverlayDataChunks = new DataChunks <OverlayChunkName>(underworldOverlayPath, OverlayChunkName.Unused); overworldOverlayDataChunks.AddDataChunk(DataChunk.DataFormatType.ByteList, "Character Animation States - including xyz", 0x00, 0x100, 0x00, OverlayChunkName.CHARACTER_ANIMATION_STATES); underworldOverlayDataChunks.AddDataChunk(DataChunk.DataFormatType.ByteList, "Character Animation States - including xyz", 0x00, 0x100, 0x00, OverlayChunkName.CHARACTER_ANIMATION_STATES); TheTimeOfDay = new TimeOfDay(dataChunks.GetDataChunk(DataChunkName.CURRENT_YEAR), dataChunks.GetDataChunk(DataChunkName.CURRENT_MONTH), dataChunks.GetDataChunk(DataChunkName.CURRENT_DAY), dataChunks.GetDataChunk(DataChunkName.CURRENT_HOUR), dataChunks.GetDataChunk(DataChunkName.CURRENT_MINUTE)); }