Param(
        [Parameter(Mandatory=$true)][String]$ResourceFileName,
        [Parameter(Mandatory=$true)][String]$OutputBaseFileName,
        [Parameter(Mandatory=$true)][Int16]$Year,
        [Parameter(Mandatory=$true)][Int16]$Month,
        [Parameter(Mandatory=$true)][Int16]$Day,
        [Int32]$StackSize=32000,
        [String]$AdditionalCodeFileName="",        # Binary file containing machine code to add at the end of CODE segment (to simulate bug in original FTL conversion tool)
        [String]$CodeResourceOrder = "",
        [Switch]$CompressCode,
        [String]$OriginalFileName,
        [Switch]$GenerateParts,
        [Switch]$PrintDebugInformation
)

if ($PrintDebugInformation) {
        "ResourceFileName: $ResourceFileName"
        "Year Month Day: $Year $Month $Day"
        "StackSize: $StackSize"
        "AdditionalCodeFileName: $AdditionalCodeFileName"
}

# Read additional code from file
if ($AdditionalCodeFileName -ne "") {
        $AdditionalCodeFileBytes = Get-Content -Encoding Byte -Path $AdditionalCodeFileName
}

$ResourceFileBytes = Get-Content -Encoding Byte -Path $ResourceFileName
# $OutputBaseFileName = "$(([System.IO.FileInfo]$ResourceFileName).DirectoryName)\$(([System.IO.FileInfo]$ResourceFileName).BaseName)"
# Resource Header
$ResourceDataOffset = $($ResourceFileBytes[0]  * 256 + $ResourceFileBytes[1])  * 65536 + $($ResourceFileBytes[2]  * 256 + $ResourceFileBytes[3])
$ResourceMapOffset =  $($ResourceFileBytes[4]  * 256 + $ResourceFileBytes[5])  * 65536 + $($ResourceFileBytes[6]  * 256 + $ResourceFileBytes[7])
$ResourceDataSize =   $($ResourceFileBytes[8]  * 256 + $ResourceFileBytes[9])  * 65536 + $($ResourceFileBytes[10] * 256 + $ResourceFileBytes[11])
$ResourceMapSize =    $($ResourceFileBytes[12] * 256 + $ResourceFileBytes[13]) * 65536 + $($ResourceFileBytes[14] * 256 + $ResourceFileBytes[15])

$ResourceTypeListOffset = $ResourceMapOffset + $ResourceFileBytes[$ResourceMapOffset + 24] * 256 + $ResourceFileBytes[$ResourceMapOffset + 25] + 2
$ResourceNameListOffset = $ResourceMapOffset + $ResourceFileBytes[$ResourceMapOffset + 26] * 256 + $ResourceFileBytes[$ResourceMapOffset + 27]
$ResourceTypeCount = $ResourceFileBytes[$ResourceMapOffset + 28] * 256 + $ResourceFileBytes[$ResourceMapOffset + 29] + 1

