def ModifyExtraFilePosition(fileBin, position):  #PS3 Version Only
    #Extra files are at the end of the normal bar file.
    #Position is assumed to have a bar offset total
    #These extra files 99% of the time replace something already present in the bar file. HD textures & so on.
    #File position of new file, file position of Old file, New file size.
    if PS3Version():
        oldPos = fileBin.tell()
        fileBin.seek(0, 0)
        barOffset = findBarHeader(fileBin)
        fileBin.seek(0, 0)
        writeIntOrHex(fileBin, position - barOffset, 4)  #Write new bar size
        amtOfExtraFileEntries = readAndUnpack(fileBin, 4)
        for x in range(amtOfExtraFileEntries):
            fileBin.seek(0x10 + (x * 0x30), 0)
            fileBin.seek(0x20, 1)  #skip string
            extraFilePos = readAndUnpack(fileBin, 4)  #Read position
            offset = position - extraFilePos  #New position minus old position ,getting
            fileBin.seek(-4, 1)  # go back
            extraFilePos += offset
            writeIntOrHex(fileBin, extraFilePos, 4)
            oldFileOldPos = readUnpackGoBack(fileBin, 4)
            oldFileOldPos -= 0x20000000
            fileBin.write(b'\x20')
            writeIntOrHex(fileBin, oldFileOldPos + offset, 3)
        fileBin.seek(oldPos, 0)

    else:
        return False
def openKHBinFile(filename, seekHex=0):
    """Open kh2 bin file and navigate to the start from the bar
        return a list/array of the file thing we opened and data like position and entry size"""
    if (copyKHFile(filename)):
        fileBin = open(filename, "rb+")
        if (fileBin):
            writeRandomizationLog(filename)
            FilePositionOfNew = 0
            FilePositionEntrySize = 0
            if (seekHex != 0):
                fileBin.seek(seekHex, 0)  #usually a bar name thing
                FilePositionOfNew = readAndUnpack(fileBin, 4)
                FilePositionEntrySize = readAndUnpack(fileBin, 4)
                fileBin.seek(FilePositionOfNew, 0)
            return fileBin
        else:
            ErrorWindow(
                "The file " + filename +
                "  could not be opened. It's probably in use by another program or instance of this program."
            )
            return False
    else:
        ErrorWindow(
            filename +
            " does not exist in the export/KH2/ folder. Make sure nothing has gone wrong during the extraction."
        )
        return False
def closeKHText(file, strings):

    fileBin = open(file, 'rb+')
    offset = findBarHeader(fileBin)
    findHeaderinBAR(fileBin, 'md_m', False)
    fileBin.seek(0x8, 1)
    md_m_size = readAndUnpack(fileBin, 4)
    findHeaderinBAR(fileBin, 'md_m', True)
    md_m_Data = fileBin.read(md_m_size)
    miscData = fileBin.read()
    test = (
        file[len(file) - 4 - 2:]
    )[:
      2]  # Find world name by removing the last 4 characters and subtracting the length to start at the world name
    findHeaderinBAR(fileBin, test, True)
    startingStringTablePos = fileBin.tell()
    fileBin.seek(0x4, 1)  # skip header thing
    amountOfTextLines = readAndUnpack(fileBin, 4)
    startReadingPos = fileBin.tell()
    fileBin.seek(startingStringTablePos + 8 + (amountOfTextLines * 8), 0)
    for x in strings:
        x.position = fileBin.tell() - startingStringTablePos
        newList = x.writeBackToFile()
        for character in newList:
            writeIntOrHex(fileBin, character, 1)

    fileEndSize = fileBin.tell() - offset
    fileBin.truncate(fileEndSize)
    newTextBarFileSize = fileEndSize - startingStringTablePos
    while fileBin.tell() % 16 != 0:
        writeIntOrHex(fileBin, 0, 1)
    newMd_mPos = fileBin.tell() - offset

    fileBin.write(md_m_Data)
    ModifyExtraFilePosition(
        fileBin,
        fileBin.tell())  #we want relative positions to 0,0 of the file.
    fileBin.write(miscData)
    fileBin.seek(startReadingPos,
                 0)  #Go back to the start with ids and positions
    for x in strings:
        stringID = readAndUnpack(fileBin, 4)
        filterStuff = list(filter(lambda x: (stringID in x.ids), strings))
        writeIntOrHex(fileBin, filterStuff[0].position,
                      4)  #Write new positions of text
    findHeaderinBAR(fileBin, 'md_m', False)
    fileBin.seek(0x4, 1)
    writeIntOrHex(fileBin, newMd_mPos, 4)
    findHeaderinBAR(fileBin, test, False)
    fileBin.seek(0x8, 1)
    writeIntOrHex(fileBin, newTextBarFileSize, 4)
    fileBin.close()
def removeEnemySpawnLimit(EnemiesWereRandomized):
    if EnemiesWereRandomized:
        enemyWeightValue = 0x8
        curFile = "00objentry.bin"
        if copyKHFile(curFile):
            writeRandomizationLog(curFile)
            fileBin = open(curFile, 'rb+')

            fileSize = os.path.getsize(curFile) #Get size since bin doesnt have an amount of objects
            offset = 0
            if PS3Version():
                fileSize-= 0x10
                offset = 0x10

            amtOfObjects = int(math.floor(fileSize/0x60))

            for objectEntry in range(amtOfObjects):
                fileBin.seek((objectEntry*0x60)+offset,0)
                fileBin.seek(0x8,1) #Skip to UCM code
                UCM = readAndUnpack(fileBin,4)
                fileBin.seek(0x4, 1) #Skip unknown Data
                Object_STR = (fileBin.read(0x20)).decode("utf-8") #PS3 Version Name endian order was left unchanged.
                ObjectMSET_STR = (fileBin.read(0x20)).decode("utf-8")
                fileBin.seek(0xC, 1)  # Skip to spawn limit value
                previousWeightValue = readUnpackGoBack(fileBin, 1)
                if previousWeightValue > enemyWeightValue: #???
                    if CheckIfEnemyTypeInTable(UCM,enemy_table) and Object_STR[:2] == "M_":
                        writeIntOrHex(fileBin,enemyWeightValue,1) #Write lower spawn limit value!
                    if CheckIfEnemyTypeInTable(UCM,boss_table) or CheckIfEnemyTypeInTable(UCM,superBoss_table) and Object_STR[:2] == "B_":
                        writeIntOrHex(fileBin,enemyWeightValue,1) #Write lower spawn limit value!
                    if CheckIfEnemyTypeInTable(UCM,ally_table) and Object_STR[:2] == "N_":
                        writeIntOrHex(fileBin,enemyWeightValue,1) #Write lower spawn limit value!
def findHeaderinBAR(fileOpened, string, navigateToNewPos):

    if PS3Version():  #if Ps3, flip string because of endians
        string = string[len(string)::-1]
    test = string.encode('utf-8')
    if PS3Version(
    ):  #if Ps3, add spacing to get to the start like on the ps2 version
        while len(test) < 4:
            test = b'\00' + test
    fileOpened.seek(findBarHeader(fileOpened), 0)

    dataRead = fileOpened.read()
    if test in dataRead:
        # find header thing
        barheaderOffsetPos = findBarHeader(fileOpened)
        btlIndex = dataRead.find(test)
        fileOpened.seek(barheaderOffsetPos + btlIndex, 0)
        if navigateToNewPos:
            if not PS3Version():
                fileOpened.seek(4, 1)
            else:
                fileOpened.seek(len(test), 1)
            newPos = readAndUnpack(fileOpened, 4)
            fileOpened.seek(newPos + barheaderOffsetPos, 0)
        return True
    else:
        return False
Example #6
0
 def getBonusLevelsFromMSN():
     fileBonuslevels = []
     path = "export/KH2/msn/jp/"
     if PS3Version():
         path = "export/msn/us/"
     msnFileList = getAllFileNamesInFolder(path)
     for msnFile in msnFileList:
         fileBin = open(path + msnFile, 'rb+')
         barOffset = findBarHeader(fileBin)
         fileBin.seek(0x18 + barOffset,
                      0)  # Skip to first header and get pos
         newPos = readAndUnpack(fileBin, 4)
         fileBin.seek(newPos + barOffset, 0)
         fileBin.seek(0xD, 1)
         fileBonuslevels.append(readAndUnpack(fileBin, 1))
         fileBin.close()
     fileBonuslevels = sorted(list(dict.fromkeys(fileBonuslevels)))
     return fileBonuslevels
 def subSpawnChanging(var):
     nonlocal spawnData,fileBin,TotalSubSpawn
     if spawnData[var].noExtraData > 0 :
         noTransforms = 0
         fileBin.seek(TotalSubSpawn + 2,0)
         noTransforms = readAndUnpack(fileBin,2)
         TotalSubSpawn += 0x8 + (noTransforms* 0xC)
     if spawnData[var].noExtraData2 > 0 :
         TotalSubSpawn += (0x10 * spawnData[var].noExtraData2)
     if spawnData[var].noExtraData3 > 0 :
         TotalSubSpawn += (8 * spawnData[var].noExtraData3)
def appendToSpecificPos(
        fileName, position, header,
        data):  #Add new data to a specific position and update bar headers
    fileBin_A = open(fileName, 'ab+')
    fileBin_A.seek(position, 0)
    lastpos = fileBin_A.tell()
    furtherData = fileBin_A.read()
    fileBin_A.seek(lastpos, 0)
    fileBin_A.truncate()
    newDataSize = len(data)
    fileBin_A.write(data)
    fileBin_A.write(furtherData)
    fileBin_A.close()
    fileBin_RW = open(fileName, 'rb+')
    barHeaderPos = findBarHeader(fileBin_RW)
    fileBin_RW.seek(barHeaderPos + 0x4, 0)
    barEntries = readAndUnpack(fileBin_RW, 4)
    foundBarHeader = False
    for x in range(barEntries):
        fileBin_RW.seek(barHeaderPos + 0x10 + (x * 0x10), 0)
        fileBin_RW.seek(0x4, 1)
        barString = ReverseEndianString(
            fileBin_RW.read(4).decode().rstrip('\x00'), 1, False)
        if foundBarHeader:
            OldPos = readUnpackGoBack(fileBin_RW, 4)
            OldPos += newDataSize
            writeIntOrHex(fileBin_RW, OldPos, 4)
        if barString == header:
            foundBarHeader = True
            fileBin_RW.seek(0x4, 1)
            OldSize = readUnpackGoBack(fileBin_RW, 4)
            OldSize += newDataSize
            writeIntOrHex(fileBin_RW, OldSize, 4)
    fileBin_RW.seek(barHeaderPos + 0x10 + ((barEntries - 1) * 0x10), 0)
    fileBin_RW.seek(0x8, 1)
    LastPos = readAndUnpack(fileBin_RW, 4)
    LastSize = readAndUnpack(fileBin_RW, 4)
    TotalBarSize = LastPos + LastSize
    ModifyExtraFilePosition(fileBin_RW,
                            TotalBarSize + 0x10)  #add for total file offset
