示例#1
0
def skipCredits(doItOrNot):
    #set roxas and kh1 sora to kh2 sora
    if doItOrNot:
        regionExtraFolder = ""
        if PS3Version():
            regionExtraFolder = "us/"
        filename = "ard/" + regionExtraFolder + 'eh20.ard'
        print("Skipping credits...")
        if copyKHFile(filename):
            fileBin = open(filename, 'rb+')
            if (fileBin):
                #BytesToWrite =   01 40
                if not PS3Version():
                    fileBin.seek(
                        0x7c0,
                        0)  #Go to map event location and change from 33 to 3C
                else:
                    fileBin.seek(0x7f8, 0)  # Diff spot in PS3 version

                writeIntOrHex(fileBin, 1, 2)  #
                writeIntOrHex(fileBin, 0, 2)  #
                writeIntOrHex(fileBin, 0x05, 2)  #
                writeIntOrHex(fileBin, 1, 2)  #
                writeIntOrHex(fileBin, 0, 2)  #
                writeIntOrHex(fileBin, 0, 2)  #
                writeIntOrHex(fileBin, 5, 2)  #
                writeIntOrHex(fileBin, 0x4001, 2)  #
                print("Done!")
                fileBin.close()
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
    def ReplaceMAP(
        self, MapReplaced, MapReplacer
    ):  #MapReplacer == filename of old map (no .bar), MapReplaced == filename of new map (no .bar)
        #PS3 version has all the maps in one singular folder for all regions while kh2fm has it in the JP folder
        fileExtension = '.map'
        importFolderName = "export/KH2/map/"
        if PS3Version():
            importFolderName = "export/map/"
        exportFolderName = "map/jp/"
        if PS3Version():
            exportFolderName = "map/"

        if (os.path.isfile(importFolderName + MapReplacer + fileExtension)):

            if not os.path.exists(exportFolderName):
                os.makedirs(exportFolderName)

            shutil.copyfile(importFolderName + MapReplacer + fileExtension,
                            exportFolderName + MapReplaced + fileExtension)
            print("Copying file...")
            writeRandomizationLog(exportFolderName + MapReplaced +
                                  fileExtension)

            fileBin = open(exportFolderName + MapReplaced + fileExtension,
                           'rb+')  # Modify file to use correct bonus level.
            ModifyExtraFileNames(fileBin, MapReplacer, MapReplaced)
            fileBin.close()