$Resources = @{}
for ($i = 0; $i -lt $ResourceTypeCount; $i++) {
        $ResourceType = [char]$ResourceFileBytes[$ResourceTypeListOffset + $i * 8]
        $ResourceType += [char]$ResourceFileBytes[$ResourceTypeListOffset + $i * 8 + 1]
        $ResourceType += [char]$ResourceFileBytes[$ResourceTypeListOffset + $i * 8 + 2]
        $ResourceType += [char]$ResourceFileBytes[$ResourceTypeListOffset + $i * 8 + 3]
        $Resources["ResourceCount_$ResourceType"] = $ResourceFileBytes[$ResourceTypeListOffset + $i * 8 + 4] * 256 + $ResourceFileBytes[$ResourceTypeListOffset + $i * 8 + 5] + 1
        if ($ResourceType -eq "CODE") {
                # Initialize an array that will contain the ordered list of CODE resource IDs
                $Resource_CODE_OrderedIDs = New-Object Int32[] $Resources["ResourceCount_$ResourceType"]
        }
        
        $Resources["ReferenceListOffset_$ResourceType"] = $ResourceTypeListOffset - 2 + $ResourceFileBytes[$ResourceTypeListOffset + $i * 8 + 6] * 256 + $ResourceFileBytes[$ResourceTypeListOffset + $i * 8 + 7]
        for ($j = 0; $j -lt $Resources["ResourceCount_$ResourceType"]; $j++) {
                $ResourceID = $ResourceFileBytes[$Resources["ReferenceListOffset_$ResourceType"] + $j * 12 + 0] * 256 + $ResourceFileBytes[$Resources["ReferenceListOffset_$ResourceType"] + $j * 12 + 1]
                $Resources["ResourceOffset_$($ResourceType)_$ResourceID"] = $ResourceDataOffset + $ResourceFileBytes[$Resources["ReferenceListOffset_$ResourceType"] + $j * 12 + 5] * 65536 + $ResourceFileBytes[$Resources["ReferenceListOffset_$ResourceType"] + $j * 12 + 6] * 256 + $ResourceFileBytes[$Resources["ReferenceListOffset_$ResourceType"] + $j * 12 + 7] + 4
                $Resources["ResourceSize_$($ResourceType)_$ResourceID"] = $($ResourceFileBytes[$Resources["ResourceOffset_$($ResourceType)_$ResourceID"] - 4]  * 256 + $ResourceFileBytes[$Resources["ResourceOffset_$($ResourceType)_$ResourceID"] - 3])  * 65536 + $($ResourceFileBytes[$Resources["ResourceOffset_$($ResourceType)_$ResourceID"] - 2]  * 256 + $ResourceFileBytes[$Resources["ResourceOffset_$($ResourceType)_$ResourceID"] - 1])
                if ($ResourceType -eq "CODE") {
                        # Build list of CODE resource IDs as ordered in the resource reference list
                        $Resource_CODE_OrderedIDs[$j] = $ResourceID
                }
        }
        if ($PrintDebugInformation) {
                if ($ResourceType -eq "CODE") {
                        Write-Host "Resource_CODE_OrderedIDs: $Resource_CODE_OrderedIDs"
                }
        }
        if ($CodeResourceOrder -ne "") {
                $Resource_CODE_OrderedIDs = $CodeResourceOrder.Split(",") + ("1", "0")
        }
        if ($PrintDebugInformation) {
                if ($ResourceType -eq "CODE") {
                        Write-Host "Resource_CODE_OrderedIDs: $Resource_CODE_OrderedIDs"
                }
        }
}
if ($PrintDebugInformation) {
        "ResourceDataOffset: $ResourceDataOffset"
        "ResourceMapOffset: $ResourceMapOffset"
        "ResourceDataSize: $ResourceDataSize"
        "ResourceMapSize: $ResourceMapSize"
        "ResourceTypeListOffset: $ResourceTypeListOffset"
        "ResourceNameListOffset: $ResourceNameListOffset"
        "ResourceTypeCount: $ResourceTypeCount"
}

# FTL file header
$HeaderSize = 20 + 3 * 12
$FTLHeader = New-Object Byte[] $HeaderSize
$ByteIndex = 0
$FTLHeader[0] = 0x61
$FTLHeader[1] = 0x60

$FTLHeader[4] = 0x00
$FTLHeader[5] = 0x02
$FTLHeader[6] = 0x01
$FTLHeader[7] = 0x00
$FTLHeader[8] = 0x00
$FTLHeader[9] = 0x07
$FTLHeader[10] = 0x00
$FTLHeader[11] = 0x01
$FTLHeader[12] = 0x04
$FTLHeader[13] = 0x01