Example #9
0
def ReduceFormGrinding(shouldIreduce):
    if (shouldIreduce):
        print("Reducing form grinding...")
        if (copyKHFile("00battle.bin")):
            fileBin = open("00battle.bin", 'rb+')  # skip 4 bytes
            findHeaderinBAR(fileBin, 'fmlv', True)  # skip 4 bytes
            if (fileBin):
                fileBin.seek(0x8, 1)  #skip foward 8
                for formType in range(5):
                    for formLevel in range(6):
                        levelUpsStartPos = fileBin.tell(
                        )  # gimmie our currentPosition
                        fileBin.seek(0x1,
                                     1)  # skip level byte, we know it already
                        FormLVL = readAndUnpack(fileBin, 1)
                        AbilityFormLvlUp = readAndUnpack(fileBin, 2)
                        FormLVLUpXP = readAndUnpack(fileBin, 4)
                        #times 0.40 drive xp
                        FormLVLUpXP = math.floor(FormLVLUpXP * 0.37)
                        fileBin.seek(-4, 1)
                        writeIntOrHex(fileBin, FormLVLUpXP, 4)
                    fileBin.seek(0x8, 1)

            fileBin.close()
def openKHText(file):  #ex : file:msg/jp/tt.bar
    #open file, grab all strings, then when we finish modifying all the strings, get the length of them all and replace.
    #Unordered list with ID and Position.
    fileBin = open(file, 'rb+')
    offset = findBarHeader(fileBin)
    test = (
        file[len(file) - 4 - 2:]
    )[:
      2]  #Find world name by removing the last 4 characters and subtracting the length to start at the world name
    findHeaderinBAR(fileBin, test, False)
    fileBin.seek(0x8, 1)  # skip header thing
    stringSize = readAndUnpack(fileBin, 4)
    findHeaderinBAR(fileBin, test, True)
    startingStringTablePos = fileBin.tell()
    fileBin.seek(0x4, 1)  #skip header thing
    amountOfTextLines = readAndUnpack(fileBin, 4)
    stringList = []
    for x in range(amountOfTextLines):

        fileBin.seek(startingStringTablePos + 8 + (x * 8), 0)
        stringID = readAndUnpack(fileBin, 4)
        stringPos = readAndUnpack(fileBin, 4)
        filterStuff = list(
            filter(lambda x: (stringPos == x.position), stringList))
        if len(filterStuff) != 0:
            filterStuff[0].addID(stringID)
        else:
            stringList.append(TextBar(stringID, stringPos, ''))

    stringList = sorted(stringList, key=lambda x: x.position)
    fileBin.seek(startingStringTablePos + 8 + (amountOfTextLines * 8), 0)
    for x in range(len(stringList)):
        stringData = []
        currentChar = -1
        currentNextID = 1

        if x < len(stringList) - 1:
            lengthOfString = (stringList[x + currentNextID].position -
                              stringList[x].position)
            while lengthOfString > 0:
                currentChar = readAndUnpack(fileBin, 1)
                stringData.append(currentChar)
                lengthOfString -= 1
        else:
            lengthOfString = ((stringSize) - stringList[x].position)
            while lengthOfString > 0:
                currentChar = readAndUnpack(fileBin, 1)
                stringData.append(currentChar)
                lengthOfString -= 1

        stringList[x].text = stringData
    fileBin.close()
    return stringList
Example #11
0
def RandomizeCriticalBonusAbilities(shouldIrandomize, shouldIrandomize2):
    offSetSeed(5)
    if (shouldIrandomize and shouldIrandomize2):
        print("Modifying critical bonus abilities...")
        if (copyKHFile("00battle.bin")):
            fileBin = open("00battle.bin", 'rb+')
            findHeaderinBAR(
                fileBin, 'plrp',
                True)  # skip to nearest bar closest to where we want to go
            if (fileBin):
                fileBin.seek(0x1f94, 1)  #skip to critical mode abilities
                currentPos = fileBin.tell()
                critBonusNum = 300
                for i in range(7):
                    fileBin.seek(currentPos + (i * 2), 0)
                    OldAbility = readAndUnpack(fileBin, 2)
                    fileBin.seek(-2, 1)  # Go bak
                    if OldAbility != 0x194:  #Do not randomize no exp
                        newList = list(
                            filter(lambda d: d.character == KHCharacter.Sora,
                                   AbilityList[AbilityTable_enum.Support])
                        )  # Check for same character
                        newList = list(
                            filter(
                                lambda d: d.abilityLearned == AbilityTypeGained
                                .CriticalBonus, newList))
                        newList = list(filter(lambda d: d.emptyItem(),
                                              newList))
                        if len(newList) != 0:
                            random.shuffle(newList)
                            fromNewList = AbilityList[
                                AbilityTable_enum.Support].index(newList[0])
                            AbilityList[AbilityTable_enum.
                                        Support][fromNewList].subtractQOne()
                            writeIntOrHex(
                                fileBin, AbilityList[AbilityTable_enum.Support]
                                [fromNewList].code, 2)
                            writeOutCome_BonusLevel(
                                KHCharacter.Sora, critBonusNum,
                                AbilityList[AbilityTable_enum.Support]
                                [fromNewList].name)
                            critBonusNum += 1
Example #12
0
 def itemShopBuyingSellingPrices():
     findHeaderinBAR(fileBin, 'item', True)
     fileBin.seek(0x4, 1)
     itemsToChange = readAndUnpack(fileBin, 4)
     OrgPos = fileBin.tell()
     for item in range(itemsToChange):
         fileBin.seek(OrgPos + (item * 0x18), 0)
         itemID = readUnpackGoBack(fileBin, 2)
         fileBin.seek(0xC, 1)
         BuyPriceExisting = readUnpackGoBack(fileBin, 2)
         #loop through and find item in list
         newItem = -1
         for item_x in ItemList_Shop:
             if item_x.codeReturn() == itemID:
                 newItem = item_x
                 break
         if newItem != -1 and item_x.shopPrice != -1:
             writeIntOrHex(fileBin, item_x.shopPrice,
                           2)  #Write new shop buy money
             writeIntOrHex(
                 fileBin, int(item_x.shopPrice * 0.50), 2
             )  #Write new shop sell money times 0.50 of buy price
def ModifyExtraFileNames(fileBin, oldFileName, NewfileName):  #PS3 Version Only
    #Extra file names that are present in some files
    #If they aren't renamed, the game will fail to load them.
    if PS3Version():
        oldPos = fileBin.tell()
        fileBin.seek(4, 0)
        amtOfExtraFileEntries = readAndUnpack(fileBin, 4)
        for x in range(amtOfExtraFileEntries):
            fileBin.seek(0x10 + (x * 0x30), 0)
            extraFileNameStr = fileBin.read(0x20).decode("UTF-8").rstrip(
                '\x00')
            extraFileNameStr = extraFileNameStr.replace(
                oldFileName, NewfileName)
            fileBin.seek(0x10 + (x * 0x30), 0)
            emptyString = '\x00' * 20  #Clear out before writing so we dont miss any leftover bytes.
            fileBin.write(emptyString.encode("UTF-8"))
            fileBin.seek(0x10 + (x * 0x30), 0)
            fileBin.write(extraFileNameStr.encode("UTF-8"))
        fileBin.seek(oldPos, 0)

    else:
        return False
Example #14
0
 def shopItemChanging():
     findHeaderinBAR(fileBin, 'shop', True)
     itemsToChange = int(
         0x3a0 /
         2)  #Size divided by entry size to get total entries
     fileBin.seek(
         0xC70, 1
     )  #skip all this data i dont know about and go to items
     for shop_item in range(itemsToChange):
         CurrentList = list(
             filter(lambda x: (x.emptyItem()), ItemList_Shop))
         previousItem = readAndUnpack(fileBin, 2)
         fileBin.seek(-2, 1)
         chooseShopItem = random.choice(CurrentList)
         ItemList_Shop[ItemList_Shop.index(
             chooseShopItem)].subtractQOne()
         writeIntOrHex(fileBin, chooseShopItem.codeReturn(), 2)
         writeOutCome_ItemShop(
             shop_item, "OLD: " + "{:<20}".format(
                 findItemInList(ItemList_Shop,
                                previousItem).name) + "NEW:" +
             "{:<20}".format(chooseShopItem.name))
def msnFileCreate(
    fileName, curWorld, curRoom, oldMsnFileName
):  #pass in a mission file name, and the current room and world & will return the new Filename
    #lets check if the filename is equal to currentworld or currentroom
    #Lets also check if a mission file ID (last 3 digits) is already present in a room, otherwise we will overwrite something we wouldnt want to and have the player softlock
    fileExtension = '.bar'
    oldMsnFileName = oldMsnFileName.rstrip(' \t\r\n\0')
    if (fileName[:4] == curWorld.upper() + curRoom.upper()):
        return fileName  #We dont need to do anything in this case.
    searchHeader = oldMsnFileName[:4]
    newFileName = curWorld.upper() + curRoom.upper() + fileName[
        4:] + '_R'  #Add _R so we dont overwrite missions (_R == Randomized)
    importFolderName = "export/KH2/msn/jp/"
    if PS3Version():
        importFolderName = "export/msn/us/"
    exportFolderName = "msn/jp/"
    if PS3Version():
        exportFolderName = "msn/us/"
    if (os.path.isfile(importFolderName + fileName + fileExtension)):
        if not os.path.exists(exportFolderName):
            os.makedirs(exportFolderName)
        try:
            fileBin = open(
                importFolderName + oldMsnFileName.rstrip() + fileExtension,
                'rb+')
        except FileNotFoundError:
            fileBin = open(exportFolderName + oldMsnFileName + fileExtension,
                           'rb+')
        barOffset = findBarHeader(fileBin)
        fileBin.seek(barOffset + 0x18, 0)  #Skip to first header and get pos
        newPos = readAndUnpack(fileBin, 4)
        fileBin.seek(barOffset + newPos, 0)
        fileBin.seek(0xD, 1)
        oldBonusLevel = readAndUnpack(fileBin, 1)
        fileBin.close()
        shutil.copyfile(importFolderName + fileName + fileExtension,
                        exportFolderName + newFileName + fileExtension)
        print("Copying file...")
        writeRandomizationLog(exportFolderName + newFileName + fileExtension)

        fileBin = open(exportFolderName + newFileName + fileExtension,
                       'rb+')  #Modify file to use correct bonus level.
        ModifyExtraFileNames(fileBin, fileName, newFileName)
        #replaceAllStringInFile(fileBin,fileName.lower(),newFileName.lower())
        findHeaderinBAR(fileBin, fileName[:4], True)
        fileBin.seek(0xD, 1)
        writeIntOrHex(fileBin, oldBonusLevel, 1)
        fileBin.close()
        if PS3Version():
            for x in regionFolders:
                filestring = 'msn/' + x + "/" + newFileName + fileExtension
                if not os.path.exists('msn/' + x + '/'):
                    os.makedirs('msn/' + x + '/')
                shutil.copyfile(exportFolderName + newFileName + fileExtension,
                                filestring)
                print("Copying file for another region...")
                writeRandomizationLog(filestring)

        return newFileName
    else:
        print("Couldn't find msn file to copy...")
        return fileName