示例#4
0
def TwilightTownTutText():
    file = "msg/jp/tt.bar"
    if PS3Version():
        file = "msg/us/tt.bar"
    if copyKHFile(file):
        strings = openKHText(file)

        messageIDS = []

        msg1 = "Welcome to the {0x04}{0x02}KH2 Randomizer! {0x04}{0x03}" + "{lf}"
        msg1 += "Your current seed is:{0x04}{0x02}" + str(settings.internalSeed) + "{0x04}{0x03}." + "{lf}"
        msg1 += "Current Version: {0x04}{0x02}" + str(applicationversion) + "{0x04}{0x03}. {eol}"
        msg2 = "Current Settings: " + "{lf}"
        msg3 = "Notes: " + "{cls}"
        msg3+= "●Missable items in the prologue{lf}are not randomized to prevent{lf}missing key items.{cls} "
        msg3+= "●Do not equip any keyblades before gaining a drive bar.{cls}If you equip a keyblade before then,{lf}you run the risk of losing that keyblade."
        if not PS3Version():
            msg3+="{cls}"
            msg3+= "●Occasionally, the game will run low on memory.{lf} You can tell by viewing a tutorial in the pause menu{lf} or seeing your limit command flash repeatedly.{cls}" \
               " When this happens, the game may crash/softlock IF:{lf} you use mickey, go into a drive form,{lf} change party members, or anything possibly taxing."
        else:
            msg3 += "{cls}"
            msg3 += "Since we're running on the PS3 Version of the game,{lf}we have more memory to work with.{lf}There is no need to play cautiously for memory."

        msg3+="{eol}"
        msg4 = "You may now equip any {0x04}{0x02}keyblades{0x04}{0x03} you have safely.{eol}"
        linesWrote = 0
        for x in settings.config["variables"]:
            if linesWrote < 12:
                msg2 += str(x) + " : " +str(settings.config["variables"][x]) + "{lf}"
                linesWrote+=1
            else:
                msg2 +='{cls}'
                linesWrote = 0
        for x in settings.config["intvars"]:
            if linesWrote < 12:
                msg2 += str(x) + " : " +str(settings.config["intvars"][x]) + "{lf}"
                linesWrote+=1
            else:
                msg2 +='{cls}'
                linesWrote = 0
        msg2 += '{eol}'
        x= 0
        for datastring in strings:

            datastring.decryptText()
            if "Move the left " in datastring.pureString and "make Roxas run." in datastring.pureString:
                datastring.text = msg1
            if "By skimming the sides of buildings," in datastring.pureString:
                datastring.text = msg2
            if "Reaction commands are used to" in datastring.pureString:
                datastring.text = msg3
            if "Drive command has been added" in datastring.pureString:
                datastring.text = msg4
            x += 1
        closeKHText(file, strings)
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 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 removeDMFromBosses():
    #here we will remove ai functions from bosses that are problematic.
    XemnasMDLFiles = ['obj/B_EX170.mdlx','obj/B_EX170_LV99.mdlx']
    for x in XemnasMDLFiles:
        XemnasModel = KHMDL(x)
        XemnasModel.removeAIFunction('rc_invitation_to_dark') #Remove xemnas skyscraper rc battle thing
        XemnasModel.removeAIFunction('warp_building_front')
    XigbarMDLfiles = ['obj/B_EX140.mdlx','obj/B_EX140_LV99.mdlx']
    for x in XigbarMDLfiles:
        XigbarModel = KHMDL(x)
        XigbarModel.removeAIFunction('change_space_battle') #Get rid of Xigbar room changing aspects
        XigbarModel.removeAIFunction('change_space') #Get rid of Xigbar room changing aspects
    SarkModel = KHMDL('obj/N_TR010_BTL.mdlx')
    SarkModel.removeAIFunction('warp')
    SarkModel.removeAIFunction('warp_move')
    SarkModel.removeAIFunction('warp_fall')
    SarkModel.removeAIFunction('warp_start')
    SarkModel.removeAIFunction('back_warp')
    SarkModel.removeAIFunction('back_warp_fall')
    SarkModel.removeAIFunction('back_warp_start')

    if PS3Version():
        DarkThornModel = KHMDL('obj/B_BB110.mdlx')
        DarkThornModel.removeAIFunction('‰sora_downshock!') #Dark Thorn Boss
        DarkThornModel.removeAIFunction('sora_spin!') #Dark Thorn Boss
        DarkThornModel.removeAIFunction('spin_hit') #Dark Thorn Boss
        DarkThornModel.removeAIFunction('chandelier_camera?') #Dark Thorn Boss
        DarkThornModel.removeAIFunction('rc_step_jump') #Dark Thorn Boss
        DarkThornModel.removeAIFunction('hop') #Dark Thorn Boss
        DarkThornModel.removeAIFunction('reaction') #Dark Thorn Boss
        DarkThornModel.removeAIFunction('spin_hit_start') #Dark Thorn Boss
        DarkThornModel.removeAIFunction('revenge_catch_wait') #Dark Thorn Boss
        DarkThornModel.removeAIFunction('battle_catch_wait') #Dark Thorn Boss
示例#8
0
def prepareRandomizationLog():
    if not PS3Version():
        if (os.path.isfile("randomizationLog.txt")):
            os.remove("randomizationLog.txt")
    else:
        if (os.path.isfile("UsedLog.log")):
            os.remove("UsedLog.log")
    utils.randomLogFirstTime = True
    utils.clearLogsWroteSoFar()
