void TailsAdvBank0Hacks::addRegularInventoryHotswapHack(
                   WritableROM& rom) {
  // Write hotswap hack
  rom.directWrite(regularInventoryHotswapHackMainAddress,
                  regularInventoryHotswapHackMainData,
                  regularInventoryHotswapHackMainLength);
  
  // Write hotswap trigger
  rom.directWrite(regularInventoryHotswapHackTriggerAddress,
                  regularInventoryHotswapHackTriggerData,
                  regularInventoryHotswapHackTriggerLength);
}
void TailsAdvBank0Hacks::addFullInventoryHotswapHack(
                   WritableROM& rom) {
  // Use full inventory
  addUseAllInventoryHack(rom);
  
  // Write hotswap hack
  rom.directWrite(fullInventoryHotswapHackMainAddress,
                  fullInventoryHotswapHackMainData,
                  fullInventoryHotswapHackMainLength);
  
  // Write hotswap trigger
  rom.directWrite(fullInventoryHotswapHackTriggerAddress,
                  fullInventoryHotswapHackTriggerData,
                  fullInventoryHotswapHackTriggerLength);
}
void TailsAdvBank0Hacks::addAutoSaveHack(
                   WritableROM& rom) {
  addSaveHackBase(rom);
  rom.directWrite(autoSaveHackAddress,
                  autoSaveHackData,
                  autoSaveHackLength);
}
void EditableSpawnPoints::exportElementToROM(WritableROM& rom,
                                Taddress address,
                                SpawnPointCollection& src) {
  Taddress writeAddress = address;
  
  for (SpawnPointCollection::iterator it = src.begin();
       it != src.end();
       ++it) {
//    std::cout << writeAddress << std::endl;
//    std::cout << '\t' << it->camX() << std::endl;
    // Buffer for data
    Tbyte dataBuffer[SpawnPoint::dataSize];
    
    // Write spawn to data
    it->writeToData(dataBuffer);
    
//    for (int i = 0; i < SpawnPoint::dataSize; i++) {
//      std::cout << (int)(dataBuffer[i]) <<  " ";
//    }
//    std::cout << std::endl;
    
    // Copy raw spawn data to ROM
    rom.directWrite(writeAddress,
                    dataBuffer,
                    SpawnPoint::dataSize);
    
    // Advance to next address
    writeAddress += SpawnPoint::dataSize;
  }
}
void TailsAdvBank0Hacks::addStartingItemHack(
                   WritableROM& rom,
                   Tbyte startingItemID,
                   Tbyte sfStartingItemID,
                   bool allItemsEnabled) {
  rom.directWrite(startingItemHackItemIDAddress,
                  &startingItemID,
                  ByteSizes::uint8Size);
  
  StartingItemHackUnlockPair unlockPair
    = startingItemHackItemUnlockLocations[startingItemID];
  StartingItemHackUnlockPair sfUnlockPair
    = startingItemHackItemUnlockLocations[sfStartingItemID];
  
  ByteConversion::toBytes(unlockPair.address,
                          rom.directWrite(
                            startingItemHackUnlockLocationAddress),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  ByteConversion::toBytes(bitNumToHLIndirectOpcodeParam(
                            unlockPair.bit),
                          rom.directWrite(
                            startingItemHackUnlockBitAddress),
                          ByteSizes::uint8Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  ByteConversion::toBytes(sfUnlockPair.address,
                          rom.directWrite(
                            startingItemHackSFUnlockLocationAddress),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  ByteConversion::toBytes(bitNumToHLIndirectOpcodeParam(
                            sfUnlockPair.bit),
                          rom.directWrite(
                            startingItemHackSFUnlockBitAddress),
                          ByteSizes::uint8Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  if (allItemsEnabled) {
    Tbyte pos = startingItemHackItemToPos[startingItemID];
    Tbyte sfPos = startingItemHackItemToPos[sfStartingItemID];
    
    rom.directWrite(startingItemHackAllItemsPosAddress,
                    &pos,
                    ByteSizes::uint8Size);
    rom.directWrite(startingItemHackAllItemsSFPosAddress,
                    &sfPos,
                    ByteSizes::uint8Size);
    rom.directWrite(startingItemHackAllItemsSFSlotAddress,
                    &sfStartingItemID,
                    ByteSizes::uint8Size);
  }
}
void TailsAdvBank0Hacks::addSaveHackBase(
                   WritableROM& rom) {
  rom.directWrite(saveHackAddress1,
                  saveHackData1,
                  saveHackLength1);
                  
  rom.directWrite(saveHackAddress2,
                  saveHackData2,
                  saveHackLength2);
                  
  rom.directWrite(saveHackAddress3,
                  saveHackData3,
                  saveHackLength3);
                  
  rom.directWrite(saveHackAddress4,
                  saveHackData4,
                  saveHackLength4);
}
void EditablePowerUpData::exportToROM(WritableROM& rom) {
  int byteCount = 0;

  for (int i = 0; i < numPowerUps_; i++) {
    ByteConversion::toBytes(MiscMath::toBCD(maxHealthPerPowerup_[i]),
                            rom.directWrite(powerUpTableAddress_
                                              + byteCount),
                            ByteSizes::uint8Size,
                            EndiannessTypes::little,
                            SignednessTypes::nosign);
    byteCount += ByteSizes::uint8Size;
    
    ByteConversion::toBytes(flightTimePerPowerup_[i],
                            rom.directWrite(powerUpTableAddress_
                                              + byteCount),
                            ByteSizes::uint16Size,
                            EndiannessTypes::little,
                            SignednessTypes::nosign);
    byteCount += ByteSizes::uint16Size;
  }
}
Example #8
0
void TailsAdvData::exportToROM(WritableROM& rom) {
  
  /* A VERY LONG SEQUENCE OF EXPORTS GOES HERE */
  
  if (romExpanded_) {
    // If the ROM has been expanded, there are now 0x40 rather than 0x20
    // valid banks. However, there are a handful of pieces of code that
    // mask a value by 0x1F to obtain a bank number. We need to adjust these
    // to 0x3F or the program will be unable to access the new banks.
    rom.directWrite(andMaskExpandAdjustAddress1,
                    andMaskExpandAdjustValue,
                    ByteSizes::uint8Size);
    rom.directWrite(andMaskExpandAdjustAddress2,
                    andMaskExpandAdjustValue,
                    ByteSizes::uint8Size);
  }
  
  standardPalettes_.exportToROM(rom);
  paletteCycles_.exportToROM(rom);
  levelEffectsHeaders_.exportToROM(rom);
  levelPaletteHeaders_.exportToROM(rom);
  levelGraphicsData_.exportToROM(rom);
  tileMaps_.exportToROM(rom);
  leafGraphicsTable_.exportToROM(rom);
  waterSplashGraphicTable_.exportToROM(rom);
  smokePuffGraphicTable_.exportToROM(rom);
  spriteMappings_.exportToROM(rom);
  musicAssignments_.exportToROM(rom);
  radioMusic_.exportToROM(rom);
  powerUpData_.exportToROM(rom);
  emeraldHealthRefills_.exportToROM(rom);
  metatileWidthMaps_.exportToROM(rom);
  metatileHeightMaps_.exportToROM(rom);
  slopeSpeedValues_.exportToROM(rom);
  metatileBehaviors_.exportToROM(rom);
  spawnPoints_.exportToROM(rom);
  warpDestinations_.exportToROM(rom);
  levelObjectEntryGroups_.exportToROM(rom);
  mapData_.exportToROM(rom);
}
void TailsAdvBank0Hacks::addDoubleJumpFixHack(
                   WritableROM& rom) {
  // Copy the original jump height
  Tbyte jHeight[1];
  std::memcpy(jHeight,
              rom.directRead(doubleJumpFixHackJumpHeightAddress),
              1);
  
  // Decrement jump height by 1 for hack
  jHeight[0] = (jHeight[0] - 1);
                   
  // Write fix to ROM
  rom.directWrite(doubleJumpFixHackAddress,
                  doubleJumpFixHackData,
                  doubleJumpFixHackLength);
                  
  // Copy jump height + 1
  rom.directWrite(doubleJumpFixHackAddress
                    + doubleJumpFixHackJumpHeightOffset,
                  jHeight,
                  1);
}
void TailsAdvBank0Hacks::addFlightLimiterHack(
                   WritableROM& rom) {
  
  rom.directWrite(flightLimiterHackMain1Address,
                  flightLimiterHackMain1Data,
                  flightLimiterHackMain1Length);
  
  rom.directWrite(flightLimiterHackMain2Address,
                  flightLimiterHackMain2Data,
                  flightLimiterHackMain2Length);
  
  rom.directWrite(flightLimiterHackTrigger1Address,
                  flightLimiterHackTrigger1Data,
                  flightLimiterHackTrigger1Length);
  
  rom.directWrite(flightLimiterHackTrigger2Address,
                  flightLimiterHackTrigger2Data,
                  flightLimiterHackTrigger2Length);
  
  rom.directWrite(flightLimiterHackTrigger3Address,
                  flightLimiterHackTrigger3Data,
                  flightLimiterHackTrigger3Length);
}
void EditableLevelPaletteHeaders::exportToROM(WritableROM& rom) {
  // Write palette headers
  int contentWriteAddress = tableContentAddress_;
  for (LevelPaletteHeaderCollection::iterator it = primaryStorage_.begin();
       it != primaryStorage_.end();
       it++) {
    it->exportToROM(rom,
                    contentWriteAddress);
    contentWriteAddress += LevelPaletteHeader::dataSize;
  }
  
  // Write table header
  int headerWriteAddress = tableHeaderAddress_;
//  std::cout << "start: " << std::hex << headerWriteAddress << std::endl;
  for (int i = 0; i < mapnumToIndex_.numPrimaryKeys(); i++) {
//    std::cout << "at: " << std::hex << headerWriteAddress << std::endl;
    // Only write used keys
    if (mapnumToIndex_.subKeyTable()[i] > 0) {
//      std::cout << '\t' << "writing " << std::hex << i << std::endl;
      int index = mapnumToIndex_.refDataByKeys(
                                         i,
                                         TwoKeyedAddress::subKeyBase);
//      std::cout << '\t' << "index: " << index << std::endl;
      // Get banked address of content
      Taddress address
        = LoadedROM::indexToBankedAddr(tableContentAddress_,
                                       index,
                                       LevelPaletteHeader::dataSize);
      
      Tbyte buffer[ByteSizes::uint16Size];
      ByteConversion::toBytes(address,
                              buffer,
                              ByteSizes::uint16Size,
                              EndiannessTypes::little,
                              SignednessTypes::nosign);
      
//      std::cout << "number: " << std::hex << i << std::endl;
//      std::cout << "write address: " << std::hex << headerWriteAddress << std::endl;
      
      // Write address to ROM
      rom.directWrite(headerWriteAddress,
                      buffer,
                      ByteSizes::uint16Size);
    }
    
    // Go to next address
    headerWriteAddress += ByteSizes::uint16Size;
  }
  
}
void TailsAdvBank0Hacks::addStartOnLevelHack(
                   WritableROM& rom,
                   Tbyte area,
                   Tbyte map,
                   Tbyte spawn) {
  rom.directWrite(startOnLevelHackAddress1,
                  startOnLevelHackData1,
                  startOnLevelHackLength1);
  // Fill in area, map, spawn num
  rom.directWrite(startOnLevelHackAddress1
                    + startOnLevelHackData1AreaOffset,
                  &area,
                  ByteSizes::uint8Size);
  rom.directWrite(startOnLevelHackAddress1
                    + startOnLevelHackData1MapOffset,
                  &map,
                  ByteSizes::uint8Size);
  rom.directWrite(startOnLevelHackAddress1
                    + startOnLevelHackData1SpawnOffset,
                  &spawn,
                  ByteSizes::uint8Size);
  
  rom.directWrite(startOnLevelHackAddress2,
                  startOnLevelHackData2,
                  startOnLevelHackLength2);
  
  // Copy and shift block
  Tbyte copyTemp[startOnLevelHackCopyLength];
  std::memcpy(copyTemp,
              rom.directRead(startOnLevelHackCopySrcAddress),
              startOnLevelHackCopyLength);
  std::memcpy(rom.directWrite(startOnLevelHackCopyDstAddress),
              copyTemp,
              startOnLevelHackCopyLength);
  
  // Fill in data
  rom.directWrite(startOnLevelHackAddress3,
                  startOnLevelHackData3,
                  startOnLevelHackLength3);
  
  rom.directWrite(startOnLevelHackAddress4,
                  startOnLevelHackData4,
                  startOnLevelHackLength4);
}
void EditableSlopeSpeedValues::exportToROM(WritableROM& rom) {
  // Write each value to ROM
  int writeAddress = baseAddress_;
  for (SlopeSpeedValueCollection::iterator it = speedValues_.begin();
       it != speedValues_.end();
       ++it) {
    Tbyte buffer[ByteSizes::int16Size];
    ByteConversion::toBytes(*it,
                            buffer,
                            ByteSizes::int16Size,
                            EndiannessTypes::little,
                            SignednessTypes::sign);
    rom.directWrite(writeAddress,
                    buffer,
                    ByteSizes::int16Size);
    writeAddress += ByteSizes::int16Size;
  }
}
Example #14
0
void MetatileStructureSet::exportToROM(WritableROM& rom) {
  // TODO: support for adding metatile definitions
  // search freespace &c
  
  FreeSpaceList::iterator spaceIt = rom.freeSpace().getFreeSpace(
    exportSize());
    
  if (spaceIt == rom.freeSpace().freeSpaceList().end()) {
    throw NotEnoughSpaceException(TALES_SRCANDLINE,
                                  "MetatileStructureSet::exportToROM("
                                  "WritableROM&)",
                                  exportSize());
  }
  
  int writeAddress = spaceIt->address();
  address_ = spaceIt->address();
  
  rom.freeSpace().claimSpace(spaceIt, exportSize());
  
//  std::cout << "addr: " << writeAddress << std::endl;
  
  // Starting address of structure definitions
  int contentStartAddress = writeAddress
        + (index_.size() * ByteSizes::uint16Size);

  // Write the index
  for (MetatileIndexToStructureMap::iterator it = index_.begin();
       it != index_.end();
       it++) {
    int contentIndex = it->second;
    
    // Compute the address of the content
    Taddress contentAddress = (contentStartAddress 
                  + (contentIndex * MetatileStructure::dataSize));
    
    // Convert to banked address
    Taddress contentBankedAddress = LoadedROM
          ::directToBankedAddress(contentAddress);
    
    // Write to index
    Tbyte buffer[ByteSizes::uint16Size];
    ByteConversion::toBytes(contentBankedAddress,
                            buffer,
                            ByteSizes::uint16Size,
                            EndiannessTypes::little,
                            SignednessTypes::nosign);
    rom.directWrite(writeAddress + (it->first * ByteSizes::uint16Size),
                    buffer,
                    ByteSizes::uint16Size);
  }
  
  // Write content
  int metatileNum = 0;
  for (MetatileStructureCollection::iterator it = primaryStorage_.begin();
       it != primaryStorage_.end();
       it++) {
    // Write metatile to buffer
    Tbyte buffer[MetatileStructure::dataSize];
    it->writeToData(buffer);
    // Write buffer to table
    rom.directWrite(contentStartAddress
                      + (metatileNum * MetatileStructure::dataSize),
                    buffer,
                    MetatileStructure::dataSize);
    ++metatileNum;
  }
  
//  std::cout << "metatiles: " << metatileNum << std::endl;
//  std::cout << std::endl;
}
void TailsAdvBank0Hacks::addBombWhileJumpingGraphicFixHack(
                   WritableROM& rom) {
  rom.directWrite(bombWhileJumpingGraphicFixAddress,
                  bombWhileJumpingGraphicFixData,
                  bombWhileJumpingGraphicFixLength);
}
void EditableLevelObjectEntryGroups::exportTable(
                 Taddress exportAddress,
                 WritableROM& rom) {
  
//  std::cout << "Exporting to: " << exportAddress << std::endl;
  
  // Subkey address write location
  Taddress subkeyWriteAddress = exportAddress
                                 + (primaryMapLimit
                                    * ByteSizes::uint16Size);
                                    
//  std::cout << std::hex << subkeyWriteAddress << std::endl;
  
  // Determine total number of maps to output
  int numSubkeyEntries = 0;
  for (int i = 0; i < mapnumToAddress_.numPrimaryKeys(); i++) {
    // If at least one entry for this primary key, use first entry
    if (mapnumToAddress_.subKeyTable()[i] > 0) {
      numSubkeyEntries += mapnumToAddress_.subKeyTable()[i];
    }
  }
  
  // Compute base address for entries
  Taddress entryWriteAddress = subkeyWriteAddress
                                 + (numSubkeyEntries
                                    * ByteSizes::uint16Size);
                                 
  // Temporarily convert address table to index table
  for (int i = 0; i < mapnumToAddress_.numPrimaryKeys(); i++) {
    for (int j = 0; j < mapnumToAddress_.subKeyTable()[i]; j++) {
    
      Taddress& addr = mapnumToAddress_.refDataByKeys(
                            i + TwoKeyedAddress::primaryKeyBase,
                            j + TwoKeyedAddress::subKeyBase);
      
      int ind = addressToIndex_.findValueOrThrow(addr);
      
      addr = ind;
    }
  }
  
  // Clear address to index map
  addressToIndex_.clear();
  
  // Create temporary mapping of indices to address
  Tmap<int, Taddress> indToAddr;
                                 
  for (int i = 0; i < primaryStorage_.size(); i++) {
    
    // Add new (temporary) index->address mapping
    indToAddr.insert(Tmap<int, Taddress>::PairType(
                      i, entryWriteAddress));
                      
    // Write entry to ROM
    int writeLength = primaryStorage_[i].writeToData(
                        rom.directWrite(entryWriteAddress));
    
    // Add new address->index mapping
    addressToIndex_.insert(
      BaseEditableMappedData<LevelObjectEntryGroup>
          ::AddressIndexPair(
              entryWriteAddress,
              i));
                      
    // Write subkey address
/*    Taddress bankedAddress = LoadedROM::directToBankedAddress(
                                entryWriteAddress);
    ByteConversion::toBytes(bankedAddress,
                            rom.directWrite(subkeyWriteAddress),
                            ByteSizes::uint16Size,
                            EndiannessTypes::little,
                            SignednessTypes::nosign);
                            
//    std::cout << std::hex << "value: " << bankedAddress << std::endl;
//    std::cout << std::hex << "addr: " << subkeyWriteAddress << std::endl;
    
    // Move to next address
    subkeyWriteAddress += ByteSizes::uint16Size; */
    entryWriteAddress += writeLength;
  }
  
  // Write the address table to the export location
  Taddress primaryWriteAddress = exportAddress;
  int totalMaps = 0;
  for (int i = 0; i < mapnumToAddress_.numPrimaryKeys(); i++) {
    
    Taddress bankedAddress = exportAddress
                           + (primaryMapLimit
                               * ByteSizes::uint16Size);
    
    // If at least one entry for this primary key, use first entry
    if (mapnumToAddress_.subKeyTable()[i] > 0) {
      bankedAddress += (totalMaps * ByteSizes::uint16Size);
      totalMaps += mapnumToAddress_.subKeyTable()[i];
/*      bankedAddress
        = indToAddr.findValueOrThrow(
                        mapnumToAddress_.refDataByKeys(
                            i + TwoKeyedAddress::primaryKeyBase,
                            TwoKeyedAddress::subKeyBase)); */
    }
    
    bankedAddress = LoadedROM::directToBankedAddress(bankedAddress);
    
    // Write primary address
    ByteConversion::toBytes(bankedAddress,
                            rom.directWrite(primaryWriteAddress),
                            ByteSizes::uint16Size,
                            EndiannessTypes::little,
                            SignednessTypes::nosign);
    primaryWriteAddress += ByteSizes::uint16Size;
  
    // Convert indices back to addresses
    for (int j = 0; j < mapnumToAddress_.subKeyTable()[i]; j++) {
      Taddress& ind = mapnumToAddress_.refDataByKeys(
                            i + TwoKeyedAddress::primaryKeyBase,
                            j + TwoKeyedAddress::subKeyBase);
                            
//      std::cout << ind << std::endl;
      
      // Get address corresponding to this index
      Taddress address = indToAddr.findValueOrThrow(ind);
      
//      std::cout << address << std::endl;
      
      // Write subkey address
      Taddress bankedSubAddress = LoadedROM::directToBankedAddress(
                                  address);
      ByteConversion::toBytes(bankedSubAddress,
                              rom.directWrite(subkeyWriteAddress),
                              ByteSizes::uint16Size,
                              EndiannessTypes::little,
                              SignednessTypes::nosign);
      
      // Move to next address
      subkeyWriteAddress += ByteSizes::uint16Size;
                            
      // Convert indexed address table back to address table
      ind = address;
    }
  }

  // Export each data element to ROM
/*  for (typename AddressIndexMap::iterator it = addressToIndex_.begin();
       it != addressToIndex_.end();
       it++) {
    // Address to write to
    Taddress address = it->first;
    
    // Write data
    exportElementToROM(rom,
                       address,
                       primaryStorage_[it->second]);
  } */
}
void EditableLevelObjectEntryGroups::exportElementToROM(WritableROM& rom,
                                Taddress address,
                                LevelObjectEntryGroup& src) {
  src.writeToData(rom.directWrite(address));
}
Taddress EditableLevelObjectEntryGroups::moveToNewBank(WritableROM& rom) {

//  std::cout << "Preparing to move to new bank" << std::endl;
  
  // More for convenience than anything else, we grab a whole bank of data
  // for use by this table (and a few bits of associated code).
  // Note that this basically requires expanding the ROM to 1 MB
  FreeSpaceList::iterator spaceIt
      = rom.freeSpace().getFreeSpace(LoadedROM::bankSize);
  
  // Throw if a full bank isn't available
  if (spaceIt == rom.freeSpace().freeSpaceList().end()) {
    throw NotEnoughSpaceException(TALES_SRCANDLINE,
                                  "EditableLevelObjectEntryGroups::"
                                  "exportToROM(WritableROM&)",
                                  LoadedROM::bankSize);
  }
  
//  std::cout << spaceIt->address() << " " << spaceIt->length() << std::endl;
                             
  Taddress newBaseAddress = spaceIt->address();
  
  // Claim the bank
  rom.freeSpace().claimSpace(spaceIt,
                             LoadedROM::bankSize);
  
//  std::cout << "New base address: " << newBaseAddress << std::endl;
  
  // Copy code segments C1 and C3 to new bank.
  // C1 and C3 both contain code that references the object table,
  // so they must (to avoid more complicated hacking) be in the same bank.
  // After rearranging the code, the new bank will contain C1, C3, and
  // the object table, in that order, starting from the beginning of the
  // bank
  
  // Copy C1 to start of bank
  Taddress newC1Address = newBaseAddress;
  std::memcpy(rom.directWrite(newC1Address),
              codeSegmentC1,
              lengthOfC1Segment);
              
  // Copy C3 to directly after C1
  Taddress newC3Address = newC1Address
                            + lengthOfC1Segment;
  std::memcpy(rom.directWrite(newC3Address),
              codeSegmentC3,
              lengthOfC3Segment);
  
  // Set new export address for table (directly after C3)
  int exportAddress = newBaseAddress
                    + lengthOfC1Segment
                    + lengthOfC3Segment;
                    
//  std::cout << "New C1 address: " << newC1Address << std::endl;
//  std::cout << "New C3 address: " << newC3Address << std::endl;
//  std::cout << "Export address: " << exportAddress << std::endl;
  
  // Update all the code that references the old locations of C1 and C3
  
  // Get the banked address for the new direct address of C1
  int newC1BankNum = LoadedROM::directToBankNum(newC1Address);
  int newC1BankedAddress = LoadedROM::directToBankedAddress(newC1Address);
  
  // Get the banked address for the new direct address of C3
  int newC3BankNum = LoadedROM::directToBankNum(newC3Address);
  int newC3BankedAddress = LoadedROM::directToBankedAddress(newC3Address);
  
  // Update bank number in code that calls C1
  ByteConversion::toBytes(newC1BankNum,
                          rom.directWrite(callReferenceToC1Bank),
                          ByteSizes::uint8Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // C1's banked address is the same (0000), so we don't need to update it
  // ... but do anyway for consistency
  ByteConversion::toBytes(newC1BankedAddress,
                          rom.directWrite(callReferenceToC1Address),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // Update banked address in code that calls C3
  ByteConversion::toBytes(newC3BankNum,
                          rom.directWrite(callReferenceToC3Bank),
                          ByteSizes::uint8Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // Update bank number in code that calls C3.
  ByteConversion::toBytes(newC3BankedAddress,
                          rom.directWrite(callReferenceToC3Address),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // C3 contains a hardcoded JP instruction into itself. Since we moved
  // C3, we have to update the JP to correspond to the new location.
  
  // Get new address of the JP instruction's address parameter
  Taddress addressOfNewJpParameter = newC3Address
                                      + offsetOfJpInC3;
  
  // Get new address of the JP instruction's jump point base
  Taddress addressOfNewJpBase = newC3Address
                                      + baseOffsetOfJpInC3;
  
  // Compute the new target address
  Taddress newJpTargetAddress = addressOfNewJpBase
                                  - absoluteLengthOfJpInC3;
                                  
//  std::cout << "New JP target: " << newJpTargetAddress << std::endl;
                                  
  // Convert to banked form
  Taddress newJpTargetBankedAddress
      = LoadedROM::directToBankedAddress(newJpTargetAddress);
  
  // Write the new target address to the JP parameter
  ByteConversion::toBytes(newJpTargetBankedAddress,
                          rom.directWrite(addressOfNewJpParameter),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // Get the banked address for the new direct address of the object table
//    int newTableBankNum
//        = LoadedROM::directToBankNum(exportAddress);
  int newTableBankedAddress
      = LoadedROM::directToBankedAddress(exportAddress);
  
  // Update C1 to refer to the new location of the object table
  ByteConversion::toBytes(newTableBankedAddress,
                          rom.directWrite(newC1Address
                                          + offsetOfTableReferenceInC1),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // Update C3 to refer to the new location of the object table
  ByteConversion::toBytes(newTableBankedAddress,
                          rom.directWrite(newC3Address
                                          + offsetOfTableReferenceInC3),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // Update table information
//    initialTableAddress_ = exportAddress;

//  initialTableContentSize_ = spaceIt->length()
//                              - exportAddress
//                              - tableHeaderSize_;

//  initialTableContentSize_ = exportAddress - spaceIt->address()
//                              - tableHeaderSize_;

//  initialTableContentSize_ = LoadedROM::bankSize;
                              
//  std::cout << initialTableContentSize_ << std::endl;
  
  // Mark that we've moved to a new bank
  movedToNewBank_ = true;
  
  return exportAddress;
}
void TailsAdvBank0Hacks::addButton1MaxHeightFixHack(
                   WritableROM& rom) {
  rom.directWrite(button1MaxHeightFixHackAddress,
                  button1MaxHeightFixHackData,
                  button1MaxHeightFixHackLength);
}
void TailsAdvBank0Hacks::addFlightDisableHack(
                   WritableROM& rom) {
  rom.directWrite(flightDisableHackMainAddress,
                  flightDisableHackMainData,
                  flightDisableHackMainLength);
}
void TailsAdvBank0Hacks::addNoGameOverHack(
                   WritableROM& rom) {
  rom.directWrite(noGameOverHackMainAddress,
                  noGameOverHackMainData,
                  noGameOverHackMainLength);
}
void TailsAdvBank0Hacks::addUseAllInventoryHack(
                   WritableROM& rom) {
  // Find free space
  FreeSpaceList::iterator spaceIt
    = rom.freeSpace().getFreeSpace(allInventoryHackCodeDataSize);
  
  // Throw if not enough space
  if (spaceIt == rom.freeSpace().freeSpaceList().end()) {
    throw NotEnoughSpaceException(TALES_SRCANDLINE,
                                  "TailsAdvBank0Hacks::addUseAllInventoryHack("
                                  "WritableROM&)",
                                  allInventoryHackCodeDataSize);
  }
  
  Taddress writeAddress = spaceIt->address();
  
  rom.freeSpace().claimSpace(spaceIt,
                             allInventoryHackCodeDataSize);
                             
//  std::cout << writeAddress << std::endl;
  
  // Write main code and data
  rom.directWrite(writeAddress,
                  allInventoryHackMainData,
                  allInventoryHackMainLength);
  
  // Fill in addresses of data tables
  
  ByteConversion::toBytes(LoadedROM::directToBankedAddress(writeAddress
                            + allInventoryHackMainTable1Offset),
                          rom.directWrite(writeAddress
                            + allInventoryHackMainTable1ReferenceOffset),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  ByteConversion::toBytes(LoadedROM::directToBankedAddress(writeAddress
                            + allInventoryHackMainTable2Offset),
                          rom.directWrite(writeAddress
                            + allInventoryHackMainTable2ReferenceOffset),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // Add trigger 1
  
  rom.directWrite(allInventoryHackTrigger1Address,
                  allInventoryHackTrigger1Data,
                  allInventoryHackTrigger1Length);
                  
  // Fill in bank
  ByteConversion::toBytes(LoadedROM::directToBankNum(writeAddress
                            + allInventoryHackMainCodeStartOffset),
                          rom.directWrite(
                            allInventoryHackTrigger1Address
                            + allInventoryHackTrigger1BankReferenceOffset),
                          ByteSizes::uint8Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  
  // Fill in address
  ByteConversion::toBytes(LoadedROM::directToBankedAddress(writeAddress
                            + allInventoryHackMainCodeStartOffset),
                          rom.directWrite(
                            allInventoryHackTrigger1Address
                            + allInventoryHackTrigger1AddressReferenceOffset),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // Add trigger 2
  
  rom.directWrite(allInventoryHackTrigger2Address,
                  allInventoryHackTrigger2Data,
                  allInventoryHackTrigger2Length);
                  
  // Fill in bank
  ByteConversion::toBytes(LoadedROM::directToBankNum(writeAddress
                            + allInventoryHackMainCodeStartOffset),
                          rom.directWrite(
                            allInventoryHackTrigger2Address
                            + allInventoryHackTrigger2BankReferenceOffset),
                          ByteSizes::uint8Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // Fill in address
  ByteConversion::toBytes(LoadedROM::directToBankedAddress(writeAddress
                            + allInventoryHackMainCodeStartOffset),
                          rom.directWrite(
                            allInventoryHackTrigger2Address
                            + allInventoryHackTrigger2AddressReferenceOffset),
                          ByteSizes::uint16Size,
                          EndiannessTypes::little,
                          SignednessTypes::nosign);
  
  // Add initializer 1
  rom.directWrite(allInventoryHackInitializer1Address,
                  allInventoryHackInitializer1Data,
                  allInventoryHackInitializer1Length);
  
  // Add initializer 2
  rom.directWrite(allInventoryHackInitializer2Address,
                  allInventoryHackInitializer2Data,
                  allInventoryHackInitializer2Length);
  
  // Add initializer 3
  rom.directWrite(allInventoryHackInitializer3Address,
                  allInventoryHackInitializer3Data,
                  allInventoryHackInitializer3Length);
  
  // Add initializer 4
  rom.directWrite(allInventoryHackInitializer4Address,
                  allInventoryHackInitializer4Data,
                  allInventoryHackInitializer4Length);
  
}