Example #16
0
def randomizeItemDrops(randomItemD, randomItemDP):
    offSetSeed(7)
    if (randomItemD or randomItemDP):
        print("Randomizing item drops from enemies...")
        if (copyKHFile("00battle.bin")):
            fileBin = open("00battle.bin", "rb+")
            if (fileBin):
                findHeaderinBAR(fileBin, 'przt', True)
                fileBin.seek(4, 1)

                #Size 0x18
                entryAmt = readAndUnpack(fileBin, 4)
                entryPos = fileBin.tell()
                for x in range(entryAmt):
                    fileBin.seek(entryPos + (x * 0x18), 0)
                    entryIndex = readAndUnpack(fileBin, 2)
                    droppedItemList = [0, 0, 0]
                    droppedItemListProbability = [0, 0, 0]
                    fileBin.seek(0xA, 1)
                    writingPosition = fileBin.tell()
                    for i in range(3):  #Clear it
                        writeIntOrHex(fileBin, 0, 2)
                        writeIntOrHex(fileBin, 0, 2)
                    #probability == percentage in clear num == 12% == 12 not 0.12 or anything silly
                    #Randomize items
                    if randomItemD:
                        for itemnum in range(len(droppedItemList)):
                            droppedItemList[itemnum] = random.choice(
                                itemDropList).code
                    if randomItemDP:
                        for itemnum in range(len(droppedItemListProbability)):
                            chanceList = [
                                random.randint(5, 100),
                                random.randint(5, 50),
                                random.randint(5, 25)
                            ]
                            chanceList_Weight = [0.3, 0.5, 0.2]
                            newRando = random.choices(
                                chanceList, k=1, weights=chanceList_Weight)[0]
                            droppedItemListProbability[
                                itemnum] = newRando  # 5% to 100 chance of an item dropping

                    #Write items
                    chanceList = [0, 1, 2, 3]
                    randomItemAmount = random.choices(
                        chanceList, k=1, weights=[0.7, 0.3, 0.2, 0.1])[0]
                    """
                    fileBin.seek(entryPos + (x * 0x18), 0)
                    fileBin.seek(2,1)
                    orbSelectionList = []
                    orbListTypes = range(10)
                    for p in range(random.randint(0,3)): #Select types of the enemy will drop
                        orbSelectionList.append(random.choice(orbListTypes)) #Select which orb type to use
                    for e in range(0xA):
                        if e in orbSelectionList:
                            writeIntOrHex(fileBin,random.randint(0,5),1)#Write amount of orbs to drop
                        else:
                            fileBin.seek(1, 1)
"""
                    fileBin.seek(writingPosition, 0)
                    for newRandomItems in range(randomItemAmount):
                        writeIntOrHex(fileBin, droppedItemList[newRandomItems],
                                      2)
                        writeIntOrHex(
                            fileBin,
                            droppedItemListProbability[newRandomItems], 2)
            fileBin.close()
Example #17
0
def RandomizeLevelUps(shouldIrandomize):
    offSetSeed(6)
    if (shouldIrandomize):
        print("Modifying level ups for all characters...")
        if (copyKHFile("00battle.bin")):
            fileBin = open(
                "00battle.bin",
                'rb+')  # skip like 4 hexs because it has useless data lol
            findHeaderinBAR(fileBin, 'lvup', True)
            if (fileBin):
                levelUpsStartPos = fileBin.tell()  #gimmie our currentPosition
                fileBin.seek(0x40, 1)
                amtOfLevels = readAndUnpack(fileBin, 4)
                #choose some abilities for some choices
                LVLLength = len(AbilityList[AbilityTable_enum.LevelUp])
                lvlAbilitiesList = [[], [], []]
                for lvlupability in AbilityList[AbilityTable_enum.LevelUp]:
                    lvlAbilitiesList[0].append(
                        (lvlupability.code, lvlupability.name))  #Sword
                    lvlAbilitiesList[1].append(
                        (lvlupability.code, lvlupability.name))  #Shield
                    lvlAbilitiesList[2].append(
                        (lvlupability.code, lvlupability.name))  #Staff
                #now shuffle
                random.shuffle(lvlAbilitiesList[0])
                random.shuffle(lvlAbilitiesList[1])
                random.shuffle(lvlAbilitiesList[2])
                noneString = ''
                emptyTuple = (0, noneString)
                AbilityLevelsNums = random.choices(
                    range(1, amtOfLevels), k=LVLLength
                )  #I'd love to do indiviudal levels based on sword,shield  & staff but that would mean weaker lvls
                for chars in range(13):
                    stats = [
                        random.randint(0, 5),
                        random.randint(0, 5),
                        random.randint(0, 5),
                        random.randint(0, 5)
                    ]
                    if (chars == 0):  #sora
                        stats = [2, 6, 2, 0]
                    if (chars == 1):  #donald
                        stats = [1, 5, 2, 5]
                    if (chars == 2):  #goofy
                        stats = [5, 0, 2, 4]
                    SwordAbility_Modified = emptyTuple
                    ShieldAbility_Modified = emptyTuple
                    StaffAbility_Modified = emptyTuple
                    for i in range(amtOfLevels):
                        beforeMoving = fileBin.tell()
                        CurrentLevel = i + 1
                        writeOutCome_LevelUps(
                            chars, i, " STR:" + "{:<4}".format(str(stats[0])) +
                            " MAGIC:" + "{:<4}".format(str(stats[1])) +
                            " DEF:" + "{:<4}".format(str(stats[2])) + " AP:" +
                            "{:<4}".format(str(stats[3])) + " SwordAbility:" +
                            "{:<20}".format(str(SwordAbility_Modified[1])) +
                            " ShieldAbility:" +
                            "{:<20}".format(str(ShieldAbility_Modified[1])) +
                            " StaffAbility:" +
                            "{:<20}".format(str(StaffAbility_Modified[1])))
                        #EXPNeeded = readAndUnpack(fileBin,4)
                        fileBin.seek(8, 1)  #skip exp and stats
                        if (chars == 0):
                            SwordAbility = readAndUnpack(fileBin, 2)
                            ShieldAbility = readAndUnpack(fileBin, 2)
                            StaffAbility = readAndUnpack(fileBin, 2)
                        else:
                            fileBin.seek(0x6, 1)
                        fileBin.seek(beforeMoving, 0)  #go back to beginning
                        fileBin.seek(4, 1)  #skip exp
                        writeIntOrHex(fileBin, stats[0], 1)  #write stats
                        writeIntOrHex(fileBin, stats[1], 1)
                        writeIntOrHex(fileBin, stats[2], 1)
                        writeIntOrHex(fileBin, stats[3], 1)
                        if (chars == 0):
                            writeIntOrHex(fileBin, SwordAbility_Modified[0], 2)
                            writeIntOrHex(fileBin, ShieldAbility_Modified[0],
                                          2)
                            writeIntOrHex(fileBin, StaffAbility_Modified[0], 2)
                        else:
                            fileBin.seek(0x6, 1)
                        #--Increase stats for next time--
                        #we can only increase 1 or 2 values depending on the ability that is present otherwise the game will not know how to handle it and crash
                        SwordAbility_Modified = emptyTuple
                        ShieldAbility_Modified = emptyTuple
                        StaffAbility_Modified = emptyTuple
                        if (i not in AbilityLevelsNums or chars != 0):
                            statsAmtToRandomize = 2
                        else:
                            #We will randomize the abilities now
                            SwordAbility_Modified = lvlAbilitiesList[0].pop(0)
                            ShieldAbility_Modified = lvlAbilitiesList[1].pop(0)
                            StaffAbility_Modified = lvlAbilitiesList[2].pop(0)
                            statsAmtToRandomize = 1

                        randomStat = [0, 1, 2, 3]
                        endingList = []
                        for x in range(statsAmtToRandomize):
                            randomnum = random.randint(0, len(randomStat) - 1)
                            poppednum = randomStat.pop(randomnum)
                            endingList.append(poppednum)
                        for y in endingList:
                            stats[y] += random.randint(0, 3)
                        #STR = readAndUnpack(fileBin,1)
                        #MAG = readAndUnpack(fileBin,1)
                        #DEF = readAndUnpack(fileBin,1)
                        #AP = readAndUnpack(fileBin,1)

                        fileBin.seek(2, 1)  # skip two bytes
                    fileBin.seek(0x4, 1)  # skip four bytes

            fileBin.close()