示例#9
0
def createNewPatch():
    if not PS3Version():
        randomLogName = "randomizationLog.txt"
        randomLog = open(randomLogName, "a")
        utils.writeNewline(randomLog, "")
        utils.writeNewline(randomLog, "")
        randomLog.write("")
        randomLog.close()
        #Delete KH2 Patch!!! Otherwise toolkit will not overwrite it :(
        if (os.path.exists("output.kh2patch")):
            os.remove("output.kh2patch")
        CommandLineString = "KH2FM_Toolkit.exe -patchmaker -batch -version 1 -author AutoBatch -skipchangelog -skipcredits -other GovanifYAutoBatch -uselog randomizationLog.txt"
        os.system(CommandLineString)
示例#10
0
 def baseiso_open():
     if not PS3Version():
         fileGotton = filedialog.askopenfilename(
             initialdir="/",
             title="Open Base KH2ISO file",
             filetypes=[("ISO file", "*.iso")])
     else:
         fileGotton = filedialog.askopenfilename(
             initialdir="/",
             title="Open Base KH2.5 file",
             filetypes=[("MSELF file", "*.mself")])
     fileGotton = fileGotton.rstrip()
     if fileGotton != '':
         guiVars['baseRom'].set(fileGotton)
         guiVarsToSave()
def msnFileCreate_NonBoss(
        oldMsnFileName):  #Non boss version of creating a mission file
    fileExtension = '.bar'
    oldMsnFileName = oldMsnFileName.rstrip(' \t\r\n\0')
    newFileName = oldMsnFileName + '_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 + oldMsnFileName + fileExtension):
        shutil.copyfile(importFolderName + oldMsnFileName + fileExtension,
                        exportFolderName + newFileName + fileExtension)
        print("Copying file...")
        writeRandomizationLog(exportFolderName + newFileName + fileExtension)

        fileBin = open(exportFolderName + newFileName + fileExtension, 'rb+')

        ModifyExtraFileNames(fileBin, oldMsnFileName, newFileName)
        #replaceAllStringInFile(fileBin,fileName.lower(),newFileName.lower())
        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 exportFolderName + newFileName + fileExtension
    else:
        print("Couldn't find msn file to copy...")
        return importFolderName + oldMsnFileName + fileExtension
def ReverseEndianString(string,
                        size=2,
                        reverseString=False,
                        goingToEndian=False):
    if PS3Version():
        if goingToEndian:
            if len(string) % 2 == 1:
                string += '\x00'  # Keep even for reverse endian strings.
        if reverseString:
            string = string[len(string)::-1]
        return "".join(
            reversed([string[i:i + size]
                      for i in range(0, len(string), size)]))
    else:
        return string
示例#13
0
def extractKH2Files(force=False):

    if not PS3Version():
        if (os.path.isfile('KH2FM_Toolkit.exe')
                and (not os.path.isdir('export') or force)):
            if (cfg.config["variables"].getboolean("EnglishPatch")):
                optionalString = " \"" + cfg.config["strings"][
                    "EnglishPatchFile"].rstrip() + "\""
                os.system("KH2FM_Toolkit" + +cfg.config["strings"]["baseRom"] +
                          " -batch" + optionalString)
                os.system("KH2FM_Toolkit -extractor -batch " +
                          os.path.dirname(cfg.config["strings"]["baseRom"]) +
                          '/KH2.NEW.ISO')
                print("Extraction complete.")
            else:
                os.system("KH2FM_Toolkit -extractor -batch " +
                          cfg.config["strings"]["baseRom"])
                print("Extraction complete.")
            return True
        else:
            if (not os.path.isfile('KH2FM_Toolkit.exe')):
                utils.ErrorWindow(
                    "No KH2FM_Toolkit.exe found! It must be in the same folder."
                )
                return False
            else:
                return True
    else:
        if (os.path.isfile('HasherHD.exe')
                and (not os.path.isdir('export') or force)):
            if os.path.isfile('index.dat'):
                os.system(
                    "HasherHD.exe --batch --extractmself index.dat " +
                    cfg.config["strings"]["baseRom"]
                )  # Patch AFTER the english because it changes some things
                print("Extraction complete.")
                return True
            else:
                utils.ErrorWindow(
                    "No index.dat found! It must be in the same folder.")
                return False
        else:
            if not os.path.isfile('HasherHD.exe'):
                utils.ErrorWindow(
                    "No HasherHD.exe found! It must be in the same folder.")
                return False
            else:
                return True