if (($Year -lt 1980) -or ($Year -gt 2107)) {
        $Year = 1980
}
if (($Month -lt 1) -or ($Month -gt 12)) {
        $Month = 1
}
if (($Day -lt 1) -or ($Day -gt 31)) {
        $Day = 1
}
$FTLDate = (($Year - 1980) -shl 9) -bor (($Month - 1) -shl 5) -bor ($Day - 1)
$FTLHeader[14] = ($FTLDate -shr 8) -band 0xFF
$FTLHeader[15] = $FTLDate -band 0xFF
$FTLHeader[16] = ($FTLDate -shr 8) -band 0xFF
$FTLHeader[17] = $FTLDate -band 0xFF
$FTLHeader[18] = 0x00
$FTLHeader[19] = 0x03

$FTLHeader[20] = 0x00
$FTLHeader[21] = 0x10
$FTLHeader[22] = 0x00
$FTLHeader[23] = 0x01
$JUMPOffset = $HeaderSize
$FTLHeader[24] = ($JUMPOffset -shr 24) -band 0xFF
$FTLHeader[25] = ($JUMPOffset -shr 16) -band 0xFF
$FTLHeader[26] = ($JUMPOffset -shr 8) -band 0xFF
$FTLHeader[27] = $JUMPOffset -band 0xFF
$JumpCount = ($Resources["ResourceSize_CODE_0"] - 16) / 8
$JUMPSize = 40 + 4 * $JumpCount
$FTLHeader[28] =  ($JUMPSize -shr 24) -band 0xFF
$FTLHeader[29] =  ($JUMPSize -shr 16) -band 0xFF
$FTLHeader[30] =  ($JUMPSize -shr 8) -band 0xFF
$FTLHeader[31] =  $JUMPSize -band 0xFF

$FTLHeader[32] = 0x00
$FTLHeader[33] = 0x11
$FTLHeader[34] = 0x00
$FTLHeader[35] = 0x01
$DATAOffset = $JUMPOffset + $JUMPSize
$FTLHeader[36] = ($DATAOffset -shr 24) -band 0xFF
$FTLHeader[37] = ($DATAOffset -shr 16) -band 0xFF
$FTLHeader[38] = ($DATAOffset -shr 8) -band 0xFF
$FTLHeader[39] = $DATAOffset -band 0xFF
$DATASize = 10 + $Resources["ResourceSize_DATA_0"] + $Resources["ResourceSize_ZERO_0"] + $Resources["ResourceSize_DREL_0"]
$FTLHeader[40] = ($DATASize -shr 24) -band 0xFF
$FTLHeader[41] = ($DATASize -shr 16) -band 0xFF
$FTLHeader[42] = ($DATASize -shr 8) -band 0xFF
$FTLHeader[43] = $DATASize -band 0xFF

$FTLHeader[44] = 0x00
$FTLHeader[45] = 0x12
$FTLHeader[46] = 0x00
$FTLHeader[47] = 0x01
$CODEOffset = $DATAOffset + $DATASize
$FTLHeader[48] = ($CODEOffset -shr 24) -band 0xFF
$FTLHeader[49] = ($CODEOffset -shr 16) -band 0xFF
$FTLHeader[50] = ($CODEOffset -shr 8) -band 0xFF
$FTLHeader[51] = $CODEOffset -band 0xFF
if ($AdditionalCodeFileName -ne "") {
        $CODESize = $AdditionalCodeFileBytes.count
} else {
        $CODESize = 0
}
$Resources["ResourceFTLOffset_CODE_1"] = 0
$FTLOffset_CODE = $Resources["ResourceSize_CODE_1"] - 4
for ($j = 0; $j -lt $Resources["ResourceCount_CODE"]; $j++) {
        if ($Resource_CODE_OrderedIDs[$j] -ne 0) { # Ignore CODE0 resource
                $CODESize += $Resources["ResourceSize_CODE_$($Resource_CODE_OrderedIDs[$j])"] - 4
        }
        if ($Resource_CODE_OrderedIDs[$j] -ge 2) {
                $Resources["ResourceFTLOffset_CODE_$($Resource_CODE_OrderedIDs[$j])"] = $FTLOffset_CODE
                $FTLOffset_CODE += $Resources["ResourceSize_CODE_$($Resource_CODE_OrderedIDs[$j])"] - 4
        }
}
if ($PrintDebugInformation) {
        $Resources.GetEnumerator() | Sort-Object -Property Name
}
$FTLHeader[52] = ($CODESize -shr 24) -band 0xFF
$FTLHeader[53] = ($CODESize -shr 16) -band 0xFF
$FTLHeader[54] = ($CODESize -shr 8) -band 0xFF
$FTLHeader[55] = $CODESize -band 0xFF
# Header checksum
$ComputedHeaderChecksum = 0
for ($i = 4; $i -lt 20; $i++) {
        $ComputedHeaderChecksum += $FTLHeader[$i] * $i
        $ComputedHeaderChecksum %= 65535
}
for ($i = 0; $i -lt 3; $i++) {
        for ($j = 0; $j -lt 12; $j++) {
                $ComputedHeaderChecksum += $FTLHeader[20 + 12 * $i + $j] * ($j + 12 * $i + 1)
                $ComputedHeaderChecksum %= 65535
        }
}
$FTLHeader[2] = ($ComputedHeaderChecksum -shr 8) -band 0xFF
$FTLHeader[3] = $ComputedHeaderChecksum -band 0xFF