Example #18
0
def RandomizeBonusLevels(bonusLevelBool, bonusItemBool, critBonusBool,
                         extraAbilitiesInt, GiveGuard):
    offSetSeed(3)

    def getBonusLevelsFromMSN():
        fileBonuslevels = []
        path = "export/KH2/msn/jp/"
        if PS3Version():
            path = "export/msn/us/"
        msnFileList = getAllFileNamesInFolder(path)
        for msnFile in msnFileList:
            fileBin = open(path + msnFile, 'rb+')
            barOffset = findBarHeader(fileBin)
            fileBin.seek(0x18 + barOffset,
                         0)  # Skip to first header and get pos
            newPos = readAndUnpack(fileBin, 4)
            fileBin.seek(newPos + barOffset, 0)
            fileBin.seek(0xD, 1)
            fileBonuslevels.append(readAndUnpack(fileBin, 1))
            fileBin.close()
        fileBonuslevels = sorted(list(dict.fromkeys(fileBonuslevels)))
        return fileBonuslevels

    if GiveGuard:
        newList = list(
            filter(lambda d: d.code == 0x052, AbilityList[
                AbilityTable_enum.Action]))  # Check for same character
        newList[0].maximum = 0
    if extraAbilitiesInt == 2:  #If user asks for more abilities
        newList = list(
            filter(lambda d: d.character == KHCharacter.Sora, AbilityList[
                AbilityTable_enum.Support]))  # Check for same character
        newList = list(
            filter(lambda d: d.abilitytype == AbilityType.Additive, newList))
        #Grab from level up pool too!
        newList2 = list(
            filter(lambda d: d.character == KHCharacter.Sora, AbilityList[
                AbilityTable_enum.LevelUp]))  # Check for same character
        newList2 = list(
            filter(lambda d: d.abilitytype == AbilityType.Additive, newList2))
        newList = newList + newList2
        for i in range(20):  #Give like 20 more bonus abilities
            itemToCopy = random.choices(newList, k=1)[0]
            itemCopied = copy.deepcopy(itemToCopy)
            itemCopied.abilityLearned = AbilityTypeGained.Normal
            AbilityList[AbilityTable_enum.Support].append(itemCopied)

    if critBonusBool:
        # Randomize critical mode abilities by setting them to normal and grabbing random normal abilities
        newList = list(
            filter(lambda d: d.character == KHCharacter.Sora, AbilityList[
                AbilityTable_enum.Support]))  # Check for same character
        newList = list(
            filter(
                lambda d: d.abilityLearned == AbilityTypeGained.CriticalBonus,
                newList))
        newList = list(filter(lambda d: d.emptyItem(), newList))
        critAbilitiesNum = 0
        for abilityitem in newList:
            critAbilitiesNum += abilityitem.maximum
            abilityitem.abilityLearned = AbilityTypeGained.Normal

        amountOfAbilitiesNum = 0
        while amountOfAbilitiesNum < critAbilitiesNum:
            newList = list(
                filter(lambda d: d.character == KHCharacter.Sora,
                       AbilityList[AbilityTable_enum.Support]))
            newList = list(
                filter(lambda d: d.abilityLearned == AbilityTypeGained.Normal,
                       newList))
            newList = list(filter(lambda d: d.emptyItem(), newList))

            itemsToBonus = random.choice(newList)
            index = AbilityList[AbilityTable_enum.Support].index(itemsToBonus)
            itemsToBonus = AbilityList[AbilityTable_enum.Support][index]
            if itemsToBonus.abilityLearned == AbilityTypeGained.Normal:
                if itemsToBonus.maximum + amountOfAbilitiesNum <= critAbilitiesNum:
                    amountOfAbilitiesNum += itemsToBonus.maximum
                    itemsToBonus.abilityLearned = AbilityTypeGained.CriticalBonus
    #character,type of boost
    CharBoosts = []
    bonusLevelCharData = []
    for i in range(15):
        bonusLevelCharData.append([])
    abilityChoosing = []
    for i in range(15):
        abilityChoosing.append([])
    abilitesForEachChar = []
    for i in range(3):
        abilitesForEachChar.append(0)

    #get number of bonus abilities for each char
    for char in KHCharacter:
        amount = 0
        for type in range(len(AbilityList)):
            if type != AbilityTable_enum.LevelUp:
                for itemAb in AbilityList[type]:
                    if itemAb.character == char and itemAb.abilityLearned == AbilityTypeGained.Normal and itemAb.emptyItem(
                    ):
                        amount += 1
        abilitesForEachChar[char] = amount

    for char in range(3):
        CharBoosts.append([0])
        for type in range(6):
            CharBoosts[char].append(0)
            #HP MP ARMOR ACCESSORY ITEM DRIVE
    maxCharBoosts = [[20, 4, 3, 6, 5, 3], [18, 0, 1, 0, 2, 1],
                     [17, 0, 1, 0, 3, 1]]

    def randomizeABonusLevel(hp, mp, armor, access, item, drive, abilityitem1,
                             abilityitem2, char, bonslevel):
        nonlocal GiveGuard
        oldChar = char
        if char + 1 == 0xE:  # If the character is roxas, change it to sora's num because theyre the same
            char = 0
        hp = mp = armor = drive = item = access = abilityitem2 = abilityitem1 = 0  #Reset all
        currentNotifications = 0
        typeOfAbility = -1
        abilityitem1_name = ""
        abilityitem2_name = ""

        if bonslevel == 0x36:
            currentNotifications = 2  #Do not randomize Stats if the bonus level is 36/ Aerial recovery since it doesnt give that for some reason
            if GiveGuard:
                abilityitem1 = 0x052
                abilityitem1_name = "Guard (Forced)"
        if (BonusLevel not in bonusNumList
            ):  # Blacklist bonus levels not in the game.
            currentNotifications = 2  #
        #handle ability swapping here

        if bonslevel in abilityChoosing[
                char]:  #if the level we are is the same level that was randomly chosen to get an ability randomize by choosing between two ability types

            def filterListQuick(AbilityTp):
                newList = list(
                    filter(lambda d: d.character == char,
                           AbilityList[AbilityTp]))  # Check for same character
                newList = list(
                    filter(
                        lambda d: d.abilityLearned == AbilityTypeGained.Normal,
                        newList))  # Normal abilities only
                newList = list(filter(lambda d: d.emptyItem(),
                                      newList))  # Check if empty ability
                return newList

            abilityChoosing[char].remove(bonslevel)
            possibleChoices = []
            for types in range(2):
                if len(filterListQuick(types)) != 0:
                    possibleChoices.append(types)
            if len(possibleChoices) != 0:
                typeOfAbility = random.choice(possibleChoices)
                newList = filterListQuick(typeOfAbility)
                random.shuffle(newList)
                abilityitem1 = newList[0]
                index = AbilityList[typeOfAbility].index(abilityitem1)
                AbilityList[typeOfAbility][index].subtractQOne(
                )  #subtract cause we're using it
                abilityitem1 = AbilityList[typeOfAbility][index].code
                abilityitem1_name = AbilityList[typeOfAbility][index].name
                currentNotifications += 1

        usedThisRound = [0, 0, 0, 0, 0, 0]
        while currentNotifications < 2:  #Do stat boosts here
            randomizeBoostList = []

            for x in CharacterBoostType:
                if (CharBoosts[char][x] < maxCharBoosts[char][x]
                        and not usedThisRound[x]):
                    randomizeBoostList.append(x)
            if len(randomizeBoostList) != 0:
                slotToRandomize = random.choices(randomizeBoostList, k=1)[0]

                #handle adding to new boosts
                for boosttype in CharacterBoostType:
                    if (slotToRandomize == boosttype):
                        if boosttype == CharacterBoostType.HPBoosts:
                            hp = KHCharacterHPTable[char]
                        if boosttype == CharacterBoostType.MPBoosts:
                            mp = 0xa
                        if boosttype == CharacterBoostType.DriveUpgrades:
                            drive = 1
                        if boosttype == CharacterBoostType.ArmorSlots:
                            armor = 1
                        if boosttype == CharacterBoostType.Items:
                            item = 1
                        if boosttype == CharacterBoostType.Accessory:
                            access = 1
                        usedThisRound[boosttype] = True
                        CharBoosts[char][boosttype] += 1
                        currentNotifications += 1

            else:
                break
        if bonusItemBool and currentNotifications < 2:  # After everything is done and we still have an empty slot, give an bonus item
            tablesToChooseFrom = (kh2rando_itemTable.accessory_table,
                                  kh2rando_itemTable.synthesis_table,
                                  kh2rando_itemTable.item_table)
            weightTable = (0.5, 0.4, 0.8)
            choosenChoice = random.choices(tablesToChooseFrom,
                                           weights=weightTable,
                                           k=1)[0]
            choosenItemKey = random.choice(list(choosenChoice.keys()))
            choosenItem = choosenChoice[choosenItemKey]
            abilityitem2 = choosenItem[3]
            abilityitem2_name = choosenItemKey
            currentNotifications += 1
        if hp == 0 and mp == 0 and armor == 0 and drive == 0 and item == 0 and access == 0 and abilityitem1 == 0 and abilityitem2 == 0:
            alertDebug = 0
        if (BonusLevel in bonusNumList):
            writeOutCome_BonusLevel(
                oldChar, bonslevel, "HP:" + "{:<4}".format(str(hp)) + " MP:" +
                "{:<4}".format(str(mp)) + " ARMOR:" +
                "{:<4}".format(str(armor)) + " DRIVE:" +
                "{:<4}".format(str(drive)) + " ITEM:" +
                "{:<4}".format(str(item)) + " ACCESSORY:" +
                "{:<4}".format(str(access)) + " Ability/Item:" +
                ("{:<20}".format(abilityitem1_name)) + " Ability/Item 2:" +
                ("{:<20}".format(abilityitem2_name)))
        #Returning format might be wrong!!!!
        #hp mp drive?,item?,armor,access
        return (hp, mp, drive, item, armor, access, abilityitem1, abilityitem2)

    if (bonusLevelBool):
        print("Modifying bonus levels...")
        bonusNumList = getBonusLevelsFromMSN()
        if (copyKHFile("00battle.bin")):
            fileBin = open(
                "00battle.bin",
                'rb+')  # skip like 4 hexs because it has useless data lol
            findHeaderinBAR(fileBin, 'bons', True)
            if (fileBin):
                levelBonusStartPos = fileBin.tell(
                )  #gimmie our currentPosition
                fileBin.seek(4, 1)
                amtOfBonusLevels = readAndUnpack(fileBin, 4)  #
                for i in range(
                        amtOfBonusLevels + 1
                ):  #Get the amount of bonus levels for specific characters
                    fileBin.seek(
                        levelBonusStartPos + 8 + (i * 0x10), 0
                    ),  # reset back to original position for writing thats coming up (Plus two to skip bonus level and character)
                    BonusLevel = readAndUnpack(fileBin, 1)  # Bonus level
                    Character = readAndUnpack(
                        fileBin, 1
                    )  # Character value. 01 == sora 02 == donald 03 == goofy ...etc for others
                    if Character == 0xE:  # If the character is roxas, change it to sora's num because theyre the same
                        Character = 1
                    if (BonusLevel != 0x36 or not GiveGuard):
                        if (
                                BonusLevel in bonusNumList
                        ):  #Make sure the bonus level is actually used ingame.
                            bonusLevelCharData[Character -
                                               1].append(BonusLevel)
                #now that we have data, choose ability locations throughout the bonuses

                for char in KHCharacter:
                    for choicenum in range(abilitesForEachChar[char]):
                        newChoice = random.choice(bonusLevelCharData[char])
                        popout = bonusLevelCharData[char].pop(
                            bonusLevelCharData[char].index(newChoice))
                        abilityChoosing[char].append(popout)

                randomBonusLevelLoop = list(range(amtOfBonusLevels + 1))
                random.shuffle(
                    randomBonusLevelLoop
                )  # We will randomize the order we go through chests in in order to be a bit more random. Kinda odd but yea so we evenly spread out priority items instead of like in a row.

                for i in randomBonusLevelLoop:
                    fileBin.seek(
                        levelBonusStartPos + 8 + (i * 0x10), 0
                    ),  # reset back to original position for writing thats coming up (Plus two to skip bonus level and character)
                    BonusLevel = readAndUnpack(fileBin, 1)  # Bonus level
                    Character = readAndUnpack(
                        fileBin, 1
                    )  # Character value. 01 == sora 02 == donald 03 == goofy ...etc for others
                    HPVal = readAndUnpack(fileBin, 1)  # HP Value.
                    MPVal = readAndUnpack(fileBin, 1)  # MP Value.
                    SlotUpgrades_Armor = readAndUnpack(
                        fileBin, 1)  # Slot upgrade to player or party member
                    SlotUpgrades_Accessory = readAndUnpack(
                        fileBin, 1)  # Slot upgrades to player or party member
                    SlotUpgrades_Item = readAndUnpack(
                        fileBin, 1)  # Slot upgrades to player or party member
                    SlotUpgrades_Drive = readAndUnpack(
                        fileBin, 1)  # Slot upgrades to player or party member
                    AbilityItem1 = readAndUnpack(
                        fileBin,
                        2)  # Ability upgrades to player or party member
                    AbilityItem2 = readAndUnpack(
                        fileBin,
                        2)  # Ability upgrades to player or party member
                    fileBin.seek(levelBonusStartPos + 8 + 2 + (i * 0x10), 0)
                    if (Character >= 1 and Character < 4 or Character == 0xE):
                        newbonusLevelVal = randomizeABonusLevel(
                            HPVal, MPVal, SlotUpgrades_Armor,
                            SlotUpgrades_Drive, SlotUpgrades_Item,
                            SlotUpgrades_Accessory, AbilityItem1, AbilityItem2,
                            Character - 1, BonusLevel)
                        for y in range(6):
                            writeIntOrHex(fileBin, newbonusLevelVal[y],
                                          1)  #write hp,mp,slot,slot,slot,slot
                        writeIntOrHex(fileBin, newbonusLevelVal[6],
                                      2)  # write ability
                        writeIntOrHex(fileBin, newbonusLevelVal[7],
                                      2)  # write ability

                fileBin.close()
