`,]']>S}Wup8d%qy)6o;]AsVl3S}Wup8d%qy)6o;]AsVl34.#""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""ݙ C ܠ """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""  """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" #2 -3#-"23" 22 3324 CC#-#"2#3"# "" #3333 2#4"#BDB#D424DB""4##4#BD3CD4#DD23C434 "!!2"!!!#"C2 #!""""!#!"3"1C3"!#23!"!!1!3""!!!122# !.#"- #22# 32 C#2"2 .3"C4"43##2##"# "## 3B2 3D$2CDD"3DD "3D B3""D3434C22#"4#4"C$C##34"3#""3B ##1 ""2314!"3"!$!"4"##2B2C#3"22!#12" #!#!3"##23!!!""!!!"! ! """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""  vv""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""wwgvfgffffffgfv|wwvw""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""~CDDDDDDDDDDDDDDDEC678D678D678D678ECDDDDDDDDDDDDDDDEC678D678D678D678ECFGHDFGHDFGHDFGHECDDDDDDDDDDDDDDDECFGHDFGHDFGHDFGHECVWXDVWXDVWXDVWXEC678D678D678D678ECVWXDVWXDVWXDVWXECDDDDDDDDDDDDDDDECFGHDFGHDFGHDFGHECDDDDDDDDDDDDDDDECDDDDDDDDDDDDDDDECVWXDVWXDVWXDVWXECDDDDDDDDDDDDDDDEC678D678D678D678ECDDDDDDDDDDDDDDDEC678D678D678D678ECFGHDFGHDFGHDFGHENOCDDDDDDDDDDDDDDDECFGHDFGHDFGHDFGHCVWXDVWXDVWXDVWXE^_C678D678D678D678ECVWXDVWXDVWXDVWXCDDDDDDDDDDDDDDDENOnoCFGHDFI;DFGHDFGHECDDDDDDDDDDDDDDDCDDDDKLMDDDDDDDDE^_noCVWXDJ:;DVWXDVWXECDDDDDDDDDDDDDDDC678D678D678D678EnonoCDDDD9YHDDDDDDDDECFGHDFI;DFGHDFGHEnonoCDDDDVWXDDDDDDDDECVWXDJ:;DVWXDVWXEnoCDDDD9YHDDDDDDDDEnoCDDDDVWXDDDDDDDDEno!" 12  פ΢-.../#=>>>?РТ#д΢РЦ$%&'(Рж)*+,)*+,)*+,)*+)аФФ׶ |pp0 @@ppp`P0  &&,.....////////////////// CDDDDDEEEEFFFFGHMMNNNNOOOOOOOOppppp "##$%&'(())*++,,---....//////ssssxx|~~~~~9 753333333333344 4040444444445555 0``0ееее ```       CCEEFd0CCEEFd0CCEEFd 00123456788888888999999::::::::w< ؖƘ|          @P@  w<[pP0 z}~}|zwpp#JF4#6ӿ¿ ptptptp t wzwzwzwz|}|}|}|}u             `M i_G?$ ` 0@P`pp``PP@0  pp      " `pp@P`Pp`p0ppppp``Ppj @ABEDH4J$LOOOOOOOOOOOOOOOOOOOOOOO     D'^'l^'lN'lN'l^'lN'lEeEEeEEeEEeEEeEeeE%%E% EE% E @@@ @@@     p`P@0 0 J J * * ** **JJJJ J * * ** **JJJ       h       hJ J * * JJ*JJJJJ**J*J*JJJ ` `0 mmm mp`P@0  ` `0D @ ` m p`P@0 oo  JJ**J*JjJJ JJ***J*JjJJJoo rJJ**J*JjJ*JJ***J*JjJ*J rr p`P@0 00VVVVVV V V V V       V V V V V VvVvV            &&F&&F&&F&&F&&F&&F&&F&&F&&F&&F&&F&&F & & F & & F & & F&&F   k kk  k k k k k  k k&FF&&FF&&Ff&fF&Ff&fF  & F  F &  & F  F &&Ff&fF&Ff&fF k kk  k k  k k kkk k&FF&&FF&&Ff&fF&Ff&fF&Ff&fF&Ff&fF&Ff&fF&Ff&fF 00B0B1B011,, , ,I,,, ,4-Te-4-e- ,mmqqrHrqqrHr(h?D"!!!"!"!"!"œ,ov""!off/""!offv"wfv!v!͚wܬ}M̝ܙ,0,]']>S}Wup8d%qy)6o;]AsVl3S}Wup8d%qy)6o;]AsVl3S}Wup8d%qy)6o;]AsVl3S}Wup8d%qy)6o;]AsVl3 a then a = a + b b = b * 2 c = c + 4 bitlen = bitlen + 1 end local t = len - a - 1 + b / 2 _length_to_deflate_code[len] = (t - (t % (b / 8))) / (b / 8) + c _length_to_deflate_extra_bitlen[len] = bitlen _length_to_deflate_extra_bits[len] = t % (b / 8) end end end do _dist256_to_deflate_code[1] = 0 _dist256_to_deflate_code[2] = 1 _dist256_to_deflate_extra_bitlen[1] = 0 _dist256_to_deflate_extra_bitlen[2] = 0 local a = 3 local b = 4 local code = 2 local bitlen = 0 for dist = 3, 256 do if dist > b then a = a * 2 b = b * 2 code = code + 2 bitlen = bitlen + 1 end _dist256_to_deflate_code[dist] = (dist <= a) and code or (code + 1) _dist256_to_deflate_extra_bitlen[dist] = (bitlen < 0) and 0 or bitlen if b >= 8 then _dist256_to_deflate_extra_bits[dist] = (dist - b / 2 - 1) % (b / 4) end end end function LibDeflate:Adler32(str) if type(str) ~= "string" then error(("Usage: LibDeflate:Adler32(str):" .. " 'str' - string expected got '%s'."):format(type(str)), 2) end local strlen = #str local i = 1 local a = 1 local b = 0 while i <= strlen - 15 do local x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16 = string.byte(str, i, i + 15) b = (b + 16 * a + 16 * x1 + 15 * x2 + 14 * x3 + 13 * x4 + 12 * x5 + 11 * x6 + 10 * x7 + 9 * x8 + 8 * x9 + 7 * x10 + 6 * x11 + 5 * x12 + 4 * x13 + 3 * x14 + 2 * x15 + x16) % 65521 a = (a + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16) % 65521 i = i + 16 end while (i <= strlen) do local x = string.byte(str, i, i) a = (a + x) % 65521 b = (b + a) % 65521 i = i + 1 end return (b * 65536 + a) % 4294967296 end local function IsEqualAdler32(actual, expected) return (actual % 4294967296) == (expected % 4294967296) end function LibDeflate:CreateDictionary(str, strlen, adler32) if type(str) ~= "string" then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. " 'str' - string expected got '%s'."):format(type(str)), 2) end if type(strlen) ~= "number" then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. " 'strlen' - number expected got '%s'."):format(type(strlen)), 2) end if type(adler32) ~= "number" then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. " 'adler32' - number expected got '%s'."):format(type(adler32)), 2) end if strlen ~= #str then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. " 'strlen' does not match the actual length of 'str'." .. " 'strlen': %u, '#str': %u ." .. " Please check if 'str' is modified unintentionally."):format( strlen, #str)) end if strlen == 0 then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. " 'str' - Empty string is not allowed."), 2) end if strlen > 32768 then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. " 'str' - string longer than 32768 bytes is not allowed." .. " Got %d bytes."):format(strlen), 2) end local actual_adler32 = self:Adler32(str) if not IsEqualAdler32(adler32, actual_adler32) then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" .. " 'adler32' does not match the actual adler32 of 'str'." .. " 'adler32': %u, 'Adler32(str)': %u ." .. " Please check if 'str' is modified unintentionally."):format( adler32, actual_adler32)) end local dictionary = {} dictionary.adler32 = adler32 dictionary.hash_tables = {} dictionary.string_table = {} dictionary.strlen = strlen local string_table = dictionary.string_table local hash_tables = dictionary.hash_tables string_table[1] = string.byte(str, 1, 1) string_table[2] = string.byte(str, 2, 2) if strlen >= 3 then local i = 1 local hash = string_table[1] * 256 + string_table[2] while i <= strlen - 2 - 3 do local x1, x2, x3, x4 = string.byte(str, i + 2, i + 5) string_table[i + 2] = x1 string_table[i + 3] = x2 string_table[i + 4] = x3 string_table[i + 5] = x4 hash = (hash * 256 + x1) % 16777216 local t = hash_tables[hash] if not t then t = {}; hash_tables[hash] = t end t[#t + 1] = i - strlen i = i + 1 hash = (hash * 256 + x2) % 16777216 t = hash_tables[hash] if not t then t = {}; hash_tables[hash] = t end t[#t + 1] = i - strlen i = i + 1 hash = (hash * 256 + x3) % 16777216 t = hash_tables[hash] if not t then t = {}; hash_tables[hash] = t end t[#t + 1] = i - strlen i = i + 1 hash = (hash * 256 + x4) % 16777216 t = hash_tables[hash] if not t then t = {}; hash_tables[hash] = t end t[#t + 1] = i - strlen i = i + 1 end while i <= strlen - 2 do local x = string.byte(str, i + 2) string_table[i + 2] = x hash = (hash * 256 + x) % 16777216 local t = hash_tables[hash] if not t then t = {}; hash_tables[hash] = t end t[#t + 1] = i - strlen i = i + 1 end end return dictionary end local function IsValidDictionary(dictionary) if type(dictionary) ~= "table" then return false, ("'dictionary' - table expected got '%s'."):format(type(dictionary)) end if type(dictionary.adler32) ~= "number" or type(dictionary.string_table) ~= "table" or type(dictionary.strlen) ~= "number" or dictionary.strlen <= 0 or dictionary.strlen > 32768 or dictionary.strlen ~= #dictionary.string_table or type(dictionary.hash_tables) ~= "table" then return false, ("'dictionary' - corrupted dictionary."):format(type(dictionary)) end return true, "" end local _compression_level_configs = { [0] = {false, nil, 0, 0, 0}, -- level 0, no compression [1] = {false, nil, 4, 8, 4}, -- level 1, similar to zlib level 1 [2] = {false, nil, 5, 18, 8}, -- level 2, similar to zlib level 2 [3] = {false, nil, 6, 32, 32}, -- level 3, similar to zlib level 3 [4] = {true, 4, 4, 16, 16}, -- level 4, similar to zlib level 4 [5] = {true, 8, 16, 32, 32}, -- level 5, similar to zlib level 5 [6] = {true, 8, 16, 128, 128}, -- level 6, similar to zlib level 6 [7] = {true, 8, 32, 128, 256}, -- (SLOW) level 7, similar to zlib level 7 [8] = {true, 32, 128, 258, 1024}, -- (SLOW) level 8,similar to zlib level 8 [9] = {true, 32, 258, 258, 4096} -- (VERY SLOW) level 9, similar to zlib level 9 } local function IsValidArguments(str, check_dictionary, dictionary, check_configs, configs) if type(str) ~= "string" then return false, ("'str' - string expected got '%s'."):format(type(str)) end if check_dictionary then local dict_valid, dict_err = IsValidDictionary(dictionary) if not dict_valid then return false, dict_err end end if check_configs then local type_configs = type(configs) if type_configs ~= "nil" and type_configs ~= "table" then return false, ("'configs' - nil or table expected got '%s'."):format( type(configs)) end if type_configs == "table" then for k, v in pairs(configs) do if k ~= "level" and k ~= "strategy" then return false, ("'configs' - unsupported table key in the configs: '%s'."):format( k) elseif k == "level" and not _compression_level_configs[v] then return false, ("'configs' - unsupported 'level': %s."):format(tostring(v)) elseif k == "strategy" and v ~= "fixed" and v ~= "huffman_only" and v ~= "dynamic" then -- random_block_type is for testing purpose return false, ("'configs' - unsupported 'strategy': '%s'."):format( tostring(v)) end end end end return true, "" end --[[ -------------------------------------------------------------------------- Compress code --]] -------------------------------------------------------------------------- local _FLUSH_MODE_MEMORY_CLEANUP = 0 local _FLUSH_MODE_OUTPUT = 1 local _FLUSH_MODE_BYTE_BOUNDARY = 2 local _FLUSH_MODE_NO_FLUSH = 3 local function CreateWriter() local buffer_size = 0 local cache = 0 local cache_bitlen = 0 local total_bitlen = 0 local buffer = {} local result_buffer = {} local function WriteBits(value, bitlen) cache = cache + value * _pow2[cache_bitlen] cache_bitlen = cache_bitlen + bitlen total_bitlen = total_bitlen + bitlen if cache_bitlen >= 32 then buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_char[cache % 256] .. _byte_to_char[((cache - cache % 256) / 256 % 256)] .. _byte_to_char[((cache - cache % 65536) / 65536 % 256)] .. _byte_to_char[((cache - cache % 16777216) / 16777216 % 256)] local rshift_mask = _pow2[32 - cache_bitlen + bitlen] cache = (value - value % rshift_mask) / rshift_mask cache_bitlen = cache_bitlen - 32 end end local function WriteString(str) for _ = 1, cache_bitlen, 8 do buffer_size = buffer_size + 1 buffer[buffer_size] = string.char(cache % 256) cache = (cache - cache % 256) / 256 end cache_bitlen = 0 buffer_size = buffer_size + 1 buffer[buffer_size] = str total_bitlen = total_bitlen + #str * 8 end local function FlushWriter(mode) if mode == _FLUSH_MODE_NO_FLUSH then return total_bitlen end if mode == _FLUSH_MODE_OUTPUT or mode == _FLUSH_MODE_BYTE_BOUNDARY then local padding_bitlen = (8 - cache_bitlen % 8) % 8 if cache_bitlen > 0 then cache = cache - _pow2[cache_bitlen] + _pow2[cache_bitlen + padding_bitlen] for _ = 1, cache_bitlen, 8 do buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_char[cache % 256] cache = (cache - cache % 256) / 256 end cache = 0 cache_bitlen = 0 end if mode == _FLUSH_MODE_BYTE_BOUNDARY then total_bitlen = total_bitlen + padding_bitlen return total_bitlen end end local flushed = table.concat(buffer) buffer = {} buffer_size = 0 result_buffer[#result_buffer + 1] = flushed if mode == _FLUSH_MODE_MEMORY_CLEANUP then return total_bitlen else return total_bitlen, table.concat(result_buffer) end end return WriteBits, WriteString, FlushWriter end local function MinHeapPush(heap, e, heap_size) heap_size = heap_size + 1 heap[heap_size] = e local value = e[1] local pos = heap_size local parent_pos = (pos - pos % 2) / 2 while (parent_pos >= 1 and heap[parent_pos][1] > value) do local t = heap[parent_pos] heap[parent_pos] = e heap[pos] = t pos = parent_pos parent_pos = (parent_pos - parent_pos % 2) / 2 end end local function MinHeapPop(heap, heap_size) local top = heap[1] local e = heap[heap_size] local value = e[1] heap[1] = e heap[heap_size] = top heap_size = heap_size - 1 local pos = 1 local left_child_pos = pos * 2 local right_child_pos = left_child_pos + 1 while (left_child_pos <= heap_size) do local left_child = heap[left_child_pos] if (right_child_pos <= heap_size and heap[right_child_pos][1] < left_child[1]) then local right_child = heap[right_child_pos] if right_child[1] < value then heap[right_child_pos] = e heap[pos] = right_child pos = right_child_pos left_child_pos = pos * 2 right_child_pos = left_child_pos + 1 else break end else if left_child[1] < value then heap[left_child_pos] = e heap[pos] = left_child pos = left_child_pos left_child_pos = pos * 2 right_child_pos = left_child_pos + 1 else break end end end return top end local function GetHuffmanCodeFromBitlen(bitlen_counts, symbol_bitlens, max_symbol, max_bitlen) local huffman_code = 0 local next_codes = {} local symbol_huffman_codes = {} for bitlen = 1, max_bitlen do huffman_code = (huffman_code + (bitlen_counts[bitlen - 1] or 0)) * 2 next_codes[bitlen] = huffman_code end for symbol = 0, max_symbol do local bitlen = symbol_bitlens[symbol] if bitlen then huffman_code = next_codes[bitlen] next_codes[bitlen] = huffman_code + 1 if bitlen <= 9 then -- Have cached reverse for small bitlen. symbol_huffman_codes[symbol] = _reverse_bits_tbl[bitlen][huffman_code] else local reverse = 0 for _ = 1, bitlen do reverse = reverse - reverse % 2 + (((reverse % 2 == 1) or (huffman_code % 2) == 1) and 1 or 0) huffman_code = (huffman_code - huffman_code % 2) / 2 reverse = reverse * 2 end symbol_huffman_codes[symbol] = (reverse - reverse % 2) / 2 end end end return symbol_huffman_codes end local function SortByFirstThenSecond(a, b) return a[1] < b[1] or (a[1] == b[1] and a[2] < b[2]) end local function GetHuffmanBitlenAndCode(symbol_counts, max_bitlen, max_symbol) local heap_size local max_non_zero_bitlen_symbol = -1 local leafs = {} local heap = {} local symbol_bitlens = {} local symbol_codes = {} local bitlen_counts = {} local number_unique_symbols = 0 for symbol, count in pairs(symbol_counts) do number_unique_symbols = number_unique_symbols + 1 leafs[number_unique_symbols] = {count, symbol} end if (number_unique_symbols == 0) then return {}, {}, -1 elseif (number_unique_symbols == 1) then local symbol = leafs[1][2] symbol_bitlens[symbol] = 1 symbol_codes[symbol] = 0 return symbol_bitlens, symbol_codes, symbol else table.sort(leafs, SortByFirstThenSecond) heap_size = number_unique_symbols for i = 1, heap_size do heap[i] = leafs[i] end while (heap_size > 1) do local leftChild = MinHeapPop(heap, heap_size) heap_size = heap_size - 1 local rightChild = MinHeapPop(heap, heap_size) heap_size = heap_size - 1 local newNode = {leftChild[1] + rightChild[1], -1, leftChild, rightChild} MinHeapPush(heap, newNode, heap_size) heap_size = heap_size + 1 end local number_bitlen_overflow = 0 local fifo = {heap[1], 0, 0, 0} -- preallocate some spaces. local fifo_size = 1 local index = 1 heap[1][1] = 0 while (index <= fifo_size) do -- Breath first search local e = fifo[index] local bitlen = e[1] local symbol = e[2] local left_child = e[3] local right_child = e[4] if left_child then fifo_size = fifo_size + 1 fifo[fifo_size] = left_child left_child[1] = bitlen + 1 end if right_child then fifo_size = fifo_size + 1 fifo[fifo_size] = right_child right_child[1] = bitlen + 1 end index = index + 1 if (bitlen > max_bitlen) then number_bitlen_overflow = number_bitlen_overflow + 1 bitlen = max_bitlen end if symbol >= 0 then symbol_bitlens[symbol] = bitlen max_non_zero_bitlen_symbol = (symbol > max_non_zero_bitlen_symbol) and symbol or max_non_zero_bitlen_symbol bitlen_counts[bitlen] = (bitlen_counts[bitlen] or 0) + 1 end end if (number_bitlen_overflow > 0) then repeat local bitlen = max_bitlen - 1 while ((bitlen_counts[bitlen] or 0) == 0) do bitlen = bitlen - 1 end -- move one leaf down the tree bitlen_counts[bitlen] = bitlen_counts[bitlen] - 1 -- move one overflow item as its brother bitlen_counts[bitlen + 1] = (bitlen_counts[bitlen + 1] or 0) + 2 bitlen_counts[max_bitlen] = bitlen_counts[max_bitlen] - 1 number_bitlen_overflow = number_bitlen_overflow - 2 until (number_bitlen_overflow <= 0) index = 1 for bitlen = max_bitlen, 1, -1 do local n = bitlen_counts[bitlen] or 0 while (n > 0) do local symbol = leafs[index][2] symbol_bitlens[symbol] = bitlen n = n - 1 index = index + 1 end end end symbol_codes = GetHuffmanCodeFromBitlen(bitlen_counts, symbol_bitlens, max_symbol, max_bitlen) return symbol_bitlens, symbol_codes, max_non_zero_bitlen_symbol end end local function RunLengthEncodeHuffmanBitlen(lcode_bitlens, max_non_zero_bitlen_lcode, dcode_bitlens, max_non_zero_bitlen_dcode) local rle_code_tblsize = 0 local rle_codes = {} local rle_code_counts = {} local rle_extra_bits_tblsize = 0 local rle_extra_bits = {} local prev = nil local count = 0 max_non_zero_bitlen_dcode = (max_non_zero_bitlen_dcode < 0) and 0 or max_non_zero_bitlen_dcode local max_code = max_non_zero_bitlen_lcode + max_non_zero_bitlen_dcode + 1 for code = 0, max_code + 1 do local len = (code <= max_non_zero_bitlen_lcode) and (lcode_bitlens[code] or 0) or ((code <= max_code) and (dcode_bitlens[code - max_non_zero_bitlen_lcode - 1] or 0) or nil) if len == prev then count = count + 1 if len ~= 0 and count == 6 then rle_code_tblsize = rle_code_tblsize + 1 rle_codes[rle_code_tblsize] = 16 rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1 rle_extra_bits[rle_extra_bits_tblsize] = 3 rle_code_counts[16] = (rle_code_counts[16] or 0) + 1 count = 0 elseif len == 0 and count == 138 then rle_code_tblsize = rle_code_tblsize + 1 rle_codes[rle_code_tblsize] = 18 rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1 rle_extra_bits[rle_extra_bits_tblsize] = 127 rle_code_counts[18] = (rle_code_counts[18] or 0) + 1 count = 0 end else if count == 1 then rle_code_tblsize = rle_code_tblsize + 1 rle_codes[rle_code_tblsize] = prev rle_code_counts[prev] = (rle_code_counts[prev] or 0) + 1 elseif count == 2 then rle_code_tblsize = rle_code_tblsize + 1 rle_codes[rle_code_tblsize] = prev rle_code_tblsize = rle_code_tblsize + 1 rle_codes[rle_code_tblsize] = prev rle_code_counts[prev] = (rle_code_counts[prev] or 0) + 2 elseif count >= 3 then rle_code_tblsize = rle_code_tblsize + 1 local rleCode = (prev ~= 0) and 16 or (count <= 10 and 17 or 18) rle_codes[rle_code_tblsize] = rleCode rle_code_counts[rleCode] = (rle_code_counts[rleCode] or 0) + 1 rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1 rle_extra_bits[rle_extra_bits_tblsize] = (count <= 10) and (count - 3) or (count - 11) end prev = len if len and len ~= 0 then rle_code_tblsize = rle_code_tblsize + 1 rle_codes[rle_code_tblsize] = len rle_code_counts[len] = (rle_code_counts[len] or 0) + 1 count = 0 else count = 1 end end end return rle_codes, rle_extra_bits, rle_code_counts end local function LoadStringToTable(str, t, start, stop, offset) local i = start - offset while i <= stop - 15 - offset do t[i], t[i + 1], t[i + 2], t[i + 3], t[i + 4], t[i + 5], t[i + 6], t[i + 7], t[i + 8], t[i + 9], t[i + 10], t[i + 11], t[i + 12], t[i + 13], t[i + 14], t[i + 15] = string.byte(str, i + offset, i + 15 + offset) i = i + 16 end while (i <= stop - offset) do t[i] = string.byte(str, i + offset, i + offset) i = i + 1 end return t end local function GetBlockLZ77Result(level, string_table, hash_tables, block_start, block_end, offset, dictionary) local config = _compression_level_configs[level] local config_use_lazy, config_good_prev_length, config_max_lazy_match, config_nice_length, config_max_hash_chain = config[1], config[2], config[3], config[4], config[5] local config_max_insert_length = (not config_use_lazy) and config_max_lazy_match or 2147483646 local config_good_hash_chain = (config_max_hash_chain - config_max_hash_chain % 4 / 4) local hash local dict_hash_tables local dict_string_table local dict_string_len = 0 if dictionary then dict_hash_tables = dictionary.hash_tables dict_string_table = dictionary.string_table dict_string_len = dictionary.strlen assert(block_start == 1) if block_end >= block_start and dict_string_len >= 2 then hash = dict_string_table[dict_string_len - 1] * 65536 + dict_string_table[dict_string_len] * 256 + string_table[1] local t = hash_tables[hash] if not t then t = {}; hash_tables[hash] = t end t[#t + 1] = -1 end if block_end >= block_start + 1 and dict_string_len >= 1 then hash = dict_string_table[dict_string_len] * 65536 + string_table[1] * 256 + string_table[2] local t = hash_tables[hash] if not t then t = {}; hash_tables[hash] = t end t[#t + 1] = 0 end end local dict_string_len_plus3 = dict_string_len + 3 hash = (string_table[block_start - offset] or 0) * 256 + (string_table[block_start + 1 - offset] or 0) local lcodes = {} local lcode_tblsize = 0 local lcodes_counts = {} local dcodes = {} local dcodes_tblsize = 0 local dcodes_counts = {} local lextra_bits = {} local lextra_bits_tblsize = 0 local dextra_bits = {} local dextra_bits_tblsize = 0 local match_available = false local prev_len local prev_dist local cur_len = 0 local cur_dist = 0 local index = block_start local index_end = block_end + (config_use_lazy and 1 or 0) while (index <= index_end) do local string_table_index = index - offset local offset_minus_three = offset - 3 prev_len = cur_len prev_dist = cur_dist cur_len = 0 hash = (hash * 256 + (string_table[string_table_index + 2] or 0)) % 16777216 local chain_index local cur_chain local hash_chain = hash_tables[hash] local chain_old_size if not hash_chain then chain_old_size = 0 hash_chain = {} hash_tables[hash] = hash_chain if dict_hash_tables then cur_chain = dict_hash_tables[hash] chain_index = cur_chain and #cur_chain or 0 else chain_index = 0 end else chain_old_size = #hash_chain cur_chain = hash_chain chain_index = chain_old_size end if index <= block_end then hash_chain[chain_old_size + 1] = index end if (chain_index > 0 and index + 2 <= block_end and (not config_use_lazy or prev_len < config_max_lazy_match)) then local depth = (config_use_lazy and prev_len >= config_good_prev_length) and config_good_hash_chain or config_max_hash_chain local max_len_minus_one = block_end - index max_len_minus_one = (max_len_minus_one >= 257) and 257 or max_len_minus_one max_len_minus_one = max_len_minus_one + string_table_index local string_table_index_plus_three = string_table_index + 3 while chain_index >= 1 and depth > 0 do local prev = cur_chain[chain_index] if index - prev > 32768 then break end if prev < index then local sj = string_table_index_plus_three if prev >= -257 then local pj = prev - offset_minus_three while (sj <= max_len_minus_one and string_table[pj] == string_table[sj]) do sj = sj + 1 pj = pj + 1 end else local pj = dict_string_len_plus3 + prev while (sj <= max_len_minus_one and dict_string_table[pj] == string_table[sj]) do sj = sj + 1 pj = pj + 1 end end local j = sj - string_table_index if j > cur_len then cur_len = j cur_dist = index - prev end if cur_len >= config_nice_length then break end end chain_index = chain_index - 1 depth = depth - 1 if chain_index == 0 and prev > 0 and dict_hash_tables then cur_chain = dict_hash_tables[hash] chain_index = cur_chain and #cur_chain or 0 end end end if not config_use_lazy then prev_len, prev_dist = cur_len, cur_dist end if ((not config_use_lazy or match_available) and (prev_len > 3 or (prev_len == 3 and prev_dist < 4096)) and cur_len <= prev_len) then local code = _length_to_deflate_code[prev_len] local length_extra_bits_bitlen = _length_to_deflate_extra_bitlen[prev_len] local dist_code, dist_extra_bits_bitlen, dist_extra_bits if prev_dist <= 256 then -- have cached code for small distance. dist_code = _dist256_to_deflate_code[prev_dist] dist_extra_bits = _dist256_to_deflate_extra_bits[prev_dist] dist_extra_bits_bitlen = _dist256_to_deflate_extra_bitlen[prev_dist] else dist_code = 16 dist_extra_bits_bitlen = 7 local a = 384 local b = 512 while true do if prev_dist <= a then dist_extra_bits = (prev_dist - (b / 2) - 1) % (b / 4) break elseif prev_dist <= b then dist_extra_bits = (prev_dist - (b / 2) - 1) % (b / 4) dist_code = dist_code + 1 break else dist_code = dist_code + 2 dist_extra_bits_bitlen = dist_extra_bits_bitlen + 1 a = a * 2 b = b * 2 end end end lcode_tblsize = lcode_tblsize + 1 lcodes[lcode_tblsize] = code lcodes_counts[code] = (lcodes_counts[code] or 0) + 1 dcodes_tblsize = dcodes_tblsize + 1 dcodes[dcodes_tblsize] = dist_code dcodes_counts[dist_code] = (dcodes_counts[dist_code] or 0) + 1 if length_extra_bits_bitlen > 0 then local lenExtraBits = _length_to_deflate_extra_bits[prev_len] lextra_bits_tblsize = lextra_bits_tblsize + 1 lextra_bits[lextra_bits_tblsize] = lenExtraBits end if dist_extra_bits_bitlen > 0 then dextra_bits_tblsize = dextra_bits_tblsize + 1 dextra_bits[dextra_bits_tblsize] = dist_extra_bits end for i = index + 1, index + prev_len - (config_use_lazy and 2 or 1) do hash = (hash * 256 + (string_table[i - offset + 2] or 0)) % 16777216 if prev_len <= config_max_insert_length then hash_chain = hash_tables[hash] if not hash_chain then hash_chain = {} hash_tables[hash] = hash_chain end hash_chain[#hash_chain + 1] = i end end index = index + prev_len - (config_use_lazy and 1 or 0) match_available = false elseif (not config_use_lazy) or match_available then local code = string_table[config_use_lazy and (string_table_index - 1) or string_table_index] lcode_tblsize = lcode_tblsize + 1 lcodes[lcode_tblsize] = code lcodes_counts[code] = (lcodes_counts[code] or 0) + 1 index = index + 1 else match_available = true index = index + 1 end end lcode_tblsize = lcode_tblsize + 1 lcodes[lcode_tblsize] = 256 lcodes_counts[256] = (lcodes_counts[256] or 0) + 1 return lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits, dcodes_counts end local function GetBlockDynamicHuffmanHeader(lcodes_counts, dcodes_counts) local lcodes_huffman_bitlens, lcodes_huffman_codes, max_non_zero_bitlen_lcode = GetHuffmanBitlenAndCode(lcodes_counts, 15, 285) local dcodes_huffman_bitlens, dcodes_huffman_codes, max_non_zero_bitlen_dcode = GetHuffmanBitlenAndCode(dcodes_counts, 15, 29) local rle_deflate_codes, rle_extra_bits, rle_codes_counts = RunLengthEncodeHuffmanBitlen(lcodes_huffman_bitlens, max_non_zero_bitlen_lcode, dcodes_huffman_bitlens, max_non_zero_bitlen_dcode) local rle_codes_huffman_bitlens, rle_codes_huffman_codes = GetHuffmanBitlenAndCode(rle_codes_counts, 7, 18) local HCLEN = 0 for i = 1, 19 do local symbol = _rle_codes_huffman_bitlen_order[i] local length = rle_codes_huffman_bitlens[symbol] or 0 if length ~= 0 then HCLEN = i end end HCLEN = HCLEN - 4 local HLIT = max_non_zero_bitlen_lcode + 1 - 257 local HDIST = max_non_zero_bitlen_dcode + 1 - 1 if HDIST < 0 then HDIST = 0 end return HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens, rle_codes_huffman_codes, rle_deflate_codes, rle_extra_bits, lcodes_huffman_bitlens, lcodes_huffman_codes, dcodes_huffman_bitlens, dcodes_huffman_codes end local function GetDynamicHuffmanBlockSize(lcodes, dcodes, HCLEN, rle_codes_huffman_bitlens, rle_deflate_codes, lcodes_huffman_bitlens, dcodes_huffman_bitlens) local block_bitlen = 17 -- 1+2+5+5+4 block_bitlen = block_bitlen + (HCLEN + 4) * 3 for i = 1, #rle_deflate_codes do local code = rle_deflate_codes[i] block_bitlen = block_bitlen + rle_codes_huffman_bitlens[code] if code >= 16 then block_bitlen = block_bitlen + ((code == 16) and 2 or (code == 17 and 3 or 7)) end end local length_code_count = 0 for i = 1, #lcodes do local code = lcodes[i] local huffman_bitlen = lcodes_huffman_bitlens[code] block_bitlen = block_bitlen + huffman_bitlen if code > 256 then -- Length code length_code_count = length_code_count + 1 if code > 264 and code < 285 then -- Length code with extra bits local extra_bits_bitlen = _literal_deflate_code_to_extra_bitlen[code - 256] block_bitlen = block_bitlen + extra_bits_bitlen end local dist_code = dcodes[length_code_count] local dist_huffman_bitlen = dcodes_huffman_bitlens[dist_code] block_bitlen = block_bitlen + dist_huffman_bitlen if dist_code > 3 then -- dist code with extra bits local dist_extra_bits_bitlen = (dist_code - dist_code % 2) / 2 - 1 block_bitlen = block_bitlen + dist_extra_bits_bitlen end end end return block_bitlen end local function CompressDynamicHuffmanBlock(WriteBits, is_last_block, lcodes, lextra_bits, dcodes, dextra_bits, HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens, rle_codes_huffman_codes, rle_deflate_codes, rle_extra_bits, lcodes_huffman_bitlens, lcodes_huffman_codes, dcodes_huffman_bitlens, dcodes_huffman_codes) WriteBits(is_last_block and 1 or 0, 1) -- Last block identifier WriteBits(2, 2) -- Dynamic Huffman block identifier WriteBits(HLIT, 5) WriteBits(HDIST, 5) WriteBits(HCLEN, 4) for i = 1, HCLEN + 4 do local symbol = _rle_codes_huffman_bitlen_order[i] local length = rle_codes_huffman_bitlens[symbol] or 0 WriteBits(length, 3) end local rleExtraBitsIndex = 1 for i = 1, #rle_deflate_codes do local code = rle_deflate_codes[i] WriteBits(rle_codes_huffman_codes[code], rle_codes_huffman_bitlens[code]) if code >= 16 then local extraBits = rle_extra_bits[rleExtraBitsIndex] WriteBits(extraBits, (code == 16) and 2 or (code == 17 and 3 or 7)) rleExtraBitsIndex = rleExtraBitsIndex + 1 end end local length_code_count = 0 local length_code_with_extra_count = 0 local dist_code_with_extra_count = 0 for i = 1, #lcodes do local deflate_codee = lcodes[i] local huffman_code = lcodes_huffman_codes[deflate_codee] local huffman_bitlen = lcodes_huffman_bitlens[deflate_codee] WriteBits(huffman_code, huffman_bitlen) if deflate_codee > 256 then -- Length code length_code_count = length_code_count + 1 if deflate_codee > 264 and deflate_codee < 285 then length_code_with_extra_count = length_code_with_extra_count + 1 local extra_bits = lextra_bits[length_code_with_extra_count] local extra_bits_bitlen = _literal_deflate_code_to_extra_bitlen[deflate_codee - 256] WriteBits(extra_bits, extra_bits_bitlen) end local dist_deflate_code = dcodes[length_code_count] local dist_huffman_code = dcodes_huffman_codes[dist_deflate_code] local dist_huffman_bitlen = dcodes_huffman_bitlens[dist_deflate_code] WriteBits(dist_huffman_code, dist_huffman_bitlen) if dist_deflate_code > 3 then -- dist code with extra bits dist_code_with_extra_count = dist_code_with_extra_count + 1 local dist_extra_bits = dextra_bits[dist_code_with_extra_count] local dist_extra_bits_bitlen = (dist_deflate_code - dist_deflate_code % 2) / 2 - 1 WriteBits(dist_extra_bits, dist_extra_bits_bitlen) end end end end local function GetFixedHuffmanBlockSize(lcodes, dcodes) local block_bitlen = 3 local length_code_count = 0 for i = 1, #lcodes do local code = lcodes[i] local huffman_bitlen = _fix_block_literal_huffman_bitlen[code] block_bitlen = block_bitlen + huffman_bitlen if code > 256 then -- Length code length_code_count = length_code_count + 1 if code > 264 and code < 285 then -- Length code with extra bits local extra_bits_bitlen = _literal_deflate_code_to_extra_bitlen[code - 256] block_bitlen = block_bitlen + extra_bits_bitlen end local dist_code = dcodes[length_code_count] block_bitlen = block_bitlen + 5 if dist_code > 3 then -- dist code with extra bits local dist_extra_bits_bitlen = (dist_code - dist_code % 2) / 2 - 1 block_bitlen = block_bitlen + dist_extra_bits_bitlen end end end return block_bitlen end local function CompressFixedHuffmanBlock(WriteBits, is_last_block, lcodes, lextra_bits, dcodes, dextra_bits) WriteBits(is_last_block and 1 or 0, 1) -- Last block identifier WriteBits(1, 2) -- Fixed Huffman block identifier local length_code_count = 0 local length_code_with_extra_count = 0 local dist_code_with_extra_count = 0 for i = 1, #lcodes do local deflate_code = lcodes[i] local huffman_code = _fix_block_literal_huffman_code[deflate_code] local huffman_bitlen = _fix_block_literal_huffman_bitlen[deflate_code] WriteBits(huffman_code, huffman_bitlen) if deflate_code > 256 then -- Length code length_code_count = length_code_count + 1 if deflate_code > 264 and deflate_code < 285 then length_code_with_extra_count = length_code_with_extra_count + 1 local extra_bits = lextra_bits[length_code_with_extra_count] local extra_bits_bitlen = _literal_deflate_code_to_extra_bitlen[deflate_code - 256] WriteBits(extra_bits, extra_bits_bitlen) end local dist_code = dcodes[length_code_count] local dist_huffman_code = _fix_block_dist_huffman_code[dist_code] WriteBits(dist_huffman_code, 5) if dist_code > 3 then -- dist code with extra bits dist_code_with_extra_count = dist_code_with_extra_count + 1 local dist_extra_bits = dextra_bits[dist_code_with_extra_count] local dist_extra_bits_bitlen = (dist_code - dist_code % 2) / 2 - 1 WriteBits(dist_extra_bits, dist_extra_bits_bitlen) end end end end local function GetStoreBlockSize(block_start, block_end, total_bitlen) assert(block_end - block_start + 1 <= 65535) local block_bitlen = 3 total_bitlen = total_bitlen + 3 local padding_bitlen = (8 - total_bitlen % 8) % 8 block_bitlen = block_bitlen + padding_bitlen block_bitlen = block_bitlen + 32 block_bitlen = block_bitlen + (block_end - block_start + 1) * 8 return block_bitlen end local function CompressStoreBlock(WriteBits, WriteString, is_last_block, str, block_start, block_end, total_bitlen) assert(block_end - block_start + 1 <= 65535) WriteBits(is_last_block and 1 or 0, 1) -- Last block identifer. WriteBits(0, 2) -- Store block identifier. total_bitlen = total_bitlen + 3 local padding_bitlen = (8 - total_bitlen % 8) % 8 if padding_bitlen > 0 then WriteBits(_pow2[padding_bitlen] - 1, padding_bitlen) end local size = block_end - block_start + 1 WriteBits(size, 16) local comp = (255 - size % 256) + (255 - (size - size % 256) / 256) * 256 WriteBits(comp, 16) WriteString(str:sub(block_start, block_end)) end local function Deflate(configs, WriteBits, WriteString, FlushWriter, str, dictionary) local string_table = {} local hash_tables = {} local is_last_block = nil local block_start local block_end local bitlen_written local total_bitlen = FlushWriter(_FLUSH_MODE_NO_FLUSH) local strlen = #str local offset local level local strategy if configs then if configs.level then level = configs.level end if configs.strategy then strategy = configs.strategy end end if not level then if strlen < 2048 then level = 7 elseif strlen > 65536 then level = 3 else level = 5 end end while not is_last_block do if not block_start then block_start = 1 block_end = 64 * 1024 - 1 offset = 0 else block_start = block_end + 1 block_end = block_end + 32 * 1024 offset = block_start - 32 * 1024 - 1 end if block_end >= strlen then block_end = strlen is_last_block = true else is_last_block = false end local lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits, dcodes_counts local HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens, rle_codes_huffman_codes, rle_deflate_codes, rle_extra_bits, lcodes_huffman_bitlens, lcodes_huffman_codes, dcodes_huffman_bitlens, dcodes_huffman_codes local dynamic_block_bitlen local fixed_block_bitlen local store_block_bitlen if level ~= 0 then LoadStringToTable(str, string_table, block_start, block_end + 3, offset) if block_start == 1 and dictionary then local dict_string_table = dictionary.string_table local dict_strlen = dictionary.strlen for i = 0, (-dict_strlen + 1) < -257 and -257 or (-dict_strlen + 1), -1 do string_table[i] = dict_string_table[dict_strlen + i] end end if strategy == "huffman_only" then lcodes = {} LoadStringToTable(str, lcodes, block_start, block_end, block_start - 1) lextra_bits = {} lcodes_counts = {} lcodes[block_end - block_start + 2] = 256 -- end of block for i = 1, block_end - block_start + 2 do local code = lcodes[i] lcodes_counts[code] = (lcodes_counts[code] or 0) + 1 end dcodes = {} dextra_bits = {} dcodes_counts = {} else lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits, dcodes_counts = GetBlockLZ77Result(level, string_table, hash_tables, block_start, block_end, offset, dictionary) end -- LuaFormatter off HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens, rle_codes_huffman_codes, rle_deflate_codes, rle_extra_bits, lcodes_huffman_bitlens, lcodes_huffman_codes, dcodes_huffman_bitlens, dcodes_huffman_codes = -- LuaFormatter on GetBlockDynamicHuffmanHeader(lcodes_counts, dcodes_counts) dynamic_block_bitlen = GetDynamicHuffmanBlockSize(lcodes, dcodes, HCLEN, rle_codes_huffman_bitlens, rle_deflate_codes, lcodes_huffman_bitlens, dcodes_huffman_bitlens) fixed_block_bitlen = GetFixedHuffmanBlockSize(lcodes, dcodes) end store_block_bitlen = GetStoreBlockSize(block_start, block_end, total_bitlen) local min_bitlen = store_block_bitlen min_bitlen = (fixed_block_bitlen and fixed_block_bitlen < min_bitlen) and fixed_block_bitlen or min_bitlen min_bitlen = (dynamic_block_bitlen and dynamic_block_bitlen < min_bitlen) and dynamic_block_bitlen or min_bitlen if level == 0 or (strategy ~= "fixed" and strategy ~= "dynamic" and store_block_bitlen == min_bitlen) then CompressStoreBlock(WriteBits, WriteString, is_last_block, str, block_start, block_end, total_bitlen) total_bitlen = total_bitlen + store_block_bitlen elseif strategy ~= "dynamic" and (strategy == "fixed" or fixed_block_bitlen == min_bitlen) then CompressFixedHuffmanBlock(WriteBits, is_last_block, lcodes, lextra_bits, dcodes, dextra_bits) total_bitlen = total_bitlen + fixed_block_bitlen elseif strategy == "dynamic" or dynamic_block_bitlen == min_bitlen then CompressDynamicHuffmanBlock(WriteBits, is_last_block, lcodes, lextra_bits, dcodes, dextra_bits, HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens, rle_codes_huffman_codes, rle_deflate_codes, rle_extra_bits, lcodes_huffman_bitlens, lcodes_huffman_codes, dcodes_huffman_bitlens, dcodes_huffman_codes) total_bitlen = total_bitlen + dynamic_block_bitlen end if is_last_block then bitlen_written = FlushWriter(_FLUSH_MODE_NO_FLUSH) else bitlen_written = FlushWriter(_FLUSH_MODE_MEMORY_CLEANUP) end assert(bitlen_written == total_bitlen) if not is_last_block then local j if dictionary and block_start == 1 then j = 0 while (string_table[j]) do string_table[j] = nil j = j - 1 end end dictionary = nil j = 1 for i = block_end - 32767, block_end do string_table[j] = string_table[i - offset] j = j + 1 end for k, t in pairs(hash_tables) do local tSize = #t if tSize > 0 and block_end + 1 - t[1] > 32768 then if tSize == 1 then hash_tables[k] = nil else local new = {} local newSize = 0 for i = 2, tSize do j = t[i] if block_end + 1 - j <= 32768 then newSize = newSize + 1 new[newSize] = j end end hash_tables[k] = new end end end end end end local function CompressDeflateInternal(str, dictionary, configs) local WriteBits, WriteString, FlushWriter = CreateWriter() Deflate(configs, WriteBits, WriteString, FlushWriter, str, dictionary) local total_bitlen, result = FlushWriter(_FLUSH_MODE_OUTPUT) local padding_bitlen = (8 - total_bitlen % 8) % 8 return result, padding_bitlen end local function CompressZlibInternal(str, dictionary, configs) local WriteBits, WriteString, FlushWriter = CreateWriter() local CM = 8 -- Compression method local CINFO = 7 -- Window Size = 32K local CMF = CINFO * 16 + CM WriteBits(CMF, 8) local FDIST = dictionary and 1 or 0 local FLEVEL = 2 -- Default compression local FLG = FLEVEL * 64 + FDIST * 32 local FCHECK = (31 - (CMF * 256 + FLG) % 31) FLG = FLG + FCHECK WriteBits(FLG, 8) if FDIST == 1 then local adler32 = dictionary.adler32 local byte0 = adler32 % 256 adler32 = (adler32 - byte0) / 256 local byte1 = adler32 % 256 adler32 = (adler32 - byte1) / 256 local byte2 = adler32 % 256 adler32 = (adler32 - byte2) / 256 local byte3 = adler32 % 256 WriteBits(byte3, 8) WriteBits(byte2, 8) WriteBits(byte1, 8) WriteBits(byte0, 8) end Deflate(configs, WriteBits, WriteString, FlushWriter, str, dictionary) FlushWriter(_FLUSH_MODE_BYTE_BOUNDARY) local adler32 = LibDeflate:Adler32(str) local byte3 = adler32 % 256 adler32 = (adler32 - byte3) / 256 local byte2 = adler32 % 256 adler32 = (adler32 - byte2) / 256 local byte1 = adler32 % 256 adler32 = (adler32 - byte1) / 256 local byte0 = adler32 % 256 WriteBits(byte0, 8) WriteBits(byte1, 8) WriteBits(byte2, 8) WriteBits(byte3, 8) local total_bitlen, result = FlushWriter(_FLUSH_MODE_OUTPUT) local padding_bitlen = (8 - total_bitlen % 8) % 8 return result, padding_bitlen end function LibDeflate:CompressDeflate(str, configs) local arg_valid, arg_err = IsValidArguments(str, false, nil, true, configs) if not arg_valid then error(("Usage: LibDeflate:CompressDeflate(str, configs): " .. arg_err), 2) end return CompressDeflateInternal(str, nil, configs) end function LibDeflate:CompressDeflateWithDict(str, dictionary, configs) local arg_valid, arg_err = IsValidArguments(str, true, dictionary, true, configs) if not arg_valid then error(("Usage: LibDeflate:CompressDeflateWithDict" .. "(str, dictionary, configs): " .. arg_err), 2) end return CompressDeflateInternal(str, dictionary, configs) end function LibDeflate:CompressZlib(str, configs) local arg_valid, arg_err = IsValidArguments(str, false, nil, true, configs) if not arg_valid then error(("Usage: LibDeflate:CompressZlib(str, configs): " .. arg_err), 2) end return CompressZlibInternal(str, nil, configs) end function LibDeflate:CompressZlibWithDict(str, dictionary, configs) local arg_valid, arg_err = IsValidArguments(str, true, dictionary, true, configs) if not arg_valid then error(("Usage: LibDeflate:CompressZlibWithDict" .. "(str, dictionary, configs): " .. arg_err), 2) end return CompressZlibInternal(str, dictionary, configs) end --[[ -------------------------------------------------------------------------- Decompress code --]] -------------------------------------------------------------------------- local function CreateReader(input_string) local input = input_string local input_strlen = #input_string local input_next_byte_pos = 1 local cache_bitlen = 0 local cache = 0 local function ReadBits(bitlen) local rshift_mask = _pow2[bitlen] local code if bitlen <= cache_bitlen then code = cache % rshift_mask cache = (cache - code) / rshift_mask cache_bitlen = cache_bitlen - bitlen else -- Whether input has been exhausted is not checked. local lshift_mask = _pow2[cache_bitlen] local byte1, byte2, byte3, byte4 = string.byte(input, input_next_byte_pos, input_next_byte_pos + 3) -- This requires lua number to be at least double () cache = cache + ((byte1 or 0) + (byte2 or 0) * 256 + (byte3 or 0) * 65536 + (byte4 or 0) * 16777216) * lshift_mask input_next_byte_pos = input_next_byte_pos + 4 cache_bitlen = cache_bitlen + 32 - bitlen code = cache % rshift_mask cache = (cache - code) / rshift_mask end return code end local function ReadBytes(bytelen, buffer, buffer_size) assert(cache_bitlen % 8 == 0) local byte_from_cache = (cache_bitlen / 8 < bytelen) and (cache_bitlen / 8) or bytelen for _ = 1, byte_from_cache do local byte = cache % 256 buffer_size = buffer_size + 1 buffer[buffer_size] = string.char(byte) cache = (cache - byte) / 256 end cache_bitlen = cache_bitlen - byte_from_cache * 8 bytelen = bytelen - byte_from_cache if (input_strlen - input_next_byte_pos - bytelen + 1) * 8 + cache_bitlen < 0 then return -1 -- out of input end for i = input_next_byte_pos, input_next_byte_pos + bytelen - 1 do buffer_size = buffer_size + 1 buffer[buffer_size] = string.sub(input, i, i) end input_next_byte_pos = input_next_byte_pos + bytelen return buffer_size end local function Decode(huffman_bitlen_counts, huffman_symbols, min_bitlen) local code = 0 local first = 0 local index = 0 local count if min_bitlen > 0 then if cache_bitlen < 15 and input then local lshift_mask = _pow2[cache_bitlen] local byte1, byte2, byte3, byte4 = string.byte(input, input_next_byte_pos, input_next_byte_pos + 3) -- This requires lua number to be at least double () cache = cache + ((byte1 or 0) + (byte2 or 0) * 256 + (byte3 or 0) * 65536 + (byte4 or 0) * 16777216) * lshift_mask input_next_byte_pos = input_next_byte_pos + 4 cache_bitlen = cache_bitlen + 32 end local rshift_mask = _pow2[min_bitlen] cache_bitlen = cache_bitlen - min_bitlen code = cache % rshift_mask cache = (cache - code) / rshift_mask -- Reverse the bits code = _reverse_bits_tbl[min_bitlen][code] count = huffman_bitlen_counts[min_bitlen] if code < count then return huffman_symbols[code] end index = count first = count * 2 code = code * 2 end for bitlen = min_bitlen + 1, 15 do local bit bit = cache % 2 cache = (cache - bit) / 2 cache_bitlen = cache_bitlen - 1 code = (bit == 1) and (code + 1 - code % 2) or code count = huffman_bitlen_counts[bitlen] or 0 local diff = code - first if diff < count then return huffman_symbols[index + diff] end index = index + count first = first + count first = first * 2 code = code * 2 end -- invalid literal/length or distance code -- in fixed or dynamic block (run out of code) return -10 end local function ReaderBitlenLeft() return (input_strlen - input_next_byte_pos + 1) * 8 + cache_bitlen end local function SkipToByteBoundary() local skipped_bitlen = cache_bitlen % 8 local rshift_mask = _pow2[skipped_bitlen] cache_bitlen = cache_bitlen - skipped_bitlen cache = (cache - cache % rshift_mask) / rshift_mask end return ReadBits, ReadBytes, Decode, ReaderBitlenLeft, SkipToByteBoundary end local function CreateDecompressState(str, dictionary) local ReadBits, ReadBytes, Decode, ReaderBitlenLeft, SkipToByteBoundary = CreateReader(str) local state = { ReadBits = ReadBits, ReadBytes = ReadBytes, Decode = Decode, ReaderBitlenLeft = ReaderBitlenLeft, SkipToByteBoundary = SkipToByteBoundary, buffer_size = 0, buffer = {}, result_buffer = {}, dictionary = dictionary } return state end local function GetHuffmanForDecode(huffman_bitlens, max_symbol, max_bitlen) local huffman_bitlen_counts = {} local min_bitlen = max_bitlen for symbol = 0, max_symbol do local bitlen = huffman_bitlens[symbol] or 0 min_bitlen = (bitlen > 0 and bitlen < min_bitlen) and bitlen or min_bitlen huffman_bitlen_counts[bitlen] = (huffman_bitlen_counts[bitlen] or 0) + 1 end if huffman_bitlen_counts[0] == max_symbol + 1 then -- No Codes return 0, huffman_bitlen_counts, {}, 0 -- Complete, but decode will fail end local left = 1 for len = 1, max_bitlen do left = left * 2 left = left - (huffman_bitlen_counts[len] or 0) if left < 0 then return left -- Over-subscribed, return negative end end local offsets = {} offsets[1] = 0 for len = 1, max_bitlen - 1 do offsets[len + 1] = offsets[len] + (huffman_bitlen_counts[len] or 0) end local huffman_symbols = {} for symbol = 0, max_symbol do local bitlen = huffman_bitlens[symbol] or 0 if bitlen ~= 0 then local offset = offsets[bitlen] huffman_symbols[offset] = symbol offsets[bitlen] = offsets[bitlen] + 1 end end return left, huffman_bitlen_counts, huffman_symbols, min_bitlen end local function DecodeUntilEndOfBlock(state, lcodes_huffman_bitlens, lcodes_huffman_symbols, lcodes_huffman_min_bitlen, dcodes_huffman_bitlens, dcodes_huffman_symbols, dcodes_huffman_min_bitlen) local buffer, buffer_size, ReadBits, Decode, ReaderBitlenLeft, result_buffer = state.buffer, state.buffer_size, state.ReadBits, state.Decode, state.ReaderBitlenLeft, state.result_buffer local dictionary = state.dictionary local dict_string_table local dict_strlen local buffer_end = 1 if dictionary and not buffer[0] then dict_string_table = dictionary.string_table dict_strlen = dictionary.strlen buffer_end = -dict_strlen + 1 for i = 0, (-dict_strlen + 1) < -257 and -257 or (-dict_strlen + 1), -1 do buffer[i] = _byte_to_char[dict_string_table[dict_strlen + i]] end end repeat local symbol = Decode(lcodes_huffman_bitlens, lcodes_huffman_symbols, lcodes_huffman_min_bitlen) if symbol < 0 or symbol > 285 then return -10 elseif symbol < 256 then -- Literal buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_char[symbol] elseif symbol > 256 then -- Length code symbol = symbol - 256 local bitlen = _literal_deflate_code_to_base_len[symbol] bitlen = (symbol >= 8) and (bitlen + ReadBits(_literal_deflate_code_to_extra_bitlen[symbol])) or bitlen symbol = Decode(dcodes_huffman_bitlens, dcodes_huffman_symbols, dcodes_huffman_min_bitlen) if symbol < 0 or symbol > 29 then return -10 end local dist = _dist_deflate_code_to_base_dist[symbol] dist = (dist > 4) and (dist + ReadBits(_dist_deflate_code_to_extra_bitlen[symbol])) or dist local char_buffer_index = buffer_size - dist + 1 if char_buffer_index < buffer_end then return -11 end if char_buffer_index >= -257 then for _ = 1, bitlen do buffer_size = buffer_size + 1 buffer[buffer_size] = buffer[char_buffer_index] char_buffer_index = char_buffer_index + 1 end else char_buffer_index = dict_strlen + char_buffer_index for _ = 1, bitlen do buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_char[dict_string_table[char_buffer_index]] char_buffer_index = char_buffer_index + 1 end end end if ReaderBitlenLeft() < 0 then return 2 -- available inflate data did not terminate end if buffer_size >= 65536 then result_buffer[#result_buffer + 1] = table.concat(buffer, "", 1, 32768) for i = 32769, buffer_size do buffer[i - 32768] = buffer[i] end buffer_size = buffer_size - 32768 buffer[buffer_size + 1] = nil end until symbol == 256 state.buffer_size = buffer_size return 0 end local function DecompressStoreBlock(state) local buffer, buffer_size, ReadBits, ReadBytes, ReaderBitlenLeft, SkipToByteBoundary, result_buffer = state.buffer, state.buffer_size, state.ReadBits, state.ReadBytes, state.ReaderBitlenLeft, state.SkipToByteBoundary, state.result_buffer SkipToByteBoundary() local bytelen = ReadBits(16) if ReaderBitlenLeft() < 0 then return 2 -- available inflate data did not terminate end local bytelenComp = ReadBits(16) if ReaderBitlenLeft() < 0 then return 2 -- available inflate data did not terminate end if bytelen % 256 + bytelenComp % 256 ~= 255 then return -2 -- Not one's complement end if (bytelen - bytelen % 256) / 256 + (bytelenComp - bytelenComp % 256) / 256 ~= 255 then return -2 -- Not one's complement end -- Note that ReadBytes will skip to the next byte boundary first. buffer_size = ReadBytes(bytelen, buffer, buffer_size) if buffer_size < 0 then return 2 -- available inflate data did not terminate end -- memory clean up when there are enough bytes in the buffer. if buffer_size >= 65536 then result_buffer[#result_buffer + 1] = table.concat(buffer, "", 1, 32768) for i = 32769, buffer_size do buffer[i - 32768] = buffer[i] end buffer_size = buffer_size - 32768 buffer[buffer_size + 1] = nil end state.buffer_size = buffer_size return 0 end local function DecompressFixBlock(state) return DecodeUntilEndOfBlock(state, _fix_block_literal_huffman_bitlen_count, _fix_block_literal_huffman_to_deflate_code, 7, _fix_block_dist_huffman_bitlen_count, _fix_block_dist_huffman_to_deflate_code, 5) end local function DecompressDynamicBlock(state) local ReadBits, Decode = state.ReadBits, state.Decode local nlen = ReadBits(5) + 257 local ndist = ReadBits(5) + 1 local ncode = ReadBits(4) + 4 if nlen > 286 or ndist > 30 then -- dynamic block code description: too many length or distance codes return -3 end local rle_codes_huffman_bitlens = {} for i = 1, ncode do rle_codes_huffman_bitlens[_rle_codes_huffman_bitlen_order[i]] = ReadBits(3) end local rle_codes_err, rle_codes_huffman_bitlen_counts, rle_codes_huffman_symbols, rle_codes_huffman_min_bitlen = GetHuffmanForDecode(rle_codes_huffman_bitlens, 18, 7) if rle_codes_err ~= 0 then -- Require complete code set here -- dynamic block code description: code lengths codes incomplete return -4 end local lcodes_huffman_bitlens = {} local dcodes_huffman_bitlens = {} -- Read length/literal and distance code length tables local index = 0 while index < nlen + ndist do local symbo%l -- Decoded value local bitlen -- Last length to repeat symbol = Decode(rle_codes_huffman_bitlen_counts, rle_codes_huffman_symbols, rle_codes_huffman_min_bitlen) if symbol < 0 then return symbol -- Invalid symbol elseif symbol < 16 then if index < nlen then lcodes_huffman_bitlens[index] = symbol else dcodes_huffman_bitlens[index - nlen] = symbol end index = index + 1 else bitlen = 0 if symbol == 16 then if index == 0 then -- dynamic block code description: repeat lengths -- with no first length return -5 end if index - 1 < nlen then bitlen = lcodes_huffman_bitlens[index - 1] else bitlen = dcodes_huffman_bitlens[index - nlen - 1] end symbol = 3 + ReadBits(2) elseif symbol == 17 then -- Repeat zero 3..10 times symbol = 3 + ReadBits(3) else -- == 18, repeat zero 11.138 times symbol = 11 + ReadBits(7) end if index + symbol > nlen + ndist then -- dynamic block code description: -- repeat more than specified lengths return -6 end while symbol > 0 do -- Repeat last or zero symbol times symbol = symbol - 1 if index < nlen then lcodes_huffman_bitlens[index] = bitlen else dcodes_huffman_bitlens[index - nlen] = bitlen end index = index + 1 end end end if (lcodes_huffman_bitlens[256] or 0) == 0 then return -9 end local lcodes_err, lcodes_huffman_bitlen_counts, lcodes_huffman_symbols, lcodes_huffman_min_bitlen = GetHuffmanForDecode(lcodes_huffman_bitlens, nlen - 1, 15) if (lcodes_err ~= 0 and (lcodes_err < 0 or nlen ~= (lcodes_huffman_bitlen_counts[0] or 0) + (lcodes_huffman_bitlen_counts[1] or 0))) then return -7 end local dcodes_err, dcodes_huffman_bitlen_counts, dcodes_huffman_symbols, dcodes_huffman_min_bitlen = GetHuffmanForDecode(dcodes_huffman_bitlens, ndist - 1, 15) if (dcodes_err ~= 0 and (dcodes_err < 0 or ndist ~= (dcodes_huffman_bitlen_counts[0] or 0) + (dcodes_huffman_bitlen_counts[1] or 0))) then return -8 end return DecodeUntilEndOfBlock(state, lcodes_huffman_bitlen_counts, lcodes_huffman_symbols, lcodes_huffman_min_bitlen, dcodes_huffman_bitlen_counts, dcodes_huffman_symbols, dcodes_huffman_min_bitlen) end local function Inflate(state) local ReadBits = state.ReadBits local is_last_block while not is_last_block do is_last_block = (ReadBits(1) == 1) local block_type = ReadBits(2) local status if block_type == 0 then status = DecompressStoreBlock(state) elseif block_type == 1 then status = DecompressFixBlock(state) elseif block_type == 2 then status = DecompressDynamicBlock(state) else return nil, -1 -- invalid block type (type == 3) end if status ~= 0 then return nil, status end end state.result_buffer[#state.result_buffer + 1] = table.concat(state.buffer, "", 1, state.buffer_size) local result = table.concat(state.result_buffer) return result end local function DecompressDeflateInternal(str, dictionary) local state = CreateDecompressState(str, dictionary) local result, status = Inflate(state) if not result then return nil, status end local bitlen_left = state.ReaderBitlenLeft() local bytelen_left = (bitlen_left - bitlen_left % 8) / 8 return result, bytelen_left end local function DecompressZlibInternal(str, dictionary) local state = CreateDecompressState(str, dictionary) local ReadBits = state.ReadBits local CMF = ReadBits(8) if state.ReaderBitlenLeft() < 0 then return nil, 2 -- available inflate data did not terminate end local CM = CMF % 16 local CINFO = (CMF - CM) / 16 if CM ~= 8 then return nil, -12 -- invalid compression method end if CINFO > 7 then return nil, -13 -- invalid window size end local FLG = ReadBits(8) if state.ReaderBitlenLeft() < 0 then return nil, 2 -- available inflate data did not terminate end if (CMF * 256 + FLG) % 31 ~= 0 then return nil, -14 -- invalid header checksum end local FDIST = ((FLG - FLG % 32) / 32 % 2) local FLEVEL = ((FLG - FLG % 64) / 64 % 4) -- luacheck: ignore FLEVEL if FDIST == 1 then if not dictionary then return nil, -16 -- need dictonary, but dictionary is not provided. end local byte3 = ReadBits(8) local byte2 = ReadBits(8) local byte1 = ReadBits(8) local byte0 = ReadBits(8) local actual_adler32 = byte3 * 16777216 + byte2 * 65536 + byte1 * 256 + byte0 if state.ReaderBitlenLeft() < 0 then return nil, 2 -- available inflate data did not terminate end if not IsEqualAdler32(actual_adler32, dictionary.adler32) then return nil, -17 -- dictionary adler32 does not match end end local result, status = Inflate(state) if not result then return nil, status end state.SkipToByteBoundary() local adler_byte0 = ReadBits(8) local adler_byte1 = ReadBits(8) local adler_byte2 = ReadBits(8) local adler_byte3 = ReadBits(8) if state.ReaderBitlenLeft() < 0 then return nil, 2 -- available inflate data did not terminate end local adler32_expected = adler_byte0 * 16777216 + adler_byte1 * 65536 + adler_byte2 * 256 + adler_byte3 local adler32_actual = LibDeflate:Adler32(result) if not IsEqualAdler32(adler32_expected, adler32_actual) then return nil, -15 -- Adler32 checksum does not match end local bitlen_left = state.ReaderBitlenLeft() local bytelen_left = (bitlen_left - bitlen_left % 8) / 8 return result, bytelen_left end function LibDeflate:DecompressDeflate(str) local arg_valid, arg_err = IsValidArguments(str) if not arg_valid then error(("Usage: LibDeflate:DecompressDeflate(str): " .. arg_err), 2) end return DecompressDeflateInternal(str) end function LibDeflate:DecompressDeflateWithDict(str, dictionary) local arg_valid, arg_err = IsValidArguments(str, true, dictionary) if not arg_valid then error(("Usage: LibDeflate:DecompressDeflateWithDict(str, dictionary): " .. arg_err), 2) end return DecompressDeflateInternal(str, dictionary) end function LibDeflate:DecompressZlib(str) local arg_valid, arg_err = IsValidArguments(str) if not arg_valid then error(("Usage: LibDeflate:DecompressZlib(str): " .. arg_err), 2) end return DecompressZlibInternal(str) end function LibDeflate:DecompressZlibWithDict(str, dictionary) local arg_valid, arg_err = IsValidArguments(str, true, dictionary) if not arg_valid then error(("Usage: LibDeflate:DecompressZlibWithDict(str, dictionary): " .. arg_err), 2) end return DecompressZlibInternal(str, dictionary) end do _fix_block_literal_huffman_bitlen = {} for sym = 0, 143 do _fix_block_literal_huffman_bitlen[sym] = 8 end for sym = 144, 255 do _fix_block_literal_huffman_bitlen[sym] = 9 end for sym = 256, 279 do _fix_block_literal_huffman_bitlen[sym] = 7 end for sym = 280, 287 do _fix_block_literal_huffman_bitlen[sym] = 8 end _fix_block_dist_huffman_bitlen = {} for dist = 0, 31 do _fix_block_dist_huffman_bitlen[dist] = 5 end local status status, _fix_block_literal_huffman_bitlen_count, _fix_block_literal_huffman_to_deflate_code = GetHuffmanForDecode(_fix_block_literal_huffman_bitlen, 287, 9) assert(status == 0) status, _fix_block_dist_huffman_bitlen_count, _fix_block_dist_huffman_to_deflate_code = GetHuffmanForDecode(_fix_block_dist_huffman_bitlen, 31, 5) assert(status == 0) _fix_block_literal_huffman_code = GetHuffmanCodeFromBitlen( _fix_block_literal_huffman_bitlen_count, _fix_block_literal_huffman_bitlen, 287, 9) _fix_block_dist_huffman_code = GetHuffmanCodeFromBitlen( _fix_block_dist_huffman_bitlen_count, _fix_block_dist_huffman_bitlen, 31, 5) end local _gsub_escape_table = { ["\000"] = "%z", ["("] = "%(", [")"] = "%)", ["."] = "%.", ["%"] = "%%", ["+"] = "%+", ["-"] = "%-", ["*"] = "%*", ["?"] = "%?", ["["] = "%[", ["]"] = "%]", ["^"] = "%^", ["$"] = "%$" } local function escape_for_gsub(str) return str:gsub("([%z%(%)%.%%%+%-%*%?%[%]%^%$])", _gsub_escape_table) end function LibDeflate:CreateCodec(reserved_chars, escape_chars, map_chars) if type(reserved_chars) ~= "string" or type(escape_chars) ~= "string" or type(map_chars) ~= "string" then error("Usage: LibDeflate:CreateCodec(reserved_chars," .. " escape_chars, map_chars):" .. " All arguments must be string.", 2) end if escape_chars == "" then return nil, "No escape characters supplied." end if #reserved_chars < #map_chars then return nil, "The number of reserved characters must be" .. " at least as many as the number of mapped chars." end if reserved_chars == "" then return nil, "No characters to encode." end local encode_bytes = reserved_chars .. escape_chars .. map_chars -- build list of bytes not available as a suffix to a prefix byte local taken = {} for i = 1, #encode_bytes do local byte = string.byte(encode_bytes, i, i) if taken[byte] then return nil, "There must be no duplicate characters in the" .. " concatenation of reserved_chars, escape_chars and" .. " map_chars." end taken[byte] = true end local decode_patterns = {} local decode_repls = {} -- the encoding can be a single gsub -- , but the decoding can require multiple gsubs local encode_search = {} local encode_translate = {} -- map single byte to single byte if #map_chars > 0 then local decode_search = {} local decode_translate = {} for i = 1, #map_chars do local from = string.sub(reserved_chars, i, i) local to = string.sub(map_chars, i, i) encode_translate[from] = to encode_search[#encode_search + 1] = from decode_translate[to] = from decode_search[#decode_search + 1] = to end decode_patterns[#decode_patterns + 1] = "([" .. escape_for_gsub(table.concat(decode_search)) .. "])" decode_repls[#decode_repls + 1] = decode_translate end local escape_char_index = 1 local escape_char = string.sub(escape_chars, escape_char_index, escape_char_index) -- map single byte to double-byte local r = 0 -- suffix char value to the escapeChar local decode_search = {} local decode_translate = {} for i = 1, #encode_bytes do local c = string.sub(encode_bytes, i, i) if not encode_translate[c] then while r >= 256 or taken[r] do r = r + 1 if r > 255 then -- switch to next escapeChar decode_patterns[#decode_patterns + 1] = escape_for_gsub(escape_char) .. "([" .. escape_for_gsub(table.concat(decode_search)) .. "])" decode_repls[#decode_repls + 1] = decode_translate escape_char_index = escape_char_index + 1 escape_char = string.sub(escape_chars, escape_char_index, escape_char_index) r = 0 decode_search = {} decode_translate = {} if not escape_char or escape_char == "" then return nil, "Out of escape characters." end end end local char_r = _byte_to_char[r] encode_translate[c] = escape_char .. char_r encode_search[#encode_search + 1] = c decode_translate[char_r] = c decode_search[#decode_search + 1] = char_r r = r + 1 end if i == #encode_bytes then decode_patterns[#decode_patterns + 1] = escape_for_gsub(escape_char) .. "([" .. escape_for_gsub(table.concat(decode_search)) .. "])" decode_repls[#decode_repls + 1] = decode_translate end end local codec = {} local encode_pattern = "([" .. escape_for_gsub(table.concat(encode_search)) .. "])" local encode_repl = encode_translate function codec:Encode(str) if type(str) ~= "string" then error( ("Usage: codec:Encode(str):" .. " 'str' - string expected got '%s'."):format( type(str)), 2) end return string.gsub(str, encode_pattern, encode_repl) end local decode_tblsize = #decode_patterns local decode_fail_pattern = "([" .. escape_for_gsub(reserved_chars) .. "])" function codec:Decode(str) if type(str) ~= "string" then error( ("Usage: codec:Decode(str):" .. " 'str' - string expected got '%s'."):format( type(str)), 2) end if string.find(str, decode_fail_pattern) then return nil end for i = 1, decode_tblsize do str = string.gsub(str, decode_patterns[i], decode_repls[i]) end return str end return codec end function LibDeflate:EncodeForPrint(str) if type(str) ~= "string" then error(("Usage: LibDeflate:EncodeForPrint(str):" .. " 'str' - string expected got '%s'."):format(type(str)), 2) end local strlen = #str local strlenMinus2 = strlen - 2 local i = 1 local buffer = {} local buffer_size = 0 while i <= strlenMinus2 do local x1, x2, x3 = string.byte(str, i, i + 2) i = i + 3 local cache = x1 + x2 * 256 + x3 * 65536 local b1 = cache % 64 cache = (cache - b1) / 64 local b2 = cache % 64 cache = (cache - b2) / 64 local b3 = cache % 64 local b4 = (cache - b3) / 64 buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_6bit_char[b1] .. _byte_to_6bit_char[b2] .. _byte_to_6bit_char[b3] .. _byte_to_6bit_char[b4] end local cache = 0 local cache_bitlen = 0 while i <= strlen do local x = string.byte(str, i, i) cache = cache + x * _pow2[cache_bitlen] cache_bitlen = cache_bitlen + 8 i = i + 1 end while cache_bitlen > 0 do local bit6 = cache % 64 buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_6bit_char[bit6] cache = (cache - bit6) / 64 cache_bitlen = cache_bitlen - 6 end return table.concat(buffer) end function LibDeflate:DecodeForPrint(str) if type(str) ~= "string" then error(("Usage: LibDeflate:DecodeForPrint(str):" .. " 'str' - string expected got '%s'."):format(type(str)), 2) end str = str:gsub("^[%c ]+", "") str = str:gsub("[%c ]+$", "") local strlen = #str if strlen == 1 then return nil end local strlenMinus3 = strlen - 3 local i = 1 local buffer = {} local buffer_size = 0 while i <= strlenMinus3 do local x1, x2, x3, x4 = string.byte(str, i, i + 3) x1 = _6bit_to_byte[x1] x2 = _6bit_to_byte[x2] x3 = _6bit_to_byte[x3] x4 = _6bit_to_byte[x4] if not (x1 and x2 and x3 and x4) then return nil end i = i + 4 local cache = x1 + x2 * 64 + x3 * 4096 + x4 * 262144 local b1 = cache % 256 cache = (cache - b1) / 256 local b2 = cache % 256 local b3 = (cache - b2) / 256 buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_char[b1] .. _byte_to_char[b2] .. _byte_to_char[b3] end local cache = 0 local cache_bitlen = 0 while i <= strlen do local x = string.byte(str, i, i) x = _6bit_to_byte[x] if not x then return nil end cache = cache + x * _pow2[cache_bitlen] cache_bitlen = cache_bitlen + 6 i = i + 1 end while cache_bitlen >= 8 do local byte = cache % 256 buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_char[byte] cache = (cache - byte) / 256 cache_bitlen = cache_bitlen - 8 end return table.concat(buffer) end local _byte_to_6bit_char = { [0] = "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "(", ")" } local _6bit_to_byte = { [97] = 0, [98] = 1, [99] = 2, [100] = 3, [101] = 4, [102] = 5, [103] = 6, [104] = 7, [105] = 8, [106] = 9, [107] = 10, [108] = 11, [109] = 12, [110] = 13, [111] = 14, [112] = 15, [113] = 16, [114] = 17, [115] = 18, [116] = 19, [117] = 20, [118] = 21, [119] = 22, [120] = 23, [121] = 24, [122] = 25, [65] = 26, [66] = 27, [67] = 28, [68] = 29, [69] = 30, [70] = 31, [71] = 32, [72] = 33, [73] = 34, [74] = 35, [75] = 36, [76] = 37, [77] = 38, [78] = 39, [79] = 40, [80] = 41, [81] = 42, [82] = 43, [83] = 44, [84] = 45, [85] = 46, [86] = 47, [87] = 48, [88] = 49, [89] = 50, [90] = 51, [48] = 52, [49] = 53, [50] = 54, [51] = 55, [52] = 56, [53] = 57, [54] = 58, [55] = 59, [56] = 60, [57] = 61, [40] = 62, [41] = 63 } function LibDeflate:EncodeForPrint(str) if type(str) ~= "string" then error(("Usage: LibDeflate:EncodeForPrint(str):" .. " 'str' - string expected got '%s'."):format(type(str)), 2) end local strlen = #str local strlenMinus2 = strlen - 2 local i = 1 local buffer = {} local buffer_size = 0 while i <= strlenMinus2 do local x1, x2, x3 = string.byte(str, i, i + 2) i = i + 3 local cache = x1 + x2 * 256 + x3 * 65536 local b1 = cache % 64 cache = (cache - b1) / 64 local b2 = cache % 64 cache = (cache - b2) / 64 local b3 = cache % 64 local b4 = (cache - b3) / 64 buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_6bit_char[b1] .. _byte_to_6bit_char[b2] .. _byte_to_6bit_char[b3] .. _byte_to_6bit_char[b4] end local cache = 0 local cache_bitlen = 0 while i <= strlen do local x = string.byte(str, i, i) cache = cache + x * _pow2[cache_bitlen] cache_bitlen = cache_bitlen + 8 i = i + 1 end while cache_bitlen > 0 do local bit6 = cache % 64 buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_6bit_char[bit6] cache = (cache - bit6) / 64 cache_bitlen = cache_bitlen - 6 end return table.concat(buffer) end function LibDeflate:DecodeForPrint(str) if type(str) ~= "string" then error(("Usage: LibDeflate:DecodeForPrint(str):" .. " 'str' - string expected got '%s'."):format(type(str)), 2) end str = str:gsub("^[%c ]+", "") str = str:gsub("[%c ]+$", "") local strlen = #str if strlen == 1 then return nil end local strlenMinus3 = strlen - 3 local i = 1 local buffer = {} local buffer_size = 0 while i <= strlenMinus3 do local x1, x2, x3, x4 = string.byte(str, i, i + 3) x1 = _6bit_to_byte[x1] x2 = _6bit_to_byte[x2] x3 = _6bit_to_byte[x3] x4 = _6bit_to_byte[x4] if not (x1 and x2 and x3 and x4) then return nil end i = i + 4 local cache = x1 + x2 * 64 + x3 * 4096 + x4 * 262144 local b1 = cache % 256 cache = (cache - b1) / 256 local b2 = cache % 256 local b3 = (cache - b2) / 256 buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_char[b1] .. _byte_to_char[b2] .. _byte_to_char[b3] end local cache = 0 local cache_bitlen = 0 while i <= strlen do local x = string.byte(str, i, i) x = _6bit_to_byte[x] if not x then return nil end cache = cache + x * _pow2[cache_bitlen] cache_bitlen = cache_bitlen + 6 i = i + 1 end while cache_bitlen >= 8 do local byte = cache % 256 buffer_size = buffer_size + 1 buffer[buffer_size] = _byte_to_char[byte] cache = (cache - byte) / 256 cache_bitlen = cache_bitlen - 8 end return table.concat(buffer) end LibDeflate.internals = { LoadStringToTable = LoadStringToTable, IsValidDictionary = IsValidDictionary, IsEqualAdler32 = IsEqualAdler32, _byte_to_6bit_char = _byte_to_6bit_char, _6bit_to_byte = _6bit_to_byte, InternalClearCache = InternalClearCache } -- bepis --sprdat = "" --local spr_compressed = LibDeflate:CompressDeflate(sprdat) --trace(LibDeflate:EncodeForPrint(spr_compressed)) --exit() ---------------------------------------------------------------- ---------------------------------------------------------------- ---------------------------------------------------------------- ---------------------------------------------------------------- -- math functions sin = math.sin cos = math.cos rand = math.random pal = {} for i=0,16 do pal[i] = {peek(0x3fc0 + (i*3)) + 0,peek(0x3fc1 + (i*3)),peek(0x3fc2 + (i*3))} end fadelevel = 1 fadespeed = 0 fadedone = false fadedir = "in" titlevars={ init = false } introcutscenevars={ init = false, state = 0, statetime = 0, pausetimer = 0, text = false, textsound = -1, textcolor = 12, chief = {talking = false, talkphase = 0}, script = { "MYLA: Officer Myla, reporting for duty,\n\nsir!", "CHIEF: At ease. I have a new assignment\n\nfor you.", "As you are no doubt aware, we have\n\ndetected the opening of multiple time\n\nrifts near the city center.", "Our intelligence suggests that\n\nthis is the work of the Time Killers.", "We're not sure what they're up to,\n\nbut if they're allowed to continue, it\n\ncould--", "MYLA: You got it, boss! I'll take care\n\nof them!", "CHIEF: I wasn't finished!", "Now, where was I... Ah yes.", "If the Time Killers are allowed to\n\ncontinue, the course of history could\n\nbe irreversibly altered.", "Your mission, should you choose to\n\naccept it, is to investigate the time\n\nrifts and put a stop to whatever their", "plans may be, by any means necessary.\n\nLethal force is hereby authorized.", "MYLA: Yes, sir! Right away!", "CHIEF: And don't forget your scouter\n\nthis time!", "MYLA: O-of course! How could I forget\n\nsomething so important?", "CHIEF: I want a full report on my\n\ndesk in 30 seconds.", "Right, off you go.", "CHIEF: That girl is such a pain..." } } thuganims = { runshoot = { 3, "9gv2nmmuiSvIVGbIJ9FeQnK7Q8tvsTEQMcgchYRHisIiJ(1gdNn3(Z7YMAMQeTvNlKZFqYsm0)c2TrYbsnWetnaXmfg8baMK6Qqdlq9OkvNSK10fQLLv1q5hvJsPd19ISdi78pTbI19A9mlhCRyRvvMONkmx8YaYhgTk7Zk8(Ep7RrF2Jb8ZEbXHlKF4dBqclGuBd6kxhx)B7Vx7(xx4tXw(YhUKq38V(nbpRDX9EHRRCDMLV8)it7N)", "1kzqUsmmim0ReRchOaC)pcJTdDA0OV(QvQLf5HAWvyi2Zhre4mJmywUsetrCMOIuXFPoAWmDQFbpAXqwwkEH2)Ur3iU5d3DZCFWecKycJPPeNwt3jPWmvhue)ikkGkWOgdY5Sa9jcE)I5qiU3aioMRvp9FM5xvApwWxz7p2QMhQLzbl277UEn5M0cXSyZ4lc5rnjvL5UuW1s)y73Jp7WjV0lI)733TsTZfwx2fDw8rYUpoVW(ANFR1UW796cn8E85d", "Tkzuoqmiiq0RKFbhihM7)rybeJ12UPjnDAdp0DhfX2(sbapAWgmskAjhZhjX4gDT7gz4GSry8ebx8OUuctAdAtwZpnC15RL2urZevKi6qIHYGTAC(tTTYHm)3QKEf4zob98U)2POq7UI1ijGKWSoC34PBKMvDsAP6vFR)HnG4GTtw042Ta5X79SoItN5nbfDZPVcJpoy9nIT4YeNKnuNJV54mxL)X7CSkOxVPRT58(DM3zFZcp1pEQO(9d", "1k52nmmmiu0vYFbdKb2)rOxEzflvh1u1sI4GtmpTh)drebAv0KUrrny(D3qFV3sOUiAQYhxbXC5yj0SYqNPoH2pSDR6GhmX(AMjY1aKVKsoQ1XVkxZMasSBMcFjbwGIb7jENgXcpH4XiOio9C)StMHwtut1dZ)VzcO1Gi7lJ35Qk1EFAp38ld4VO7GfZcAkNS5Rr46A8cJGz1P)SMFZkfsXhoxwnYE9UIID3zFvlx5hF)QDASUgTL2t1ZDbSJ7opS9x)", "9k1sYommiSReRqhid6(Fek)YuN8w0(MmPkZyzmHyHiYpaMzXQBETXRnn72xvT1RVH3lXZ)vl(f((WJUO0HNiyMqeiqbIyavJGKunc1MRniBL0iCNNqv082wwEqmkBP6ArvmSc8x1Why(9jeTggVONNKL9gnb78RkghkMDC6yz7KNAANmmZ08khbWw7mrDE9fgEGjE)Jbznf2nZXx4d6pCeZXTnCF7Jk2YT)sPupoM7SCv6B1FQI7Hxp", "9kvBUommiSRe)coqy4(FeMD(OA6v1QjTxNvfMemKeO2JbaqBHcc1YrCnyAP)nzJnlVrUuUmmzdt6xH4Yi1ewpryHheweoD0hbzrE6MCcW6jvUpZY2PBsRkR7W1H6ODTHNzlojS34VAc9XsqExkCsQRw3QpO3fDs9846mhlRewp6tRoM0xJ45ScQjaTveivP2Chndog1uZEK37lKqVk6rF8b)t4m2N4F4HTT1ERLZ42Xn8KZL8jD)ppYx", "1kz3nomqiq4wINwki(P)lHmmWg7lk6SJucpWhYWGawlFFZDh(WdVIIoGmiHpqfbT3P2hur0ZwuUrmKfjTFW4)P2miQOlvvruDvbfqGqSmHbATAmhLILjhRevFef5qfONRvrZsq1Gv5Bglc)Zoa((UMZ1)s521nv1mXdsTvGMp0ubiyd2VZdz9ZLZQvWTQ0uBIg4nzL)rky)OVF9NZNS3KF0Fe)x7NrjpZgDYPOJI3bN3JJeYZ151ALB8)EEJb(S94d", "Tk1wsqmiiSReFbhicC)pclc4w7J9X0PPDiGTrXO0tcaerdwXJKMTKRXhjJAYdSxnYWcSkupJqaFfNAHjBfBtUhFk4SYBdHewYeH5rmiEuYftDD(j6D7efI75FlCQLrKfm8ixJx1zbIgymhjdWjvgHGFDIqw7KULqBFt)UbO))UpHRAS3e3GwUo27(wB6RN7zFKnvmbnN3nSL7il8MiFYoHEF8mNNZz5t8vk2AOBVOBlZX17iFL8Ds8d(XVAQxd", "1kzwUomimu0TeF57cYd7)LWZtGaPhrnsTUv(ajXZE8lerexRIwmo0utwppoO)V1sQ2eTu1Vq5IfY1uyYocZindO9fl3opWaeI7aefAhuCLko675R2mnL8RbL2sIFYPy(z2)ZgbbSlHpsksWWbVBYm0UJAQEP))EPRhuKfapR80ZSW)8w3x7QwxfVVm41qLoa5G1jsAyTJSXSKTE6ZD)J7gH08L9L1OCCy9Yl2tZ(ox25hVFnnASwJoc7T85jho97jV85)b", "9kvqsommiSVeNGhKb9)Fcva2joDp0UtBQYeKXoAaKJ8dG7oJHh1IOw0C4VLAVJNi6aF(V9s8e)5i4uu9rKGmsiIjMAgZntvMKKQmvBUwy5OKgre4ckrZV2t5KaLnuDmGkUni(B3GB4(7vGJMn9I((eOSxoeOpFu7BRo2780XYXj311(qAMP5voIz(yNHbVTybtEcxI(hdG6wy3mN(cUr)bZMzvTMNvNVR0Q84CJs5HeSZYv6OV3kXxzuEa" }, idleshoot = { 3, "9gv2nmmuiSvIVGbIJ9FeQnK7Q8tvsTEQMcgchYRHisIiJ(1gdNn3(Z7YMAMQeTvNlKZFqYsm0)c2TrYbsnWetnaXmfg8baMK6Qqdlq9OkvNSK10fQLLv1q5hvJsPd19ISdi78pTbI19A9mlhCRyRvvMONkmx8YaYhgTk7Zk8(Ep7RrF2Jb8ZEbXHlKF4dBqclGuBd6kxhx)B7Vx7(xx4tXw(YhUKq38V(nbpRDX9EHRRCDMLV8)it7N)", "9g1wommmiSReFroqy4(FeMbsuRAx7M0QMvATtumHhY3b)d8za4jGJCHs0CjCVp7A7yXLQTYhSIa330)cJjRNAmjInm0bHQ5IFfiJKTAPdmmtQRzwzIXjMc6VRBTfbfjBr)0gTUXx3)Uby1xJNP34qZKjc3nK1ffEwEEZwYsWmozX79199iDACugYag4z0aSq8id0mdVjrR2)Q)9Kt83JqoLrRj3KN)K1HYA8UD73LUhd8XIzN)9X5NXR", "Tgzusmimiq0ReFbhiG9(FekiGtuRoTD6orEXyYsaPNLTfDZl62j63EqpLfAl0XG7R5z0FoXbnR9R2BaV9N(FAmdOOWhOWf5M0qsIIeRscXCoIh24T5gIjAmuWIjAOCBjrNs0tK2ywoMPjH6kDZ((A1M(kEZhXP(WqPrrT8qtgLwwhzFqnaVK0Sxi2wtFEpxaTB5belpE2)mfvgNBbE8px5Y0)(jP31hiCQTGdKM)67ZO1hcZTA)QDXHpv4Qb)E9UOxp", "Tgzusmimiq0ReFbhiG9(FekiGtuRoTD6orEXyYsaPNLTfDZl62j63EqpLfAl0XG7R5z0FoXbnR9R2BaV9N(FAmdOOWhOWf5M0qsIIeRscXCoIh24T5gIjAmuWIjAOCBjrNs0tK2ywoMPjH6kDZ((A1M(kEZhXP(WqPrrT8qtgLwwhzFqnaVK0Sxi2wtFEpxaTB5belpE2)mfvgNBbE8px5Y0)(jP31hiCQTGdKM)67ZO1hcZTA)QDXHpv4Qb)E9UOxp", "Tgzusmimiq0ReFbhiG9(FekiGtuRoTD6orEXyYsaPNLTfDZl62j63EqpLfAl0XG7R5z0FoXbnR9R2BaV9N(FAmdOOWhOWf5M0qsIIeRscXCoIh24T5gIjAmuWIjAOCBjrNs0tK2ywoMPjH6kDZ((A1M(kEZhXP(WqPrrT8qtgLwwhzFqnaVK0Sxi2wtFEpxaTB5belpE2)mfvgNBbE8px5Y0)(jP31hiCQTGdKM)67ZO1hcZTA)QDXHpv4Qb)E9UOxp", "Tgzusmimiq0ReFbhiG9(FekiGtuRoTD6orEXyYsaPNLTfDZl62j63EqpLfAl0XG7R5z0FoXbnR9R2BaV9N(FAmdOOWhOWf5M0qsIIeRscXCoIh24T5gIjAmuWIjAOCBjrNs0tK2ywoMPjH6kDZ((A1M(kEZhXP(WqPrrT8qtgLwwhzFqnaVK0Sxi2wtFEpxaTB5belpE2)mfvgNBbE8px5Y0)(jP31hiCQTGdKM)67ZO1hcZTA)QDXHpv4Qb)E9UOxp", "Tgzusmimiq0ReFbhiG9(FekiGtuRoTD6orEXyYsaPNLTfDZl62j63EqpLfAl0XG7R5z0FoXbnR9R2BaV9N(FAmdOOWhOWf5M0qsIIeRscXCoIh24T5gIjAmuWIjAOCBjrNs0tK2ywoMPjH6kDZ((A1M(kEZhXP(WqPrrT8qtgLwwhzFqnaVK0Sxi2wtFEpxaTB5belpE2)mfvgNBbE8px5Y0)(jP31hiCQTGdKM)67ZO1hcZTA)QDXHpv4Qb)E9UOxp", "Tgzusmimiq0ReFbhiG9(FekiGtuRoTD6orEXyYsaPNLTfDZl62j63EqpLfAl0XG7R5z0FoXbnR9R2BaV9N(FAmdOOWhOWf5M0qsIIeRscXCoIh24T5gIjAmuWIjAOCBjrNs0tK2ywoMPjH6kDZ((A1M(kEZhXP(WqPrrT8qtgLwwhzFqnaVK0Sxi2wtFEpxaTB5belpE2)mfvgNBbE8px5Y0)(jP31hiCQTGdKM)67ZO1hcZTA)QDXHpv4Qb)E9UOxp" }, crouch = { 3, "9gv2nmmuiSvIVGbIJ9FeQnK7Q8tvsTEQMcgchYRHisIiJ(1gdNn3(Z7YMAMQeTvNlKZFqYsm0)c2TrYbsnWetnaXmfg8baMK6Qqdlq9OkvNSK10fQLLv1q5hvJsPd19ISdi78pTbI19A9mlhCRyRvvMONkmx8YaYhgTk7Zk8(Ep7RrF2Jb8ZEbXHlKF4dBqclGuBd6kxhx)B7Vx7(xx4tXw(YhUKq38V(nbpRDX9EHRRCDMLV8)it7N)", "1g1womiqiWReFbhiEC)pcLby1ASTjnXLOmS4Wkmq71CImZC84P3GVcAN5FRqW1wysRRnrVRQko2C3F3KBd4yzqaJIGfyKWzat5BgWfW6Gy0KIxeRYGNiWLk0y8ZylyKGvnakAA95eD7p6DBe2s2Gy(qYN4MI7oc3vaIO5gcq1QIC(DFjzRZyoinxMzZK0Yub43yQooQNkS17bJd9V1T2Vn7xx(A19gsZgDswiDTpNGZJxspv)jEhjEKj(1p", "flvqssqiiSVeNGhKb()pHnb0E9WEzQP2zsvTHwnib1(CaaCmrcfLtWROgBsr9itXhS()BiFKTFsvqAcbZQgwyHhryweUceXaRjF1MaBXuwULvBiropgUxqvKr5U41Q8VT5fKrcD10EB6jZ9AvQpqQ9VjkU(V9ASiK)go9MqLGnbS46zeK50ruOa))jZhGZ7IA39F6FwT3s9V(eyQM6W6GF4PwSRpn0R2A313izQ7RGZghnxj)3G3c)m", "fl1woiqqiSReFbhiEC)pc2cS6eJ)ymQn7sjBOZszq(DiIaXmYGz5K8oQJLywhXr8d7)xd6JS9tYgIFGqKQHyIPMzIyMYesirAs92eXkgYYvwTGIu8BqTbubokvj7EP)BZtqJy8QP92mtM71zoqggIC9eJeZbO)o4zQYAqafzHJcBSK5ZjmX7iU2pQ9w4(Cu8DtZ)kRaJpRlUU6oYtpihVv33tr5UbNhAoYKAD58847Nv(j42", "fl1woiqqiSReFbhiEC)pc2cS6eJ)ymQn7sjBOZszq(DiIaXmYGz5K8oQJLywhXr8d7)xd6JS9tYgIFGqKQHyIPMzIyMYesirAs92eXkgYYvwTGIu8BqTbubokvj7EP)BZtqJy8QP92mtM71zoqggIC9eJeZbO)o4zQYAqafzHJcBSK5ZjmX7iU2pQ9w4(Cu8DtZ)kRaJpRlUU6oYtpihVv33tr5UbNhAoYKAD58847Nv(j42", "fl1woiqqiSReFbhiEC)pc2cS6eJ)ymQn7sjBOZszq(DiIaXmYGz5K8oQJLywhXr8d7)xd6JS9tYgIFGqKQHyIPMzIyMYesirAs92eXkgYYvwTGIu8BqTbubokvj7EP)BZtqJy8QP92mtM71zoqggIC9eJeZbO)o4zQYAqafzHJcBSK5ZjmX7iU2pQ9w4(Cu8DtZ)kRaJpRlUU6oYtpihVv33tr5UbNhAoYKAD58847Nv(j42", "fl1woiqqiSReFbhiEC)pc2cS6eJ)ymQn7sjBOZszq(DiIaXmYGz5K8oQJLywhXr8d7)xd6JS9tYgIFGqKQHyIPMzIyMYesirAs92eXkgYYvwTGIu8BqTbubokvj7EP)BZtqJy8QP92mtM71zoqggIC9eJeZbO)o4zQYAqafzHJcBSK5ZjmX7iU2pQ9w4(Cu8DtZ)kRaJpRlUU6oYtpihVv33tr5UbNhAoYKAD58847Nv(j42", "fl1woiqqiSReFbhiEC)pc2cS6eJ)ymQn7sjBOZszq(DiIaXmYGz5K8oQJLywhXr8d7)xd6JS9tYgIFGqKQHyIPMzIyMYesirAs92eXkgYYvwTGIu8BqTbubokvj7EP)BZtqJy8QP92mtM71zoqggIC9eJeZbO)o4zQYAqafzHJcBSK5ZjmX7iU2pQ9w4(Cu8DtZ)kRaJpRlUU6oYtpihVv33tr5UbNhAoYKAD58847Nv(j42", "fl1woiqqiSReFbhiEC)pc2cS6eJ)ymQn7sjBOZszq(DiIaXmYGz5K8oQJLywhXr8d7)xd6JS9tYgIFGqKQHyIPMzIyMYesirAs92eXkgYYvwTGIu8BqTbubokvj7EP)BZtqJy8QP92mtM71zoqggIC9eJeZbO)o4zQYAqafzHJcBSK5ZjmX7iU2pQ9w4(Cu8DtZ)kRaJpRlUU6oYtpihVv33tr5UbNhAoYKAD58847Nv(j42" }, die = { 3, "9gv2nmmuiSvIVGbIJ9FeQnK7Q8tvsTEQMcgchYRHisIiJ(1gdNn3(Z7YMAMQeTvNlKZFqYsm0)c2TrYbsnWetnaXmfg8baMK6Qqdlq9OkvNSK10fQLLv1q5hvJsPd19ISdi78pTbI19A9mlhCRyRvvMONkmx8YaYhgTk7Zk8(Ep7RrF2Jb8ZEbXHlKF4dBqclGuBd6kxhx)B7Vx7(xx4tXw(YhUKq38V(nbpRDX9EHRRCDMLV8)it7N)", "flzSvmqimm0vIkyGWw7)iejziVxiPifKxCX9nhwhY(OD9iJiYKGjz0sNecIAnFb3VI3uVOKAQytMfl5HrEBZpowUwp6FEFgOcwYOIE3puSWS3dTkgZzvXC65ejq1gRVsRpQeQWNfOsphqzbPCXyN)xd2ajDcyFXe4rqMfNQXiC7QYQgLB)CUP2q)tzzC7sOkPz0GpHVWg6QHOUEzr(qQ)p)6baSfXYVhCF8yBe8IJWjXj3jTt9xPXEm", "fl1wommmiSReFfoqe4(FeMnpu762K6hvASvzOHyHDrEYyV3f4eDVQ9t1UOA4i0fsq8bfUNy2Brzsc5G0GNmbuS5)hD(frVu21667NNhPmK1s5pDvjz0GTwBwTvZyV4nwQqGWcsLq3aAsgBb3itcCZ0hIAe4npJ)9iNFOdOlKePz4EHMhcuMHHLTfgBV)Q3jJmMfHGTNo)2YLjT2PUe9sIh3DmNffVzJlJpLbmks695tWO0P1FYWCE0wrCqs8MbD9UERKJKyCL7yoVc", "To1wYnmmiWReFbhiw4(FekpLBCNP1ntit8IqI1SGf9)m0GTO94ebMmHfgbl(TbFddp(n)eB1XnuCVxls)u4AjZnkmhQjLrlguIlLM5E45W4GJ0yoZUq(8hWXiKTxK8znwBe8qn2LIqTJ8jLpn6z0z2agC0)2hC5vKCwuMvxfbIQHEIvA6yfgmMDKQ3fosCorHGaJDfSVaI)Jkuh8T)G53n7Mo9x0)v4FSFik1Qi5m3j)Yw)RZxXAE6ihEMQyN5NSUDGZa5SXoOUUrILkmfy)HvuG7vq)Bu91", "TovWnommmSvYVmhijZ9FekLSuV4db4aYfw0s1h0IKoz8VG7pv5kXZ1)yH3hJ84KDwL382JTztMKjdGK0G)lS6FxXNn4fmbbMyo3FrT6HVxP8qVYXXkznGYYeVy(LJ2dZI7)pAMTBkcLjIqOy4mdKsJidM5QICtGrpiE3d6KJbeRuKQrRp5559Q9M3V)fiWzR(t7Flx3fmkcyUj5rMnluAPwUJ7yFRNkZHVCQUnW5Zzs5QLED73HUVQhFg97u9BxmmYzioWN)", "fpv0omiqiSFP7PJpiG())jSw40KBrZYwIzvh90jhTGo(xiIu4xtpJiEavL3W3blor2XSxK1ISnzM4aMztJXb5jp7Cv7q7a5kjw4vZPZ6GXG5yQWtJ7Yd0a(wiBimQifNU2C5pHqcpdeIQ(GzL10FwXao6gjMKDVNRoXI3QhoQ7ZyNCVm4AgnJrnpnpOxmQCQvAnxdouZ8T536xDRrDGpjN174RVt0w2vhBQ6sJOMT41tFM0B41p", "Tl1wommmiSReFbhiEC)pcZMKOT08rLMM2x1sTgtIrKeKh8Zqez2eGijKnNjcAgbYiGCrS82RITh7ih)6ALduB4OhUW5L1xgoD(1Wmtnqiq1wRnlQ(Pgnl2PW)88tbckAg25EygsHvDYOc1CZDCVyw4acYrssuQ)aQDEERnV3lQt21oFCyJ6fcOQQ(LswptV)KHE4wwhd)(wbGZtSYNZp3HEYH800Y7R)", "TlvqommmmOVuofEqG9))jmBh7o1DRs7YKgQsKgfcGBx)XpimzfKEQYrHKSVyG0TBFYvKWB8Ay3BDqnSHolmRwAEvt)cBG9oEgGus5SD6ZyvE4HZfyJJHbQZdhpVM(qZD3VJDA9XQmUHhzYdVITcM8eFQ3vXl9Nwu1AdcMAaer(11fLy5IRvDvPR5iQBMhNj9EXEKtYM)4pMEW0H8AU86", "TdzWvmmmim0vItWabM9FeIqkUT(ypKBrXp)jbmkg7vV65ujS2CDs7lxu1hTodqk(i1nwuiLmAQrKMXIPtYlw8MiWdp(3ltBQfg7WSX3vQZkBAD3bQcmgIareKSjTLiL7A9JcVNpejoqmQWbZ5Kzvyh3YUyR8jlmBQqSlhmtnysi7EoW5ZQ3)9Kx)", "TdzWvmmmim0vItWabM9FeIqkUT(ypKBrXp)jbmkg7vV65ujS2CDs7lxu1hTodqk(i1nwuiLmAQrKMXIPtYlw8MiWdp(3ltBQfg7WSX3vQZkBAD3bQcmgIareKSjTLiL7A9JcVNpejoqmQWbZ5Kzvyh3YUyR8jlmBQqSlhmtnysi7EoW5ZQ3)9Kx)", "TdzWvmmmim0vItWabM9FeIqkUT(ypKBrXp)jbmkg7vV65ujS2CDs7lxu1hTodqk(i1nwuiLmAQrKMXIPtYlw8MiWdp(3ltBQfg7WSX3vQZkBAD3bQcmgIareKSjTLiL7A9JcVNpejoqmQWbZ5Kzvyh3YUyR8jlmBQqSlhmtnysi7EoW5ZQ3)9Kx)", "TdzWvmmmim0vItWabM9FeIqkUT(ypKBrXp)jbmkg7vV65ujS2CDs7lxu1hTodqk(i1nwuiLmAQrKMXIPtYlw8MiWdp(3ltBQfg7WSX3vQZkBAD3bQcmgIareKSjTLiL7A9JcVNpejoqmQWbZ5Kzvyh3YUyR8jlmBQqSlhmtnysi7EoW5ZQ3)9Kx)", "TdzWvmmmim0vItWabM9FeIqkUT(ypKBrXp)jbmkg7vV65ujS2CDs7lxu1hTodqk(i1nwuiLmAQrKMXIPtYlw8MiWdp(3ltBQfg7WSX3vQZkBAD3bQcmgIareKSjTLiL7A9JcVNpejoqmQWbZ5Kzvyh3YUyR8jlmBQqSlhmtnysi7EoW5ZQ3)9Kx)", "TdzWvmmmim0vItWabM9FeIqkUT(ypKBrXp)jbmkg7vV65ujS2CDs7lxu1hTodqk(i1nwuiLmAQrKMXIPtYlw8MiWdp(3ltBQfg7WSX3vQZkBAD3bQcmgIareKSjTLiL7A9JcVNpejoqmQWbZ5Kzvyh3YUyR8jlmBQqSlhmtnysi7EoW5ZQ3)9Kx)", } } gamevars={ init = false, level = 0 } bullets = {} objects = {} dummyanim = {} levelsubtitles = { "Enter the time rift!", -- level 1 "Get to the castle!", -- level 2 "Clear them out!", -- level 3 "Escape!", -- level 4 } solids = {{},{},{},{},{},{}} topsolids = {{},{},{},{},{},{}} for i=1,256 do solids[1][i] = false solids[2][i] = false solids[3][i] = false solids[4][i] = false solids[5][i] = false solids[6][i] = false topsolids[1][i] = false topsolids[2][i] = false topsolids[3][i] = false topsolids[4][i] = false topsolids[5][i] = false topsolids[6][i] = false end levelmusic = { 1, 2, 0, 0 } solids = { { -- city [1] = true, [17] = true }, { -- medieval [1] = true, [17] = true }, { -- level 2 }, { -- level 3 }, { -- level 4 }, { -- level 5 } } topsolids = { { -- test map [2] = true }, { -- level 1 }, { -- level 2 }, { -- level 3 }, { -- level 4 }, { -- level 5 } } gamevars = { init = false, level = 0, mx = 0, my = 0, tmy = 0 } -- Weapons: -- 0 = Peashooter (Normal damage) -- 1 = Machine gun -- 2 = Plasma beam (Continuous beam, needs to recharge after use) -- 3 = Spread shot (Shoots 5 bullets in a cone shape) -- 4 = Shotgun (Instakills enemies but has short range) (NYI) -- 5 = Homing shot (Low damage but shots home in on enemies) (NYI) -- 6 = Displacer (Screen nuke, disappears after a single use) (NYI) player = { x = 0, y = 0, vx = 0, vy = 0, dir = "r", airborne = 0, weapon = 0, -- see above for list of weapons weapontime = 0, weaponcooldown = 0, weaponneedscooldown = false, anim = dummyanim, frame = 0, animtimer = 0, animframe = 0, anims = { idle = { 8, "1kzdQrqmiu4RKAdtY74KQ07)rO(xGoLDBlu2hm(LjgdAu6XcFJ)M20Ufoa5sulaqziGviAT4q5HJlidQiAogbbEBr06UiryH)Jj3RvSNkSq(xKtffJs4)lnt3m3Npzu)IOAuiIU(qKGkuNM6YVDXSGxs(7CAS5VHMVB(CQ3sLzAVUMZW6A2iz6n9fhT5tuFV6H2ZNhQ2ys40nS34naU6LmkcQB1eomkGOq2B1gVhJjK19)ronKZbjhviu6mJT23o1XpxpVsHCUokRkN2NCZBIFf0YwfJb4MNd7w7wqKDEZFq4U5S4FQp)d", "1ozdUnmimu4RKXjc4DCO2Q3)JW8FzlRkkRst9jf(mPg45GlDTWl8V0IwLWbqeImaaXWKShx0S5IJK9niwusKCFpi22MenN1YkXnU1EtZ9zLBeMnW83uzI5iiOLqrZY)qdklINfjZNmVzuGK0KT7Q6S3zhJrxBkSx2f1)CkJZojN07JHpAQyop)1rTIX4UAkoAhAoxVPFWlJMLVncRs8zyPM5A(DyXvHDFpQRCVNaQ4TjIU)WjOi18(poRtmB0qAbubVx98rv0Bhwl9eo8gPYzqtDM0BKlg))iRlD9RS16B)vl3goc(N6Rd", "1ozuoommiq0ReMyzBooz9O9(FewyGiLDvv3kv15d)WTGZqmrESS)W)tNYzj7cgdTmWmJllXwuYQ5svMCCaSOKgzVN84WZwwxLvsBAR9IM7ZQWiQ6WTKUf1js6bfvWF3tues36eyVvfW7VV12XHiBBRKH8thKJbXCoqdMam2iEDUN3DsUzmMZy1vXCF(VZQI58z9eF0bqUhpzEiAJ2M0AGBTt4MR5xL9INf6Xzux5XmHHDmMSr)RGMWuZ5a(SUXCqZslyvWR1pFuXzBAT0t2L38lV7qwyLmgKlYVpY(cN)kBuV7Fu5(YvWBQF(d", "1ozuoommiq0ReMyzBooz9O9(FewyGiLDvv3kv15d)WTGZqmrESS)W)tNYzj7cgdTmWmJllXwuYQ5svMCCaSOKgzVN84WZwwxLvsBAR9IM7ZQWiQ6WTKUf1js6bfvWF3tues36eyVvfW7VV12XHiBBRKH8thKJbXCoqdMam2iEDUN3DsUzmMZy1vXCF(VZQI58z9eF0bqUhpzEiAJ2M0AGBTt4MR5xL9INf6Xzux5XmHHDmMSr)RGMWuZ5a(SUXCqZslyvWR1pFuXzBAT0t2L38lV7qwyLmgKlYVpY(cN)kBuV7Fu5(YvWBQF(d", "1ozdUnmimu4RKXjc4DCO2Q3)JW8FzlRkkRst9jf(mPg45GlDTWl8V0IwLWbqeImaaXWKShx0S5IJK9niwusKCFpi22MenN1YkXnU1EtZ9zLBeMnW83uzI5iiOLqrZY)qdklINfjZNmVzuGK0KT7Q6S3zhJrxBkSx2f1)CkJZojN07JHpAQyop)1rTIX4UAkoAhAoxVPFWlJMLVncRs8zyPM5A(DyXvHDFpQRCVNaQ4TjIU)WjOi18(poRtmB0qAbubVx98rv0Bhwl9eo8gPYzqtDM0BKlg))iRlD9RS16B)vl3goc(N6Rd", "1kzdQrqmiu4RKAdtY74KQ07)rO(xGoLDBlu2hm(LjgdAu6XcFJ)M20Ufoa5sulaqziGviAT4q5HJlidQiAogbbEBr06UiryH)Jj3RvSNkSq(xKtffJs4)lnt3m3Npzu)IOAuiIU(qKGkuNM6YVDXSGxs(7CAS5VHMVB(CQ3sLzAVUMZW6A2iz6n9fhT5tuFV6H2ZNhQ2ys40nS34naU6LmkcQB1eomkGOq2B1gVhJjK19)ronKZbjhviu6mJT23o1XpxpVsHCUokRkN2NCZBIFf0YwfJb4MNd7w7wqKDEZFq4U5S4FQp)d" }, run = { 3, "1ozuUrmmiq0RKXnYXCCOG69)i0zaI0Q2vnAvB5J8gZACGmEh)NHzgEQMwKIMAYk)puTLpEwKhQQh32cxulQnVTWxiWGKN6grMqMsczoRLjjMnAkckLL92UdHfjZnX0HcC)b0bwQmr4iwiDa1A39aEZNNvpSsXyTwNFdJgJEtFnKxE4ZP4k43bc6RG0aLbx75HBAuFV4VBP)J5eJJEkIhirOwKc3oS3pa9GUT6XrAHwDNAWCu4rniKue(ixR)H(7TUFDF2UUh0T2addwVXiePZK4HRjKz1yBwjY)CWTHda(B9gAXUXdLV)1D)Nd", "1kzuUrmmiq0RKXnYXCCOG69)i0zaI0QTBKQu3Yh(n2Xydz84)imZWOAArkAQjR1PqFD2wo8QipuvpqQBeFCBjCX(gUUPJE99BSDzHKczkjK5SMMKy2OPiecIDhctsMBIPdf4(lOdmv5cHJyHLJGuMyQEIB(8SQHvkgR168hy0y0BA4rl(JHKDHQOHaOVcw(pNhadP89r57w7)A(EqepGkWwtH5hXNWDrZr3gIJ0ctZpjZ2QSXxyFWgj8r2p6B0x)LHD9oMLgzOzj7re0y4yAqp9Ajz(3qJ8FJIMOoa3R9g(1tSN49XJh(J8MT)n", "TkvxUzmmiSRucRQbFCYaT7)ryyi9RQvQpmTIuJjP8RSBVRnZtmrHyEdR3Bqlu7FsCMhFmCG48LWfAudOQ21YU24SehikS6j22Qo(vLsM7y8w79Ap696SljiISaIT1DrIayqPXlXls9z8NIO)e(ECf83UzwgL7wMsChO3nhq4ISpgs05999r0bcntsOzfqm3wmmNoWj(o7Fmsy5S432f(hfhqM7Y7wYUi2gNymrFVrEZtEhZTGclUVKgmTSiulGmK4ZT24uADOWEYWn9Y)30y8Nus6U3WHK8qzEQqFyEYnXJkKtK)x7UXEWeTQvUxtGEFqEW(9d", "1ozdUnmmiu4ReWIInhhpq7(Fe27boTtRvAAARuf)bK4FW8Q8ASvn6lVPV(g78Yf)Yex1WnZVOFpdC9jwdFoNpFJRL4IEZEV8JJk)8T5)y5E7CO9JQvGQgIWOzsdRYtQIz4d0zBkdqgRFc(sZMFa)eHoFDgruFvMKQHyoxzmeJoNJHHD(88CGDGqcRGenihK(iYY5pBAzBpFN6QVUV772I39D2b9Dm8uns2DZa)arrLVFG(vK7((bAHDVVLgugX1IkbpzDmqCgY4U06rL1RYW9oRhGiwusozD0sZiLFqM1fXk5nbqU6)IK)2trSzUfJz0NGsC18PZ7Zp", "9k1cUvmmiSRuiRkjCCyyT7)rygiz6P9K2pvnR2AqjuIXP9VaZIVQPfZGh5VSYS6NHU5F3ji4QLM(TT(hdvlDXGvYRLuRiKJhPNjsVlrcXM6wmu4HjW6b0RD3RxNe51BmgmvDUmCIRRQtVuDMTE1MZKxdgWUpgJzRxuRx0o7wqEiLw8rc5fql9wZfrotF1lRWqn2ulKfOsc5s5OKDKRyicCyx41l1DdHTh5HfEm)risIPJmabZafEBMnz35BZT)mchm1PEUph252mW2tqrRJfTxo1rwDkzgO5fc0a1oNan3zPa1(XXI)4hT(RN6tHVd", "1kz3Trqmiq4wc4SSnLdhO0)LqGbV6KIYp3dBMh8h2lGGfO)rzMLNQPWqHrtfmVQ)A0wF(nc5s1X4DRf9l8gLwk5Uu9almxGfbusDGWhGRmZQwr9yFjeKKm)S3UT)idpYRQltj8uZPiru8Qi20AbUNTXCoxVaDaDWX7Fu8728m6IJmTrn54WR5eLvznSO0q1EHa7dgM)glz7OlN9iFi8SRGHnINJYLOYIs2O3v6DkI6DOmRNgjjmCAD)t4)y6By(xNOMQsd1A33vXfbMnEVFCTN0HBWBKgdXaF18hr7XH7to2VYX(gk)p)d", "1kzyoouiiq4RKyFrLJdfYE)pclZiVnnD7lPjBx(HFOrqWH2)HzMLRQPBcNIk5(C4OVoAJlVYysv9idDL2TllHtwVW5lDuNV(GTlke6iDHq699wsGEHIIaiPTktqqsFb090l56R0pYTkoi80g5Xrak9CRoZxEo31WGoTXym)fAfA1LAEuo)rtqxKIs2qcuMmXagkofczc5h9g0k9x58GizaQgMh0XSJ4(bya1g7PesXNCNwgnFUjBKWBSF0pOU(MMDohJsdmuwYEebegSsb6PPfs(BOb)B0Sj2jW99Dd)Ce7jET9yYFKxC9V)", "Tk1wUrmimWRe4gfyooupQ3)Jq9yNSR2iLpQASsySb8l80EwzLRyHcX6cw73WSWz)LJRC5LGteV3juXmIbMZzFwYNjodXjIcRCITTkJFvUK(ogpvFF0h9ET2TemZoaHTdBZIlOlfc6Yi2XQFxhA28NqNHj0X0DpVfPWUf2l07obm1i7JHfzEFFFezqqZTeAEbcZUfdNsbu4Z0)rBep6URzvZPxV981Ch1mqtUp4fUMUyfEq5k243BYxEmX3IWuAf1qULbrCb9L)0BJ3uRtg2DcUWx()Y0DUeLKKnCsjpzMVzO3upzNWiczfX)A2DLd5OxPISQG51c5g53", "1kzaUrqiiu0ReqNmkhhlKE)pc9)bNDB6UjnnTRjJpa1rq(YRzSQzF5n913yhxU4xo4QMUn8l63JatFI)HpNZNFX1V4IEZ(U8JJk(8T5)y5Elp0(t1YrvdEy2mPHvXjvXmSbD2dLoiI1Fbx0S5hWoHRZLZiIAxzsQg85zLXqmACoggU5ZZZbUbcjScs0GCq6JilJ)8GzI6T1U)gzrKEB)oU39c2b9TmarunYYisyWfpY3py7o3D8dCS2QLgugX2FT5K1Xa(ziJ7sRhvwVQbE3z9aGYLsYjRJwAgP8dYSUiwSWHzMR(Pk)TzrSzUfJz0zqjUA(0Z95", "9ovcUrqimSVeHocipN0e1))tO2jq1QUs9qDuTMb7igiy8UT)fyghvtlgIh5VCL5QFg6M)DNaYvln9BB9pgQw(cIvYRLuZiG5J0ZcP3fwaSPUXlfCyiwpGE91961bbE9g0bkvhthoW1v1PxQoJwVAZzYRbeO7JXy26f16fTRUfKhsPXbH2Jql)w3lICU9vVIclQRn1OTc4eAxyhfSh5mwqHh2v86L6Ufm2znJWt4pOjbMEKIGmeA4Tz2KDNVT0(ZGjy6t987zgN7Wi2zsu06er7PtFKRoTmeQv)ljIAtDOQpoo57h7YzF(l49" }, jump = { -3, "ToDxUkqimua4TulHaTlNM29)AqO)mI61yYnt9HpfIgpWzG)1isk)LTLej5RZNFvo)Lt79sIOLuFdqK)X7zyws5AH)w4DnHJCKu2yb3AmInPHngBU2YgIOMw5ydIpvvIueg66nkm2Q4CgA2WuLrwNamM()KXyoD(0JTHzzqnALN38NJAzEkzxrHNUpkGTX99lA66MMvB9Yp91EO1fVc0LOrCA0pcRCCLNlVRYXVh5QVB(5MXUujX(YLaD8uZkhg7YgfvTq4WyJQWFv8VJ()J)", "TkzuYnmmiq0RKG6rcoouy69)iuqEjUPPFKoj8HEcjVYG0oEQWmqDdvnqfBBagWFePivKAubfrydhP1h1XbY)i3o)fYgdGHWetjz5lFp5FhZ1jMR11I6tkoa9BcZcKZAsfItgzbwKhm4EzI8GoPsfOqRrYyx96Wy3loJisoNvoTwjRpoMrPq9v41fPh(Es1gZDdDXU9oRVUh7M938vdT6hLY39So197pbFqZ2xm0MW3umo(C7ac70jCadbsR878hLVb527PdE9Wqn11MgWEakHCsP5pU)mnkr24MO4oXpO(AY7i((" }, fall = { -3, "TozuYrmimm0RumndGpoU2tV)hHkzmTj70pA7U6dEXdyIvgLJFLmROMqvROwBBfSc)Gqt6CYvG5QAkwDL2(QopR63W24vmtCqiKnriBnPLp8VvFCPq)JnhfDAgrAnnxL2XeOjbNWSwUqm6EilQC(rpZp8g9JRUlKqy4Iia7DwlJbioCe9qcvuFeo)G6boYGgPdDNl717RbDB2X4oFwHPHcddwvXoyLM5azLhKDU4lQBc5PrW9C(EMecBLioRGrvY6B5eMFSxOpEcrBOPT0CwZKEUr4zozgZ8GRK81h((W83cAi7WcF1KVp78XMEP6Zd", "fpzuUrmmiq0Re4nY2CC8oOE)pcLbCu3evTFuv1I21pWblnKmwEFSUsZUYB9Twl()1W(kXIFtltMtlRMtEK9rxwrR4XrTV9yodYMJKAvcQQk)7HtzPukjAnr4Qs2c6jY6nZTvfUMK7XbPbWMem)aSgWaeP7icP3H7qhJElEQ6E3v3udJOLrQKEFms07x55Jlbp2cFmUmh4N(cag1Vs1Wi(4fRMUewz1h3167j9goOVaoYK4f6XZ0h4B)WrbzxY6YVSTGNZXT55pncVSTrsAXljwA2IPJC6ZS)YbxjSN1lnZBhCJ4IKJ6q4S3BN(xj(8p" }, idle_shoot = { -4, "9kzysvmmiq4ReGzAYECIHX7)rWfi9P9noA)H6otZhPjmfkR89cpXFstzUfobYqubaOweGrOhjg6KOi2S1cc8cV94QUzz9hQXqdjIAMQMWhgyXwkxsW9jEW6wjuJjZxVwrGTgVzwWfwK(IsKdZzK07wSfU7Qh)gxxQLEUEC07XkvFJK5P5zXv3Cl9k1B3(S61ykZwjgTt2)rHrYc1l65OvL9iwqrKMbFfPX7Wao4NTxBNZ90x0My7pkFckRy(TO8Z(4A)8pQ0qpZkdzTMg98OyKfwKLxoLX2X8rGGDJWCC5ZjjsLLm8ViTFn9(d", "fpzuoommiq0Re4wzdhhlq9(Fe2bdjBAsuLw1p2rP5nGn1jccDNMZjURtnzyOYKmJHrEVQRs)1aRUKCq7fVrLQ)6KpFM8rTZTAou63lr40WTeBSDI8fYqTwCHFnZwEtEHahHAe7gYhR7Eqg5TOoNDToyQvM6K6wWEVBR7bhdGbPU3hJOhydWDv2ELl26X4plMVNe)gUTs0yDtzEUmC0Wv15QxJ8RUpLdceLRR0Av4MtZXZO5OHh0(8tAncUpN8FRT3I6A9rJBowbnB3IzlJskK4cTp3Vsi)1xd5e)w9d", "TovuUvmmiSReWQAchNOG29)imJjPR7V(MQFsXqcgfA8tUWGWXpYEfkRaWGCxqqhqKExbkvxQLL4IpoepZ(Qlu0nOMPMkpg9Nx6NI8QGBIc22SXTzUTyES(B9Gvw7CIJb1)gYcK6ttSycKQJiz1yAtdnG2qZpms(98oAC98S1YvG2zrTmipfnJfnJO9wZFII9CoraEVZnKHtsgJTfHSV50uqtt6xOZ5AhE2YhSCxvlC2CV8vyoACoCP9wZZNJ6kXbR4X6DjIIM70Ygs)FX1CYw48HnRoK)iBU4(8sgBqF3N)bER)p8Zp", "1o5cUnmmmm0ReLxqS1Xjqc7(Feg1NKTouS1v0Xc0NKJKRSdlU0rkLFsQvi6ascvbdwuaRLqvDD1n6MlUTbnYEBHSPVizmKHGhwRhV0)QIrHtIqoo5ixoZhnZhlFwpPK1AgFmX6D2MZu1gy4gv0T7bLrMcXfp)rJlge3N)G233RVj9zrLB3CId1CFENE612NZElM3KFVZFOIACozaFFxZOMi8baUMVPnZZCZdpr5ws)Y3csleA7bAG0Cau2QKMhJwSCWF5g5)r9mfdvXJEkCVGDMw2W0)xSoL15jk2JQDCtBwZLD1wUbRZ95j0R6)dFm", "1ozuUnqmiq0Re4gvBooRa17)rOdZ4DBJuuuAv7KpEgBgc7Aw7shub(rgAPTxaceHHfliZwlhsUUCBBZI3Uzrh92YOPVjFm8HBVSwVEQ)u1Tc6ehCCYb3MXJn5X(x5d6m3mXXaRpGTcHroSrLqT7QA6dgAE5f)td(EkEwJ9oeWCkwfzKOGtynRA(mVZ75K8bo6Rrxm6NtSq9fWXgDCf98GLzjw9mHMw48cNC499E74CQAtnLPAh7I2dxfATE)Ud7tNZ)Vl7hk1kDZiQNB(kxipd1yiN)f7pkoK1Jo5QZUS7SLBUYlBSaRZ68l0F13dFo", "1ozuUnqmiq0Re4gvBooRa17)rOdZ4DBJuuuAv7KpEgBgc7Aw7shub(rgAPTxaceHHfliZwlhsUUCBBZI3Uzrh92YOPVjFm8HBVSwVEQ)u1Tc6ehCCYb3MXJn5X(x5d6m3mXXaRpGTcHroSrLqT7QA6dgAE5f)td(EkEwJ9oeWCkwfzKOGtynRA(mVZ75K8bo6Rrxm6NtSq9fWXgDCf98GLzjw9mHMw48cNC499E74CQAtnLPAh7I2dxfATE)Ud7tNZ)Vl7hk1kDZiQNB(kxipd1yiN)f7pkoK1Jo5QZUS7SLBUYlBSaRZ68l0F13dFo", "1ozuUnqmiq0Re4gvBooRa17)rOdZ4DBJuuuAv7KpEgBgc7Aw7shub(rgAPTxaceHHfliZwlhsUUCBBZI3Uzrh92YOPVjFm8HBVSwVEQ)u1Tc6ehCCYb3MXJn5X(x5d6m3mXXaRpGTcHroSrLqT7QA6dgAE5f)td(EkEwJ9oeWCkwfzKOGtynRA(mVZ75K8bo6Rrxm6NtSq9fWXgDCf98GLzjw9mHMw48cNC499E74CQAtnLPAh7I2dxfATE)Ud7tNZ)Vl7hk1kDZiQNB(kxipd1yiN)f7pkoK1Jo5QZUS7SLBUYlBSaRZ68l0F13dFo" }, run_shoot = { 3, "1ov0UnqmiSFjGDQ54ZHf0())eMnKSP2kTk1PZpGnKJeqWjxgIiG1dpi8LGSxmSq)hzhBMQMDzDzcnhhxx1)cO)WEd5SbczkGOQbHbxaeJKLLfouO8tyoFGS2PZdPWSPXhXo)YmYtFsEcWhoZIV9of)Gjsm2rQNqQ6(X(7o3NhtvZQvp7UQtqCUMQI50moOpk5u0WZzEi(EFOxhWzUmZBjcGZhZwmIppGym6P9q2BkX6H9Ly3hJcV980FX5NpW)Mi3N9LTwm7nCj5cpNxzwj2K07i4EAw2)d0Fn4(Z489oX5YFL2(E(347d", "1kzuUnqmiq0ReMAfBooUG69)i0zWKnnsnQDLYoFWdRf8cgK3VwRfS2Yw0Z2ojTKWAicl1VL9Qa9kAfYKTExSj0hZlO8pLAImtrFT1W5wt1KkuBdn2aHqBRSqZsmjfeFWrwIQZVuL0nhmCi8t0iiVP4OjX4EH8VEjq03snoy1g6r7C2haiZYwjNRGCq5cpJsfpaCQ5CE)yeUbN)Eat4JGoG94ZoCgoJrgJ(Y(XsvDl16f)Yylz8OfVcnF5ZC2fSuwzhHjLLR3EebtiTClPUGz5vKjfz)HUFhchWZTZZXECjNOq)Rm((p", "Tk1covmqiWReS2yHJdUeV)hbh(Sn23R(mA60egGw2YSaDNWmdw10IdNM1KR8KksetcZY5QT0CfYdv1nCicWBsJNAHfRfRnV15xf8CL)lWLLhnnclOrgaCqeNeNMfuTYmKr86z9bYNW3rOgj8jquT7bZdeQoZth3fU8AHStV3yVSZ9cGVPHEiJCUU4yd4BZ9WIyvxZ)o)0YuqnqiU6t)JT4vEmTrvB5i0QDkkg(wVeHhYkhYBDCpYzDz(t8fvG2pAnXDpK6FDTkvSpR92WHkNh(VV4yp3IYb)RfM4Rd", "1kvBUvmmiSRuiRAfoomq7(FeMnKmPNu7BFP5Fed0ssCmJ)d4UJvZTMzWITI76iqTR72RLRqTPMDGnrbE52RWMxNGT4JvD9NPi5z1vv6TtKjRaAYvqZkbytOELn4cGUq93YuN8ZXSs13rCIuJfYaGDNjzzIudN9sp63srNJZxlenF(xT6secFDjv(6M5eGt7Cu(U1(oDWQUvZdIejIGMYkaIkFJUBK0Tr3hLf69m1GMVVgIyqC2Gm)E20483PSpFnFKVFCbV7UvdJrWRMQuhUXgI8RpWAGoB9GhHEUn3nIcxFFEIc0996r(MF)Jp", "9o1wsnqmmSR06WoeRJJjA4(Feq2UPuE8rPWG(WYzJtgBPSh)diIqreOsqL0mI760rh)gGFAVGpXpgSBsGMIQpaCKS7M71M2WSIgdftQJzshTulaop1HfEY3iRZgIvvRHDi2Fvxd1sS01XLWx7mFZ(VDUU3JSNk7Dan2jfP)QzmwS08SJLzguRrPBXyqMZHn0Ms9Sf1gSQr8ko5lsCwbt3gmolTE2VP2yEC8CH5CZxXLkMxR8pfr9kwndQ3Zi)c631UtYK8CcttTng)whA)paAXQ(lH9AM2RYj76Vq3CrpMj)b8g", "1ovqYnqimSVe4SdGFoe7P))NqLSnzAZHmtBMOdwAj4aAL32hd79gvDRBcTeK1Grf6x09(WuLS2Q)SglxxFUB)RrVFennrBLaljDaSfbcbpcG1ijEuXdu05wyp3qxN25psHiMWdrwFjcztnYgapy3bpgJ)WLEorbTm(jx2q(LV6p8NNuEMu8CmfMThEER9UbcG3oMt7l3IG3TEe7xn9mpKJdWokVmowWnFAEY(9lWZzM2GRjLDDWAjgZWwT57fO6)UropRvngmZj8CYx9iQI3IldX7JKo7EToFdWDhC9g3TNy)0XHxVNJl8n", "1k1wUnamiSRuGgvchNmq9(FeM5XIAL6uxLw9hyIcKayg))yV3WQBDhEA5KSMmSkIqt8SS3nfEnRnLjRZ5qxaxwFGY)TangReHpteoteZjZaurSxecjSuBbwnIKyW4cdznyEDJ5Gn1a7ga(e29IXrm8KFkK)0KarFnHC4Un4t78iSxoaicclLeujZ8sSq1LkM5uThelahjSOq)nhg3epCmtM(xt1DXZyezU17wQ6xPxVIBKcNbH8z051VoMZUikLD2rqP0C92C3JesBSL0pWQ9AosYZ(dtHkKqGxLZJXEEK3OqFvgFd", "Tkzaonqqiu0RemUXfooieV)hb5dSnP2TRwJ)MWdOLPddq)NYmlTQPnHZqTyNNurqmjml3xTvMZuDOQULhIK6nz0dxHdQn1HBt(JcESY)K42YRblytSQGu3aXf4YmkBQoZsw4R9(hiFM(rgQir4Pq1raYRmudM9iFlc56gzNO3lr7f299wjVQo)fEcymzY7eGfEnSSOM7yEJPFsvpM)Z(GBvgpQgXST4JnWahaIRrO17uuLBwIYpK1oum9X1TZVvhpMpJNuH7bUAsebA1xDTcDroy79w4qTZ3(FV4yV)kk34pwyPV(d", "1kv0UrmmiSFPKCrxGphwq7))ty2aDsNuBpnDA(HyWnjfhO9FaZmSQMMmdkwdo1rGONFAlwodXLQ6exIa84Ys4GR)Gw8S0L)MJ63PlspVUEFqfqdUcAejahe0JSgxaKcXU7dzWpVhrQ8nIDKQuW3a80UtUpqQ6szerU1rRw7zG2kO1EL4tB1Hju(ktk6RB3yokVSVVtD23yJLtbrEmp07BhrUU9iW0P)1K7Wz3g8mAHwE3TqRgIyWUSGx8h6OFFnFLVECbV7OI4WiTRAIqFyQepeV)hgd0E6h0yZ5w)4Gq4865ghih11R8fB)Nd", "9ozxUrmimq4ReMgv8CCCzuV)hHo2esxTTpSDBvhP4psWq8pq7FqreYIa1audweXdT6yz)gHFASG74Zj7Mbqzrfhaos6U5EnP1nRqVlBILnhSSwwlaoo0ILEX3k9Z6IYRz3AI(7ABOEftTDCk91iZ30)T51JUKDwzFkO0orK9xLJXKvnpJy1mdQ3rv3IENmZdRRjv1ZMutWYhXzCW3uXzgm72GXrvRhRZuBnATxlngBEPtpgxE(NQOofRGb15zKFbRZ1UtYeoNf8S9SW5tZ33bWQy1orBF1GC9F4vF138P6W3Rpo" }, jump_shoot = { -3, "TkDykmmmiua4Ru1vs8DCK49)mm1yOTdkSFeHTVyXgYBzh7SuvNFNIxmxekIO3E18PATqFw4P4tIiFE7OGx88N(nue5bjiweYmvYlPBYxseGNcphaqKyJymeFuH5Xi2rMTb18HXymAe8w3gIwZvQ8uk3oyD)tR16LTP9Q)iDhX3ZbI47XrZFhyOZNdmhOKkrkc1ih9Et1LNdZpzHrcMg)NPEPSUCLJ2kV77E9Flu55alTPMzlZbnzQugxw3YJnZNjlLuzELIhxTBR(c", "Tkzakoqmiu0Ru0ws0JJO07)rOFJoZclZclTZhkpDIjO1)47LAqj0IzGoQGIA(9mqY8HabqqY(s4y7AP1RQpXJiIQpKFPJMWoAM)GpBECHFU53kIymiGmZepgCQoVzFEw4MvorkPm5VErIeS7QJAdhIXReiAo5mDoNkfUMu9iI1Ym3bwxnhl8dLUAolU25rCxZ954NZHLbyhH)UPr5hY9)Mw990huS9hLtXqhHotXkEufx7TQ2ttK1b6oyFE438O8XcT0MDhjNSwoh20l9CsVro9YY9zn)h69" }, fall_shoot = { -3, "TkzuUrmmiq0RKHDLnCCSaT3)JqNXy3QwTB)jzKIEJtaliq76YNqeErA8wzk6890y8CZGifrSvs4ZZ3lVUv)jUeZC)H9hDkI5Py(aFU5jHFY8Ysu0iSBuvjvQwBHZ5IvCktyNgveIzQe2RqKuJWdeBgqkULeUEx5XEV7sgoPhzMJX)1hd8GqhB2lowNZ8U6Eix8TzsGzf)Tl1Eb3dwCUFVF4CnCJaTXyorfHkZXOUvbxZVk2VxMMBJVm32m8s6ujbmKzu)CTSgoN103nRq7LrfC(RGB2nUI(z91p", "flvakoqmiWVKAxs0NtqP))NqhJjTxVEfk0fUzz3zCJtqrPVh2aijR4uyujk2Y)NcnJjfy6KzDAchp(By1TAh4su1Sl6VWUig7I5n8XI3gE487bZSKKGNmsKjljiAsmxX88yyGR0xqviDhFe21RotH4U5Wr4a5Teq1Asg2AnJd3a)j9rhVi1(IBf3NXNqZVAhamKsXAENH2J9JCFyYJ9)l4re9(y4oiWrqOYmmYPk5AowEUVunwcK9)n277ZAlzhIKdVkonQH0ED9NZmBuUq7fELC8uYKEMRQVGB)" }, idle_gunless = { 8, "flzyQvmqiq4Ru03(d944tP3)JqDutAsE)PqdudSFJWolmr3EYYmlpvtBcX2iAU3lcOiKC19NL(JOKkmB4ORdZ3P2uhUwnFnoe5bZnXubI5tmplYd37HGgBOyoZbat1hZoUzWU8v2gU7k8abEBpkguIn5wqOhDG(lJFwd0UV(RdSp)VWWBM5YYl5ywrwgRuqwSEN0Sat7KRerVCOE1RkCITkp(hI7hv4Zw2SNJL0UpCaPXXS6yMLcTcITvXrBVAS)UNr(mh2LZ8pvFd", "flzyQvmqiq4Ru03(d944tP3)JqDutAsE)PqdudSFJWolmr3EYYmlpvtBcX2iAU3lcOiKC19NL(JOKkmB4ORdZ3P2uhUwnFnoe5bZnXubI5tmplYd37HGgBOyoZbat1hZoUzWU8v2gU7k8abEBpkguIn5wqOhDG(lJFwd0UV(RdSp)VWWBM5YYl5ywrwgRuqwSEN0Sat7KRerVCOE1RkCITkp(hI7hv4Zw2SNJL0UpCaPXXS6yMLcTcITvXrBVAS)UNr(mh2LZ8pvFd", "flzyQvmqiq4Ru03(d944tP3)JqDutAsE)PqdudSFJWolmr3EYYmlpvtBcX2iAU3lcOiKC19NL(JOKkmB4ORdZ3P2uhUwnFnoe5bZnXubI5tmplYd37HGgBOyoZbat1hZoUzWU8v2gU7k8abEBpkguIn5wqOhDG(lJFwd0UV(RdSp)VWWBM5YYl5ywrwgRuqwSEN0Sat7KRerVCOE1RkCITkp(hI7hv4Zw2SNJL0UpCaPXXS6yMLcTcITvXrBVAS)UNr(mh2LZ8pvFd", "flzyQvmqiq4Ru03(d944tP3)JqDutAsE)PqdudSFJWolmr3EYYmlpvtBcX2iAU3lcOiKC19NL(JOKkmB4ORdZ3P2uhUwnFnoe5bZnXubI5tmplYd37HGgBOyoZbat1hZoUzWU8v2gU7k8abEBpkguIn5wqOhDG(lJFwd0UV(RdSp)VWWBM5YYl5ywrwgRuqwSEN0Sat7KRerVCOE1RkCITkp(hI7hv4Zw2SNJL0UpCaPXXS6yMLcTcITvXrBVAS)UNr(mh2LZ8pvFd", "flzxoommiq4RKXRFaooSG69)iSd)y12K8w3OsR83GcGmgg3HPQItrLIHy0IIBFMVo7ZM8uKsjsgNNs(i7i2rUwf)H))AxMPQA0KsqZ5leNjNn3(HG42Oi4K4Ju(BoTisFA8d46MzsKtiIABqm2VG8HNs6wgSxB4Y29DYas5NV6b2Z)3OBQsKtOnIGSywrkAlii1x)cQQhtBWfGxlhIL(Iez(9nmx6(P3Y698yrVIqY7j711L3dlqek(BUKcDKUsS3cZhvzRIWo)w6mZF(s8F", "fpzxoiqmiq4Rub7dWXbH49)iidS14Vrt0nYd7hSTdbc0XoyMz5x10YrlNr7OfxXIOpv9RTozMnH4m6W7Qf9oo3O87AxriPshXebqmViJ)YflqBX15jsLTHlxehMhd6WnyxoXdoC3vKf4aXEakxkI9ys(rgA7UFlIVAhRk1yn)VHHNKccTXGu3WmYY2cowmp2et9KZerVDOEfRAP8VB5CPk9W1A)EGTuqSR2xjQcvAmWCE5GhdQh4UvwU6rcAxODtvkxEq(xx8Np", "fpzxoiqmiq4Rub7dWXbH49)iidS14Vrt0nYd7hSTdbc0XoyMz5x10YrlNr7OfxXIOpv9RTozMnH4m6W7Qf9oo3O87AxriPshXebqmViJ)YflqBX15jsLTHlxehMhd6WnyxoXdoC3vKf4aXEakxkI9ys(rgA7UFlIVAhRk1yn)VHHNKccTXGu3WmYY2cowmp2et9KZerVDOEfRAP8VB5CPk9W1A)EGTuqSR2xjQcvAmWCE5GhdQh4UvwU6rcAxODtvkxEq(xx8Np", "fpzxoiqmiq4Rub7dWXbH49)iidS14Vrt0nYd7hSTdbc0XoyMz5x10YrlNr7OfxXIOpv9RTozMnH4m6W7Qf9oo3O87AxriPshXebqmViJ)YflqBX15jsLTHlxehMhd6WnyxoXdoC3vKf4aXEakxkI9ys(rgA7UFlIVAhRk1yn)VHHNKccTXGu3WmYY2cowmp2et9KZerVDOEfRAP8VB5CPk9W1A)EGTuqSR2xjQcvAmWCE5GhdQh4UvwU6rcAxODtvkxEq(xx8Np", "fpzxoiqmiq4Rub7dWXbH49)iidS14Vrt0nYd7hSTdbc0XoyMz5x10YrlNr7OfxXIOpv9RTozMnH4m6W7Qf9oo3O87AxriPshXebqmViJ)YflqBX15jsLTHlxehMhd6WnyxoXdoC3vKf4aXEakxkI9ys(rgA7UFlIVAhRk1yn)VHHNKccTXGu3WmYY2cowmp2et9KZerVDOEfRAP8VB5CPk9W1A)EGTuqSR2xjQcvAmWCE5GhdQh4UvwU6rcAxODtvkxEq(xx8Np", "flzxoommiq4RKXRFaooSG69)iSd)y12K8w3OsR83GcGmgg3HPQItrLIHy0IIBFMVo7ZM8uKsjsgNNs(i7i2rUwf)H))AxMPQA0KsqZ5leNjNn3(HG42Oi4K4Ju(BoTisFA8d46MzsKtiIABqm2VG8HNs6wgSxB4Y29DYas5NV6b2Z)3OBQsKtOnIGSywrkAlii1x)cQQhtBWfGxlhIL(Iez(9nmx6(P3Y698yrVIqY7j711L3dlqek(BUKcDKUsS3cZhvzRIWo)w6mZF(s8F" }, run_gunless = { 3, "1ozuYnmmiq0RKq1Fioouy69)i0DxHMjF0PzIt7(HFifTYGHm(pvebE6HVjdA6I79)f3HE8tsxQ7xpnfo030B(uJVGqHOBDbPnSPjyZ5EPiXSrtZGvA7JvlJMS5IyMicC9fIlS05gvcr3fIgRoh6384Kc3u2l7qvXr87ab7RGSbAdUo1LhET)EXFpu)h1jlhCOS0qrujpugxXNKzPwxwxIXEMAWMF8h2dVV8Z8CCMdoPw5mLxOek1zeEymHuUXXIDG(ZbpgUa0F3VHoy14b7VvVw67d", "flzqUommiq0RKXnlmhhkOE)pcFMbsvuuYU2FNf(HTcXGhgFdzMLRQPfrqtLSohb61zBC5kXFQQBzQRupUTe2zFd730wF(6d2UOqyGmfczoRTKaZgnfbqsTAjijzUaMEgLC9kJJCRIdcpfslcqzITJ(Mh7LW)Te2fQMnuc4Rjl)h7JedP89r57w7)kNheXdouyHhWV8T4zYS5O1P(gjnFsKTvzB6pPNpjBFogLgyufMhraJbRhmO3tlK81qd(2OHxZTWGhvqFhRt8ED8NFK385)n", "1k1woiqimWReu3p6CCWoX7)rW(auXeJXK1j7YaLwABM2oxmYvmqXy8gx2Bqlw7pcCKlpawmEAX3c1FdOQ21c7joFIfJIRCIJJkJxQqEn2taZ(O3R1UKKiYKcUnplI7q4uI4GBrQFlUue9MVN(rextZS0lsldXpd07grtMnImRGidbSf325)b8scZnt9TTP)O0Gq52SBP6cVByOt041u3ORHURJdxclTVgnIWYhjMfIV1C2pGvaJtR7vV8hXijjBynwTMU(2uw1j0FHSI4VM9qxJuqRsfzvb67fYhW9p", "1k1wommmiSRuG1pGJtgOD)pcZ8iDpuLM2uhvngiVWXm(p2mh1PwOoFdR8Jf(0gN5WUPluFKbUQGZqfro(IZJyHAH1DPBBzE5ICI0DVoO6NOmGigryK5rbCMpqAWmwajLrraYW1VftYSCd(oc1yA3mlxL7bsmIL(nGBhMQcPUPXWw44v88mkT2t7ulDTF7lzrlDpuqTJHhrMRynUHpGGu(1qVmhBm09TP2TevRr0gfNv0jC605h0Ej4daZMrlPaE0TMGqFOnljHo94LaG3uY)2QyPRE3m6wvbISJhUV7)", "9kvuovmmmSRutPF0CCcX6D)pcy30IMEibmeG1wDI2IsCCB)licD6HxmdUYFALRQ)i8nFVjqC1YW)Yw)TH7LUyWCXZPvFXiRhRVsSE3ucXM6HwkCyeMxqV(7E9MKipFWyWup5NrsmgvNEP6mB9zeQG9G06pX)IynKwthMKNGx6T2lMD2(EwwrGAT5HKfOsKCPCurjCDxjGcsed86WZmGSDLhoYBz()Pqo4sN(5(SSZTjGTxGlwYXIAILMu1RLbd81fc0ayoYwMSuG6)X7w78Qh)tWPW3(", "nlvuQvqqiSRKA3pMCCSJ07)rOX4SuOukVp2cnFmrFpvmB0(drMjFrcfafmmeZu8RDNZ7panlGRRxDxW34heOb5vJ(h8W9M8iehehk8dPu3DGUR3w3qnfK5FVNYwFW2lMIDyrTjmlIQA(gRBE9iAYF5cLkoiXqTZ51U9jJBzBwgdaMdcDpKY)tpKCmFxYAOQuqEvVFXGS6PumNVSY5MYS5g6FaGUNH2OzN6vtAz0TevjVzpUZ9DY0EQQ1ys1JQf8dXuXHxNzS(AgpHv)5", "9kzqYnuimm0ReMWc8XXbn9(FeQKXKjTj)DTrl4zyWGb52)HIi4Oh(MkOONCVUc83NDKdVt5H6(GPoPUDzjCyDdNBAuRp)dFUQqYaRBjSEFpnPqVqrZemQzjtjz9PqFXiY5xmgCQRfWIsPbiADnTv3C7ucFAz6vqtHpitotBbHGfNS5Oryp8BXO8Fp7hmJjiFAbg403h4(q7aYT5WiTW08tUp2m7412huu)nFifN(yvAznSlSfaKXa8dd6r3sY83Wr(34yT7BXP6X5vm)fVwpF4pZl2(3", "1k1wsrmmmSRuI3(H1XjR1W9)iGvCsH2zaggw00gLx(vSAVwmMJyGIX4gx73GxS3pnCmhob2m(yNCk80hWDV7fUg4Pl2mkUIjooQi(Om5Z2(cWQo69ASBtYmBrIBR1MLxqxkb6ArUJv)Ho0m)TCoZLqhZiI5Tif3TC9a9EqaBvi2kdueeIn3UY)hilJ8rpc1RAbJ6TNN9Du9a15UOlc1DXiTGYuCWNhYwU64hPBQzL0qMnDI0c6B(ZyjTwm)2Cf30l)D4rWHKKKSHTSARU(jvwvjm9WmJ4Vn6QOviYxHzOiRmWVNiFbE)", "1k1wUrmmiWRKH6pGJJlO9(FewgaNUB2ivvPulfpW4xmzy8)mw5SU0c11jS4hB8LdUYPJHUr9hMiuL4ourKRF48k2Owy9w6CM8YxYnk3J6GQpIYeI4ilMzEuaN8aPbZXgiPgescgU(mSiZYJi2Jufl7Mz5UChiXrU0)d4oGPQqQxAmSnoEhVVbQesRO2FnpXO868IxlVaoO2TbbdrMRWFmpcWIt)7jSBVD85H7xTgOnc2p285Qr9gBH63UE)07fONac5Iwsb6OCdZh)sBwkcDbHhHU3s6px2BF17Mr3QkqKd8YZ98", "9o1wUnmmmSRKLx(W64OjHE)pcJ00EiTdyBf9brIPeSv0d60ElicU6HlggN5FnYz0)e(IVVkGSsz4)zQ)3WD1xWym5XW0ogy(y9PJ17gDawup4qbfdX4e660D9MGapUa7cUEITRe44qz6dLzK6DjiJvH063WprmlsRXfJThHR(vZfZ2tFpLueLgBEW2QqNW2fTddklN3vIIgzfh1NhTmJIAh9PeExI)lfubN9PVVpt5Cjc1slQtsYwIAK5vzg9Cyadp0FjvPpAclD46BDDCLXJHV(" }, salute = { -4, "nlzBQrmqiy4RK6o)W3JZSk9(FeQFLYUlbAGsG(cXNrYOrJsNl8b)nTP9iCauhrFaaTHa0uKQCQ6YzcQGAIHRvsGhkr67IeHf(If39kokfwO4jRPMItfcFzy9AMN7xm7FrmlBeX0VejPblOBHISlU3SDjN96R62(QZM7U)RXyremmmYrk4E0YOzuXfJgC8Z9bBAeF9SzVgqRazNMU24N)b2vmr2X)L(NqTxhC310(NAZTxbPU2mxGhEC5W6Vfe5(K)tcpmhh(J67)", "nl5sommmiq0RKHMfEooUG69)iuga3kfLDDrZeh)8pS8iyCPWQj2lCIN06JW3byJ8JnGz0AjukpZ(gqr084Ge4XmyhuZXqfvg3bjQk9VUP6AcjgO96eXM15fpi9VRMLgXMVuL0Gv0mE9UxSNoIitzl8VDE7FQLrczTIoGmj6EMtJ3VvZjpslv5CwpeRwg54zrF1ZJijJP2MwfKXnWDX)Lnw5lklDZs9ChVszF40NfZk4I7dh29uqDI(QOz)EWpQ3)", "fpzuommmim0RuGLpchNiq7(FegXalQRQAFmvnRT(QRce5gA7OM4QmLGs49BoYwXru1z5TyFJa4Am8FHOLy2xr1cjOKS3JD8b2JOOKUNyQDdIUG8h(DbmVIbh)nDr1yDb19EcDlBEqvJyLanIW7gt9fHEoEYypurdQk6VLmrZQdk5oI)P3dFFH4qwfei)CUfjBZwrmp0Xqv4HSmi9KV9IL5mc(CgEjFEnz()fIbYNGzx)sLL6ml5WIpxYryW6tSCSFxJDzTh6XVQx", "fpzuoqmiiq0RKW6hYXXazV)hHfgW20TPz)yttN00NyendITJAI)YuskzSp4iBloYSolFl2hiaUgd)lffIzFfRTqskf798eFHZitQOhtm1Ubrxq(R49eyMivzNSQMsaScNXMgqy2cojwPOqqgrOIyAKk83BgNHkAsvX(Bfl0S1fLCh2)uD43l0nImvHYbZyIqBSTi6h6OPkJHSYi9IBXIv(mn(CMXsn)QZ85fSb8NGE3OmuEzDNvCy5ZLQfgC9eRA73ZXUm3d7X)Qpd", } } } splashvars={ init = false, t = 0, l1 = { x = 0, y = 0, s = 1, a = 0, d = 0 }, l2 = { x = 0, y = 0, s = 1, a = 0, d = 0 }, l3 = { x = 0, y = 0, s = 1, a = 0, d = 0 }, l4 = { x = 0, y = 0, s = 1, a = 0, d = 0 }, l5 = { x = 0, y = 0, s = 1, a = 0, d = 0 }, p = { x = 0, y = 0 } } function BOOT() proc = Disclaimer end disclaimervars = {init = false} galleryvars = { init = false, pic = 1, pics = {} } t=0 function TIC() cls() DoFade() for i=0,15 do poke(0x3fc0 + (i*3), (pal[i][1] * fadelevel)) poke(0x3fc1 + (i*3), (pal[i][2] * fadelevel)) poke(0x3fc2 + (i*3), (pal[i][3] * fadelevel)) end proc() t=t+1 end function Disclaimer() print("DISCLAIMER",0,0,12) print("This is an unfinished prototype.",0,16,12) print("A full version of this game is currently",0,24,12) print("unlikely, but may happen in the future.",0,32,12) print("Press Z to continue",0,56,12) print("Press X for gallery",0,64,12) if btnp(4) then t=0 proc = DevEdSplash end if btnp(5) then proc = Gallery end end function Gallery() if galleryvars.init == false then galleryvars.init = true local m = math.random(3) music(m-1) galleryvars.pic = 1 sync(1<<1,2) end if galleryvars.pic == 1 then print("Title portrait",0,0,12) spr(256,80,16,0,1,0,0,16,16) end if galleryvars.pic == 2 then print("Time Killers thug concept",0,0,12) spr(256,120-64,8,0,1,0,0,16,16) end if galleryvars.pic == 3 then print("Time Killers thug shoot",0,0,12) player.x = 120 player.y = 68 player.anim = thuganims.idleshoot AnimatePlayer() if player.dir == "l" then spr(288,player.x-16,player.y-16,0,1,1,0,4,1) spr(292,player.x-16,player.y-8,0,1,1,0,4,1) spr(296,player.x-16,player.y,0,1,1,0,4,1) spr(300,player.x-16,player.y+8,0,1,1,0,4,1) elseif player.dir == "r" then spr(288,player.x-16,player.y-16,0,1,0,0,4,1) spr(292,player.x-16,player.y-8,0,1,0,0,4,1) spr(296,player.x-16,player.y,0,1,0,0,4,1) spr(300,player.x-16,player.y+8,0,1,0,0,4,1) end end if galleryvars.pic == 4 then print("Time Killers thug run+shoot",0,0,12) player.x = 120 player.y = 68 player.anim = thuganims.runshoot AnimatePlayer() if player.dir == "l" then spr(288,player.x-16,player.y-16,0,1,1,0,4,1) spr(292,player.x-16,player.y-8,0,1,1,0,4,1) spr(296,player.x-16,player.y,0,1,1,0,4,1) spr(300,player.x-16,player.y+8,0,1,1,0,4,1) elseif player.dir == "r" then spr(288,player.x-16,player.y-16,0,1,0,0,4,1) spr(292,player.x-16,player.y-8,0,1,0,0,4,1) spr(296,player.x-16,player.y,0,1,0,0,4,1) spr(300,player.x-16,player.y+8,0,1,0,0,4,1) end end if galleryvars.pic == 5 then print("Time Killers thug crouch+shoot",0,0,12) player.x = 120 player.y = 68 player.anim = thuganims.crouch AnimatePlayer() if player.dir == "l" then spr(288,player.x-16,player.y-16,0,1,1,0,4,1) spr(292,player.x-16,player.y-8,0,1,1,0,4,1) spr(296,player.x-16,player.y,0,1,1,0,4,1) spr(300,player.x-16,player.y+8,0,1,1,0,4,1) elseif player.dir == "r" then spr(288,player.x-16,player.y-16,0,1,0,0,4,1) spr(292,player.x-16,player.y-8,0,1,0,0,4,1) spr(296,player.x-16,player.y,0,1,0,0,4,1) spr(300,player.x-16,player.y+8,0,1,0,0,4,1) end end if galleryvars.pic == 6 then print("Time Killers thug die",0,0,12) player.x = 120 player.y = 68 player.anim = thuganims.die AnimatePlayer() if player.dir == "l" then spr(288,player.x-16,player.y-16,0,1,1,0,4,1) spr(292,player.x-16,player.y-8,0,1,1,0,4,1) spr(296,player.x-16,player.y,0,1,1,0,4,1) spr(300,player.x-16,player.y+8,0,1,1,0,4,1) elseif player.dir == "r" then spr(288,player.x-16,player.y-16,0,1,0,0,4,1) spr(292,player.x-16,player.y-8,0,1,0,0,4,1) spr(296,player.x-16,player.y,0,1,0,0,4,1) spr(300,player.x-16,player.y+8,0,1,0,0,4,1) end end if btnp(2) then galleryvars.pic = galleryvars.pic-1 end if btnp(3) then galleryvars.pic = galleryvars.pic+1 end if galleryvars.pic > 6 then galleryvars.pic = 1 end if galleryvars.pic < 1 then galleryvars.pic = 6 end if btnp(2) or btnp(3) then player.frame = 0 player.animtimer = 1 if galleryvars.pic == 1 then sync(1<<1,2) end if galleryvars.pic == 2 then sync(1<<1,3) end if galleryvars.pic >= 3 then sync(1<<1,0) end end print("Use left and right to select pics",0,128,12) end function DevEdSplash() if splashvars.init == false then splashvars.init = true vbank(0) sync(1<<3 | 1<<4,7,false) music(0) ss = 512 rs = 4 ls = 8 py = 425 psy = -4 timer = 6 * 60 end timer = timer - 1 if timer == 0 or btnp(4) then FadeOut() end if fadelevel < 0.01 then sync(1<<3 | 1<<4, 0) music() proc = Title end ss = lerp(ss, 1, 0.06) rs = lerp(rs, 8, 0.01) ls = lerp(ls, 1, 0.04) if psy < 0 then psy = psy + 0.0225 else if psy > 0 then psy = 0 end end py = py + psy -- update letters splashvars.l1.x = 88 + sin((t - 0)/rs) * ss splashvars.l2.x = 104 + sin((t - 8)/rs) * ss splashvars.l3.x = 120 + sin((t - 16)/rs) * ss splashvars.l4.x = 136 + sin((t - 24)/rs) * ss splashvars.l5.x = 152 + sin((t - 32)/rs) * ss splashvars.l1.y = 60 + cos((t - 0)/rs) * ss splashvars.l2.y = 60 + cos((t - 8)/rs) * ss splashvars.l3.y = 60 + cos((t - 16)/rs) * ss splashvars.l4.y = 60 + cos((t - 24)/rs) * ss splashvars.l5.y = 60 + cos((t - 32)/rs) * ss splashvars.l1.s = ls splashvars.l2.s = ls splashvars.l3.s = ls splashvars.l4.s = ls splashvars.l5.s = ls -- draw letters Splash_DrawLetterScaled(splashvars.l1.x, splashvars.l1.y, 0, 128, splashvars.l1.s) Splash_DrawLetterScaled(splashvars.l2.x, splashvars.l2.y, 16, 128, splashvars.l2.s) Splash_DrawLetterScaled(splashvars.l3.x, splashvars.l3.y, 32, 128, splashvars.l3.s) Splash_DrawLetterScaled(splashvars.l4.x, splashvars.l4.y, 16, 128, splashvars.l4.s) Splash_DrawLetterScaled(splashvars.l5.x, splashvars.l5.y, 0, 128, splashvars.l5.s) spr(262,84,py + sin(t/12),0,1,0,0,9,1) end function Splash_DrawLetterScaled(x,y,u,v,s) ttri( x - (s * 8), y - (s * 8), x + (s * 8), y - (s * 8), x - (s * 8), y + (s * 8), u + 0, v + 0, u + 16, v + 0, u + 0, v + 16, 0, 0) ttri( x + (s * 8), y - (s * 8), x - (s * 8), y + (s * 8), x + (s * 8), y + (s * 8), u + 16, v + 0, u + 0, v + 16, u + 16, v + 16, 0, 0) end function Title() if titlevars.init == false then titlevars.init = true FadeIn() end print("Title screen will go here",0,0) print("Press Z to play intro cutscene",0,8) if btnp(4) then proc = IntroCutscene end end skipprompt = 120 function IntroCutscene() if introcutscenevars.init == false then music(0) introcutscenevars.init = true player.x = 0 player.y = 64 FadeIn() local textpos = 0 local curtext = nil end DoFade() -- draw map map(0,119,30,17,0,0,0) -- draw chief spr(316,123,48,0,1,0,0,3,4) -- draw mouth if (introcutscenevars.chief.talkphase//8)%2 == 1 then spr(319,131,56,0,1,0,0,1,1) else spr(335,131,56,0,1,0,0,1,1) end if introcutscenevars.chief.talking then introcutscenevars.chief.talkphase = introcutscenevars.chief.talkphase + 1 else introcutscenevars.chief.talkphase = 0 end if introcutscenevars.pausetimer == 0 then if introcutscenevars.state == 0 then if player.x < 94 then player.anim = player.anims.run_gunless player.x = player.x + 2 else player.anim = player.anims.idle_gunless introcutscenevars.pausetimer = 30 introcutscenevars.state = 1 textpos = 0 curtext = introcutscenevars.script[1] introcutscenevars.textsound = 63 end elseif introcutscenevars.state == 1 then text = true if player.anim ~= player.anims.salute then player.frame = 0 player.animtimer = 0 player.anim = player.anims.salute end if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[2] introcutscenevars.textsound = 62 introcutscenevars.state = 2 introcutscenevars.chief.talking = true end elseif introcutscenevars.state == 2 then text = true if textpos == #curtext and btnp(4) then player.anim = player.anims.idle_gunless textpos = 0 curtext = introcutscenevars.script[3] introcutscenevars.state = 3 introcutscenevars.chief.talking = true end elseif introcutscenevars.state == 3 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[4] introcutscenevars.state = 4 introcutscenevars.chief.talking = true end elseif introcutscenevars.state == 4 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[5] introcutscenevars.state = 5 introcutscenevars.chief.talking = true end elseif introcutscenevars.state == 5 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[6] introcutscenevars.state = 6 introcutscenevars.chief.talking = false end elseif introcutscenevars.state == 6 then text = true introcutscenevars.textsound = 63 if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[7] introcutscenevars.state = 7 introcutscenevars.chief.talking = true end elseif introcutscenevars.state == 7 then text = true introcutscenevars.textsound = 62 if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[8] introcutscenevars.state = 8 introcutscenevars.chief.talking = true end elseif introcutscenevars.state == 8 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[9] introcutscenevars.state = 9 introcutscenevars.chief.talking = true end elseif introcutscenevars.state == 9 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[10] introcutscenevars.state = 10 introcutscenevars.chief.talking = true end elseif introcutscenevars.state == 10 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[11] introcutscenevars.state = 11 introcutscenevars.chief.talking = true end elseif introcutscenevars.state == 11 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[12] introcutscenevars.state = 12 introcutscenevars.textsound = 63 end elseif introcutscenevars.state == 12 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[13] introcutscenevars.state = 13 introcutscenevars.chief.talking = true introcutscenevars.textsound = 62 end elseif introcutscenevars.state == 13 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[14] introcutscenevars.state = 14 introcutscenevars.textsound = 63 end elseif introcutscenevars.state == 14 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[15] introcutscenevars.state = 15 introcutscenevars.chief.talking = true introcutscenevars.textsound = 62 end elseif introcutscenevars.state == 15 then text = true if textpos == #curtext and btnp(4) then textpos = 0 curtext = introcutscenevars.script[16] introcutscenevars.state = 16 introcutscenevars.chief.talking = true end elseif introcutscenevars.state == 16 then text = true if textpos == #curtext and btnp(4) then introcutscenevars.state = 17 end elseif introcutscenevars.state == 17 then text = false introcutscenevars.chief.talking = false player.anim = player.anims.run_gunless player.dir = "l" player.x = player.x - 2 if player.x < 0 then textpos = 0 curtext = introcutscenevars.script[17] introcutscenevars.state = 18 introcutscenevars.pausetimer = 60 end elseif introcutscenevars.state == 18 then text = true introcutscenevars.chief.talking = true if textpos == #curtext and btnp(4) and fadelevel == 1 then FadeOut() end if fadedone == true and fadelevel ~= 1 then proc = Game end else error("Cutscene machine broke") end else introcutscenevars.pausetimer = introcutscenevars.pausetimer - 1 end -- draw player AnimatePlayer() if player.dir == "l" then spr(288,player.x-16,player.y-16,0,1,1,0,4,1) spr(292,player.x-16,player.y-8,0,1,1,0,4,1) spr(296,player.x-16,player.y,0,1,1,0,4,1) spr(300,player.x-16,player.y+8,0,1,1,0,4,1) elseif player.dir == "r" then spr(288,player.x-16,player.y-16,0,1,0,0,4,1) spr(292,player.x-16,player.y-8,0,1,0,0,4,1) spr(296,player.x-16,player.y,0,1,0,0,4,1) spr(300,player.x-16,player.y+8,0,1,0,0,4,1) end if text == true then introcutscenevars.statetime = introcutscenevars.statetime + 1 if introcutscenevars.statetime%2 == 1 or (btn(4)) then if textpos < #curtext then if introcutscenevars.statetime%4 == 1 then sfx(introcutscenevars.textsound) end textpos = textpos + 1 end end if textpos == #curtext then introcutscenevars.chief.talking = false if (t//16)%2 == 1 then spr(271,223,126) end end end -- mask left side so player can walk through door rect(0,0,55,87,0) -- draw text box rectb(8,89,223,45,12) -- draw text if text == true and curtext ~= nil then print(string.sub(curtext,1,textpos),16,96,12) end -- draw skip prompt if skipprompt > 0 then skipprompt = skipprompt - 1 print("Press S to skip...") end -- skip if btnp(7) then proc = Game end end function Game() if btnp(7) then gamevars.init = false gamevars.level = gamevars.level + 1 objects = {} end if gamevars.init == false then gamevars.init = true FadeIn() player.dir = "r" player.x = 16 player.y = 88 player.vx = 0 player.vy = 0 gamevars.mx = 0 gamevars.my = 0 gamevars.tmy = 0 psx = 0 psy = 0 sync(1<<0 | 1<<2,gamevars.level) music(levelmusic[gamevars.level+1]) end -- read through the map for object tiles for y=(player.y//136)*17,240 do for x=0,240 do local o=mget(x,y) if o>=224 then mset(x,y,0) CreateObject((o-223),256,x*8,y*8,1,1,0,0) end end end if player.x < 120 then gamevars.mx = 0 elseif player.x > 1800 then gamevars.mx = 1800 else gamevars.mx = 120 - player.x end if player.y > gamevars.tmy + 136 and gamevars.tmy ~= 952 then gamevars.tmy = gamevars.tmy + 136 end if (player.y < gamevars.tmy) and gamevars.tmy ~= 0 and player.airborne == 0 then gamevars.tmy = gamevars.tmy - 136 end gamevars.my = lerp(gamevars.my,gamevars.tmy,0.1) -- background map(60,119,30,17,((gamevars.mx/4)%240)-240,0,0) map(60,119,30,17,((gamevars.mx/4)%240),0,0) map(60,119,30,17,((gamevars.mx/4)%240)+240,0,0) map(30,119,30,17,((gamevars.mx/2)%240)-240,0,0) map(30,119,30,17,((gamevars.mx/2)%240),0,0) map(30,119,30,17,((gamevars.mx/2)%240)+240,0,0) -- foreground if gamevars.my > gamevars.tmy then map(0,0,240,136,gamevars.mx,-math.floor(gamevars.my),0) elseif gamevars.my < gamevars.tmy then map(0,0,240,136,gamevars.mx,-math.ceil(gamevars.my),0) else map(0,0,240,136,gamevars.mx,-gamevars.tmy,0) end AnimatePlayer() -- do camera if player.x < 120 then psx = player.x elseif player.x > 1800 then psx = player.x - 1800 else psx = 120 end if gamevars.my < gamevars.tmy then psy = math.floor(player.y - gamevars.my) elseif gamevars.my > gamevars.tmy then psy = math.ceil(player.y - gamevars.my) else psy = player.y - gamevars.my end --movement if btn(2) and not btn(3) then if player.airborne == 0 then if btn(5) then player.anim = player.anims.run_shoot else player.anim = player.anims.run end end player.dir = "l" if player.vx > 0 then player.vx = 0 end if player.vx > -2 then player.vx = player.vx -0.2 else player.vx = -2 end end if btn(3) and not btn(2) then if player.airborne == 0 then if btn(5) then player.anim = player.anims.run_shoot else player.anim = player.anims.run end end player.dir = "r" if player.vx < 0 then player.vx = 0 end if player.vx < 2 then player.vx = player.vx + 0.2 else player.vx = 2 end end if btn(2) == false and btn(3) == false then if player.dir == "l" and player.vx < 0 then player.vx = player.vx + 0.1 elseif player.dir == "r" and player.vx > 0 then player.vx = player.vx - 0.1 else if player.airborne == 0 then if btn(5) then if btnp(5) then player.frame = 0 player.animtimer = 1 end player.anim = player.anims.idle_shoot else player.anim = player.anims.idle end end player.vx = 0 end end if player.airborne == 0 and player.vy > 1.5 then player.airborne = 2 if btn(5) then player.anim = player.anims.fall_shoot else player.anim = player.anims.fall end --player.frame = -1 end -- get collision points local oxl = 8 local oxr = 8 local oyu = 12 local oyg = 15 local oyd = 16 local om = (oyd - oyu) // 3 local tl = mget((player.x-oxl)//8, (player.y-oyu)//8) local tc = mget((player.x)//8, (player.y-oyu)//8) local tr = mget((player.x+oxr)//8, (player.y-oyu)//8) local bl = mget((player.x-oxl)//8, (player.y+oyd)//8) local bc = mget((player.x)//8, (player.y+oyd)//8) local br = mget((player.x+oxr)//8, (player.y+oyd)//8) local gl = mget((player.x-oxl)//8, (player.y+oyg)//8) local gc = mget((player.x)//8, (player.y+oyg)//8) local gr = mget((player.x+oxr)//8, (player.y+oyg)//8) local l1 = mget((player.x-oxl)//8,(player.y-om)//8) local l2 = mget((player.x-oxl)//8,(player.y+om)//8) local r1 = mget((player.x+oxr)//8,(player.y-om)//8) local r2 = mget((player.x+oxr)//8,(player.y+om)//8) local q = gamevars.level if player.dir == "l" then if not IsSolid(q,tl) and not IsSolid(q,gl) and not IsSolid(q,l1) and not IsSolid(q,l2) then player.x = player.x + player.vx end end if player.dir == "r" then if not IsSolid(q,tr) and not IsSolid(q,gr) and not IsSolid(q,r1) and not IsSolid(q,r2) then player.x = player.x + player.vx end end if player.dir == "l" then if (IsSolid(q,tl) or IsSolid(q,gl) or IsSolid(q,l1) or IsSolid(q,l2)) then if player.airborne == 0 then player.vx = 0 end end end if player.dir == "r" then if (IsSolid(q,tr) or IsSolid(q,gr) or IsSolid(q,r1) or IsSolid(q,r2)) then if player.airborne == 0 then player.vx = 0 end end end -- since we may have moved, recalculate collision points local oxl = 8 local oxr = 8 local tl = mget((player.x-oxl)//8, (player.y-oyu)//8) local tc = mget((player.x)//8, (player.y-oyu)//8) local tr = mget((player.x+oxr)//8, (player.y-oyu)//8) local bl = mget((player.x-oxl)//8, (player.y+oyd)//8) local bc = mget((player.x)//8, (player.y+oyd)//8) local br = mget((player.x+oxr)//8, (player.y+oyd)//8) local gl = mget((player.x-oxl)//8, (player.y+oyg)//8) local gc = mget((player.x)//8, (player.y+oyg)//8) local gr = mget((player.x+oxr)//8, (player.y+oyg)//8) local l1 = mget((player.x-oxl)//8,(player.y-om)//8) local l2 = mget((player.x-oxl)//8,(player.y+om)//8) local r1 = mget((player.x+oxr)//8,(player.y-om)//8) local r2 = mget((player.x+oxr)//8,(player.y+om)//8) -- jumping + air physics if btnp(4) and player.airborne == 0 then sfx(48) player.airborne = 1 player.vy = -3.6 if btn(5) then player.anim = player.anims.jump_shoot else player.anim = player.anims.jump end player.frame = -1 end -- recalculate collsions again local tl = mget((player.x-oxl)//8, (player.y-oyu)//8) local tc = mget((player.x)//8, (player.y-oyu)//8) local tr = mget((player.x+oxr)//8, (player.y-oyu)//8) local bl = mget((player.x-oxl)//8, (player.y+oyd)//8) local bc = mget((player.x)//8, (player.y+oyd)//8) local br = mget((player.x+oxr)//8, (player.y+oyd)//8) local gl = mget((player.x-oxl)//8, (player.y+oyg)//8) local gc = mget((player.x)//8, (player.y+oyg)//8) local gr = mget((player.x+oxr)//8, (player.y+oyg)//8) local l1 = mget((player.x-oxl)//8,(player.y-om)//8) local l2 = mget((player.x-oxl)//8,(player.y+om)//8) local r1 = mget((player.x+oxr)//8,(player.y-om)//8) local r2 = mget((player.x+oxr)//8,(player.y+om)//8) if player.airborne == 1 and player.vy >= 0 then player.airborne = 2 player.anim = player.anims.fall player.frame = -1 end if not btn(4) and player.airborne == 1 then player.airborne = 2 player.vy = player.vy / 2 end if keyp(28) then player.weapon = 0 end if keyp(29) then player.weapon = 1 end if keyp(30) then player.weapon = 2 end if keyp(31) then player.weapon = 3 end local gox = 6 local goy = -8 if btnp(5) then player.weapontime = 0 if player.weapon == 0 then sfx(50) if player.dir == "l" then table.insert(bullets,{278,false,player.x-(gox+8),player.y+goy,-4,0,0}) end if player.dir == "r" then table.insert(bullets,{278,false,player.x+gox,player.y+goy,4,0,0}) end end if player.weapon == 2 and player.weaponneedscooldown == false then sfx(57) end end if btn(5) then if player.weapon == 1 and player.weapontime%5 == 1 then sfx(52) if player.dir == "l" then table.insert(bullets,{279,false,player.x-(gox+8),player.y+goy,-4,0,0}) end if player.dir == "r" then table.insert(bullets,{279,false,player.x+gox,player.y+goy,4,0,0}) end end if player.weapon == 2 then if player.weaponcooldown < 100 and player.weaponneedscooldown == false then if player.weapontime%2 == 1 then sfx(57) end player.vx = 0 player.vy = 0 player.weaponcooldown = player.weaponcooldown + 5 if player.dir == "l" then table.insert(bullets,{280,false,player.x-(gox+8),player.y+goy,-8,0,0}) end if player.dir == "r" then table.insert(bullets,{280,false,player.x+gox,player.y+goy,8,0,0}) end else player.weaponneedscooldown = true end end if player.weapon == 3 then if player.weaponneedscooldown == false then player.weaponcooldown = 100 player.weaponneedscooldown = true sfx(58) if player.dir == "l" then table.insert(bullets,{281,false,player.x-(gox+8),player.y+goy,-2.5,-0.75,0}) table.insert(bullets,{281,false,player.x-(gox+8),player.y+goy,-2.75,-0.375,0}) table.insert(bullets,{281,false,player.x-(gox+8),player.y+goy,-2.875,0,0}) table.insert(bullets,{281,false,player.x-(gox+8),player.y+goy,-2.75,0.375,0}) table.insert(bullets,{281,false,player.x-(gox+8),player.y+goy,-2.5,0.75,0}) end if player.dir == "r" then table.insert(bullets,{281,false,player.x+gox,player.y+goy,2.5,-0.75,0}) table.insert(bullets,{281,false,player.x+gox,player.y+goy,2.75,-0.375,0}) table.insert(bullets,{281,false,player.x+gox,player.y+goy,2.875,0,0}) table.insert(bullets,{281,false,player.x+gox,player.y+goy,2.75,0.375,0}) table.insert(bullets,{281,false,player.x+gox,player.y+goy,2.5,0.75,0}) end end end player.weapontime = player.weapontime + 1 end if player.weapon == 2 then if player.weaponcooldown > 0 then player.weaponcooldown = player.weaponcooldown-1 else player.weaponneedscooldown = false end end if player.weapon == 3 then if player.weaponcooldown > 0 then player.weaponcooldown = player.weaponcooldown-5 else player.weaponneedscooldown = false end end -- gravity if player.vy < 8 then player.vy = player.vy + 0.15 end -- ceiling / ground collision if player.vy > 0 then if IsSolid(q,bc) or IsTopsolid(q,bc) then if player.airborne ~= 0 then player.airborne = 0 if player.vy > 3 then sfx(49) end end if player.vx ~= 0 then if btn(5) then player.anim = player.anims.run_shoot else player.anim = player.anims.run end end player.vy = 0 player.y = (player.y//8)*8 else player.y = player.y + player.vy end else local oxl = 5 local oxr = 5 local tl = mget((player.x-oxl)//8, (player.y-oyu)//8) local tc = mget((player.x)//8, (player.y-oyu)//8) local tr = mget((player.x+oxr)//8, (player.y-oyu)//8) if IsSolid(q,tl) or IsSolid(q,tc) or IsSolid(q,tr) then sfx(56) player.vy = 0 player.y = player.y + player.vy else player.y = player.y + player.vy end end ProcessObjects() -- draw player sprite if player.dir == "l" then spr(288,psx-16,psy-16,0,1,1,0,4,1) spr(292,psx-16,psy-8,0,1,1,0,4,1) spr(296,psx-16,psy,0,1,1,0,4,1) spr(300,psx-16,psy+8,0,1,1,0,4,1) elseif player.dir == "r" then spr(288,psx-16,psy-16,0,1,0,0,4,1) spr(292,psx-16,psy-8,0,1,0,0,4,1) spr(296,psx-16,psy,0,1,0,0,4,1) spr(300,psx-16,psy+8,0,1,0,0,4,1) end ProcessBullets() if player.x < 4 then player.x = 4 end end function StageClear() if stageclearvars.init == false then stageclearvars.init = true FadeIn() end print("Stage clear screen will go here",0,0) print("Press Z to go to stage select",0,8) end function Credits() if creditsvars.init == false then creditsvars.init = true FadeIn() end print("Temp credits screen",0,0) print("Code:",0,16) print("DevEd",0,24) print("Graphics:",0,40) print("DevEd",0,48) print("mirageofher",0,56) print("Music and SFX:",0,72) print("DevEd",0,80) print("Press any button to go restart",0,96) if btn() then proc = DevEdSplash end end function DummyProc() FadeIn() print("dummy process") end function lerp(source, target, speed) return source + speed * (target - source) end function FadeOut() fadedir = "out" fadespeed = 0.025 fadedone = false end function FadeIn() fadedir = "in" fadespeed = 0.025 fadedone = false end function DoFade() if fadedir == "out" then if fadelevel > 0.01 then fadelevel = fadelevel - fadespeed else fadedone = true end elseif fadedir == "in" then if fadelevel < 1 then fadelevel = fadelevel + fadespeed else fadedone = true end end end function IsSolid(q,id) if solids[q+1][id] ~= nil then return solids[q+1][id] else return false end end function IsTopsolid(q,id) if topsolids[q+1][id] ~= nil then return topsolids[q+1][id] else return false end end function ProcessBullets() for i=1,#bullets do if bullets[i] ~= nil then bullets[i][6] = bullets[i][6] + bullets[i][7] -- gravity bullets[i][3] = bullets[i][3] + bullets[i][5] -- x velocity bullets[i][4] = bullets[i][4] + bullets[i][6] -- y velocity spr(bullets[i][1],bullets[i][3]+gamevars.mx,bullets[i][4]-gamevars.my,0,1,0,0,1,1) if bullets[i][3] > -gamevars.mx + 240 or bullets[i][3] < -gamevars.mx then table.remove(bullets,i) end end end end function AnimatePlayer() if player.frame > #player.anim-2 then player.frame = 2 end if player.animtimer == 0 then player.animtimer = math.abs(player.anim[1]) if player.anim[1] >= 0 then player.frame = math.fmod(player.frame+1,#player.anim-1) else if player.frame < #player.anim-2 then player.frame = player.frame + 1 end end local sprdat = "" local sprdat_cmp = player.anim[player.frame + 2] -- sprites are deflate compressed and stored as printable strings in the code -- so we need to decode them first if sprdat_cmp == nil then sprdat_cmp = "dWp" end local sprdat_dec = LibDeflate:DecodeForPrint(sprdat_cmp) if sprdat_dec ~= nil then sprdat = LibDeflate:DecompressDeflate(sprdat_dec) end -- now decompress -- transfer to VRAM if sprdat ~= nil then for i=1,#sprdat - 2 do poke4((0x6400 * 2) + i-1,tonumber(string.sub(sprdat,i,i),16)) end end else player.animtimer = player.animtimer - 1 end end -- 2d object handler function CreateObject(ai,sp,px,py) local grav=0 ttl=-1 dowrap=false -- object-specific creation code -- 01 - weapon pickup if ai==1 then sp=302 + ((math.random(4)*2)//1) grav=0.1 flags={["airborne"]=false,["dead"]=false} sx=2 sy=2 ttl = (60 * 5) end -- 02 - attack drone if ai==2 then sp=312 sx=2 sy=2 flags = {["airborne"]=true,["dead"]=false} end -- 03 - explosion if ai == 3 then sp = 400 sx = 2 sy = 2 end -- 04 - killed grunt -- 05 - stationary grunt if ai == 5 then sp = 336 sx = 4 sy = 4 end -- 17 - proximity bomb if ai == 17 then sp = 340 sx = 1 sy = 1 end ittl=ttl ox=0 oy=0 st=0 vx=0 vy=0 flags={} table.insert(objects,{ai,sp,px,py,sx,sy,vx,vy,cs,grav,ttl,ittl,ox,oy,st,flags}) end function DrawObjects() xp=x yp=y for x=#objects,1,-1 do if objects[x]~=nil then local ai=objects[x][1] local sp=objects[x][2] local px=objects[x][3] local py=objects[x][4] local sx=objects[x][5] local sy=objects[x][6] -- TODO: don't draw sprite if this is a grunt (grunts have their own draw routine) spr(sp,px+(gamevars.mx),py-(gamevars.my),0,1,0,0,sx,sy) end end end function ProcessObjects() local xp=x local yp=y for x=#objects,1,-1 do if objects[x] ~= nil then -- get object vars local ai=objects[x][1] local sp=objects[x][2] local px=objects[x][3] local py=objects[x][4] local sx=objects[x][5] local sy=objects[x][6] local vx=objects[x][7] local vy=objects[x][8] local cs=objects[x][9] local grav=objects[x][10] local ttl=objects[x][11] local ittl=objects[x][12] local ox=objects[x][13] local oy=objects[x][14] local st=objects[x][15] local flags=objects[x][16] local xp1=(player.x-4) local yp1=(player.y-4) local xp2=(player.x+4) local yp2=(player.y+4) local cx=px+(sx*4) local cy=py+(sy*4) pcol=isColliding(xp1,xp2,yp1,yp2,px,px+(sx*8)-1,py,py+(sy*8)) -- player collision fcol=(IsSolid(gamevars.level,mget(px//8,(py+(sy*8))//8)) or IsSolid(gamevars.level,mget((px+(sx*8)-1)//8,(py+(sy*8))//8))) or (IsTopsolid(gamevars.level,mget(px//8,(py+(sy*8))//8)) or IsTopsolid(gamevars.level,mget((px+(sx*8)-1)//8,(py+(sy*8)//8)))) -- floor collision ccol=(IsSolid(gamevars.level,mget(px//8,py//8)) or IsSolid(gamevars.level,mget((px+(sx*8)-1)//8,py//8))) -- ceiling collision wcol=(IsSolid(gamevars.level,mget(px//8,cy//8)) or IsSolid(gamevars.level,mget((px+(sx*8))//8,cy//8))) -- wall collision -- AI methods -- object 00 - null object if ai == 0 then ai = -1 end -- object 01 - weapon pickup if ai==1 then if IsSolid(gamevars.level,mget(px//8,py//8)) then py = py - 8 end if wcol then px = px-vx vx=-vx end if vy<0 then if ccol then py=py-vy vy=-vy/4 end else if fcol then flags["airborne"]=false py=py-vy vy=0 end end if not (IsSolid(gamevars.level,mget((cx+(vx*8))//8,(py+(sy*8)+4)//8)) or IsTopsolid(gamevars.level,mget((cx+(vx*8))//8,(py+(sy*8)+4)//8))) and not flags["airborne"] then flags["airborne"]=true vy=-2 end if (IsSolid(gamevars.level, mget((cx+(vx*16))//8,cy//8)) or IsTopsolid(gamevars.level, mget((cx+(vx*16))//8,cy//8))) and not flags["airborne"] then flags["airborne"]=true vy=-2 end if pcol then ai = -1 sfx(54) player.weapon = ((sp-302)//2)-1 end end -- object 02 - attack drone if ai == 2 then vy = math.sin((st/128)*16) if player.x > px - 256 and player.x < px + 256 then px = px - 0.5 else vy = 0 st = 0 end for i=1,#bullets do if bullets[i] ~= nil then if bullets[i][3] > px-(sx*8) and bullets[i][3]+8 < px+(sx*8) then if bullets[i][4] > py-(sy*8) and bullets[i][4]+8 < py+(sy*8) then table.remove(bullets,i) ai = -1 sfx(46) CreateObject(3,256,px,py,1,1,0,0) if math.random(16)//1 == 1 then CreateObject(1,256,px,py,1,1,0,0) end end end end end end -- object 03 - drone explosion if ai == 3 then if st % 2 == 1 then sp = sp + 2 end if sp == 416 then ai = -1 end end -- object 04 - killed thug if ai == 4 then if py > gamevars.my+136 then ai = -1 end -- TODO: draw sprite end -- object 05 - stationary thug if ai == 5 then for i=1,#bullets do if bullets[i] ~= nil then if bullets[i][3] > px and bullets[i][3]+8 < px+(sx*8) then if bullets[i][4] > py and bullets[i][4]+8 < py+(sy*8) then table.remove(bullets,i) ai = 4 grav = 0.1 vy = -4 if math.random(16)//1 == 1 then CreateObject(1,256,px+8,py+8,1,1,0,0) end end end end end -- TODO: draw sprite end -- object 17 - proximity bomb if ai == 17 then if player.x > px-48 then sfx(46) CreateObject(3,256,px-4,py-4,1,1,0,0) mset(px//8,(py//8)+1,0) ai = -1 end if t%8<=2 then sp = 341 else sp = 340 end end -- default case if ai==-1 then table.remove(objects,x) else -- gravity vy=vy+grav -- get position px=px+vx py=py+vy -- do ttl if ttl>-1 then ttl=ttl-1 end st=st+1 -- we're done, store vars back objects[x][1]=ai objects[x][2]=sp objects[x][3]=px objects[x][4]=py objects[x][5]=sx objects[x][6]=sy objects[x][7]=vx objects[x][8]=vy objects[x][9]=cs objects[x][10]=grav objects[x][11]=ttl objects[x][12]=ittl objects[x][13]=ox objects[x][14]=oy objects[x][15]=st objects[x][16]=flags -- remove object if TTL is over if ttl<=0 and ttl~=-1 then table.remove(objects,x) end end end end DrawObjects() end function isColliding(px1,px2,py1,py2,ox1,ox2,oy1,oy2) local colX=(px1ox1) or (px2>ox1 and px2oy1) or (py2>oy1 and py2