# FTL file JUMP segment
$FTLJUMP = New-Object Byte[] $JUMPSize
for ($i = 0; $i -lt 16; $i++) {
        $FTLJUMP[$i] = $ResourceFileBytes[$Resources["ResourceOffset_CODE_0"] + $i]
}
$FTLJUMP[16] = ($StackSize -shr 24) -band 0xFF
$FTLJUMP[17] = ($StackSize -shr 16) -band 0xFF
$FTLJUMP[18] = ($StackSize -shr 8) -band 0xFF
$FTLJUMP[19] = $StackSize -band 0xFF
$FTLJUMP[20] = ($CODESize -shr 24) -band 0xFF
$FTLJUMP[21] = ($CODESize -shr 16) -band 0xFF
$FTLJUMP[22] = ($CODESize -shr 8) -band 0xFF
$FTLJUMP[23] = $CODESize -band 0xFF
$FTLJUMP[24] = ($DATASize -shr 24) -band 0xFF
$FTLJUMP[25] = ($DATASize -shr 16) -band 0xFF
$FTLJUMP[26] = ($DATASize -shr 8) -band 0xFF
$FTLJUMP[27] = $DATASize -band 0xFF
$FTLJUMP[28] = 0x00
$FTLJUMP[29] = 0x01
$FTLJUMP[30] = 0x00
if ($CompressCode) {
        $FTLJUMP[31] = 0x01
} else {
        $FTLJUMP[31] = 0x00
}
$FTLJUMP[32] = 0x00
$FTLJUMP[33] = 0x00
$FTLJUMP[34] = 0x00
$FTLJUMP[35] = 0x00
# "Jumps Start"
for ($i = 0; $i -lt $JumpCount; $i++) {
        $JumpOffset = $ResourceFileBytes[$Resources["ResourceOffset_CODE_0"] + 16 + 8 * $i] * 256 + 
                      $ResourceFileBytes[$Resources["ResourceOffset_CODE_0"] + 16 + 8 * $i + 1] + 
                      $Resources["ResourceFTLOffset_CODE_$($ResourceFileBytes[$Resources["ResourceOffset_CODE_0"] + 16 + 8 * $i + 4] * 256 + $ResourceFileBytes[$Resources["ResourceOffset_CODE_0"] + 16 + 8 * $i + 5])"]
        $FTLJUMP[40 + 4 * $i + 0] = ($JumpOffset -shr 24) -band 0xFF
        $FTLJUMP[40 + 4 * $i + 1] = ($JumpOffset -shr 16) -band 0xFF
        $FTLJUMP[40 + 4 * $i + 2] = ($JumpOffset -shr 8) -band 0xFF
        $FTLJUMP[40 + 4 * $i + 3] = $JumpOffset -band 0xFF
}
# "Jumps End"