示例#14
0
def worldMapGummiShipTxtSkip():
    file = "msg/jp/wm.bar"
    if PS3Version():
        file = "msg/us/wm.bar"
    if copyKHFile(file):
        strings = openKHText(file)

        messageIDS = []

        msg1 = "To skip gummiship missions, simply fly to the world and enter.{lf} It may seem locked but it isn't." + "{cls}"
        msg1 += "Be sure to visit every world when possible{lf} to unlock them before revisting the worlds on the second visit." + "{eol}"
        for datastring in strings:
            datastring.decryptText()
            if datastring.pureString.find("Gummi Route") != -1:
                datastring.text = msg1
        closeKHText(file, strings)
示例#15
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
示例#16
0
def skipGummiShipMissions(doItOrNot):
    #set roxas and kh1 sora to kh2 sora
    if doItOrNot:
        print("Skipping gummiship missions...")
        if copyKHFile("00progress.bin"):
            fileBin = open("00progress.bin", 'rb+')
            if (fileBin):
                skipCode = [
                    0x04, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0A, 0x00,
                    0x01, 0x00, 0x01, 0x00, 0x00
                ]
                findHeaderinBAR(fileBin, 'wldf', True)
                if PS3Version():
                    skipCode.insert(0, 0x00)
                fileBin.seek(0x9b4, 1)
                fileBin.write(bytearray(skipCode))
                print("Done!")
                fileBin.close()
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
示例#18
0
def createNewIsoWithPatch():
    if not PS3Version():
        optionalString = ""
        if (cfg.config["variables"].getboolean("EnglishPatch")):
            optionalString = " \"" + cfg.config["strings"][
                "EnglishPatchFile"].rstrip() + "\""
        os.system("KH2FM_Toolkit " + cfg.config["strings"]["baseRom"] +
                  " -batch" + optionalString + " output.kh2patch"
                  )  #Patch AFTER the english because it changes some things
        newName = "KH2FMRandom_Seed_" + str(cfg.internalSeed)
        filetype = ".ISO"
        #while os.path.isfile(cfg.config["strings"]["romDirSelect"].rstrip() + newName + filetype):
        #newName += "_Copy"
        print("created new Iso called:" + newName)
        #os.rename("KH2FM.NEW.ISO",newName + filetype)
        try:
            if (cfg.config["strings"]["romDirSelect"]).rstrip() != "":
                print("Moving/Renaming KH2FM to new Directory....")
                shutil.move(
                    os.path.dirname(cfg.config["strings"]["baseRom"]) +
                    '/KH2FM.NEW.ISO',
                    (cfg.config["strings"]["romDirSelect"]).rstrip() + '/' +
                    newName + filetype)
        except Exception:
            print("Unable to move/rename to new Directory!!!")
    else:
        if os.path.isfile('HasherHD.exe'):
            if os.path.isfile('index.dat'):
                os.system("HasherHD.exe --batch --createNewMSelf index.dat " +
                          cfg.config["strings"]["baseRom"])
            else:
                utils.ErrorWindow(
                    "An index.dat is not found! It must be in the same folder as this program. It can be found in the same folder as the .mself file."
                )
        else:
            utils.ErrorWindow(
                "HasherHD.exe not found! It must be in the same folder as this program."
            )
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
示例#20
0
def randomizeNewRun():
    try:
        if cfg.config["strings"]["baseRom"] != "" and cfg.config["strings"][
                "romDirSelect"] != "":
            setSeed(cfg.config["strings"]["seed"])
            print('Starting Seed:' + str(cfg.internalSeed))
            prepareRandomizationLog()
            initAllVars()
            gui.setProgressBar(10)
            if (extractKH2Files()):
                TwilightTownTutText()
                if cfg.config["variables"].getboolean("SkipGummishipMission"):
                    worldMapGummiShipTxtSkip()
                RandomizeChestContents(
                    cfg.config["variables"].getboolean("RandomizeChestItems"))
                kh2rando_shops.randomizeShops(
                    cfg.config["variables"].getboolean("RandomItemShops"))
                gui.setProgressBar(20)
                RandomizeARD(
                    cfg.config["variables"].getboolean("RandomizeEnemies"),
                    cfg.config["variables"].getboolean("RandomizeBosses"),
                    cfg.config["variables"].getboolean("RandomizeAllies"),
                    cfg.config["variables"].getboolean("KH2SoraForced"),
                    cfg.config["variables"].getboolean("EnemyOptimizations"),
                    cfg.config["intvars"].getint("SuperBossEncounterRate"))
                randomizeMusic(
                    cfg.config["variables"].getboolean("RandomizeMusic"))
                randomizeItemDrops(
                    cfg.config["variables"].getboolean("RandomizeItemDrop"),
                    cfg.config["variables"].getboolean(
                        "RandomizeItemDropPercentage"))
                randomizeEquipmentStats(
                    cfg.config["variables"].getboolean(
                        "RandomizeEquipmentStats"),
                    cfg.config["variables"].getboolean(
                        "RandomizeEquipmentAbilities"))
                removeEnemySpawnLimit(
                    cfg.config["variables"].getboolean("RandomizeEnemies"))
                skipGummiShipMissions(
                    cfg.config['variables'].getboolean("SkipGummishipMission"))
                skipCredits(cfg.config['variables'].getboolean("SkipCredits"))
                #giveHUDElements()
                setSoraPartyMembers(
                    cfg.config["variables"].getboolean("KH2SoraForced"))
                gui.setProgressBar(40)
                RandomizeBonusLevels(
                    cfg.config["variables"].getboolean(
                        "RandomizeBonusLevelsAndAbilities"),
                    cfg.config["variables"].getboolean("RandomizeBonusItems"),
                    cfg.config["variables"].getboolean(
                        "RandomizeCritBonusAbilities"),
                    cfg.config["intvars"].getint("RandomAbilityAmount"),
                    cfg.config["variables"].getboolean("GuardFirst"))
                RandomizeDriveFormAbilities(cfg.config["variables"].getboolean(
                    "RandomizeBonusLevelsAndAbilities"))
                RandomizeCriticalBonusAbilities(
                    cfg.config["variables"].getboolean(
                        "RandomizeBonusLevelsAndAbilities"),
                    cfg.config["variables"].getboolean(
                        "RandomizeCritBonusAbilities"))
                RandomizeLevelUps(
                    cfg.config["variables"].getboolean("RandomizeLevelUps"))
                gui.setProgressBar(50)
                ReduceFormGrinding(
                    cfg.config["variables"].getboolean("ReduceDriveForm"))
                gui.setProgressBar(60)
                gui.setProgressBar(70)
                if cfg.config["variables"].getboolean("OutcomeTextFile"):
                    printOutComeText()

                createNewPatch()
                if not cfg.config["variables"].getboolean("CreateOnlyPatch"):
                    gui.setProgressBar(80)
                    createNewIsoWithPatch()
                    gui.setProgressBar(90)
                    gui.setProgressBar(100)
                    PS3String = ""
                    if PS3Version():
                        PS3String = "\nBe sure to move the .NEW.mself file and index.NEW.dat into the game directory and rename the old game files."
                    utils.GeneralMessageWindow(
                        "All done!!!\nIt was put in \n" +
                        cfg.config["strings"]["romDirSelect"].rstrip() +
                        "\nwith the seed:" + str(cfg.internalSeed) + PS3String,
                        "Randomization Complete!")
                else:
                    gui.setProgressBar(100)
                    PatchMessage = "A patch was created in the directory of this program."
                    if PS3Version():
                        PatchMessage = "An outcome was created."
                    utils.GeneralMessageWindow(PatchMessage,
                                               "Randomization Complete!")
                print('Randomization Complete.')
        else:
            utils.ErrorWindow(
                "Error: Either the base rom or the directory is not set yet.")
    except Exception as e:
        traceback.print_exc()
        utils.ErrorWindow("An error has occured during the randomization!")

    CleanUPRandomizedFiles()
    gui.turnBackOnRandoButton()
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 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])
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()