Example #19
0
def RandomizeDriveFormAbilities(shouldIrandomize):
    offSetSeed(4)
    if (shouldIrandomize):
        print("Modifying drive form abilities...")
        if (copyKHFile("00battle.bin")):
            fileBin = open("00battle.bin", 'rb+')  # skip 4 bytes
            findHeaderinBAR(fileBin, 'fmlv', True)  # skip 4 bytes
            if (fileBin):
                fileBin.seek(0x8, 1)  #skip foward 8
                formData = []
                filePos = fileBin.tell()
                #Read
                for formType in FormTypeEnum:
                    formData.append([])
                    for formLevel in range(7):
                        formData[formType].append([])
                        fileBin.seek(0x2,
                                     1)  # skip level byte, we know it already
                        AbilityFormLvlUp = readAndUnpack(fileBin, 2)
                        fileBin.seek(0x4, 1)
                        formData[formType][formLevel] = AbilityFormLvlUp
                #Modify
                formBonusNum = 200
                AutoAbility = {0x181, 0x183, 0x184}
                randomFormType = list(FormTypeEnum)
                random.shuffle(randomFormType)
                randomFormData = list(range(len(formData[formType])))
                random.shuffle(randomFormData)

                for formType in randomFormType:
                    for dt in randomFormData:
                        newList = list(
                            filter(lambda d: d.character == KHCharacter.Sora,
                                   AbilityList[AbilityTable_enum.Support])
                        )  # Check for same character
                        newList = list(
                            filter(
                                lambda d: d.abilityLearned == AbilityTypeGained
                                .DriveForm, newList))
                        newList = list(
                            filter(lambda d: d.emptyItem(),
                                   newList))  # Check if empty ability
                        random.shuffle(newList)
                        if formType in range(1, 6):
                            if formData[formType][dt] != 0:
                                name = ""
                                if formData[formType][dt] == 0x181:
                                    name = 'Auto Valor'
                                if formData[formType][dt] == 0x183:
                                    name = 'Auto Master'
                                if formData[formType][dt] == 0x184:
                                    name = 'Auto Final'
                                if formData[formType][dt] not in AutoAbility:
                                    if len(newList) != 0:
                                        fromNewList = AbilityList[
                                            AbilityTable_enum.Support].index(
                                                newList[0])
                                        AbilityList[AbilityTable_enum.Support][
                                            fromNewList].subtractQOne()
                                        formData[formType][dt] = AbilityList[
                                            AbilityTable_enum.
                                            Support][fromNewList].code
                                        name = AbilityList[
                                            AbilityTable_enum.
                                            Support][fromNewList].name
                                    else:
                                        name = 'None.'
                                        formData[formType][dt] = 0

                                writeOutCome_BonusLevel(
                                    KHCharacter.Sora, formBonusNum,
                                    str(formType.name) + ":" + name)
                        formBonusNum += 1

                #Write
                fileBin.seek(filePos, 0)
                for formType in FormTypeEnum:
                    formData.append([])
                    for formLevel in range(7):
                        formData[formType].append([])
                        fileBin.seek(0x2,
                                     1)  # skip level byte, we know it already
                        AbilityFormLvlUp = writeIntOrHex(
                            fileBin, formData[formType][formLevel], 2)
                        fileBin.seek(0x4, 1)

            fileBin.close()
Example #20
0
def randomizeEquipmentStats(randomEquipStat, randomEquipAbility):
    offSetSeed(8)
    if (randomEquipStat or randomEquipAbility):
        print("Randomizing equipment stats...")
        if (copyKHFile("03system.bin")):
            fileBin = open("03system.bin", "rb+")
            if (fileBin):
                findHeaderinBAR(fileBin, 'item', True)

                #Size 0x18
                fileBin.seek(4, 1)  #Skip ??
                entryAmt = readAndUnpack(fileBin, 4)
                entryPos = fileBin.tell()
                StatusEffectIdList = []
                for x in range(entryAmt):
                    fileBin.seek(entryPos + (x * 0x18), 0)
                    ItemID = readAndUnpack(fileBin, 2)
                    CategoryID = readAndUnpack(
                        fileBin, 1
                    )  #This is really conflicting. Sometimes the status ID is only 2 bytes away and sometimes its 4. :<
                    if CategoryID == 0x0E or CategoryID == 0x0F:  #If armor or accessory
                        fileBin.seek(1, 1)
                    elif CategoryID == 0x02 or CategoryID == 0x03 or CategoryID == 0x04:  #If keyblade/shield/staff
                        fileBin.seek(3, 1)
                    else:
                        continue  #Skip, we dont want any other item if it isnt an armor, accessory or keyblade/weapon
                    StatusID = readAndUnpack(fileBin, 2)
                    StatusEffectIdList.append((StatusID, ItemID))

                RealStatusItems = [
                ]  #if the item matches up with an equipment, accessory or armor item we will add it to the list along with its object for later reference
                for itemThing in StatusEffectIdList:
                    for itemReal in newItemList:
                        if itemReal.code == itemThing[1] and itemThing[0] != 0:
                            RealStatusItems.append((itemThing[0], itemReal))

                fileBin.seek(entryPos + (entryAmt * 0x18), 0)
                statusModifier = []
                for whatever in range(12):
                    statusModifier.append(0)
                fileBin.seek(4, 1)
                statusAmt = readAndUnpack(fileBin, 4)  #I counted
                statusPos = fileBin.tell()
                for x in range(statusAmt):
                    statusPos_Entry = fileBin.tell()
                    statsID = readAndUnpack(fileBin, 2)
                    abilityID = readAndUnpack(fileBin, 2)
                    for d in range(12):
                        statusModifier[d] = readAndUnpack(fileBin, 1)

                    #Modify
                    ifinStatusItem = False
                    itemToUse = None
                    for xd in RealStatusItems:
                        if xd[0] == statsID:
                            itemToUse = xd[1]
                            ifinStatusItem = True
                            break

                    if ifinStatusItem:
                        fileBin.seek(statusPos_Entry + 2, 0)
                        if randomEquipAbility:
                            if itemToUse.type == itemType.Equipment or (
                                    itemToUse.type == itemType.Accessory
                                    and random.randint(0, 5) > 4
                            ):  #If the player is lucky, an ability is added.
                                abilityID = random.choice(newAbilityList).code
                        if randomEquipStat:
                            if itemToUse.type == itemType.Equipment or itemToUse.type == itemType.Accessory:
                                chanceList = [
                                    random.randint(1, 6),
                                    random.randint(1, 10),
                                    random.randint(0, 10)
                                ]
                                chanceList_Weight = [0.3, 0.5, 0.2]
                                newRando = random.choices(
                                    chanceList, k=1,
                                    weights=chanceList_Weight)[0]
                                chanceList = [
                                    random.randint(1, 6),
                                    random.randint(1, 10),
                                    random.randint(0, 10)
                                ]
                                newRando2 = random.choices(
                                    chanceList, k=1,
                                    weights=chanceList_Weight)[0]
                                statusModifier[
                                    EquipmentStats.StrengthStat] = newRando
                                statusModifier[
                                    EquipmentStats.MagicStat] = newRando2
                            if itemToUse.type == itemType.Accessory:
                                chanceList = [
                                    random.randint(1, 30),
                                    random.randint(1, 10),
                                    random.randint(0, 10)
                                ]
                                chanceList_Weight = [0.3, 0.5, 0.2]
                                newRando = random.choices(
                                    chanceList, k=1,
                                    weights=chanceList_Weight)[0]
                                statusModifier[
                                    EquipmentStats.APStat] = newRando
                            if itemToUse.type == itemType.Armor:
                                chanceList = [
                                    random.randint(1, 5),
                                    random.randint(1, 4),
                                    random.randint(0, 10)
                                ]
                                chanceList_Weight = [0.3, 0.5, 0.2]
                                newRando = random.choices(
                                    chanceList, k=1,
                                    weights=chanceList_Weight)[0]
                                statusModifier[
                                    EquipmentStats.DefenseStat] = newRando
                                for resistNums in range(4, 9):
                                    statusModifier[resistNums] = random.randint(
                                        75, 150
                                    )  #Not too OP, but gives the chance of reducing resistance
                                #for resistNums in range(9,10): #Global resist and invisible stuff so dont go too crazy
                                #statusModifier[resistNums] = random.randint(80,120)
                        writeIntOrHex(fileBin, abilityID, 2)
                        for d in range(12):
                            writeIntOrHex(fileBin, statusModifier[d], 1)