# FTL file DATA segment
$FTLDATA = New-Object Byte[] ($DATASize - $Resources["ResourceSize_DREL_0"])
$ByteIndex = 0
$FTLDATA[$ByteIndex++] = 0x00
$FTLDATA[$ByteIndex++] = 0x01
$FTLDATA[$ByteIndex++] = (($Resources["ResourceSize_DATA_0"] + $Resources["ResourceSize_ZERO_0"]) -shr 24) -band 0xFF
$FTLDATA[$ByteIndex++] = (($Resources["ResourceSize_DATA_0"] + $Resources["ResourceSize_ZERO_0"]) -shr 16) -band 0xFF
$FTLDATA[$ByteIndex++] = (($Resources["ResourceSize_DATA_0"] + $Resources["ResourceSize_ZERO_0"]) -shr 8) -band 0xFF
$FTLDATA[$ByteIndex++] = ($Resources["ResourceSize_DATA_0"] + $Resources["ResourceSize_ZERO_0"]) -band 0xFF
$FTLDATA[$ByteIndex++] = ($Resources["ResourceSize_DREL_0"] -shr 24) -band 0xFF
$FTLDATA[$ByteIndex++] = ($Resources["ResourceSize_DREL_0"] -shr 16) -band 0xFF
$FTLDATA[$ByteIndex++] = ($Resources["ResourceSize_DREL_0"] -shr 8) -band 0xFF
$FTLDATA[$ByteIndex++] = $Resources["ResourceSize_DREL_0"] -band 0xFF
$i = $Resources["ResourceOffset_DATA_0"]
$j = $Resources["ResourceOffset_ZERO_0"]
while ($i -lt ($Resources["ResourceOffset_DATA_0"] + $Resources["ResourceSize_DATA_0"])) {
        $FTLDATA[$ByteIndex++] = $ResourceFileBytes[$i]
        $FTLDATA[$ByteIndex++] = $ResourceFileBytes[$i + 1]
        if (($ResourceFileBytes[$i] -eq 0) -and ($ResourceFileBytes[$i + 1] -eq 0)) {
                $FTLDATA[$ByteIndex++] = $ResourceFileBytes[$j++]
                $FTLDATA[$ByteIndex++] = $ResourceFileBytes[$j++]
        }
        $i += 2
}
if ($Resources["ResourceSize_DREL_0"] -ge 1) {
        $FTLDATA += [Byte[]]$ResourceFileBytes[($Resources["ResourceOffset_DREL_0"])..($Resources["ResourceOffset_DREL_0"] + $Resources["ResourceSize_DREL_0"] - 1)]
}
$ComputedDATAChecksum = 0
for ($i = 0; $i -lt $DATASize; $i++) {
        $ComputedDATAChecksum += $FTLDATA[$i]
        $ComputedDATAChecksum %= 65536
}
$FTLJUMP[38] = ($ComputedDATAChecksum -shr 8) -band 0xFF
$FTLJUMP[39] = $ComputedDATAChecksum -band 0xFF

# FTL file CODE segment
$MFWhash = @{} # Most Frequent Words
# Copy bytes from CODE1 resource
$FTLCODE = [Byte[]]$ResourceFileBytes[($Resources["ResourceOffset_CODE_1"] + 4)..($Resources["ResourceOffset_CODE_1"] + $Resources["ResourceSize_CODE_1"] - 1)]
# Copy bytes from all other CODE resources (all except the last two which are CODE1 and CODE0)
for ($i = 0; $i -lt $Resources["ResourceCount_CODE"] - 2; $i++) {
        if ($Resources["ResourceSize_CODE_$($Resource_CODE_OrderedIDs[$i])"] -ge 5) {
                $FTLCODE += [Byte[]]$ResourceFileBytes[($Resources["ResourceOffset_CODE_$($Resource_CODE_OrderedIDs[$i])"] + 4)..($Resources["ResourceOffset_CODE_$($Resource_CODE_OrderedIDs[$i])"] + $Resources["ResourceSize_CODE_$($Resource_CODE_OrderedIDs[$i])"] - 1)]
        }
}
# Copy bytes from additional code
if ($AdditionalCodeFileName -ne "") {
        $FTLCODE += [Byte[]]$AdditionalCodeFileBytes
}