def RandomizeARD(randomizeEnemies, randomizeBosses,randomizeAllies, KH2SoraForced,PS2EnemyOptimizations,SuperBossEncounterRate):
    """
    Bosses when doing their DM go to the 0,0,0 XYZ point in the map
    Which sucks cause we have two options:
    Move the map data to a better location and also re adjust positions somehow
    Remove DMs from the boss
    """
    def FixMulanMSNSoftlock():
        findHeaderinBAR(fileBin, 'btl', True)
        stringToFind = ReverseEndianString('MU02_MS103B', 2, True,True).encode()
        posBefore = fileBin.tell()
        readData = fileBin.read()
        newPos = readData.find(stringToFind)
        fileBin.seek(posBefore + newPos, 0)
        #MSNFile text ID location : 0x14 from the first position == textid
        #MSNFile Help/Continue Pause button toggler: 0x16 from first position and needs to be 0x18 to work
        """
        What mission file seems to determine:
        First Mission Bar Entry:
        If enemies should drop items
        How pausing should work
        What text ID to display on the information tab
        
        Second Mission Bar Entry:
        ???
        Probably controls when enemies should attack during the camera movement phase
        Anything Else after these two entries:
        Camera Movement & Panning at the start of the mission
        Camera Movement & Panning when a boss dies or something fails
        The graphical effect when you defeat a boss
        ^ intrestingly unique for many fights. Take a look at Lingering Will's defeat camera and effect VS when roxas is defeated
        What images should be displayed EX: Luxord time bar, Mulan's Heartless Count and Motivation bar
        
        Seems like how enemies should spawn in is determined by ARD files not by MSN files
        
        MSN Files are loaded through reference in the ard file from 'BTL' and usually is assigned to an entry starting with 'b_'
"""
        newMSNFile_Location = msnFileCreate_NonBoss('MU02_MS103A')
        fileBin.write(ReverseEndianString('MU02_MS103A_R', 2, True, True).encode())
        MsnFileBin = open(newMSNFile_Location, 'rb+')
        findHeaderinBAR(MsnFileBin, 'MU02', True)
        MsnFileBin.seek(0x38, 1)
        writeIntOrHex(MsnFileBin, 0x0C, 4)
        MsnFileBin.close()

    def ucmPropertyModify(UCM,enemyType):
        fileBin.seek(position, 0)
        if EnemyPropertyExists(UCM,enemyType):

            if EnemyProperty(UCM,enemyType).extraEnemyData != -1:
                fileBin.seek(0x20, 1)  # Skip 20, find super boss variable
                writeIntOrHex(fileBin, EnemyProperty(UCM,enemyType).extraEnemyData, 4) #Seems like its 4 bytes.
            else:
                fileBin.seek(0x20, 1)  # Skip 20, find super boss variable
                writeIntOrHex(fileBin, 0, 4)
            if EnemyProperty(UCM,enemyType).extraEnemyData2 != -1:
                fileBin.seek(position, 0)
                fileBin.seek(0x24, 1)  # Skip 20,move past last variable find super boss variable
                writeIntOrHex(fileBin, EnemyProperty(UCM,enemyType).extraEnemyData2, 4)
            oldPos = [0,0,0] #Modify XYZ
            fileBin.seek(position+4, 0) #Skip UCM digit
            for  i in range(len(oldPos)):
                oldPos[i] = unpackfromBinaryByte(fileBin.read(4),'f')
            for  i in range(len(oldPos)):
                oldPos[i] += EnemyProperty(UCM,enemyType).positionOffset[i]
            for  i in range(len(oldPos)):
                fileBin.seek(position + 4 + (i * 4), 0)
                writeFloat(fileBin, oldPos[i], 4)


        fileBin.seek(position, 0)

    offSetSeed(2)
    filteredBossList = filterUcmProperty(BossList)
    bossListWeights = []
    randomLittleChests = [0x140,0x141,0x142,0x143,0x332,0x333,0x334,0x335,0x336,0x337,0x338,0x339,0x85e,0x8BB]
    randomBigChests = [0x144,0x145,0x33a,0x33b,0x33c,0x33d,0x33e,0x33f,0x340,0x341,0x342,0x343,0x343,0x08BC,0x9EC]

    for i in range(len(filteredBossList)):
        bossListWeights.append(random.uniform(0.7,1.0)) #random cause why the hell not



    def subSpawnChanging(var):
        nonlocal spawnData,fileBin,TotalSubSpawn
        if spawnData[var].noExtraData > 0 :
            noTransforms = 0
            fileBin.seek(TotalSubSpawn + 2,0)
            noTransforms = readAndUnpack(fileBin,2)
            TotalSubSpawn += 0x8 + (noTransforms* 0xC)
        if spawnData[var].noExtraData2 > 0 :
            TotalSubSpawn += (0x10 * spawnData[var].noExtraData2)
        if spawnData[var].noExtraData3 > 0 :
            TotalSubSpawn += (8 * spawnData[var].noExtraData3)


    print("Modifying enemies & bosses...")

    path = "export/KH2/ard"
    if PS3Version():
        path = "export/ard/us"
    fileList = getAllFileNamesInFolder(path)
    path2 = "export/KH2/msn/jp/"
    if PS3Version():
        path2 = "export/msn/jp/"
    msnFileList = getAllFileNamesInFolder(path2)
    if randomizeBosses:
        removeDMFromBosses()
        KHMapReplacer().ReplaceMAP('hb32','tt14')
    for j in fileList:
        EntryName = []
        EntryPositions = []
        EntrySizes = []
        filename = j
        currentWorld =filename[0:2]
        currentRoom  =filename[2:4]
        """Memory usage notes:
        Can't have too many unique enemies/ too many high memory usage enemies either
        All enemy data is loaded on room loadin and stored to prevent having to find a model file on every enemy spawn
        It explains why the game might crash sometimes on room loads, we run out of memory simply.
        We can check if a room's memory is low by loading in a help tutorial where images are simply not loaded because it costs too much.
        """

        #shutil.copyfile(path+ "/" +filename, "ard/"+filename) #Move to native folder
        regionExtraFolder = ""
        if PS3Version():
            regionExtraFolder = "us/"
        filename = "ard/"+regionExtraFolder+filename

        noEntries = 0

        if copyKHFile(filename):
            writeRandomizationLog(filename)
            fileBin = open(filename, 'rb+')
            if currentWorld.upper() == 'MU' and currentRoom == '02':
                FixMulanMSNSoftlock()
            barHeaderOffset=  findBarHeader(fileBin)
            fileBin.seek(barHeaderOffset+0x4,0)
            noEntries = readAndUnpack(fileBin,4);
            UniqueEnemyID = 0
            if noEntries > 0:
                for k in range(noEntries):
                    EntryName.append("")
                    EntryPositions.append(0)
                    EntrySizes.append(0)
                    fileBin.seek(barHeaderOffset+0x14 + (0x10 * k), 0)
                    buffer = fileBin.read(4)# read and then somehow change the last hex num into a 0!
                    EntryPositions[k] = barHeaderOffset + readAndUnpack(fileBin,4)
                    EntrySizes[k] = readAndUnpack(fileBin,4)
                    EntryName[k] = buffer;
                for l in range(noEntries):
                    check = EntryName[l].decode("utf-8")
                    check =ReverseEndianString(check, 1)
                    entrySize = EntrySizes[l]
                    starterNames = ["b_","m_","z_","p_","e_"]
                    if(check[0:2] in starterNames) and entrySize > 0 and filename[len(filename)-8:] not in {"al08.ard","po10.ard","eh23.ard"}:
                        noSubSpawns = 0
                        fileBin.seek(EntryPositions[l]+0x4,0)
                        noSubSpawns = readAndUnpack(fileBin,4)
                        
                        if noSubSpawns > 0:
                            spawnData = []
                            for x in range(noSubSpawns+1): #Create list in place of original codes vector and populate it with objects
                                spawnData.append(SpawnData())
                                
                            fileBin.seek(EntryPositions[l] + 0xC,0)
                            spawnData[0].noUCMSpawn = readAndUnpack(fileBin,2)
                            spawnData[0].noLocationSpawn = readAndUnpack(fileBin,2)
                            spawnData[0].noExtraData  = readAndUnpack(fileBin,2)
                            spawnData[0].noExtraData2 = readAndUnpack(fileBin,2)
                            spawnData[0].noExtraData3 = readAndUnpack(fileBin,2)
                                
                            TotalSubSpawn = EntryPositions[l] + 0x34 + ((spawnData[0].noUCMSpawn + spawnData[0].noLocationSpawn) * 0x40)
                            spawnData[0].positionInFile = EntryPositions[l] + 8
                                
                            subSpawnChanging(0)
                            #Get all spawn data.
                                
                            for c in range(1,noSubSpawns):
                                spawnData[c].positionInFile = TotalSubSpawn
                                fileBin.seek(TotalSubSpawn+4,0)
                                spawnData[c].noUCMSpawn = readAndUnpack(fileBin,2)
                                spawnData[c].noLocationSpawn = readAndUnpack(fileBin,2)
                                spawnData[c].noExtraData = readAndUnpack(fileBin,2)
                                spawnData[c].noExtraData2 = readAndUnpack(fileBin,2)
                                spawnData[c].noExtraData3 = readAndUnpack(fileBin,2)
                                    
                                TotalSubSpawn += 0x2C + ((spawnData[c].noUCMSpawn + spawnData[c].noLocationSpawn)* 0x40)  
                                subSpawnChanging(c)

                            randomizedUniqueEnemyList = []
                            randomizedUniqueEnemyListcodes = []
                            EnemiesWrote = 0 #For turning off memory optimizations
                            MaxEnemies = 4#For turning off memory optimizations
                            uniqueEnemyList = []
                            enemiesMaxWrittenUsage = [0, 0, 0]
                            enemiesUniqueMaxWrittenUsage = [0, 0, 0]
                            randomenemiesWrittenUsage = [0, 0, 0]
                            randomEnemiesUniqueWrittenUsage = [0, 0, 0]
                            if PS2EnemyOptimizations:
                                #Gathering data about the subspawns
                                for s in range(noSubSpawns):
                                    noUCMSpawns = spawnData[s].noUCMSpawn
                                    noSpawnObjects = spawnData[s].noLocationSpawn
                                    UCM = 0
                                    for b in range(noUCMSpawns):
                                        position = spawnData[s].positionInFile + 0x2C + (b * 0x40)
                                        fileBin.seek(position, 0)
                                        UCM = readAndUnpack(fileBin, 4)
                                        if CheckIfEnemyTypeInTable(UCM, enemy_table) and randomizeEnemies:
                                            # find weight of enemyenemiesMaxWrittenUsage
                                            memUsageFound = list(filter(lambda x: (x.code == UCM), EnemyList))[0].memoryUsage
                                            enemiesMaxWrittenUsage[memUsageFound] += 1
                                            if UCM not in uniqueEnemyList:
                                                enemiesUniqueMaxWrittenUsage[memUsageFound] += 1
                                                uniqueEnemyList.append(UCM)
                            # Modifiying the spawns
                            for s in range(noSubSpawns):
                                noUCMSpawns = spawnData[s].noUCMSpawn
                                noSpawnObjects = spawnData[s].noLocationSpawn
                                UCM = 0
                                for b in range(noUCMSpawns):
                                    position = spawnData[s].positionInFile + 0x2C + (b * 0x40)
                                        
                                    #EntryLimit = (EntryPositions[l] + EntrySizes[l])
                                    #if(position > EntryLimit)
                                    fileBin.seek(position,0)
                                    UCM = readUnpackGoBack(fileBin,4)
                                    fileBin.seek(0x20,1) #Skip 20, find if its a super boss version of a regular boss or not.
                                    #Spawn Order Group Byte
                                    #Spawn Order Sub Group Byte
                                    #writeIntOrHex(fileBin,8*b,2)#2 bytes --- Enemy Unique Spawn ID, size doesn't matter here only if it was unique or not or else the game wont spawn the character object and it wont be counted against winning the mission

                                    DataBoss = readAndUnpack(fileBin,4)
                                    DataBoss2 = readAndUnpack(fileBin, 4)
                                    #avoidUCMList = [0x237,0x238,0x319,0x31A,0x3EE] this is obsolete.
                                    if(not CheckIfEnemyBlackListed(currentWorld,currentRoom,UniqueEnemyID) and not CheckIfGroupBlackListed(currentWorld,currentRoom,check) ):
                                        fileBin.seek(position,0)  
                                        randomValue = 0

                                        def enemyBTLMSNEdit():
                                            #PS3 Version Note: Little Endian to Big Endian change: every 2 bytes is swapped. GREAT.
                                            #Bytearray=  "BB"[::-1] + "50"[::-1] + "M_"[::-1] + "1S"[::-1] + "40"[::-1] +".B"[::-1]
                                            """
                                            def replaceAllMSN(): #very destructive, has problems with ard files that has multiple bosses
                                                nonlocal x
                                                # write new mission file
                                                BeforeReplaced = fileBin.read(18)  # i assume 18 is the most?????
                                                fileBin.seek(0, 0)

                                                replace1 = BeforeReplaced.decode('utf-8').rstrip('\x00')
                                                strLength = len(bossMSNTable[x])
                                                strLength2 = len(replace1)
                                                spacingNum = strLength2 - strLength
                                                beforeEncode = bossMSNTable[x]
                                                beforeEncode = msnFileCreate(beforeEncode, currentWorld, currentRoom)

                                                for x in range(spacingNum):
                                                    beforeEncode += '\x00'
                                                for x in range(-spacingNum):
                                                    replace1 += '\x00'

                                                replace2 = str.encode(beforeEncode)
                                                replace1 = str.encode(replace1)
                                                # note: we should add extra bytes based on length so we dont offset the file if we replace stuff
                                                allData = fileBin.read()
                                                allData = allData.replace(replace1, replace2)  # oh my god i forget to store it back and i was wondering why it wasnt working
                                                fileBin.seek(0, 0)
                                                fileBin.write(allData)
                                            """
                                            def replaceOneMSN(newMSN):
                                                # write new mission file
                                                BeforeReplaced = fileBin.read(0x20)  # i assume 18 is the most?????
                                                BeforeReplaced = BeforeReplaced.decode('utf-8').rstrip('\x00')
                                                BeforeReplaced = ReverseEndianString(BeforeReplaced,2,True)
                                                fileBin.seek(-0x20, 1)

                                                beforeEncode = msnFileCreate(newMSN,currentWorld,currentRoom,BeforeReplaced)

                                                """
                                                All of this doesn't work when trying to fix Final Xemnas MSN softlocking. Great.
                                                exportFolderName = "msn/jp/"
                                                if PS3Version():
                                                    exportFolderName = "msn/us/"
                                                fileBin_MSN = open(exportFolderName + beforeEncode+'.bar','rb+')
                                                findHeaderinBAR(fileBin_MSN,newMSN[:4],True)
                                                fileBin_MSN.write(bytearray([0x00, 0x02, 0x01 ,0x11 ,0x11 ,0x71]))
                                                findHeaderinBAR(fileBin_MSN, newMSN[:4], False)
                                                fileBin_MSN.seek(0x4+0x4,1)
                                                barSize = readAndUnpack(fileBin_MSN,4)
                                                findHeaderinBAR(fileBin_MSN, newMSN[:4], True)
                                                fileBin_MSN.seek(barSize,1)
                                                beforePos = fileBin_MSN.tell()
                                                findHeaderinBAR(fileBin_MSN,newMSN[:4],False)
                                                fileBin_MSN.seek(0x10 + 0x4,1) #Skip down an entry and move to New location
                                                newPos = readAndUnpack(fileBin_MSN,4)
                                                offsetPos = findBarHeader(fileBin_MSN)
                                                fileBin_MSN.seek(newPos+offsetPos,0)
                                                writingString = 'eh20_ms113'.ljust(0x10,'\x00').encode() #Write new mission objective
                                                fileBin_MSN.write(writingString)
                                                fileBin_MSN.close()
                                                appendToSpecificPos(exportFolderName + beforeEncode+'.bar',beforePos,newMSN[:4],bytearray([0x08, 0xD1, 0x00, 0x04 ,0x00 ,0x00, 0x00, 0x00]))
                                                """

                                                beforeEncode = ReverseEndianString(beforeEncode, 2, True,True)
                                                spacingNum = 0x20 - len(beforeEncode)
                                                # note: we should add extra bytes based on length so we dont offset the file if we replace stuff
                                                for x in range(spacingNum):
                                                    beforeEncode += '\x00'

                                                replace2 = str.encode(beforeEncode)
                                                fileBin.write(replace2)
                                                fileBin.seek(-len(replace2), 1) #Write, go back and we're done.





                                            #eh20_ms113 == replace ms_boss if the final boss mission is being replaced EH20_MS113.bar
                                            #end of utility functions. start of main function
                                            #This maybe need to be looked at again.
                                            btl_String = 'btl'
                                            findHeaderinBAR(fileBin,btl_String,True)
                                            # find "btl" header thing
                                            # go to position from the btl header
                                            endcodedCheck = ReverseEndianString(check,2,True).encode('utf-8')  # get entry name ex: b_00
                                            posBeforeRead = fileBin.tell()
                                            data2 = fileBin.read()

                                            seekToRead = data2.find(endcodedCheck)
                                            fileBin.seek(posBeforeRead, 0)
                                            fileBin.seek(seekToRead, 1)
                                            # goto name closest
                                            # find original msn by backing up a lil so we find the currentworld string
                                            posBeforeRead = fileBin.tell()
                                            seekToRead = -1
                                            offset = 0
                                            #15 00 09 find this byte and offset foward by 4 bytes and write this way
                                            while seekToRead != 0:  # This is slow..... But the best I can do ATM.
                                                fileBin.seek(posBeforeRead, 0)
                                                offset += 1
                                                if offset > 300:
                                                    return #We probrably can't find anything because an boss has already taken its place. In this case, we will just stop the function
                                                fileBin.seek(fileBin.tell() - offset, 0)
                                                data3 = fileBin.read()
                                                findThing =data3.find(b'\x15\x00\x09')
                                                if findThing == 0:
                                                    seekToRead = findThing+3+4 #Skip the byte we found and the following 4 bytes to get to the string
                                                    break;
                                            fileBin.seek(seekToRead, 1)
                                            fileBin.seek(posBeforeRead, 0)
                                            fileBin.seek(-offset, 1)
                                            offset = 0
                                            if not PS3Version():
                                                offset = 1
                                            fileBin.seek(seekToRead+offset, 1)
                                            testRead = fileBin.read(0x20)
                                            testRead = ReverseEndianString(testRead.decode('utf-8'),2,True).rstrip('\x00')
                                            fileBin.seek(-0x20, 1)
                                            if not testRead == 'EH20_MS113':  # Final Xemnas Specific dont edit
                                                if  testRead== "HB38_FM_MAR" or testRead == 'CA01_MS204': #Replace Marluxia MSN as it softlocks at the start of battle and Grim Reaper Mission cause it crashes on PS3
                                                    replaceOneMSN("HB33_FM_LAR") #Generic Battle MSN file
                                                    enemyBTLMSNEdit()  # Try again......
                                                else:
                                                    for x in bossMSNTable:
                                                        if enemyToWrite.code == x:
                                                            replaceOneMSN(bossMSNTable[x])





                                        if CheckIfEnemyTypeInTable(UCM, boss_table) and ( DataBoss2 != 1) and randomizeBosses and replaceableUCMproperty(UCM,enemyType.Boss):
                                            # get Random boss UCM value here!


                                            if random.random() < 0.07*SuperBossEncounterRate and SuperBossEncounterRate > 0:
                                                enemyToWrite =  random.choices(SuperBossList_Non,k=1)[0]
                                                writeIntOrHex(fileBin, enemyToWrite.code, 4)
                                                fileBin.seek(position, 0)
                                            else:
                                                enemyToWrite = random.choices(filteredBossList, bossListWeights)[0]
                                                if UCM != enemyToWrite.code:
                                                    index = filteredBossList.index(enemyToWrite)
                                                    bossListWeights[index] *= 0.26  # Decrease weight of object we just spawned for lesser chance of being picked next time
                                                    writeIntOrHex(fileBin, enemyToWrite.code, 4)
                                                    fileBin.seek(position, 0)

                                            ucmPropertyModify(enemyToWrite.code, enemyToWrite.type)
                                            writeOutCome_Enemy(currentWorld, int(currentRoom), UniqueEnemyID, UCM, enemyToWrite.name, check,enemyType.Boss,enemyToWrite.type)
                                            enemyBTLMSNEdit()
                                        elif CheckIfEnemyTypeInTable(UCM, enemy_table) and randomizeEnemies and replaceableUCMproperty(UCM,enemyType.Normal):
                                            # Get random Enemy UCM value here!
                                            # Choose 3 enemies to put in list as backup
                                            curEnemyList= filterUcmProperty(EnemyList)
                                            currentEnemyList = curEnemyList
                                            if PS2EnemyOptimizations:
                                                currentEnemyList = curEnemyList
                                                for maxwritten in range(len(enemiesUniqueMaxWrittenUsage)):  # Filter out if reached maximum enemies allowed
                                                    if randomEnemiesUniqueWrittenUsage[maxwritten] == enemiesUniqueMaxWrittenUsage[maxwritten]:
                                                        currentEnemyList = list(filter(lambda x: (x.memoryUsage != maxwritten), currentEnemyList))
                                                currentEnemyList = currentEnemyList + randomizedUniqueEnemyList

                                                # memUsageFound = list(filter(lambda x: (x.code == UCM), EnemyList))[0].memoryUsage
                                                # currentEnemyList = list(filter(lambda x: (x.memoryUsage == memUsageFound),currentEnemyList))
                                                for maxwritten in range(len(enemiesMaxWrittenUsage)):  # Filter out if reached maximum enemies allowed
                                                    if randomenemiesWrittenUsage[maxwritten] == enemiesMaxWrittenUsage[maxwritten]:
                                                        currentEnemyList = list(filter(lambda x: (x.memoryUsage != maxwritten), currentEnemyList))
                                            if not PS2EnemyOptimizations and EnemiesWrote >= MaxEnemies: # If enemy optimizations are off to provide a quick cap
                                                currentEnemyList = randomizedUniqueEnemyList

                                            random.shuffle(currentEnemyList)
                                            enemyToWrite = currentEnemyList[0]
                                            randomenemiesWrittenUsage[enemyToWrite.memoryUsage] += 1
                                            EnemiesWrote+=1
                                            ucmPropertyModify(enemyToWrite.code, enemyToWrite.type)
                                            writeIntOrHex(fileBin, enemyToWrite.code, 4)
                                            writeOutCome_Enemy(currentWorld, int(currentRoom), UniqueEnemyID, UCM,enemyToWrite.name, check,enemyType.Normal,enemyToWrite.type)
                                            if enemyToWrite.code not in randomizedUniqueEnemyListcodes:
                                                randomEnemiesUniqueWrittenUsage[enemyToWrite.memoryUsage] += 1
                                                randomizedUniqueEnemyList.append(enemyToWrite)
                                                randomizedUniqueEnemyListcodes.append(enemyToWrite.code)



                                        elif CheckIfEnemyTypeInTable(UCM, superBoss_table) and randomizeBosses and replaceableUCMproperty(UCM,enemyType.SuperBoss):

                                            # if not (currentWorld.upper() == "HB" and currentRoom == "33" and UCM == 0x933): #SOMEONE put vexen data into a place where he isnt suppost to be

                                            random.shuffle(SuperBossList)
                                            enemyToWrite = SuperBossList.pop(0)
                                            if UCM != enemyToWrite.code:
                                                writeIntOrHex(fileBin, enemyToWrite.code, 4)
                                                fileBin.seek(position, 0)

                                            ucmPropertyModify(enemyToWrite.code, enemyToWrite.type)
                                            writeOutCome_Enemy(currentWorld, int(currentRoom), UniqueEnemyID, UCM, enemyToWrite.name, check,enemyType.SuperBoss,enemyToWrite.type)
                                            enemyBTLMSNEdit()
                                        elif CheckIfEnemyTypeInTable(UCM, ally_table) and randomizeBosses and replaceableUCMproperty(UCM,enemyType.Ally):
                                            curEnemyList = filterUcmProperty(AllyList)
                                            # if not (currentWorld.upper() == "HB" and currentRoom == "33" and UCM == 0x933): #SOMEONE put vexen data into a place where he isnt suppost to be

                                            random.shuffle(curEnemyList)
                                            enemyToWrite = curEnemyList[0]
                                            ucmPropertyModify(enemyToWrite.code, enemyType.Ally)
                                            writeIntOrHex(fileBin, enemyToWrite.code, 4)
                                            writeOutCome_Enemy(currentWorld, int(currentRoom), UniqueEnemyID, UCM, enemyToWrite.name, check,enemyType.Ally,enemyToWrite.type)
                                        elif UCM == 0x5AB and KH2SoraForced:
                                            # replace roxas skateboards with sora
                                            writeIntOrHex(fileBin, 0x81A, 4)
                                        elif UCM == 0x236 and currentWorld.upper() == "TT" and currentRoom == "34" and KH2SoraForced:
                                            # replace Sora with roxas for this fight
                                            writeIntOrHex(fileBin, 0x5A, 4)
                                        elif UCM == 0x236 and check == "b_42" and currentWorld.upper() == "TT" and currentRoom == "10" and KH2SoraForced:
                                            # replace Sora with roxas for this event
                                            writeIntOrHex(fileBin, 0x5A, 4)
                                        elif UCM == 0x236 and check == "b_40" and currentWorld.upper() == "TT" and currentRoom == "12" and KH2SoraForced:
                                            # replace Sora with roxas for this event
                                            writeIntOrHex(fileBin, 0x5A, 4)
                                        elif UCM in randomLittleChests:
                                            # replace Sora with roxas for this event
                                            writeIntOrHex(fileBin, random.choice(randomLittleChests), 4)
                                        elif UCM in randomBigChests:
                                            # replace Sora with roxas for this event
                                            writeIntOrHex(fileBin, random.choice(randomBigChests), 4)
                                        elif UCM == 0x988:
                                            # todo randomize puzzle pieces
                                            pass
                                        elif UCM in blackListUCM_List:
                                            writeIntOrHex(fileBin, 0, 4)  # Write nothing.


                                    UniqueEnemyID+=1
            #End of noentries if statement
            fileBin.close()
def randomizeMusic(ranMusic):
    if ranMusic:
        offSetSeed(50)
        print("Modifying music...")
        path = "export/KH2/ard"
        if PS3Version():
            path = "export/ard/us"
        fileList = getAllFileNamesInFolder(path)
        for j in fileList:
            musicOccurenceNum = 0
            musicListUsed= []
            filename = j
            currentWorld = filename[0:2].upper()
            currentRoom = int(filename[2:4])
            # shutil.copyfile(path+ "/" +filename, "ard/"+filename) #Move to native folder
            regionExtraFolder = ""
            if PS3Version():
                regionExtraFolder = "us/"
            filename = "ard/"+regionExtraFolder + filename
            if copyKHFile(filename):
                writeRandomizationLog(filename)
                fileBin = open(filename, 'rb+')
                """
                        Notes:
                        Affecting music data also affects the space of ram. Great. Some places may softlock because of this.....
                        Another music weighting system based on file size?
                        
                        EVT Data: Amt of entries not given. Size of entries not given. 
                        Anything after the evt bar entry in the main header will be in evt, btl header sometimes 
                        Start of EVT entry depending on event type:
                        Event ID, Used by a general event. EX: Bosses with their respective cutscene on death/enter
                        Empty?
                        Event 2ndID, Possibly a type? Changes and isnt very consistent.

                        Event 2ndID's when a boss is assigned to an eventId may be:
                        2C if 48 (Super Boss?)
                        22 if 44 (Normal Boss?)
                        possibly use an if statement if an value is above an amount
                        Music event starts with 10 00 01? Wow, what a waste of time trying to decipher this
                        5 Unknown Bytes,
                        Music Num Data, 0C == Current World music? 09 == Current World Battle Music?
                        Empty,
                        Music Num Data,

                        FF Sometimes ends the data, sometimes it doesn't.
                """
                if findHeaderinBAR(fileBin, 'evt', False):
                    fileBin.seek(0x8, 1)
                    evtSize = readAndUnpack(fileBin, 4)
                    """ Useless
                    eventIDList = []
                    if findHeaderinBAR(fileBin, 'map', False):
                        fileBin.seek(0x8, 1)
                        mapSize = readAndUnpack(fileBin, 4)
                        findHeaderinBAR(fileBin, 'map', True)  # go back and start going through
                        filePosition = fileBin.tell()
                        mapFileText = fileBin.read(mapSize)
                        fileBin.seek(filePosition, 0)
                        difBytes = [b'\x01\x00\x02']
                        for differentEvtTypes in difBytes:
                            curPos = 0
                            while (mapFileText.count(differentEvtTypes, curPos) != 0):
                                curPos = mapFileText.find(differentEvtTypes, curPos)  # Skip 5 bytes
                                fileBin.seek(filePosition + curPos, 0)
                                fileBin.seek(-0x4, 1)  # Go back, find 2nd id
                                eventIDList.append(readUnpackGoBack(fileBin, 1))
                                curPos += 1
                        if len(eventIDList) != 0:
                            debughi = 0
                    """
                    findHeaderinBAR(fileBin, 'evt', True)  # go back and start going through
                    filePosition = fileBin.tell()
                    evtFileText = fileBin.read(evtSize)
                    fileBin.seek(filePosition, 0)

                    difBytes = [b'\x10\x00\x01']

                    for differentEvtTypes in difBytes:
                        curPos = 0
                        while (evtFileText.count(differentEvtTypes, curPos) != 0):
                            curPos = evtFileText.find(differentEvtTypes, curPos)  # Skip 5 bytes
                            fileBin.seek(filePosition + curPos, 0)
                            if not CheckIfMusicBlackList(currentWorld,currentRoom,musicOccurenceNum):
                                fileBin.seek(-0x4, 1)  # Go back, find 2nd id
                                evtFirstEventID = readAndUnpack(fileBin, 1)
                                fileBin.seek(1, 1)
                                evtSecondEventID = readAndUnpack(fileBin, 1)
                                fileBin.seek(1, 1)
                                fileBin.seek(len(differentEvtTypes), 1)  # skip over what we just found
                                fileBin.seek(0x1, 1)  # skip empty
                                firstMusicID = readUnpackGoBack(fileBin, 1)
                                random.shuffle(musicList)
                                chooseNewMusic = musicList[0]
                                for xd in musicListUsed:
                                    if evtFirstEventID == xd[0]:
                                        chooseNewMusic =xd[1]
                                writeIntOrHex(fileBin, chooseNewMusic, 1)
                                fileBin.seek(0x1, 1)  # skip empty
                                firstMusicID2 = readUnpackGoBack(fileBin, 1)
                                writeIntOrHex(fileBin, chooseNewMusic, 1)
                                usedOnce = False
                                for xd in musicListUsed:
                                    if evtFirstEventID == xd[0]:
                                        usedOnce = True
                                if not usedOnce:
                                    musicListUsed.append((evtFirstEventID,chooseNewMusic))
                            curPos += 1
                            musicOccurenceNum+=1
                fileBin.close()