# Overwrite first instructions
$FTLCODE[4] = [Byte]0x22
$FTLCODE[5] = [Byte]0x3A
$FTLCODE[6] = [Byte]0xFF
$FTLCODE[7] = [Byte]0xFA
$FTLCODE[8] = [Byte]0x4E
$FTLCODE[9] = [Byte]0xF5
$FTLCODE[10] = [Byte]0x10
$FTLCODE[11] = [Byte]0x00
$ComputedCODEChecksum = 0
for ($i = 0; $i -lt $CODESize; $i++) {
        $ComputedCODEChecksum += $FTLCODE[$i]
        $ComputedCODEChecksum %= 65536
}
$FTLJUMP[36] = ($ComputedCODEChecksum -shr 8) -band 0xFF
$FTLJUMP[37] = $ComputedCODEChecksum -band 0xFF

if ($CompressCode) {
        $FTLCompressedCODE = New-Object Byte[] $CODESize
        $FTLCompressedCODE[0] = 0x52
        $FTLCompressedCODE[1] = 0x23
        $FTLCompressedCODE[2] = 0x52
        $FTLCompressedCODE[3] = 0x23
        $FTLCompressedCODE[4] = (($CODESize / 2) -shr 24) -band 0xFF
        $FTLCompressedCODE[5] = (($CODESize / 2) -shr 16) -band 0xFF
        $FTLCompressedCODE[6] = (($CODESize / 2) -shr 8) -band 0xFF
        $FTLCompressedCODE[7] = ($CODESize / 2) -band 0xFF
        # Read most frequent words table from original FTL file
        $OriginalFileBytes = Get-Content -Encoding Byte -Path $OriginalFileName
        for ($SegmentIndex = 0; $SegmentIndex -lt 3; $SegmentIndex++) {
                $Type = $($OriginalFileBytes[12 * $SegmentIndex + 20] * 256 + $OriginalFileBytes[12 * $SegmentIndex + 21])
                $Offset = $($OriginalFileBytes[12 * $SegmentIndex + 24] * 256 + $OriginalFileBytes[12 * $SegmentIndex + 25]) * 65536 + $($OriginalFileBytes[12 * $SegmentIndex + 26] * 256 + $OriginalFileBytes[12 * $SegmentIndex + 27])
                
                if ($type -eq 16) {
                        $CODECompressed = $($OriginalFileBytes[$Offset + 30] * 256 + $OriginalFileBytes[$Offset + 31])
                        if ($CODECompressed -ne 1) {
                                "Original File does not contain compressed CODE!"
                                exit
                        }
                }
                if ($type -eq 18) {
                        $MostFrequentWords = New-Object Byte[] 3840
                        for ($i = 0; $i -lt 1920; $i++) {
                                $MostFrequentWords[2 * $i] = $OriginalFileBytes[$Offset + 8 + 2 * $i]
                                $MostFrequentWords[2 * $i + 1] = $OriginalFileBytes[$Offset + 8 + 2 * $i + 1]
                                $MFWhash[$OriginalFileBytes[$Offset + 8 + 2 * $i] * 256 + $OriginalFileBytes[$Offset + 8 + 2 * $i + 1]] = $i
                        }
                        $MostFrequentWords
                }
        }
        # Compression
        $Offset = 8
        $MostSignificantNibble = $true
        for ($i = 0; $i -lt $CODESize / 2; $i += 2) {
                $Key = $FTLCODE[$i] * 256 + $FTLCODE[$i + 1]
                if ($MFWhash.ContainsKey($Key)) {
                        $WordIndex = $MFWhash[$Key]
                        if ($WordIndex -lt 128) {
                                if ($MostSignificantNibble) {
                                        $FTLCompressedCODE[$Offset] = (($WordIndex -band 0x00F0) -shr 4) * 16
                                        $MostSignificantNibble = $false
                                } else {
                                        $FTLCompressedCODE[$Offset] = $FTLCompressedCODE[$Offset] -bor (($WordIndex -band 0x00F0) -shr 4)
                                        $MostSignificantNibble = $true
                                        $Offset++
                                }
                                if ($MostSignificantNibble) {
                                        $FTLCompressedCODE[$Offset] = ($WordIndex -band 0x000F) * 16
                                        $MostSignificantNibble = $false
                                        $LastByteUsed = $true
                                } else {
                                        $FTLCompressedCODE[$Offset] = $FTLCompressedCODE[$Offset] -bor ($WordIndex -band 0x000F)
                                        $MostSignificantNibble = $true
                                        $Offset++
                                        $LastByteUsed = $false
                                }
                        } else {
                                if ($MostSignificantNibble) {
                                        $FTLCompressedCODE[$Offset] = (($WordIndex -band 0x0F00) -shr 8) * 16
                                        $MostSignificantNibble = $false
                                } else {
                                        $FTLCompressedCODE[$Offset] = $FTLCompressedCODE[$Offset] -bor (($WordIndex -band 0x0F00) -shr 8)
                                        $MostSignificantNibble = $true
                                        $Offset++
                                }
                                if ($MostSignificantNibble) {
                                        $FTLCompressedCODE[$Offset] = (($WordIndex -band 0x00F0) -shr 4) * 16
                                        $MostSignificantNibble = $false
                                } else {
                                        $FTLCompressedCODE[$Offset] = $FTLCompressedCODE[$Offset] -bor (($WordIndex -band 0x00F0) -shr 4)
                                        $MostSignificantNibble = $true
                                        $Offset++
                                }
                                if ($MostSignificantNibble) {
                                        $FTLCompressedCODE[$Offset] = ($WordIndex -band 0x000F) * 16
                                        $MostSignificantNibble = $false
                                        $LastByteUsed = $true
                                } else {
                                        $FTLCompressedCODE[$Offset] = $FTLCompressedCODE[$Offset] -bor ($WordIndex -band 0x000F)
                                        $MostSignificantNibble = $true
                                        $Offset++
                                        $LastByteUsed = $false
                                }
                        }
                } else {
                        if ($MostSignificantNibble) {
                                $FTLCompressedCODE[$Offset] = 0xF * 16
                                $MostSignificantNibble = $false
                        } else {
                                $FTLCompressedCODE[$Offset] = $FTLCompressedCODE[$Offset] -bor 0xF
                                $MostSignificantNibble = $true
                                $Offset++
                        }
                        if ($MostSignificantNibble) {
                                $FTLCompressedCODE[$Offset] = (($Key -band 0xF000) -shr 12) * 16
                                $MostSignificantNibble = $false
                        } else {
                                $FTLCompressedCODE[$Offset] = $FTLCompressedCODE[$Offset] -bor (($Key -band 0xF000) -shr 12)
                                $MostSignificantNibble = $true
                                $Offset++
                        }
                        if ($MostSignificantNibble) {
                                $FTLCompressedCODE[$Offset] = (($Key -band 0x0F00) -shr 8) * 16
                                $MostSignificantNibble = $false
                        } else {
                                $FTLCompressedCODE[$Offset] = $FTLCompressedCODE[$Offset] -bor (($Key -band 0x0F00) -shr 8)
                                $MostSignificantNibble = $true
                                $Offset++
                        }
                        if ($MostSignificantNibble) {
                                $FTLCompressedCODE[$Offset] = (($Key -band 0x00F0) -shr 4) * 16
                                $MostSignificantNibble = $false
                        } else {
                                $FTLCompressedCODE[$Offset] = $FTLCompressedCODE[$Offset] -bor (($Key -band 0x00F0) -shr 4)
                                $MostSignificantNibble = $true
                                $Offset++
                        }
                        if ($MostSignificantNibble) {
                                $FTLCompressedCODE[$Offset] = ($Key -band 0x000F) * 16
                                $MostSignificantNibble = $false
                                $LastByteUsed = $true
                        } else {
                                $FTLCompressedCODE[$Offset] = $FTLCompressedCODE[$Offset] -bor ($Key -band 0x000F)
                                $MostSignificantNibble = $true
                                $Offset++
                                $LastByteUsed = $false
                        }
                }
        }
        if ($LastByteUsed) {
                $CompressedCODESize = $Offset
        } else {
                $CompressedCODESize = $Offset - 1
        }
        $FTLCompressedCODE2 = New-Object Byte[] $CompressedCODESize
        for ($i = 0; $i -lt $CompressedCODESize; $i++) {
                $FTLCompressedCODE2[$i] = $FTLCompressedCODE[$i]
        }
}


$ComputedJUMPChecksum = 0
for ($i = 0; $i -lt $JUMPSize; $i += 2) {
        $ComputedJUMPChecksum += $FTLJUMP[$i] * 256 + $FTLJUMP[$i + 1]
        $ComputedJUMPChecksum %= 65536
}
$FTLJUMP[34] = ($ComputedJUMPChecksum -shr 8) -band 0xFF
$FTLJUMP[35] = $ComputedJUMPChecksum -band 0xFF

if ($GenerateParts) {
        # DATA resource
        Set-Content -Encoding Byte -Value ([Byte[]]$ResourceFileBytes[($Resources["ResourceOffset_DATA_0"])..($Resources["ResourceOffset_DATA_0"] + $Resources["ResourceSize_DATA_0"] - 1)]) -Path "$($OutputBaseFileName)_DATA_0"

        # ZERO resource
        Set-Content -Encoding Byte -Value ([Byte[]]$ResourceFileBytes[($Resources["ResourceOffset_ZERO_0"])..($Resources["ResourceOffset_ZERO_0"] + $Resources["ResourceSize_ZERO_0"] - 1)]) -Path "$($OutputBaseFileName)_ZERO_0"

        # DREL resource
        Set-Content -Encoding Byte -Value ([Byte[]]$ResourceFileBytes[($Resources["ResourceOffset_DREL_0"])..($Resources["ResourceOffset_DREL_0"] + $Resources["ResourceSize_DREL_0"] - 1)]) -Path "$($OutputBaseFileName)_DREL_0"

        # CODE resources
        for ($j = 0; $j -lt $Resources["ResourceCount_CODE"]; $j++) {
                Set-Content -Encoding Byte -Value ([Byte[]]$ResourceFileBytes[($Resources["ResourceOffset_CODE_$($Resource_CODE_OrderedIDs[$j])"])..($Resources["ResourceOffset_CODE_$($Resource_CODE_OrderedIDs[$j])"] + $Resources["ResourceSize_CODE_$($Resource_CODE_OrderedIDs[$j])"] - 1)]) -Path "$($OutputBaseFileName)_CODE_$($Resource_CODE_OrderedIDs[$j])"
        }

        # FTL file parts
        Set-Content -Encoding Byte -Value $FTLHeader -Path "$($OutputBaseFileName)_FTLHeader"
        Set-Content -Encoding Byte -Value $FTLJUMP -Path "$($OutputBaseFileName)_FTLJUMP"
        Set-Content -Encoding Byte -Value $FTLDATA -Path "$($OutputBaseFileName)_FTLDATA"
        Set-Content -Encoding Byte -Value $FTLCODE -Path "$($OutputBaseFileName)_FTLCODE"
}

# Build full FTL file
Set-Content -Encoding Byte -Value $FTLHeader -Path "$OutputBaseFileName"
Add-Content -Encoding Byte -Value $FTLJUMP -Path "$OutputBaseFileName"
Add-Content -Encoding Byte -Value $FTLDATA -Path "$OutputBaseFileName"
if ($CompressCode) {
        Add-Content -Encoding Byte -Value $FTLCompressedCODE2 -Path "$OutputBaseFileName"
} else {
        Add-Content -Encoding Byte -Value $FTLCODE -Path "$OutputBaseFileName"
}