def RandomizeChestContents(randomizeChests):
    offSetSeed(0)
    if (randomizeChests):
        print("Randomizing chests...")
        if (copyKHFile("03system.bin")):
            fileBin = open("03system.bin", "rb+")
            if (fileBin):
                TreasureFilePosition = 0
                TreasureFileSize = 0
                """So the way this works is that there is a value of hex inside 03system.bin that
                    has the fileposition of the treasure. we navigate to it and get the number of chests in the position in decimal.
                    hex editor displays hex backwards for some odd reason and makes reading pure hex annoying
                    
                    
                    more info:doing file.read(2) in binary files such as done below will be the equivalent of reading 0000
                    reading 1 for 00

                    """
                findHeaderinBAR(fileBin, 'trsr', True)
                TreasureFilePosition = fileBin.tell()
                noChests = 0
                UniqueChestID = 0  #We're going to make our own unique chest id cause I don't trust KH2 at all.
                fileBin.seek(2, 1)  #TrsrMagic
                noChests = readAndUnpack(fileBin, 2)  #noChests
                itemDict = Vividict()
                # because im dumb lets make a dictonary with unique chest item ids
                for i in range(noChests + 1):
                    fileBin.seek(TreasureFilePosition + 4 + 2 + (i * 0xC), 0)
                    Item = readAndUnpack(
                        fileBin,
                        2)  #Item ID that the chest currently contains.
                    Type = readHex(
                        fileBin,
                        1)  #Type of item it is. 0 for chest, 1 for Event.
                    WorldID = readHex(
                        fileBin, 1
                    )  #Which world is it? we can get that chest info here.
                    RoomIndex = readHex(
                        fileBin,
                        1)  #Which room is it? we can get that chest info here.
                    RoomChestIndex = readHex(
                        fileBin, 1
                    )  #Which roomchestindex is it? we can get that chest info here.
                    EventID = readHex(fileBin, 2)
                    itemDict[WorldID][RoomIndex][RoomChestIndex][Type][
                        EventID][Item] = UniqueChestID
                    UniqueChestID += 1
                #because im dumb lets make a dictonary with unique chest item ids

                randomChestLoop = list(range(noChests + 1))
                random.shuffle(
                    randomChestLoop
                )  #We will randomize the order we go through chests in in order to be a bit more random. Kinda odd but yea so we evenly spread out priority items instead of like in a row.
                for i in randomChestLoop:
                    Item = 0
                    Type = 0
                    fileBin.seek(TreasureFilePosition + 4 + 2 + (i * 0xC), 0)
                    Item = readAndUnpack(
                        fileBin,
                        2)  #Item ID that the chest currently contains.
                    Type = readHex(
                        fileBin,
                        1)  #Type of item it is. 0 for chest, 1 for Event.
                    WorldID = readHex(
                        fileBin, 1
                    )  #Which world is it? we can get that chest info here.
                    RoomIndex = readHex(
                        fileBin,
                        1)  #Which room is it? we can get that chest info here.
                    RoomChestIndex = readHex(
                        fileBin, 1
                    )  #Which roomchestindex is it? we can get that chest info here.
                    EventID = readHex(fileBin, 2)
                    UniqueChestID = itemDict[WorldID][RoomIndex][
                        RoomChestIndex][Type][EventID][Item]
                    fileBin.seek(
                        TreasureFilePosition + 4 + 2 + (i * 0xC),
                        0)  #reset back to original position for writing
                    """So now that we've gotten some info about the original item, we can do some randomization stuff
                    We can randomize a certain group of items depending on where the chest location is now that we have the world and room id of those locations."""
                    if (checkIfItemExists(ItemList, Item)
                            and not CheckIfChestBlackListed(
                                WorldID, RoomIndex, UniqueChestID)):
                        newChestVal = randomizeAChest(Item, Type, WorldID,
                                                      RoomIndex, UniqueChestID,
                                                      EventID)
                        writeIntOrHex(fileBin, newChestVal, 2)

                        newitem = findItemInList(ItemList, newChestVal)
                        if isinstance(newitem, kh2rando_item.KHItem):
                            newItemName = newitem.name
                        else:
                            newItemName = "NoItemFound"

                        newitem = findItemInList(ItemList, Item)
                        if isinstance(newitem, kh2rando_item.KHItem):
                            oldItemName = newitem.name
                        else:
                            oldItemName = "NoItemFound"
                        writeOutCome_Chest(WorldID, RoomIndex, Type,
                                           UniqueChestID, oldItemName,
                                           newItemName)

                fileBin.close()
            else:
                ErrorWindow(
                    "The file 03system.bin could not be opened. It's probably in use by another program or instance of this program."
                )

            writeRandomizationLog("03system.bin")
        else:
            ErrorWindow(
                "03system.bin does not exist in the export/KH2/ folder. Make sure nothing has gone wrong during the extraction."
            )