commit d0307c8765be66aba4888d4709dc8727a2c8626f Author: Squishy (C6H12O6+NaCl+H2O) <106439598+SweetSea-ButImNotSweet@users.noreply.github.com> Date: Thu Apr 11 08:33:58 2024 +0700 first commit diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a59b386 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "Lua.diagnostics.globals": [ + "love" + ] +} \ No newline at end of file diff --git a/conf.lua b/conf.lua new file mode 100644 index 0000000..de55417 --- /dev/null +++ b/conf.lua @@ -0,0 +1,11 @@ +function love.conf(t) + t.identity = "tromi_ver3" + t.externalstorage=true + +-- t.console = true + + t.window.title = "Tromi" + t.window.width = 1280 + t.window.height = 960 + t.window.vsync = false +end diff --git a/funcs.lua b/funcs.lua new file mode 100644 index 0000000..5a1d69f --- /dev/null +++ b/funcs.lua @@ -0,0 +1,162 @@ +function copy(t) + -- returns deep copy of t (as opposed to the shallow copy you get from var = t) + if type(t) ~= "table" then return t end + local meta = getmetatable(t) + local target = {} + for k, v in pairs(t) do target[k] = v end + setmetatable(target, meta) + return target +end + +function strTrueValues(tbl) + -- returns a concatenation of all the keys in tbl with value true, separated with spaces + str = "" + for k, v in pairs(tbl) do + if v == true then + str = str .. k .. " " + end + end + return str +end + +function frameTime(min, sec, hth) + -- returns a time in frames from a time in minutes-seconds-hundredths format + if min == nil then min = 0 end + if sec == nil then sec = 0 end + if hth == nil then hth = 0 end + return min*3600 + sec*60 + math.ceil(hth * 0.6) +end + +function vAdd(v1, v2) + -- returns the sum of vectors v1 and v2 + return { + x = v1.x + v2.x, + y = v1.y + v2.y + } +end + +function vNeg(v) + -- returns the opposite of vector v + return { + x = -v.x, + y = -v.y + } +end + +function formatTime(frames) + -- returns a mm:ss:hh (h=hundredths) representation of the time in frames given + if frames < 0 then return formatTime(0) end + local min, sec, hund + min = math.floor(frames/3600) + sec = math.floor(frames/60) % 60 + hund = math.floor(frames/.6) % 100 + str = string.format("%02d:%02d.%02d", min, sec, hund) + return str +end + +function formatBigNum(number) + -- returns a string representing a number with commas as thousands separator (e.g. 12,345,678) + local s + if type(number) == "number" then + s = string.format("%d", number) + elseif type(number) == "string" then + if not tonumber(number) then + return + else + s = number + end + else + return + end + local pos = Mod1(string.len(s), 3) + return string.sub(s, 1, pos) + .. string.gsub(string.sub(s, pos+1), "(...)", ",%1") +end + +function Mod1(n, m) + -- returns a number congruent to n modulo m in the range [1;m] (as opposed to [0;m-1]) + return ((n-1) % m) + 1 +end + +function table.contains(table, element) + for _, value in pairs(table) do + if value == element then + return true + end + end + return false +end + +function table.highest(table) + local i = 1 + local highest = nil + for key, value in pairs(table) do + if highest == nil then highest = key end + if table[key] > table[highest] then highest = key end + end + return highest +end + +function table.lowest(table) + local i = 1 + local lowest = nil + for key, value in pairs(table) do + if lowest == nil then lowest = key end + if table[key] < table[lowest] then lowest = key end + end + return lowest +end + +function clamp(x, min, max) + if max < min then + min, max = max, min + end + return x < min and min or (x > max and max or x) +end + +function drawText(text, x, y, size, orientation, color) + if color == nil then color = {1, 1, 1, 1} end + love.graphics.setFont(tromi_font) + love.graphics.setColor(0, 0, 0, 0.8) + love.graphics.printf(text, x+1, y+1, size*2, orientation, nil, 0.50) + love.graphics.setColor(color) + love.graphics.printf(text, x, y, size*2, orientation, nil, 0.5) +end + +function drawBigText(text, x, y, size, orientation, color) + if color == nil then color = {1, 1, 1, 1} end + love.graphics.setFont(big_font) + love.graphics.setColor(0, 0, 0, 0.8) + love.graphics.printf(text, x+1, y+1, size*2, orientation, nil, 0.50) + love.graphics.setColor(color) + love.graphics.printf(text, x, y, size*2, orientation, nil, 0.5) +end + +function boolToInt(value) + if value then return 1 else return 0 end +end + +function pairsByKeysReverse (t, f) + local a = {} + for n in pairs(t) do table.insert(a, n) end + table.sort(a, f) + local i = #t+1 -- iterator variable + local iter = function () -- iterator function + i = i - 1 + if a[i] == nil then return nil + else return a[i], t[a[i]] + end + end + return iter +end + +function split_string(inputstr, sep) + if sep == nil then + sep = "%s" + end + local t={} + for str in string.gmatch(inputstr, "([^"..sep.."]+)") do + table.insert(t, str) + end + return t +end diff --git a/game/gamemode.lua b/game/gamemode.lua new file mode 100644 index 0000000..2ee571f --- /dev/null +++ b/game/gamemode.lua @@ -0,0 +1,1154 @@ +local Object = require 'libs.classic' +local bit = require("bit") +local lualzw = require 'libs.lualzw' +local binser = require 'libs.binser' +require 'funcs' +require 'load.save' + +local playedReadySE = false +local playedGoSE = false + +local Grid = require 'game.grid' +local Randomizer = require 'game.randomizer' +local Piece = require 'game.piece' + +local GameMode = Object:extend() + +function GameMode:new(player_name, input_file, replay_grade) + if player_name == nil then self.training = true else self.training = false end + if input_file ~= nil then + input_file = io.open(REPLAY_DIR..input_file, 'rb'):read('a') + input_file = lualzw.decompress(input_file) + seed = self:getInputPieceSeq(input_file) + self.replay_inputs = self:getReplayInputs(input_file) + self.randomizer = Randomizer(false, tonumber(seed)) + self.input_playback = true + self.grade = replay_grade + self.frames = 1 + elseif self.training then + player_name = 'TRN' + replay_grade = 'N/A' + self.randomizer = Randomizer(false, nil) + self.input_playback = false + self.frames = 0 + else + self.randomizer = Randomizer(false, nil) + self.input_playback = false + self.frames = 0 + end + self.player_name = player_name + self.grid = Grid(10, 20) + self.piece = nil + self.ready_frames = 100 + self.game_over_frames = 0 + self.are = 0 + self.lcd = 0 + self.das = { direction = "none", frames = -1 } + self.move = "none" + self.prev_inputs = {} + self.next_queue = {} + self.game_over = false + self.clear = false + self.completed = false + self.next_queue_length = 1 + self.irs = true + self.drop_locked = false + self.hard_drop_locked = false + self.cleared_block_table = {} + self.last_lcd = 0 + self.grade_score = 0 + self.did_grades = false + self.active_frames = 0 + self.total_lines = 0 + self.lineClearPoints = {[0]=0, 0, 1667, 3750, 6668, 8335} + self.gradeNames = { + "19k", "18k", "17k", "16k", "15k", "14k", "13k", "12k", "11k", "10k", + "9k", "8k", "7k", "6k", "5k", "4k", "3k", "2k", "1k", + "1D", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D" + } + self.promo_table = { + 26666, 53333, 79999, 106666, 133333, 159999, 186666, 213333, 239999, 266666, + 293333, 319999, 346666, 373333, 399999, 426666, 453333, 479999, 506666, + 533333, 559999, 586666, 613333, 639999, 666666, 693333, 719999, 719999 + } + self.autopromo_table = { + 79999, 106666, 133333, 159999, 186666, 213333, 239999, 266666, 293333, 319999, + 346666, 373333, 399999, 426666, 453333, 479999, 506666, 533333, 559999, + 586666, 613333, 639999, 666666, 693333, 719999, 746666, 773333, 1000000 + } + self.demo_table = { + -1, 13332, 25000, 40000, 50000, 60000, 60000, 120000, 120000, 120000, + 180000, 180000, 240000, 240000, 300000, 300000, 360000, 360000, 360000, + 420000, 420000, 480000, 480000, 480000, 480000, 540000, 540000, 540000 + } + self.speed_divisor = 10000 + self.line_clear_flash = 0 + self.lines_cleared = 0 + sounds['bgm_firsthalf']:setVolume(0.3) + sounds['bgm_secondhalf']:setVolume(0.35) + self.audio_stopped = false + self.recorded_inputs = {} + self.input_saved = false + self.end_grid_clear = false + self.last_active = 0 + self.move_count = 0 + self.target = 0 + self.last_percent = 0 + self.total_speed_loss = 0 + self.grade_change_flash = 1 + self.grade_change_color = {1,1,1,1} + self.point_flash = 0 + self.point_flash_color = {1,1,1,1} + self.end_game_sound = nil + self.speed_level = 0 + self.last_level = 0 + self.nextbgmflag = false + self.firstbgmlooped = false + self.last_holes = 0 + self.last_meter = 0 + self.speed_table = {} + self.holes_bonus_freeze = 0 + self.holes_bonus = 0 + self.last_speed = 0 + self.holes_bonus_lines = 0 + self.bonus_components = {speed=1666,clean=750} + self.score_totals = {clean=0,speed=0,lines=0} + self.score_percents = {clean=0,speed=0,lines=0} + self.directions_pressed = {} + self.lines_bonus = 0 + self.moved = false + self.midspeed_flash = false + self.lastdir = 1 + self.spin_rng = {0,0,0,0,0,0,0,0,0,0} + self.lastlock = 0 + self.up_lock = false + -- gravity, are, lock, das + self.delay_table = { + [0]={0.013, 20, 30, 12},{0.015, 20, 30, 12},{0.016, 20, 30, 12},{0.018, 20, 30, 12},{0.021, 20, 30, 12},{0.025, 20, 30, 12}, + {0.027, 20, 30, 12},{0.030, 20, 30, 12},{0.033, 20, 30, 12},{0.038, 20, 30, 12},{0.043, 20, 30, 12},{0.051, 20, 30, 12}, + {0.056, 20, 30, 12},{0.062, 20, 30, 12},{0.070, 20, 30, 12},{0.079, 20, 30, 12},{0.092, 20, 30, 12},{0.109, 20, 30, 12}, + {0.120, 20, 30, 12},{0.134, 20, 30, 12},{0.152, 20, 30, 12},{0.175, 20, 30, 12},{0.206, 20, 30, 12},{0.250, 20, 30, 12}, + {0.281, 20, 30, 12},{0.319, 20, 30, 12},{0.370, 20, 30, 12},{0.441, 20, 30, 12},{0.545, 20, 30, 12},{0.712, 20, 30, 12}, + {0.842, 20, 30, 12},{1.029, 20, 30, 12},{1.323, 20, 30, 12},{1.852, 20, 30, 11},{3.086, 20, 30, 10},{9.259, 20, 30, 9}, + {20, 20, 30, 8},{20, 20, 30, 8},{20, 19, 28, 8},{20, 18, 27, 8},{20, 17, 26, 8},{20, 17, 25, 8}, + {20, 16, 24, 8},{20, 16, 23, 8},{20, 15, 23, 8},{20, 15, 22, 8},{20, 14, 21, 8},{20, 14, 21, 8}, + {20, 14, 20, 8},{20, 13, 20, 8},{20, 13, 20, 8},{20, 13, 19, 8},{20, 13, 19, 8},{20, 13, 19, 8}, + {20, 12, 18, 8} + } + if not self.input_playback and not self.training and not PENTO_MODE then + self:readGradeHistory() + end +end + +function GameMode:readGradeHistory() + outfile = io.open(SAVE_DIR..self.player_name.."_grade_history.sav", 'rb') + if outfile ~= nil then + self.grade_history = binser.deserialize(outfile:read('a'))[1] + outfile:close() + else + self.grade_history = {1,2,0,0} + end + self.grade = self.grade_history[1] + self.starting_grade = self.grade + if self.grade > 1 then + temp_grade = copy(self.grade_history) + temp_grade[2] = 0 + gradefile = io.open(SAVE_DIR..self.player_name.."_grade_history.sav", 'wb') + gradefile:write(binser.serialize(temp_grade)) + gradefile:close() + end +end + +function GameMode:readHiScores() + outfile = io.open(HIscoreFILE, 'rb') + if outfile ~= nil then + self.hi_scores = binser.deserialize(outfile:read('a'))[1] + outfile:close() + else + self.hi_scores = {"TRO",0,"MIT",0,"ROM",0,"ITR",0,"OMI",0} + end +end + +function GameMode:updateGradeHistory() + promo_string = "" + if self.grade_score >= self.promo_table[self.grade] then + if (self.grade == 28 and self.grade_history[2] < 4) or self.grade < 28 then self.grade_history[2] = self.grade_history[2] + 1 end + self.point_flash = 60 + self.point_flash_color = {0,1,0,1} + elseif self.grade_score <= self.demo_table[self.grade] then + if (self.grade == 1 and self.grade_history[2] > 0) or self.grade > 1 then self.grade_history[2] = self.grade_history[2] - 1 end + self.point_flash = 60 + self.point_flash_color = {1,0,0,1} + end + local auto_flag = false + while self.grade_score >= self.autopromo_table[self.grade] and self.grade < 28 do + self.grade = self.grade + 1 + self.point_flash = 1 + self.grade_change_flash = 120 + self.grade_change_color = {0,0,1,1} + self.end_game_sound = "autopromote" + auto_flag = true + end + if self.grade_history[2] >= 5 and self.grade < 28 and auto_flag == false then + self.grade = self.grade + 1 + self.point_flash = 1 + self.grade_change_flash = 120 + self.grade_change_color = {0,1,0,1} + self.end_game_sound = "promote" + elseif self.grade_history[2] < 0 and self.grade > 1 and auto_flag == false then + self.grade = self.grade - 1 + self.point_flash = 1 + self.grade_change_flash = 120 + self.grade_change_color = {1,0,0,1} + self.end_game_sound = "demote" + end + if self.starting_grade ~= self.grade then + self.grade_history[1] = self.grade + self.grade_history[2] = 2 + end + self.grade_history[4] = self.grade_history[4] + 1 + return promo_string +end + +function GameMode:updateHiScores() + self:readHiScores() + hiscore_pos = {0,0} + i = 2 + score_position = -1 + while i <= 10 do + if score_position == -1 and self.hi_scores[i] < self.grade_score then + score_position = i + end + i = i + 2 + end + if score_position ~= -1 then + i = 8 + while i >= score_position-1 do + self.hi_scores[i+2] = self.hi_scores[i] + i = i - 1 + end + self.hi_scores[score_position-1] = self.player_name:upper() + self.hi_scores[score_position] = self.grade_score + hiscore_pos = {score_position-1, score_position} + end + local scoresfile = io.open(HIscoreFILE, 'wb') + scoresfile:write(binser.serialize(self.hi_scores)) + scoresfile:close() + return hiscore_pos +end + +function GameMode:getARR() return 1 end +function GameMode:getDropSpeed() return 1 end +function GameMode:getARE() + if self.training then return 20 end + if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][2] + else return self.delay_table[#self.delay_table][2] end +end + +function GameMode:getLineARE() return self:getARE() end + +function GameMode:getLockDelay() + if self.training then return 99999999999 end + if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][3] + else return self.delay_table[#self.delay_table][3] end +end + +function GameMode:getLineClearDelay() return self:getARE() end + +function GameMode:getDasLimit() + if self.training then return 8 end + if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][4] + else return self.delay_table[#self.delay_table][4] end +end +function GameMode:getDasCutDelay() return 0 end + +function GameMode:getGravity() + if self.training then return 20 end + if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][1] + else return self.delay_table[#self.delay_table][1] end +end + +function GameMode:getNextPiece(ruleset) + local shape = self.randomizer:nextPiece() + return { + skin = self:getSkin(), + shape = shape, + orientation = ruleset:getDefaultOrientation(shape), + } +end + +function GameMode:getSkin() + return "2tie" +end + +function GameMode:initialize(ruleset) + self.ruleset = ruleset + for i = 1, math.max(self.next_queue_length, 1) do + table.insert(self.next_queue, self:getNextPiece(ruleset)) + end +end + +function GameMode:saveInputs() + input_string = 'NEW'..string.format("%16d", self.randomizer.seed)..';' + for frame, input_set in pairs(self.recorded_inputs) do + input_string = input_string..string.format('%03d', tostring(input_set)) + end + local inputfile = love.fileSystem.newFile(REPLAY_DIR..tostring(os.time()).."_"..self.player_name.."_"..self.starting_grade.."_"..self.grade_score.."_replay"..'.sav', 'wb') + inputfile:write(lualzw.compress(input_string)) + inputfile:close() +end + +function GameMode:storeInput(input_set) + input_right = 1 + input_rotright2 = 2 + input_up = 4 + input_rotleft = 8 + input_left = 16 + input_down = 32 + input_rotright = 64 + input_rotleft2 = 128 + if not input_set['right'] then input_right = 0 end + if not input_set['rotate_right2'] then input_rotright2 = 0 end + if not input_set['up'] then input_up = 0 end + if not input_set['rotate_left'] then input_rotleft = 0 end + if not input_set['left'] then input_left = 0 end + if not input_set['down'] then input_down = 0 end + if not input_set['rotate_right'] then input_rotright = 0 end + if not input_set['rotate_left2'] then input_rotleft2 = 0 end + self.recorded_inputs[self.frames] = bit.bor(input_right, input_rotright2, input_up, input_rotleft, input_left, input_down, input_rotright, input_rotleft2) +end + +function GameMode:getInputPieceSeq(input_file) + local seed = '' + if string.sub(input_file, 1, 3) == 'NEW' then + string_start = 4 + self.old_replay = false + else + string_start = 1 + self.old_replay = true + end + for i = string_start, #input_file do + c = string.sub(input_file, i, i) + if c == ';' then break + else seed = seed..c + end + end + return seed +end + +function GameMode:getReplayInputs(input_file) + input_right = 1 + input_rotright2 = 2 + input_up = 4 + input_rotleft = 8 + input_left = 16 + input_down = 32 + input_rotright = 64 + input_rotleft2 = 128 + replay_inputs = {} + reached_inputs = false + i = 1 + while not reached_inputs do + c = string.sub(input_file,i,i) + if c == ';' then + reached_inputs = true + end + i = i+1 + end + if reached_inputs then + while i <= #input_file - 3 do + input_list = {right = false, rotate_right2 = false, up = false, rotate_left = false, left = false, down = false, rotate_right = false, rotate_left2 = false} + coded_input = tonumber(string.sub(input_file, i, i+2)) + if bit.band(coded_input, input_right) == 1 then input_list["right"] = true end + if bit.band(coded_input, input_rotright2) == 2 then input_list["rotate_right2"] = true end + if bit.band(coded_input, input_up) == 4 then input_list["up"] = true end + if bit.band(coded_input, input_rotleft) == 8 then input_list["rotate_left"] = true end + if bit.band(coded_input, input_left) == 16 then input_list["left"] = true end + if bit.band(coded_input, input_down) == 32 then input_list["down"] = true end + if bit.band(coded_input, input_rotright) == 64 then input_list["rotate_right"] = true end + if bit.band(coded_input, input_rotleft2) == 128 then input_list["rotate_left2"] = true end + table.insert(replay_inputs, input_list) + i = i + 3 + end + end + return replay_inputs +end + +function GameMode:update(inputs, ruleset) + if self.input_playback and self.replay_inputs[self.frames] ~= nil then + inputs = self.replay_inputs[self.frames] + end + if self.grade_change_flash > 0 and self.game_over_frames >= 2 then self.grade_change_flash = self.grade_change_flash - 1 end + if self.point_flash > 0 and self.game_over_frames >= 2 then self.point_flash = self.point_flash - 1 end + if self.game_over_frames == 2 then + playSEOnce(self.end_game_sound) + end + if self.game_over or self.completed then + self.game_over_frames = self.game_over_frames + 1 + if self.game_over_frames == 1 then self:storeInput(inputs) end + if self.lcd > 0 then + self.lcd = self.lcd - 1 + elseif self.game_over_frames == 30 then + local cleared_row_count = self.grid:getClearedRowCount() + self.grid:clearClearedRows() + self:afterLineClear(cleared_row_count) + elseif not self.input_playback and not self.input_saved and not self.training and not PENTO_MODE and self.game_over_frames == 50 then + self:saveInputs() + self.input_saved = true + end + return + end + if inputs["up"] and self.training and not self.up_lock then + table.remove(self.next_queue, 1) + table.insert(self.next_queue, self:getNextPiece(ruleset)) + self.up_lock = true + end + if not inputs["up"] then self.up_lock = false end + local dir_list = {"down", "left", "right"} + for i = 1, #dir_list do + if inputs[dir_list[i]] and not table.contains(self.directions_pressed, dir_list[i]) then + table.insert(self.directions_pressed, dir_list[i]) + elseif not inputs[dir_list[i]] then + for j=1, #self.directions_pressed do + if self.directions_pressed[j] == dir_list[i] then table.remove(self.directions_pressed, j) end + end + end + end + if #self.directions_pressed > 0 then + for i=1, #self.directions_pressed-1 do + inputs[self.directions_pressed[i]] = false + end + inputs[self.directions_pressed[#self.directions_pressed]] = true + if inputs['left'] then self.lastdir = -1 + elseif inputs['right'] then self.lastdir = 1 end + end + + -- advance one frame + + if self:advanceOneFrame(inputs, ruleset) == false then return end + + self:chargeDAS(inputs, self:getDasLimit(), self:getARR()) + + -- set attempt flags + if inputs["left"] or inputs["right"] then self:onAttemptPieceMove(self.piece, self.grid) end + if ( + inputs["rotate_left"] or inputs["rotate_right"] or + inputs["rotate_left2"] or inputs["rotate_right2"] + ) then + self:onAttemptPieceRotate(self.piece, self.grid) + end + + if self.piece == nil then + self:processDelays(inputs, ruleset) + else + self:whilePieceActive() + local gravity = self:getGravity() + + -- diff vars to use in checks + local piece_y = self.piece.position.y + local piece_x = self.piece.position.x + local piece_rot = self.piece.rotation + ruleset:processPiece( + inputs, self.piece, self.grid, gravity, self.prev_inputs, self.move, + self:getLockDelay(), self:getDropSpeed(), + self.drop_locked, self.hard_drop_locked, + false, false, false, self.lastdir + ) + + local piece_dy = self.piece.position.y - piece_y + local piece_dx = self.piece.position.x - piece_x + local piece_drot = self.piece.rotation - piece_rot + + -- das cut + if ( + (piece_dy ~= 0 and (inputs.up or inputs.down)) or + (piece_drot ~= 0 and ( + inputs.rotate_left or inputs.rotate_right or + inputs.rotate_left2 or inputs.rotate_right2 + )) + ) then + self:dasCut() + end + + if (piece_dx ~= 0) then + self.piece.last_rotated = false + self:onPieceMove(self.piece, self.grid, piece_dx) + end + if (piece_dy ~= 0) then + self.piece.last_rotated = false + self:onPieceDrop(self.piece, self.grid, piece_dy) + end + if (piece_drot ~= 0) then + self.piece.last_rotated = true + self:onPieceRotate(self.piece, self.grid, piece_drot) + end + + if inputs["down"] == true then + if self.piece:isDropBlocked(self.grid) and not self.drop_locked then + self.lastlock = self.piece.lock_delay + self.piece.locked = true + self.piece_soft_locked = true + end + end + + if self.piece.locked == true then + local last_x = self.piece.position.x + self.grid:applyPiece(self.piece) + + local cleared_row_count = self.grid:getClearedRowCount() + self:onPieceLock(self.piece, cleared_row_count) + if not self.training then self:updateScore(cleared_row_count) end + + self.cleared_block_table = self.grid:markClearedRows() + self.piece = nil + + if cleared_row_count > 0 then + for i=1, #self.spin_rng do + local spin = math.abs(i-(last_x+3)) + --if spin < 0 then spin = 0 end + self.spin_rng[i] = spin + end + playSE("erase") + self.lcd = self:getLineClearDelay() + self.last_lcd = self.lcd + self.are = self:getLineARE() + if self.lcd == 0 then + self.grid:clearClearedRows() + self:afterLineClear(cleared_row_count) + if self.are == 0 then + self:initializeOrHold(inputs, ruleset) + end + end + self:onLineClear(cleared_row_count) + else + self.are = self:getARE() + end + + end + end + self.moved = false + if not self.input_playback and not self.game_over and not self.completed and not self.training and not PENTO_MODE then self:storeInput(inputs) end + self.prev_inputs = inputs +end + +function GameMode:detectHoles(x, y) + if y < 1 then return true end -- reached the top, no hole + local cell = self.grid:getCell(x, y) + if table.contains(self.visited, x..'.'..y) then + return false + else + table.insert(self.visited, x..'.'..y) + end + if cell.colour ~= "" or cell.oob then return false end + if self:detectHoles(x+1, y, attempt_num) then return true end + if self:detectHoles(x-1, y, attempt_num) then return true end + if self:detectHoles(x, y+1, attempt_num) then return true end + if self:detectHoles(x, y-1, attempt_num) then return true end + return false +end + +function GameMode:stackQualityCheck() + local hole_num = 0 + self.visited = {} + for x=1, 10 do + for y = 1, 20 do + if self.grid:getCell(x, y).colour == "" and not table.contains(self.visited, x..'.'..y) then + stack_clean = self:detectHoles(x, y) + if not stack_clean then + hole_num = hole_num + 1 + end + end + end + end + return hole_num +end + +function GameMode:doStackQuality() + local total_speed = 0 + local contiguous_holes = self:stackQualityCheck() + local total_speed = 0 + if contiguous_holes > self.last_holes then + self.speed_table[1] = 0 + self.last_percent = 0 + end + for i=1, #self.speed_table do + total_speed = total_speed + self.speed_table[i] + end + if total_speed <= 0 then total_speed = 0.001 end + self.total_speed_loss = total_speed / #self.speed_table + if #self.speed_table == 0 then self.total_speed_loss = 0 end + self.last_holes = contiguous_holes +end + +function GameMode:doSpeedCheck() + self.target = self.move_count + local speed = (self.target/self.active_frames) + if speed > 1 then speed = 1 end + table.insert(self.speed_table, 1, speed) + while #self.speed_table > 50 do + table.remove(self.speed_table, #self.speed_table) + end + local total_speed = 0 + for i=1, #self.speed_table do + total_speed = total_speed + self.speed_table[i] + end + if total_speed <= 0 then total_speed = 0.001 end + self.total_speed_loss = total_speed / #self.speed_table + if #self.speed_table == 0 then self.total_speed_loss = 0 end + self.last_active = self.active_frames + self.last_percent = speed + self.active_frames = 0 + self.move_count = 0 +end + +function GameMode:updateScore(cleared_lines) + self:doSpeedCheck() + if cleared_lines >= 1 then + while cleared_lines+self.total_lines > 300 do + cleared_lines = cleared_lines - 1 + end + self.last_speed = math.ceil(self.total_speed_loss * self.bonus_components['speed'] * cleared_lines) + self.line_clear_flash = 240 + self.lines_cleared = cleared_lines + self.score_to_add = self.lineClearPoints[cleared_lines] + self.last_speed + self.grade_score = self.grade_score + self.score_to_add + self.last_meter = self.holes_bonus + self.last_speed + self.speed_level = math.floor(self.grade_score / self.speed_divisor) + self.score_totals['speed'] = self.score_totals['speed'] + self.last_speed + self.score_totals['lines'] = self.score_totals['lines'] + self.lineClearPoints[cleared_lines] + end +end + +function GameMode:advanceOneFrame() + if self.ready_frames ~= 0 and not self.audio_stopped and not self.training then + if sounds['bgm_title']:getVolume() > 0.01 then sounds['bgm_title']:setVolume(sounds['bgm_title']:getVolume()-0.01) end + if self.ready_frames == 5 then + love.audio.stop() + self.audio_stopped = true + end + end + if self.training and not sounds['bgm_title']:isPlaying() and config["music"] then sounds['bgm_title']:play() end + if not self.training then + if self.nextbgmflag and sounds['bgm_firsthalf']:isPlaying() then + if sounds['bgm_firsthalf']:getVolume() > 0.1 then + sounds['bgm_firsthalf']:setVolume(sounds['bgm_firsthalf']:getVolume()-0.01) + else + sounds['bgm_firsthalf']:stop() + end + end + if self.ready_frames < 1 and not sounds['bgm_firsthalf']:isPlaying() and not sounds['bgm_secondhalf']:isPlaying() and config["music"] then + if not self.nextbgmflag then sounds['bgm_firsthalf']:play() + elseif self.total_lines < 296 then sounds['bgm_secondhalf']:play() end + end + if self.total_lines >= 296 then + sounds['bgm_firsthalf']:stop() + sounds['bgm_secondhalf']:stop() + end + end + if self.clear then + self.completed = true + end + self.frames = self.frames + 1 + if self.input_playback == true and self.old_replay == true and self.ready_frames ~= 0 then + self.frames = 0 + end + if self.line_clear_flash > 0 then self.line_clear_flash = self.line_clear_flash - 1 end + if self.line_clear_flash == 0 then + self.lines_cleared = 0 + self.score_to_add = 0 + self.last_meter = 0 + self.holes_bonus = 0 + self.last_speed = 0 + self.holes_bonus_lines = 0 + self.lines_bonus_lines = 0 + self.lines_bonus = 0 + end + return true +end + +-- event functions +function GameMode:whilePieceActive() + self.active_frames = self.active_frames + 1 +end +function GameMode:onAttemptPieceMove(piece, grid) end +function GameMode:onAttemptPieceRotate(piece, grid) end +function GameMode:onPieceMove(piece, grid, dx) + if not self.moved then + self.move_count = self.move_count + 1 + self.moved = true + end +end +function GameMode:onPieceRotate(piece, grid, drot) + if not self.moved then + self.move_count = self.move_count + 1 + self.moved = true + end +end +function GameMode:onPieceDrop(piece, grid, dy) + if not self.moved then + self.move_count = self.move_count + 1 + self.moved = true + end +end +function GameMode:onPieceLock(piece, cleared_row_count) + if not self.moved then + self.move_count = self.move_count + 1 + self.moved = true + end + self.lastdir = 0 + playSE("lock") +end + +function GameMode:onLineClear(cleared_row_count) + if not self.training then self.total_lines = math.min(self.total_lines + cleared_row_count, 300) end + if self.total_lines == 300 and not self.clear then + self.clear = true + end +end + +function GameMode:afterLineClear(cleared_row_count) end + +function GameMode:onPieceEnter() + self:doStackQuality() +end + +function GameMode:onGameOver() + if not self.input_playback and not self.training and not PENTO_MODE then + if not self.did_grades then + self.grade_score = self.grade_score + self.speed_level + promo_string = self:updateGradeHistory() + hiscore_pos = self:updateHiScores() + gradefile = io.open(SAVE_DIR..self.player_name.."_grade_history.sav", 'wb') + gradefile:write(binser.serialize(self.grade_history)) + gradefile:close() + self.did_grades = true + end + self:drawEndScoringInfo() + elseif not self.did_grades then + self.grade_score = self.grade_score + self.speed_level + self.did_grades = true + end + if PENTO_MODE and not self.training then self:drawEndScoringInfo() end +end + +function GameMode:drawEndScoringInfo() + love.graphics.setColor(1, 1, 1, 1) + drawText("Score: ", 247, 135, 1000, "left") + drawBigText(string.format("%s", self.grade_score), 247, 150, 100, "center") + if not PENTO_MODE then + drawText("Best scores:", 247, 220, 1000, "left") + + i = 2 + while i <= 10 do + if i == hiscore_pos[1] or i == hiscore_pos[2] then + drawText(self.hi_scores[i-1]..' - '..self.hi_scores[i], 255, 220+(i*10), 1000, "left", {0,1,0,1}) + else + drawText(self.hi_scores[i-1]..' - '..self.hi_scores[i], 255, 220+(i*10), 1000, "left") + end + i = i + 2 + end + end +end + +function GameMode:onGameComplete() + self:onGameOver() +end + +-- DAS functions + +function GameMode:startRightDAS() + self.move = "right" + self.das = { direction = "right", frames = 0 } + if self:getDasLimit() == 0 then + self:continueDAS() + end +end + +function GameMode:startLeftDAS() + self.move = "left" + self.das = { direction = "left", frames = 0 } + if self:getDasLimit() == 0 then + self:continueDAS() + end +end + +function GameMode:continueDAS() + local das_frames = self.das.frames + 1 + if das_frames >= self:getDasLimit() then + if self.das.direction == "left" then + self.move = (self:getARR() == 0 and "speed" or "") .. "left" + self.das.frames = self:getDasLimit() - self:getARR() + elseif self.das.direction == "right" then + self.move = (self:getARR() == 0 and "speed" or "") .. "right" + self.das.frames = self:getDasLimit() - self:getARR() + end + else + self.move = "none" + self.das.frames = das_frames + end +end + +function GameMode:stopDAS() + self.move = "none" + self.das = { direction = "none", frames = -1 } +end + +function GameMode:chargeDAS(inputs) + if inputs[self.das.direction] == true then + self:continueDAS() + elseif inputs["right"] == true then + self:startRightDAS() + elseif inputs["left"] == true then + self:startLeftDAS() + else + self:stopDAS() + end +end + +function GameMode:dasCut() + self.das.frames = math.max( + self.das.frames - self:getDasCutDelay(), + -(self:getDasCutDelay() + 1) + ) +end + +function GameMode:processDelays(inputs, ruleset, drop_speed) + if self.ready_frames == 100 then + playedReadySE = false + playedGoSE = false + end + if self.ready_frames > 0 then + if not playedReadySE then + playedReadySE = true + playSEOnce("ready") + end + self.ready_frames = self.ready_frames - 1 + if self.ready_frames == 0 then + self:initializeOrHold(inputs, ruleset) + end + elseif self.lcd > 0 then + self.lcd = self.lcd - 1 + if self.lcd == 0 then + local cleared_row_count = self.grid:getClearedRowCount() + self.grid:clearClearedRows() + self:afterLineClear(cleared_row_count) + playSE("fall") + if self.are == 0 then + self:initializeOrHold(inputs, ruleset) + end + end + elseif self.are > 0 then + self.are = self.are - 1 + if self.are == 0 then + self:initializeOrHold(inputs, ruleset) + end + end +end + +function GameMode:initializeOrHold(inputs, ruleset) + self:initializeNextPiece(inputs, ruleset, self.next_queue[1]) + self:onPieceEnter() + if not self.grid:canPlacePiece(self.piece) then + self.game_over = true + end + ruleset:dropPiece( + inputs, self.piece, self.grid, self:getGravity(), + self:getDropSpeed(), self.drop_locked, self.hard_drop_locked + ) +end + +function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next_piece) + self.piece = ruleset:initializePiece( + inputs, piece_data, self.grid, self:getGravity(), + self.prev_inputs, self.move, + self:getLockDelay(), self:getDropSpeed(), + self.drop_locked, self.hard_drop_locked, false, + ( + self.frames == 0 or self:getARE() ~= 0 + ) and self.irs or false, self.lastdir + ) + self.piece_hard_dropped = false + self.piece_soft_locked = false + if self.piece:isDropBlocked(self.grid) and + self.grid:canPlacePiece(self.piece) then + playSE("bottom") + end + if generate_next_piece == nil then + table.remove(self.next_queue, 1) + table.insert(self.next_queue, self:getNextPiece(ruleset)) + end +end + +function GameMode:animation(x, y, skin, colour) + return { + 1, 1, 1, + -0.25 + 1.25 * (self.lcd / self.last_lcd), + skin, colour, + 200 + x * 16, y * 16 + } +end + +function GameMode:canDrawLCA() + return self.lcd > 0 +end + +function GameMode:drawLineClearAnimation() + local grid_position = {x=200,y=64} + for y, row in pairs(self.cleared_block_table) do + for x, block in pairs(row) do + local real_x = (x * 16) + grid_position['x'] + local real_y = (y * 16) + grid_position['y'] + local drift = self.spin_rng[x]*-1 + local fall_timer = (self:getLineClearDelay()-self.lcd)/2 + fall_timer = (fall_timer*fall_timer)+drift + fade_timer = self.lcd/20 + love.graphics.setColor(1,1,1,fade_timer) + love.graphics.draw(blocks[block.skin][block.colour..'_d'], real_x, real_y+fall_timer) + if self.lcd > self:getLineClearDelay() - 5 then + love.graphics.setColor(1,1,1,fade_timer*0.3) + love.graphics.draw(blocks[block.skin]['W'], real_x, real_y+fall_timer) + end + end + end +end + +function GameMode:drawPiece() + if self.piece ~= nil then + local b = ( + 1 - (self.piece.lock_delay / self:getLockDelay()) + ) + self.piece:draw(0.50 + 0.50 * b, 0.50 + 0.50 * b, self.grid) + end +end + +function GameMode:drawNextQueue(ruleset) + local colourscheme + function drawPiece(piece, skin, offsets, pos_x, pos_y) + for index, offset in pairs(offsets) do + local x = offset.x + ruleset:getDrawOffset(piece, rotation).x + ruleset.spawn_positions[piece].x + local y = offset.y + ruleset:getDrawOffset(piece, rotation).y + 4.7 + love.graphics.draw(blocks[skin][ColourSchemes.Arika[piece]], pos_x+x*16, pos_y+y*16) + end + end + for i = 1, self.next_queue_length do + love.graphics.setColor(1, 1, 1, 1) + local highness = -54 + local next_piece = self.next_queue[i].shape + local skin = self.next_queue[i].skin + local rotation = self.next_queue[i].orientation + drawPiece(next_piece, skin, ruleset.block_offsets[next_piece][rotation], 136+i*80, highness) + end + return false +end + +function GameMode:getBackground() + bg = math.floor(self.speed_level/6) + if bg > 9 then bg = 9 end + if (self.total_lines >= 130 or self.frames >= 23640) and self.last_level ~= bg then self.nextbgmflag = true end + self.last_level = bg + return bg +end + +function GameMode:drawGrid() + local greyscale = false + if self.game_over or self.completed then greyscale = true end + self.grid:draw(greyscale, (self.game_over_frames/50)) +end + +function GameMode:drawInputDisplay(left, top) + if self.replay_inputs[self.frames] ~= nil then + drawText("+", left+10, top+8, 1000, "left") + drawText("v", left+10, top+18, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['down']),1,1-boolToInt(self.replay_inputs[self.frames]['down']),1}) + drawText("<", left, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['left']),1,1-boolToInt(self.replay_inputs[self.frames]['left']),1}) + drawText(">", left+20, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['right']),1,1-boolToInt(self.replay_inputs[self.frames]['right']),1}) + drawText("L", left+35, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_left']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_left']),1}) + drawText("R", left+50, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_right']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_right']),1}) + drawText("L", left+65, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_left2']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_left2']),1}) + drawText("R", left+80, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_right2']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_right2']),1}) + else + drawText("+", left+10, top+8, 1000, "left") + drawText("v", left+10, top+18, 1000, "left") + drawText("<", left, top+8, 1000, "left") + drawText(">", left+20, top+8, 1000, "left") + drawText("L", left+35, top+8, 1000, "left") + drawText("R", left+50, top+8, 1000, "left") + drawText("L", left+65, top+8, 1000, "left") + drawText("R", left+80, top+8, 1000, "left") + end +end + +function GameMode:drawSpeedStats(left, top) + love.graphics.setColor(0,0,0,0.5) + love.graphics.rectangle("fill", left+3, top+3, 190, 145, 10, 10) + love.graphics.setColor(0.05,0.05,0.05,1) + love.graphics.rectangle("fill", left, top, 190, 145, 10, 10) + drawText("Efficiency Bonus: ", left+15, top+10, 1000, "left") + local lines = self.total_lines + if lines == 0 then lines = 1 end + if self.move_count == 0 then + drawText(string.format(" %4d Num. of Moves", self.target), left+15, top+25, 1000, "left") + else + drawText(string.format(" %4d Num. of Moves", self.move_count), left+15, top+25, 1000, "left") + end + drawText(string.format("/ %4d Active Frames", self.last_active), left+15, top+40, 1000, "left") + drawText(string.format("= %1.2f\n (0 added for hole)\n %1.2f %dpc Average\nx %s x Lines\n+ %4d", self.last_percent, self.total_speed_loss, #self.speed_table, self.bonus_components['speed'], self.last_speed), left+15, top+55, 1000, "left") +end + +function GameMode:drawLinesStats(left, top) + love.graphics.setColor(0,0,0,0.5) + love.graphics.rectangle("fill", left+3, top+3, 190, 90, 10, 10) + love.graphics.setColor(0.05,0.05,0.05,1) + love.graphics.rectangle("fill", left, top, 190, 90, 10, 10) + local lines = self.total_lines + if lines == 0 then lines = 1 end + drawText("Lines Bonus: ", left+15, top+10, 1000, "left") + --drawText(string.format("+ %4d %3d%%", self.lineClearPoints[self.lines_cleared], (self.score_totals['lines']/(self.lineClearPoints[4]*math.ceil(lines/4)))*100), left+15, top+25, 1000, "left") + drawText(string.format("2 x Lines = %d\n3 x Lines = %d\n4 x Lines = %d", self.lineClearPoints[2], self.lineClearPoints[3], self.lineClearPoints[4]), left+15, top+25, 1000, "left") +end + +function GameMode:drawScoringInfo() + love.graphics.setColor(0,0,0,0.5) + love.graphics.rectangle("fill", 98, 83, 110, 180, 10, 10) --name, grade + love.graphics.setColor(0,0,0,0.5) + love.graphics.rectangle("fill", 241, 407, 116, 40, 5, 5) --lines + love.graphics.setColor(0.05,0.05,0.05,1) + love.graphics.rectangle("fill", 239, 405, 116, 40, 5, 5) --lines + love.graphics.rectangle("fill", 95, 80, 110, 180, 10, 10) --name, grade + drawText(string.format("Level: %2d\nLines: %3d/300", self:getBackground(), self.total_lines), 249, 408, 1000, "left") + if not PENTO_MODE then drawText("Grade:", 100, 128, 1000, "left") end + if self.input_playback then + love.graphics.setColor(0,0,0,0.5) + love.graphics.rectangle("fill", 68, 270, 140, 190, 10, 10) + love.graphics.setColor(0.05,0.05,0.05,1) + love.graphics.rectangle("fill", 65, 267, 140, 190, 10, 10) + drawText(string.format("Replay in progress\nRotate Left:\n Pause/Frame Step\nRotate Right:\n Unpause\nLeft:\n Rewind 5 sec\nRight:\n FF 10 secs\n%s", formatTime(self.frames)), 70, 275, 1000, "left") + drawBigText(string.format("%s", self.grade), 100, 143, 1000, "left") + self:drawInputDisplay(103,185) + elseif self.training or PENTO_MODE then + else + if math.mod(self.grade_change_flash, 5) ~= 0 then + drawBigText(string.format("%s", self.gradeNames[self.grade]), 100, 143, 1000, "left", self.grade_change_color) + else + drawBigText(string.format("%s", self.gradeNames[self.grade]), 100, 143, 1000, "left") + end + local points_text = nil + if self.grade == 1 and self.grade_history[2] == 2 then + points_text = " |.." + elseif self.grade == 1 and self.grade_history[2] == 3 then + points_text = " .|." + elseif self.grade == 1 and self.grade_history[2] == 4 then + points_text = " ..|" + elseif self.grade_history[2] == 0 then + points_text = "|...." + elseif self.grade_history[2] == 1 then + points_text = ".|..." + elseif self.grade_history[2] == 2 then + points_text = "..|.." + elseif self.grade_history[2] == 3 then + points_text = "...|." + elseif self.grade_history[2] == 4 then + points_text = "....|" + end + if self.grade > 1 then points_text = '-'..points_text + else points_text = ' '..points_text end + if self.grade < 28 then points_text = points_text..'+' end + drawText("Promotion\nMeter:", 100, 174, 1000, "left") + if self.point_flash > 0 then + drawBigText(points_text, 100, 208, 1000, "left", self.point_flash_color) + else + drawBigText(points_text, 100, 208, 1000, "left") + end + end + if (self.game_over or self.completed) and self.game_over_frames <= 50 and not self.input_playback and not self.training and not PENTO_MODE then + drawText("SAVING, PLEASE WAIT", 232, 460, 1000, "left") + end + drawText("Name:", 100, 83, 1000, "left") + drawBigText(self.player_name:upper(), 100, 98, 1000, "left") + drawText("Ver. 2", 550, 435, 1000, "left") + if self.input_playback then + self:drawSpeedStats(385, 99) + self:drawLinesStats(385, 251) + love.graphics.setColor(0,0,0,0.5) + love.graphics.rectangle("fill", 385+3, 348+3, 190, 50, 10, 10) + love.graphics.setColor(0.05,0.05,0.05,1) + love.graphics.rectangle("fill", 385, 348, 190, 50, 10, 10) + drawText(string.format("Added: %d\nScore: %d",self.score_to_add, self.grade_score), 392, 356, 1000, "left") + end + + + if self.clear or self.game_over then + sounds['bgm_firsthalf']:stop() + sounds['bgm_secondhalf']:stop() + end +end + +function GameMode:drawBackground() + local bg = self:getBackground() + local brightness = 0.9 + local limit = 4 + if self.training then bg = 0 end + --if self.training then bg = math.mod(math.floor(((self.frames+1)/1200)), 10) end + if bg == 0 or bg == 6 or bg == 9 then limit = 5 end + if bg == 5 then limit = 4.76 end + if not backgrounds[bg]:isPlaying() then + backgrounds[bg]:play() + end + if backgrounds[bg]:tell() >= limit then + backgrounds[bg]:rewind() + end + if bg == 0 or bg == 8 or bg == 9 or bg == 3 then brightness = 0.7 end + love.graphics.setColor(brightness, brightness, brightness, 1) + love.graphics.draw( + backgrounds[bg], + 0, 0, 0, + 0.5, 0.5 + ) +end + +function GameMode:drawFrame() + love.graphics.setColor(1, 1, 1, 1) + love.graphics.line(216,80,216,80+(16*self.grid.height)) + love.graphics.line(216+(16*self.grid.width),80,216+(16*self.grid.width),80+(16*self.grid.height)) + love.graphics.line(216,80+(16*self.grid.height),216+(16*self.grid.width),80+(16*self.grid.height)) + love.graphics.line(216,80,216+(16*self.grid.width),80) + love.graphics.setColor(0, 0, 0, 1) + love.graphics.rectangle( + "fill", 216, 80, + 16 * self.grid.width, 16 * (self.grid.height) + ) +end + +function GameMode:drawReadyGo() + -- ready/go graphics + love.graphics.setColor(1, 1, 1, 1) + + if self.ready_frames <= 100 and self.ready_frames > 52 then + drawBigText("Ready...", 246, 240 - 14, 1000) + elseif self.ready_frames <= 50 and self.ready_frames > 2 then + drawBigText("Go!", 276, 240 - 14, 1000) + end +end + +function GameMode:drawCustom() end + +function GameMode:draw(paused) + self:drawBackground() + self:drawFrame() + self:drawGrid() + self:drawPiece() + self:drawNextQueue(self.ruleset) + if not self.training then self:drawScoringInfo() end + self:drawReadyGo() + self:drawCustom() + if self:canDrawLCA() then + self:drawLineClearAnimation() + end + + if self.completed then + self:onGameComplete() + elseif self.game_over then + self:onGameOver() + end +end + +return GameMode diff --git a/game/grid.lua b/game/grid.lua new file mode 100644 index 0000000..c84cee5 --- /dev/null +++ b/game/grid.lua @@ -0,0 +1,212 @@ +local Object = require 'libs.classic' + +local Grid = Object:extend() + +local empty = { skin = "", colour = "", oob=false } +local oob = { skin = "", colour = "", oob=true } +local block = { skin = "2tie", colour = "A", oob=false } + +function Grid:new(width, height) + self.grid = {} + self.grid_age = {} + self.width = width + self.height = height + for y = 1, self.height do + self.grid[y] = {} + self.grid_age[y] = {} + for x = 1, self.width do + self.grid[y][x] = empty + self.grid_age[y][x] = 0 + end + end +end + +function Grid:clear() + for y = 1, self.height do + for x = 1, self.width do + self.grid[y][x] = empty + self.grid_age[y][x] = 0 + end + end +end + +function Grid:getCell(x, y) + if x < 1 or x > self.width or y > self.height then return oob + elseif y < 1 then return oob + else return self.grid[y][x] + end +end + +function Grid:isOccupied(x, y) + return self:getCell(x+1, y+1) ~= empty +end + +function Grid:isRowFull(row) + for index, square in pairs(self.grid[row]) do + if square == empty then return false end + end + return true +end + +function Grid:canPlacePiece(piece) + local offsets = piece:getBlockOffsets() + for index, offset in pairs(offsets) do + local x = piece.position.x + offset.x + local y = piece.position.y + offset.y + if self:isOccupied(x, y) then + return false + end + end + return true +end + +function Grid:canPlacePieceInVisibleGrid(piece) + local offsets = piece:getBlockOffsets() + for index, offset in pairs(offsets) do + local x = piece.position.x + offset.x + local y = piece.position.y + offset.y + if y < 1 or self:isOccupied(x, y) ~= empty then + return false + end + end + return true +end + +function Grid:getClearedRowCount() + local count = 0 + local cleared_row_table = {} + for row = 1, self.height do + if self:isRowFull(row) then + count = count + 1 + table.insert(cleared_row_table, row) + end + end + return count, cleared_row_table +end + +function Grid:markClearedRows() + local block_table = {} + for row = 1, self.height do + if self:isRowFull(row) then + block_table[row] = {} + for x = 1, self.width do + block_table[row][x] = { + skin = self.grid[row][x].skin, + colour = self.grid[row][x].colour, + } + self.grid[row][x] = { + skin = self.grid[row][x].skin, + colour = "X" + } + end + end + end + return block_table +end + +function Grid:clearClearedRows() + for row = 1, self.height do + if self:isRowFull(row) then + for above_row = row, 2, -1 do + self.grid[above_row] = self.grid[above_row - 1] + self.grid_age[above_row] = self.grid_age[above_row - 1] + end + self.grid[1] = {} + self.grid_age[1] = {} + for i = 1, self.width do + self.grid[1][i] = empty + self.grid_age[1][i] = 0 + end + end + end + return true +end + +function Grid:clearSpecificRow(row) + for col = 1, self.width do + self.grid[row][col] = empty + end +end + +function Grid:applyPiece(piece) + if piece.big then + self:applyBigPiece(piece) + return + end + offsets = piece:getBlockOffsets() + for index, offset in pairs(offsets) do + x = piece.position.x + offset.x + y = piece.position.y + offset.y + if y + 1 > 0 and y < self.height then + self.grid[y+1][x+1] = { + skin = piece.skin, + colour = piece.colour, + flash = 5 + } + end + end +end + +function Grid:checkStackHeight() + for i = 0, self.height - 1 do + for j = 0, self.width - 1 do + if self:isOccupied(j, i) then return self.height - i end + end + end + return 0 +end + +function Grid:applyMap(map) + for y, row in pairs(map) do + for x, block in pairs(row) do + self.grid_age[y][x] = 0 + self.grid[y][x] = block + end + end +end + +function Grid:update() + for y = 1, self.height do + for x = 1, self.width do + if self.grid[y][x] ~= empty then + self.grid_age[y][x] = self.grid_age[y][x] + 1 + end + end + end +end + +function Grid:draw(greyscale, timer) + love.graphics.setColor(0,0,0,1) + love.graphics.rectangle("fill", 256, 31, 80, 45, 0, 0) + love.graphics.setColor(0.3, 0.3, 0.3, 1) + love.graphics.line(256,31,256,31+45) + love.graphics.line(256,31,256+80,31) + love.graphics.line(256+80,31,256+80,31+45) + love.graphics.line(256,31+45,256+80,31+45) + for y = 1, self.height do + for x = 1, self.width do + if blocks[self.grid[y][x].skin] and + blocks[self.grid[y][x].skin][self.grid[y][x].colour] then + if self.grid[y][x].flash ~= nil then + if self.grid[y][x].flash > 0 then + love.graphics.setColor(0.4+(self.grid[y][x].flash*0.1), 0.4+(self.grid[y][x].flash*0.1), 0.4+(self.grid[y][x].flash*0.1), 1) + love.graphics.draw(blocks[self.grid[y][x].skin]['W'], 200+x*16, 64+y*16) + self.grid[y][x].flash = self.grid[y][x].flash - 1 + else + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour..'_d'], 200+x*16, 64+y*16) + end + end + if greyscale then + if timer > 1 then timer = 1 end + love.graphics.setColor(0.7, 0.7, 0.7, 0+timer) + if self.grid[y][x] ~= empty and self.grid[y][x].colour ~= 'X' then + love.graphics.draw(blocks[self.grid[y][x].skin]["A"], 200+x*16, 64+y*16) + end + end + end + end + end +end + +return Grid diff --git a/game/piece.lua b/game/piece.lua new file mode 100644 index 0000000..e1f11c5 --- /dev/null +++ b/game/piece.lua @@ -0,0 +1,174 @@ +local Object = require 'libs.classic' + +local Piece = Object:extend() + +function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay, skin, colour, big) + self.shape = shape + self.rotation = rotation + self.position = position + self.block_offsets = block_offsets + self.gravity = gravity + self.lock_delay = lock_delay + self.skin = skin + self.colour = colour + self.lowest_point = -1 +-- self.ghost = false + self.locked = false +-- self.big = big +end + +-- Functions that return a new piece to test in rotation systems. + +function Piece:withOffset(offset) + return Piece( + self.shape, self.rotation, + {x = self.position.x + offset.x, y = self.position.y + offset.y}, + self.block_offsets, self.gravity, self.lock_delay, self.skin, self.colour + ) +end + +function Piece:withRelativeRotation(rot) + local new_rot = self.rotation + rot + while new_rot < 0 do new_rot = new_rot + 4 end + while new_rot >= 4 do new_rot = new_rot - 4 end + return Piece( + self.shape, new_rot, self.position, + self.block_offsets, self.gravity, self.lock_delay, self.skin, self.colour + ) +end + +-- Functions that return predicates relative to a grid. + +function Piece:getBlockOffsets() + return self.block_offsets[self.shape][self.rotation + 1] +end + +function Piece:occupiesSquare(x, y) + local offsets = self:getBlockOffsets() + for index, offset in pairs(offsets) do + local new_offset = {x = self.position.x + offset.x, y = self.position.y + offset.y} + if new_offset.x == x and new_offset.y == y then + return true + end + end + return false +end + +function Piece:isMoveBlocked(grid, offset) + local moved_piece = self:withOffset(offset) + return not grid:canPlacePiece(moved_piece) +end + +function Piece:isDropBlocked(grid) + return self:isMoveBlocked(grid, { x=0, y=1 }) +end + +-- Procedures to actually do stuff to pieces. + +function Piece:setOffset(offset) + self.position.x = self.position.x + offset.x + self.position.y = self.position.y + offset.y + return self +end + +function Piece:setRelativeRotation(rot) + new_rot = self.rotation + rot + while new_rot < 0 do new_rot = new_rot + 4 end + while new_rot >= 4 do new_rot = new_rot - 4 end + self.rotation = new_rot + return self +end + +function Piece:moveInGrid(step, squares, grid, instant) + local moved = false + for x = 1, squares do + if grid:canPlacePiece(self:withOffset(step)) then + moved = true + self:setOffset(step) + if instant then + self:dropToBottom(grid) + end + else + break + end + end + return self +end + +function Piece:dropSquares(dropped_squares, grid) + self:moveInGrid({ x = 0, y = 1 }, dropped_squares, grid) +end + +function Piece:dropToBottom(grid) + local piece_y = self.position.y + self:dropSquares(math.huge, grid) + self.gravity = 0 + if self.position.y > piece_y then + --self.lock_delay = 0 + end + return self +end + +function Piece:lockIfBottomed(grid) + if self:isDropBlocked(grid) then + self.locked = true + end + return self +end + +function Piece:addGravity(gravity, grid, classic_lock) + gravity = gravity / (self.big and 2 or 1) + local new_gravity = self.gravity + gravity + if self:isDropBlocked(grid) then + if classic_lock then + self.gravity = new_gravity + else + self.gravity = 0 + self.lock_delay = self.lock_delay + 1 + end + elseif not ( + self:isMoveBlocked(grid, { x=0, y=-1 }) and gravity < 0 + ) then + local dropped_squares = math.floor(math.abs(new_gravity)) + if gravity >= 0 then + local new_frac_gravity = new_gravity - dropped_squares + self.gravity = new_frac_gravity + self:dropSquares(dropped_squares, grid) + if self:isDropBlocked(grid) then + playSE("bottom") + end + else + local new_frac_gravity = new_gravity + dropped_squares + self.gravity = new_frac_gravity + self:moveInGrid({ x=0, y=-1 }, dropped_squares, grid) + if self:isMoveBlocked(grid, { x=0, y=-1 }) then + playSE("bottom") + end + end + else + self.gravity = 0 + end + return self +end + +-- Procedures for drawing. + +function Piece:draw(opacity, brightness, grid, partial_das) + if opacity == nil then opacity = 1 end + if brightness == nil then brightness = 1 end + love.graphics.setColor(brightness, brightness, brightness, opacity) + local offsets = self:getBlockOffsets() + local gravity_offset = 0 + if partial_das == nil then partial_das = 0 end + for index, offset in pairs(offsets) do + local x = self.position.x + offset.x + local y = self.position.y + offset.y + love.graphics.draw( + blocks[self.skin][self.colour], + 216+x*16+partial_das, 80+y*16+gravity_offset + ) + end + return false +end + +return Piece diff --git a/game/randomizer.lua b/game/randomizer.lua new file mode 100644 index 0000000..f313a92 --- /dev/null +++ b/game/randomizer.lua @@ -0,0 +1,148 @@ +local Object = require 'libs.classic' + +local Randomizer = Object:extend() + +local highest_count = 0 + +function Randomizer:new(always, seed) + self.always = always + if seed ~= nil then + self.seed = seed + else + self.seed = love.math.random(1, 9007199254740991) + end + self.drought = { + I = 0, + J = 0, + L = 0, + T = 0, + S = 0, + Z = 0, + O = 0 + } + self.droughted_deals = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} + self.piece_counts = { + I = 0, + J = 0, + L = 0, + T = 0, + S = 0, + Z = 0, + O = 0 + } + self.piece_round = 0 + self:initialize() +end + +function Randomizer:nextPiece() + return self:generatePiece() +end + +function Randomizer:runTest() + local i_distance = 0 + local highest_distance = 0 + local distance_total = 0 + local i_appearances = 0 + local dupe = 0 + local trip = 0 + local quad = 0 + local quin = 0 + local lastpiece = 0 + local lastpiece2 = 0 + local lastpiece3 = 0 + local lastpiece4 = 0 + local pieceseq_rep = 0 + local pieceseq = {} + local last_pieceseq = {} + local highest_discrepancy = 0 + local discrepancy = self.piece_counts[table.highest(self.piece_counts)] - self.piece_counts[table.lowest(self.piece_counts)] + local total_chance = 0 + for i=0, 750000 do + piece = self:generatePiece() + if #pieceseq < 7 then + table.insert(pieceseq, piece) + else + --print(table.concat(pieceseq)) + if table.concat(pieceseq) == table.concat(last_pieceseq) then + pieceseq_rep = pieceseq_rep + 1 + end + last_pieceseq = copy(pieceseq) + pieceseq = {} + end + if piece == lastpiece then dupe = dupe + 1 end + if piece == lastpiece and piece == lastpiece2 then trip = trip + 1 end + if piece == lastpiece and piece == lastpiece2 and piece == lastpiece3 then quad = quad + 1 end + if piece == lastpiece and piece == lastpiece2 and piece == lastpiece3 and piece == lastpiece4 then quin = quin + 1 end + if piece == 'I' then + distance_total = distance_total + i_distance + i_appearances = i_appearances + 1 + i_distance = 0 + else i_distance = i_distance + 1 end + if highest_distance < i_distance then highest_distance = i_distance end + lastpiece4 = lastpiece3 + lastpiece3 = lastpiece2 + lastpiece2 = lastpiece + lastpiece = piece + --if self.piece_round <= 750 then print(discrepancy) end + local new_discrepancy = self.piece_counts[table.highest(self.piece_counts)] - self.piece_counts[table.lowest(self.piece_counts)] + if new_discrepancy > discrepancy then highest_discrepancy = new_discrepancy end + discrepancy = new_discrepancy + local chance = 0 + for piece,drought in pairs(self.drought) do + local piece_chance = 0.14/( ((self.drought[table.highest(self.drought)]+1)-drought) / (self.drought[table.highest(self.drought)]) ) + chance = chance + piece_chance + end + chance = chance / 7 + total_chance = total_chance + chance + end + --something = something / 750000 + print(string.format('dupes: %d, trips: %s, quads: %s, quins: %s, highest i distance: %d, average i distance: %f, pieceseq reps: %d, highest discrepancy:%d, average chance:%f\ndrought lengths dealt: %s', dupe, trip, quad, quin, highest_distance, distance_total/i_appearances, pieceseq_rep, highest_discrepancy, total_chance/750000, table.concat(self.droughted_deals, '-'))) + for piece,count in pairs(self.piece_counts) do + print(piece..' '..count) + end +end + +function Randomizer:initialize() + local start_pieces = {"I", "J", "L", "T"} + local shapes = {"I", "J", "L", "T", "S", "Z", "O"} + love.math.setRandomSeed(self.seed) + self.drought[table.remove(shapes, love.math.random(1, 4))] = 10 + for i=4,9 do + self.drought[table.remove(shapes, love.math.random(1, #shapes))] = i + end + + --self:runTest() +end + +function Randomizer:generatePiece(always) + if self.always then + return "I" + end + + local shapes = {"I", "J", "L", "T", "S", "Z", "O"} + local new_piece = shapes[love.math.random(1,7)] + local chance = love.math.random(0,self.drought[table.highest(self.drought)]) + while self.drought[new_piece] < chance do + new_piece = shapes[love.math.random(1,7)] + end + for piece,drought in pairs(self.drought) do + if drought >= 10 then + new_piece = piece + end + end + generated_piece = new_piece + + for piece,drought in pairs(self.drought) do + if new_piece ~= piece then self.drought[piece] = self.drought[piece] + 1 + else + if drought < #self.droughted_deals then self.droughted_deals[drought+1] = self.droughted_deals[drought+1] + 1 end + self.piece_counts[piece] = self.piece_counts[piece] + 1 + self.drought[piece] = 0 + end + end + self.piece_round = self.piece_round + 1 + + return generated_piece +end + +return Randomizer diff --git a/game/rotation.lua b/game/rotation.lua new file mode 100644 index 0000000..d09b5fb --- /dev/null +++ b/game/rotation.lua @@ -0,0 +1,299 @@ +local Object = require 'libs.classic' +local Piece = require 'game.piece' + +local Rotation = Object:extend() + +Rotation.spawn_positions = { + I = { x=3, y= -1 }, + J = { x=3, y= -1 }, + L = { x=3, y= -1 }, + O = { x=3, y= -1 }, + S = { x=3, y= -1 }, + T = { x=3, y= -1 }, + Z = { x=3, y= -1 }, +} + +Rotation.colourscheme = { + I = "R", + L = "O", + J = "B", + S = "M", + Z = "G", + O = "Y", + T = "C", +} + +Rotation.block_offsets = { + I={ + { {x=0, y=1}, {x=1, y=1}, {x=2, y=1}, {x=3, y=1} }, + { {x=2, y=0}, {x=2, y=1}, {x=2, y=2}, {x=2, y=3} }, + { {x=0, y=1}, {x=1, y=1}, {x=2, y=1}, {x=3, y=1} }, + { {x=2, y=0}, {x=2, y=1}, {x=2, y=2}, {x=2, y=3} }, + }, + J={ + { {x=0, y=1}, {x=1, y=1}, {x=2, y=1}, {x=2, y=2} }, + { {x=1, y=0}, {x=1, y=1}, {x=1, y=2}, {x=0, y=2} }, + { {x=0, y=1}, {x=0, y=2}, {x=1, y=2}, {x=2, y=2} }, + { {x=1, y=0}, {x=2, y=0}, {x=1, y=1}, {x=1, y=2} }, + }, + L={ + { {x=0, y=1}, {x=0, y=2}, {x=1, y=1}, {x=2, y=1} }, + { {x=0, y=0}, {x=1, y=0}, {x=1, y=1}, {x=1, y=2} }, + { {x=0, y=2}, {x=1, y=2}, {x=2, y=1}, {x=2, y=2} }, + { {x=1, y=0}, {x=1, y=1}, {x=1, y=2}, {x=2, y=2} }, + }, + O={ + { {x=1, y=1}, {x=2, y=1}, {x=1, y=2}, {x=2, y=2} }, + { {x=1, y=1}, {x=2, y=1}, {x=1, y=2}, {x=2, y=2} }, + { {x=1, y=1}, {x=2, y=1}, {x=1, y=2}, {x=2, y=2} }, + { {x=1, y=1}, {x=2, y=1}, {x=1, y=2}, {x=2, y=2} }, + }, + S={ + { {x=1, y=1}, {x=2, y=1}, {x=0, y=2}, {x=1, y=2} }, + { {x=0, y=0}, {x=0, y=1}, {x=1, y=1}, {x=1, y=2} }, + { {x=1, y=1}, {x=2, y=1}, {x=0, y=2}, {x=1, y=2} }, + { {x=0, y=0}, {x=0, y=1}, {x=1, y=1}, {x=1, y=2} }, + }, + T={ + { {x=0, y=1}, {x=1, y=1}, {x=1, y=2}, {x=2, y=1} }, + { {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=1, y=2} }, + { {x=0, y=2}, {x=1, y=1}, {x=1, y=2}, {x=2, y=2} }, + { {x=1, y=0}, {x=1, y=1}, {x=2, y=1}, {x=1, y=2} }, + }, + Z={ + { {x=0, y=1}, {x=1, y=1}, {x=1, y=2}, {x=2, y=2} }, + { {x=2, y=0}, {x=1, y=1}, {x=2, y=1}, {x=1, y=2} }, + { {x=0, y=1}, {x=1, y=1}, {x=1, y=2}, {x=2, y=2} }, + { {x=2, y=0}, {x=1, y=1}, {x=2, y=1}, {x=1, y=2} }, + } +} + +Rotation.pieces = 7 + +-- Component functions. + +function Rotation:new(game_mode) + self.game = require 'game.gamemode' +end + +function Rotation:rotatePiece(inputs, piece, grid, prev_inputs, initial, lastdir) + local new_inputs = {} + + for input, value in pairs(inputs) do + if value and not prev_inputs[input] then + new_inputs[input] = true + end + end + local was_drop_blocked = piece:isDropBlocked(grid) + + if self:canPieceRotate(piece, grid) then +-- if not self.held_rotate then +-- self:attemptRotate(inputs, piece, grid, initial) +-- self.held_rotate = true +-- else + self:attemptRotate(new_inputs, piece, grid, initial, lastdir) +-- end + end + + if not initial and not was_drop_blocked and piece:isDropBlocked(grid) then + playSE("bottom") + end + + -- prev_inputs becomes the previous inputs + for input, value in pairs(inputs) do + prev_inputs[input] = inputs[input] + end +end + +function Rotation:attemptRotate(new_inputs, piece, grid, initial, lastdir) + local rot_dir = 0 + + if (new_inputs["rotate_left"] or new_inputs["rotate_left2"]) then + rot_dir = 3 + if lastdir == 0 then lastdir = -1 end + elseif (new_inputs["rotate_right"] or new_inputs["rotate_right2"]) then + rot_dir = 1 + if lastdir == 0 then lastdir = 1 end + end + if rot_dir == 0 then return end + + local new_piece = piece:withRelativeRotation(rot_dir) + self:attemptWallkicks(piece, new_piece, rot_dir, grid, lastdir) +end + +function Rotation:attemptWallkicks(piece, new_piece, rot_dir, grid, lastdir) + -- wallkick routine designed to maximize flexibility while minimizing teleports + + -- O doesn't kick + if (piece.shape == "O") then return end + + -- assess precisely what rows/columns would be blocked given the desired rotation + local sides = {top=false,uright=false,lright=false,uleft=false,lleft=false,center=false,bottom=false} + local left_exists = false + local right_exists = false + local kick = {x=0,y=0} + for _,offset in pairs(new_piece:getBlockOffsets()) do + local x = piece.position.x + offset.x + local y = piece.position.y + offset.y + if offset.x == 0 then left_exists = true end + if offset.x == 2 or offset.x == 3 then right_exists = true end + + if grid:isOccupied(x,y) then + if offset.y == 0 then sides.top = true end + if offset.y == 3 then sides.bottom = true end + if offset.y == 1 and offset.x == 0 then sides.uleft = true end + if offset.y == 2 and offset.x == 0 then sides.lleft = true end + if offset.y == 1 and (offset.x == 2 or offset.x == 3) then sides.uright = true end + if offset.y == 2 and (offset.x == 2 or offset.x == 3) then sides.lright = true end + if offset.x == 1 then sides.center = true end + end + end + + if sides.top then kick = {x=0,y=1} + elseif (sides.uleft and sides.lright) or (sides.uright and sides.lleft) or (sides.uright and sides.uleft) then kick = {x=0,y=1} + elseif (sides.lleft and sides.lright) then kick = {x=0,y=-1} + elseif (sides.lleft or sides.uleft) then kick = {x=1,y=0} + elseif (sides.lright or sides.uright) then kick = {x=-1,y=0} + elseif sides.center and left_exists then kick = {x=1,y=0} + elseif sides.center and right_exists then kick = {x=-1,y=0} + elseif sides.bottom then kick = {x=0,y=-1} + end + + + if grid:canPlacePiece(new_piece:withOffset({x=0,y=0})) then + self:onPieceRotate(piece, grid) + piece:setRelativeRotation(rot_dir):setOffset({x=0,y=0}) + elseif grid:canPlacePiece(new_piece:withOffset(kick)) then + self:onPieceRotate(piece, grid) + piece:setRelativeRotation(rot_dir):setOffset(kick) + end +end + +function Rotation:movePiece(piece, grid, move, instant) + local was_drop_blocked = piece:isDropBlocked(grid) + local offset = ({x=0, y=0}) + local moves = 0 + local y = piece.position.y + if move == "left" then + offset.x = -1 + moves = 1 + elseif move == "right" then + offset.x = 1 + moves = 1 + elseif move == "speedleft" then + offset.x = -1 + moves = grid.width + elseif move == "speedright" then + offset.x = 1 + moves = grid.width + end + if not self:canPieceMove(piece, grid) then return end + for i = 1, moves do + local x = piece.position.x + if moves ~= 1 then + piece:moveInGrid(offset, 1, grid, instant) + else + piece:moveInGrid(offset, 1, grid, false) + end + if piece.position.x ~= x then + self:onPieceMove(piece, grid) + if piece.locked then break end + end + end + if not was_drop_blocked and piece:isDropBlocked(grid) then + playSE("bottom") + end +end + +function Rotation:dropPiece( + inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked, + hard_drop_enabled, additive_gravity, classic_lock +) + local y = piece.position.y + if inputs["down"] == true and drop_locked == false then + piece:addGravity(math.max(gravity, drop_speed), grid, classic_lock) + else + piece:addGravity(gravity, grid, classic_lock) + end + if piece.position.y ~= y then + self:onPieceDrop(piece, grid) + end +end + +function Rotation:lockPiece(piece, grid, lock_delay, classic_lock) + if piece:isDropBlocked(grid) and piece.lock_delay >= lock_delay then + piece.locked = true + end +end + +function Rotation:get180RotationValue() return 3 end +function Rotation:getDefaultOrientation() return 1 end +function Rotation:getDrawOffset(shape, orientation) return { x=0, y=0 } end +function Rotation:getAboveFieldOffset(shape, orientation) + if shape == "I" then + return 1 + else + return 2 + end +end + +function Rotation:initializePiece( + inputs, data, grid, gravity, prev_inputs, + move, lock_delay, drop_speed, + drop_locked, hard_drop_locked, big, irs, lastdir +) + local spawn_positions + spawn_positions = self.spawn_positions + + local colours + colours = self.colourscheme + self.last_dir = 0 + self.held_rotate = false + if inputs['left'] then self.last_dir = -1 + elseif inputs['right'] then self.last_dir = 1 end + local spawn_x = math.floor(spawn_positions[data.shape].x / 10 * grid.width) + + local spawn_dy + spawn_dy = 0 + + local piece = Piece(data.shape, data.orientation - 1, { + x = spawn_x or spawn_positions[data.shape].x, + y = spawn_positions[data.shape].y - spawn_dy + }, self.block_offsets, 0, 0, data.skin, colours[data.shape], big) + + self:onPieceCreate(piece) + if irs then + self:rotatePiece(inputs, piece, grid, {}, true, lastdir) + end + return piece +end + +function Rotation:onPieceCreate(piece) end + +function Rotation:processPiece( + inputs, piece, grid, gravity, prev_inputs, + move, lock_delay, drop_speed, + drop_locked, hard_drop_locked, + hard_drop_enabled, additive_gravity, classic_lock, lastdir +) + self:rotatePiece(inputs, piece, grid, prev_inputs, false, lastdir) + self:movePiece(piece, grid, move, gravity >= grid.height) + self:dropPiece( + inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked, + hard_drop_enabled, additive_gravity, classic_lock + ) + self:lockPiece(piece, grid, lock_delay, classic_lock) +end + +function Rotation:canPieceMove(piece, grid) return true end +function Rotation:canPieceRotate(piece, grid) return true end +function Rotation:onPieceMove(piece) end +function Rotation:onPieceRotate(piece) end +function Rotation:onPieceDrop(piece) + if piece.position.y > piece.lowest_point then + piece.lock_delay = 0 + piece.lowest_point = piece.position.y + end +end + +return Rotation diff --git a/game/rotation_pent.lua b/game/rotation_pent.lua new file mode 100644 index 0000000..7e11df3 --- /dev/null +++ b/game/rotation_pent.lua @@ -0,0 +1,287 @@ +local Object = require 'libs.classic' +local Piece = require 'game.piece' + +local Rotation = Object:extend() + +Rotation.spawn_positions = { + I = { x=3, y= -2 }, + J = { x=3, y= -2 }, + L = { x=3, y= -2 }, + O = { x=3, y= -2 }, + S = { x=3, y= -2 }, + T = { x=3, y= -2 }, + Z = { x=3, y= -2 }, +} + +Rotation.colourscheme = { + I = "R", + L = "O", + J = "B", + S = "M", + Z = "G", + O = "Y", + T = "C", +} + +Rotation.block_offsets = { + I={ + { {x=0, y=2}, {x=1, y=2}, {x=2, y=2}, {x=3, y=2}, {x=4, y=2} }, + { {x=2, y=0}, {x=2, y=1}, {x=2, y=2}, {x=2, y=3}, {x=2, y=4} }, + { {x=0, y=2}, {x=1, y=2}, {x=2, y=2}, {x=3, y=2}, {x=4, y=2} }, + { {x=2, y=0}, {x=2, y=1}, {x=2, y=2}, {x=2, y=3}, {x=2, y=4} }, + }, + J={ + { {x=0, y=2}, {x=1, y=2}, {x=2, y=2}, {x=2, y=3}, {x=3, y=2} }, + { {x=1, y=0}, {x=1, y=1}, {x=1, y=2}, {x=0, y=2}, {x=1, y=3} }, + { {x=1, y=2}, {x=1, y=3}, {x=2, y=3}, {x=3, y=3}, {x=0, y=3} }, + { {x=1, y=1}, {x=2, y=1}, {x=1, y=2}, {x=1, y=3}, {x=1, y=0} }, + }, + L={ + { {x=0, y=2}, {x=0, y=3}, {x=1, y=2}, {x=2, y=2}, {x=3, y=2} }, + { {x=0, y=0}, {x=1, y=0}, {x=1, y=1}, {x=1, y=2}, {x=1, y=3} }, + { {x=1, y=3}, {x=2, y=3}, {x=3, y=2}, {x=3, y=3}, {x=0, y=3} }, + { {x=1, y=1}, {x=1, y=2}, {x=1, y=3}, {x=2, y=3}, {x=1, y=0} }, + }, + O={ + { {x=0, y=2}, {x=0, y=3}, {x=1, y=2}, {x=2, y=2}, {x=1, y=3} }, + { {x=0, y=1}, {x=1, y=1}, {x=1, y=2}, {x=1, y=3}, {x=0, y=2} }, + { {x=0, y=3}, {x=1, y=3}, {x=2, y=2}, {x=2, y=3}, {x=1, y=2} }, + { {x=1, y=1}, {x=1, y=2}, {x=1, y=3}, {x=2, y=3}, {x=2, y=2} }, + }, + S={ + { {x=1, y=2}, {x=2, y=2}, {x=0, y=3}, {x=1, y=3}, {x=3, y=2} }, + { {x=0, y=0}, {x=0, y=1}, {x=1, y=1}, {x=1, y=2}, {x=1, y=3} }, + { {x=2, y=2}, {x=3, y=2}, {x=1, y=3}, {x=2, y=3}, {x=0, y=3} }, + { {x=1, y=1}, {x=1, y=2}, {x=2, y=2}, {x=2, y=3}, {x=1, y=0} }, + }, + T={ + { {x=0, y=2}, {x=1, y=2}, {x=1, y=3}, {x=2, y=2}, {x=3, y=2} }, + { {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=1, y=2}, {x=1, y=3} }, + { {x=1, y=3}, {x=2, y=2}, {x=2, y=3}, {x=3, y=3}, {x=0, y=3} }, + { {x=2, y=1}, {x=2, y=2}, {x=3, y=2}, {x=2, y=3}, {x=2, y=0} }, + }, + Z={ + { {x=0, y=2}, {x=1, y=2}, {x=1, y=3}, {x=2, y=3}, {x=2, y=2} }, + { {x=1, y=1}, {x=0, y=2}, {x=1, y=2}, {x=0, y=3}, {x=1, y=3} }, + { {x=0, y=2}, {x=1, y=2}, {x=1, y=3}, {x=2, y=3}, {x=0, y=3} }, + { {x=2, y=1}, {x=1, y=2}, {x=2, y=2}, {x=1, y=3}, {x=1, y=1} }, + } +} + +Rotation.pieces = 7 + +-- Component functions. + +function Rotation:new(game_mode) + self.game = require 'game.gamemode' +end + +function Rotation:rotatePiece(inputs, piece, grid, prev_inputs, initial, lastdir) + local new_inputs = {} + + for input, value in pairs(inputs) do + if value and not prev_inputs[input] then + new_inputs[input] = true + end + end + local was_drop_blocked = piece:isDropBlocked(grid) + + if self:canPieceRotate(piece, grid) then +-- if not self.held_rotate then +-- self:attemptRotate(inputs, piece, grid, initial) +-- self.held_rotate = true +-- else + self:attemptRotate(new_inputs, piece, grid, initial, lastdir) +-- end + end + + if not initial and not was_drop_blocked and piece:isDropBlocked(grid) then + playSE("bottom") + end + + -- prev_inputs becomes the previous inputs + for input, value in pairs(inputs) do + prev_inputs[input] = inputs[input] + end +end + +function Rotation:attemptRotate(new_inputs, piece, grid, initial, lastdir) + local rot_dir = 0 + + if (new_inputs["rotate_left"] or new_inputs["rotate_left2"]) then + rot_dir = 3 + if lastdir == 0 then lastdir = -1 end + elseif (new_inputs["rotate_right"] or new_inputs["rotate_right2"]) then + rot_dir = 1 + if lastdir == 0 then lastdir = 1 end + end + if rot_dir == 0 then return end + + local new_piece = piece:withRelativeRotation(rot_dir) + self:attemptWallkicks(piece, new_piece, rot_dir, grid, lastdir) +end + +function Rotation:attemptWallkicks(piece, new_piece, rot_dir, grid, lastdir) + -- assess precisely what rows/columns would be blocked given the desired rotation + local sides = {top=false,uright=false,lright=false,uleft=false,lleft=false,center=false,bottom=false} + local left_exists = false + local right_exists = false + local kick = {x=0,y=0} + for _,offset in pairs(new_piece:getBlockOffsets()) do + local x = piece.position.x + offset.x + local y = piece.position.y + offset.y + + if grid:isOccupied(x,y) then + if offset.y <= 1 then sides.top = true end + if offset.y == 4 then sides.bottom = true end + if offset.x <= 1 then sides.lleft = true end + if offset.x >= 2 then sides.lright = true end + end + end + + if sides.top then kick = {x=0,y=1} + elseif sides.bottom then kick = {x=0,y=-1} + elseif (sides.lleft or sides.uleft) then kick = {x=1,y=0} + elseif (sides.lright or sides.uright) then kick = {x=-1,y=0} + end + + if grid:canPlacePiece(new_piece:withOffset({x=0,y=0})) then + self:onPieceRotate(piece, grid) + piece:setRelativeRotation(rot_dir):setOffset({x=0,y=0}) + elseif grid:canPlacePiece(new_piece:withOffset(kick)) then + self:onPieceRotate(piece, grid) + piece:setRelativeRotation(rot_dir):setOffset(kick) + elseif grid:canPlacePiece(new_piece:withOffset({x=kick.x*2,y=kick.y*2})) then + self:onPieceRotate(piece, grid) + piece:setRelativeRotation(rot_dir):setOffset({x=kick.x*2,y=kick.y*2}) + end +end + +function Rotation:movePiece(piece, grid, move, instant) + local was_drop_blocked = piece:isDropBlocked(grid) + local offset = ({x=0, y=0}) + local moves = 0 + local y = piece.position.y + if move == "left" then + offset.x = -1 + moves = 1 + elseif move == "right" then + offset.x = 1 + moves = 1 + elseif move == "speedleft" then + offset.x = -1 + moves = grid.width + elseif move == "speedright" then + offset.x = 1 + moves = grid.width + end + if not self:canPieceMove(piece, grid) then return end + for i = 1, moves do + local x = piece.position.x + if moves ~= 1 then + piece:moveInGrid(offset, 1, grid, instant) + else + piece:moveInGrid(offset, 1, grid, false) + end + if piece.position.x ~= x then + self:onPieceMove(piece, grid) + if piece.locked then break end + end + end + if not was_drop_blocked and piece:isDropBlocked(grid) then + playSE("bottom") + end +end + +function Rotation:dropPiece( + inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked, + hard_drop_enabled, additive_gravity, classic_lock +) + local y = piece.position.y + if inputs["down"] == true and drop_locked == false then + piece:addGravity(math.max(gravity, drop_speed), grid, classic_lock) + else + piece:addGravity(gravity, grid, classic_lock) + end + if piece.position.y ~= y then + self:onPieceDrop(piece, grid) + end +end + +function Rotation:lockPiece(piece, grid, lock_delay, classic_lock) + if piece:isDropBlocked(grid) and piece.lock_delay >= lock_delay then + piece.locked = true + end +end + +function Rotation:get180RotationValue() return 3 end +function Rotation:getDefaultOrientation() return 1 end +function Rotation:getDrawOffset(shape, orientation) return { x=0, y=0 } end +function Rotation:getAboveFieldOffset(shape, orientation) + if shape == "I" then + return 1 + else + return 2 + end +end + +function Rotation:initializePiece( + inputs, data, grid, gravity, prev_inputs, + move, lock_delay, drop_speed, + drop_locked, hard_drop_locked, big, irs, lastdir +) + local spawn_positions + spawn_positions = self.spawn_positions + + local colours + colours = self.colourscheme + self.last_dir = 0 + self.held_rotate = false + if inputs['left'] then self.last_dir = -1 + elseif inputs['right'] then self.last_dir = 1 end + local spawn_x = math.floor(spawn_positions[data.shape].x / 10 * grid.width) + + local spawn_dy + spawn_dy = 0 + + local piece = Piece(data.shape, data.orientation - 1, { + x = spawn_x or spawn_positions[data.shape].x, + y = spawn_positions[data.shape].y - spawn_dy + }, self.block_offsets, 0, 0, data.skin, colours[data.shape], big) + + self:onPieceCreate(piece) + if irs then + self:rotatePiece(inputs, piece, grid, {}, true, lastdir) + end + return piece +end + +function Rotation:onPieceCreate(piece) end + +function Rotation:processPiece( + inputs, piece, grid, gravity, prev_inputs, + move, lock_delay, drop_speed, + drop_locked, hard_drop_locked, + hard_drop_enabled, additive_gravity, classic_lock, lastdir +) + self:rotatePiece(inputs, piece, grid, prev_inputs, false, lastdir) + self:movePiece(piece, grid, move, gravity >= grid.height) + self:dropPiece( + inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked, + hard_drop_enabled, additive_gravity, classic_lock + ) + self:lockPiece(piece, grid, lock_delay, classic_lock) +end + +function Rotation:canPieceMove(piece, grid) return true end +function Rotation:canPieceRotate(piece, grid) return true end +function Rotation:onPieceMove(piece) end +function Rotation:onPieceRotate(piece) end +function Rotation:onPieceDrop(piece) + if piece.position.y > piece.lowest_point then + piece.lock_delay = 0 + piece.lowest_point = piece.position.y + end +end + +return Rotation diff --git a/libs/bigint/bigint.lua b/libs/bigint/bigint.lua new file mode 100644 index 0000000..4c4ed5d --- /dev/null +++ b/libs/bigint/bigint.lua @@ -0,0 +1,566 @@ +#!/usr/bin/env lua +-- If this variable is true, then strict type checking is performed for all +-- operations. This may result in slower code, but it will allow you to catch +-- errors and bugs earlier. +local strict = false + +-------------------------------------------------------------------------------- + +local bigint = {} + +local mt = { + __add = function(lhs, rhs) + return bigint.add(lhs, rhs) + end, + __unm = function(arg) + return bigint.negate(arg) + end, + __sub = function(lhs, rhs) + return bigint.subtract(lhs, rhs) + end, + __mul = function(lhs, rhs) + return bigint.multiply(lhs, rhs) + end, + __div = function(lhs, rhs) + return bigint.divide(lhs, rhs) + end, + __mod = function(lhs, rhs) + return bigint.modulus(lhs, rhs) + end, + __pow = function(lhs, rhs) + return bigint.exponentiate(lhs, rhs) + end, + __tostring = function(arg) + return bigint.unserialize(arg, "s") + end, + __eq = function(lhs, rhs) + return bigint.compare(lhs, rhs, "==") + end, + __lt = function(lhs, rhs) + return bigint.compare(lhs, rhs, "<") + end, + __le = function(lhs, rhs) + return bigint.compare(lhs, rhs, "<=") + end +} + +local named_powers = require("libs.bigint.named-powers-of-ten") + +-- Create a new bigint or convert a number or string into a big +-- Returns an empty, positive bigint if no number or string is given +function bigint.new(num) + local self = { + sign = "+", + digits = {} + } + + -- Return a new bigint with the same sign and digits + function self:clone() + local newint = bigint.new() + newint.sign = self.sign + for _, digit in pairs(self.digits) do + newint.digits[#newint.digits + 1] = digit + end + return newint + end + + setmetatable(self, mt) + + if (num) then + local num_string = tostring(num) + for digit in string.gmatch(num_string, "[0-9]") do + table.insert(self.digits, tonumber(digit)) + end + if string.sub(num_string, 1, 1) == "-" then + self.sign = "-" + end + end + + return self +end + +-- Check the type of a big +-- Normally only runs when global variable "strict" == true, but checking can be +-- forced by supplying "true" as the second argument. +function bigint.check(big, force) + if (strict or force) then + assert(getmetatable(big) == mt, "at least one arg is not a bigint") + assert(#big.digits > 0, "bigint is empty") + assert(big.sign == "+" or big.sign == "-", "bigint is unsigned") + for _, digit in pairs(big.digits) do + assert(type(digit) == "number", "at least one digit is invalid") + assert(digit <= 9 and digit >= 0, digit .. " is not between 0 and 9") + assert(math.floor(digit) == digit, digit .. " is not an integer") + end + end + return true +end + +-- Return a new big with the same digits but with a positive sign (absolute +-- value) +function bigint.abs(big) + bigint.check(big) + local result = big:clone() + result.sign = "+" + return result +end + +-- Return a new big with the same digits but the opposite sign (negation) +function bigint.negate(big) + bigint.check(big) + local result = big:clone() + if (result.sign == "+") then + result.sign = "-" + else + result.sign = "+" + end + return result +end + +-- Return the number of digits in the big +function bigint.digits(big) + bigint.check(big) + return #big.digits +end + +-- Convert a big to a number or string +function bigint.unserialize(big, output_type, precision) + bigint.check(big) + + local num = "" + if big.sign == "-" then + num = "-" + end + + + if ((output_type == nil) + or (output_type == "number") + or (output_type == "n") + or (output_type == "string") + or (output_type == "s")) then + -- Unserialization to a string or number requires reconstructing the + -- entire number + + for _, digit in pairs(big.digits) do + num = num .. math.floor(digit) -- lazy way of getting rid of .0$ + end + + if ((output_type == nil) + or (output_type == "number") + or (output_type == "n")) then + return tonumber(num) + else + return num + end + + else + -- Unserialization to human-readable form or scientific notation only + -- requires reading the first few digits + if (precision == nil) then + precision = math.min(#big.digits, 3) + else + assert(precision > 0, "Precision cannot be less than 1") + assert(math.floor(precision) == precision, + "Precision must be a positive integer") + end + + -- num is the first (precision + 1) digits, the first being separated by + -- a decimal point from the others + num = num .. math.floor(big.digits[1]) + if (precision > 1) then + num = num .. "." + for i = 1, (precision - 1) do + num = num .. math.floor(big.digits[i + 1]) + end + end + + if ((output_type == "human-readable") + or (output_type == "human") + or (output_type == "h")) + and (#big.digits >= 3 and #big.digits <= 10002) then + -- Human-readable output contributed by 123eee555 + + local name + local walkback = 0 -- Used to enumerate "ten", "hundred", etc + + -- Walk backwards in the index of named_powers starting at the + -- number of digits of the input until the first value is found + for i = (#big.digits - 1), (#big.digits - 4), -1 do + name = named_powers[i] + if (name) then + if (walkback == 1) then + name = "ten " .. name + elseif (walkback == 2) then + name = "hundred " .. name + end + break + else + walkback = walkback + 1 + end + end + + return num .. " " .. name + + else + return num .. "*10^" .. (#big.digits - 1) + end + + end +end + +-- Basic comparisons +-- Accepts symbols (<, >=, ~=) and Unix shell-like options (lt, ge, ne) +function bigint.compare(big1, big2, comparison) + bigint.check(big1) + bigint.check(big2) + + local greater = false -- If big1.digits > big2.digits + local equal = false + + if (big1.sign == "-") and (big2.sign == "+") then + greater = false + elseif (#big1.digits > #big2.digits) + or ((big1.sign == "+") and (big2.sign == "-")) then + greater = true + elseif (#big1.digits == #big2.digits) then + -- Walk left to right, comparing digits + for digit = 1, #big1.digits do + if (big1.digits[digit] > big2.digits[digit]) then + greater = true + break + elseif (big2.digits[digit] > big1.digits[digit]) then + break + elseif (digit == #big1.digits) + and (big1.digits[digit] == big2.digits[digit]) then + equal = true + end + end + + end + + -- If both numbers are negative, then the requirements for greater are + -- reversed + if (not equal) and (big1.sign == "-") and (big2.sign == "-") then + greater = not greater + end + + return (((comparison == "<") or (comparison == "lt")) + and ((not greater) and (not equal)) and true) + or (((comparison == ">") or (comparison == "gt")) + and ((greater) and (not equal)) and true) + or (((comparison == "==") or (comparison == "eq")) + and (equal) and true) + or (((comparison == ">=") or (comparison == "ge")) + and (equal or greater) and true) + or (((comparison == "<=") or (comparison == "le")) + and (equal or not greater) and true) + or (((comparison == "~=") or (comparison == "!=") or (comparison == "ne")) + and (not equal) and true) + or false +end + +-- BACKEND: Add big1 and big2, ignoring signs +function bigint.add_raw(big1, big2) + bigint.check(big1) + bigint.check(big2) + + local result = bigint.new() + local max_digits = 0 + local carry = 0 + + if (#big1.digits >= #big2.digits) then + max_digits = #big1.digits + else + max_digits = #big2.digits + end + + -- Walk backwards right to left, like in long addition + for digit = 0, max_digits - 1 do + local sum = (big1.digits[#big1.digits - digit] or 0) + + (big2.digits[#big2.digits - digit] or 0) + + carry + + if (sum >= 10) then + carry = 1 + sum = sum - 10 + else + carry = 0 + end + + result.digits[max_digits - digit] = sum + end + + -- Leftover carry in cases when #big1.digits == #big2.digits and sum > 10, ex. 7 + 9 + if (carry == 1) then + table.insert(result.digits, 1, 1) + end + + return result + +end + +-- BACKEND: Subtract big2 from big1, ignoring signs +function bigint.subtract_raw(big1, big2) + -- Type checking is done by bigint.compare + assert(bigint.compare(bigint.abs(big1), bigint.abs(big2), ">="), + "Size of " .. bigint.unserialize(big1, "string") .. " is less than " + .. bigint.unserialize(big2, "string")) + + local result = big1:clone() + local max_digits = #big1.digits + local borrow = 0 + + -- Logic mostly copied from bigint.add_raw --------------------------------- + -- Walk backwards right to left, like in long subtraction + for digit = 0, max_digits - 1 do + local diff = (big1.digits[#big1.digits - digit] or 0) + - (big2.digits[#big2.digits - digit] or 0) + - borrow + + if (diff < 0) then + borrow = 1 + diff = diff + 10 + else + borrow = 0 + end + + result.digits[max_digits - digit] = diff + end + ---------------------------------------------------------------------------- + + + -- Strip leading zeroes if any, but not if 0 is the only digit + while (#result.digits > 1) and (result.digits[1] == 0) do + table.remove(result.digits, 1) + end + + return result +end + +-- FRONTEND: Addition and subtraction operations, accounting for signs +function bigint.add(big1, big2) + -- Type checking is done by bigint.compare + + local result + + -- If adding numbers of different sign, subtract the smaller sized one from + -- the bigger sized one and take the sign of the bigger sized one + if (big1.sign ~= big2.sign) then + if (bigint.compare(bigint.abs(big1), bigint.abs(big2), ">")) then + result = bigint.subtract_raw(big1, big2) + result.sign = big1.sign + else + result = bigint.subtract_raw(big2, big1) + result.sign = big2.sign + end + + elseif (big1.sign == "+") and (big2.sign == "+") then + result = bigint.add_raw(big1, big2) + + elseif (big1.sign == "-") and (big2.sign == "-") then + result = bigint.add_raw(big1, big2) + result.sign = "-" + end + + return result +end +function bigint.subtract(big1, big2) + -- Type checking is done by bigint.compare in bigint.add + -- Subtracting is like adding a negative + local big2_local = big2:clone() + if (big2.sign == "+") then + big2_local.sign = "-" + else + big2_local.sign = "+" + end + return bigint.add(big1, big2_local) +end + +-- BACKEND: Multiply a big by a single digit big, ignoring signs +function bigint.multiply_single(big1, big2) + bigint.check(big1) + bigint.check(big2) + assert(#big2.digits == 1, bigint.unserialize(big2, "string") + .. " has more than one digit") + + local result = bigint.new() + local carry = 0 + + -- Logic mostly copied from bigint.add_raw --------------------------------- + -- Walk backwards right to left, like in long multiplication + for digit = 0, #big1.digits - 1 do + local this_digit = big1.digits[#big1.digits - digit] + * big2.digits[1] + + carry + + if (this_digit >= 10) then + carry = math.floor(this_digit / 10) + this_digit = this_digit - (carry * 10) + else + carry = 0 + end + + result.digits[#big1.digits - digit] = this_digit + end + + -- Leftover carry in cases when big1.digits[1] * big2.digits[1] > 0 + if (carry > 0) then + table.insert(result.digits, 1, carry) + end + ---------------------------------------------------------------------------- + + return result +end + +-- FRONTEND: Multiply two bigs, accounting for signs +function bigint.multiply(big1, big2) + -- Type checking done by bigint.multiply_single + + local result = bigint.new(0) + local larger, smaller -- Larger and smaller in terms of digits, not size + + if (bigint.unserialize(big1) == 0) or (bigint.unserialize(big2) == 0) then + return result + end + + if (#big1.digits >= #big2.digits) then + larger = big1 + smaller = big2 + else + larger = big2 + smaller = big1 + end + + -- Walk backwards right to left, like in long multiplication + for digit = 0, #smaller.digits - 1 do + -- Sorry for going over column 80! There's lots of big names here + local this_digit_product = bigint.multiply_single(larger, + bigint.new(smaller.digits[#smaller.digits - digit])) + + -- "Placeholding zeroes" + if (digit > 0) then + for placeholder = 1, digit do + table.insert(this_digit_product.digits, 0) + end + end + + result = bigint.add(result, this_digit_product) + end + + if (larger.sign == smaller.sign) then + result.sign = "+" + else + result.sign = "-" + end + + return result +end + +-- Raise a big to a positive integer or big power (TODO: negative integer power) +function bigint.exponentiate(big, power) + -- Type checking for big done by bigint.multiply + assert(bigint.compare(power, bigint.new(0), ">="), + " negative powers are not supported") + local exp = power:clone() + + if (bigint.compare(exp, bigint.new(0), "==")) then + return bigint.new(1) + elseif (bigint.compare(exp, bigint.new(1), "==")) then + return big:clone() + else + local result = bigint.new(1) + local base = big:clone() + + while (true) do + if (bigint.compare( + bigint.modulus(exp, bigint.new(2)), bigint.new(1), "==" + )) then + result = bigint.multiply(result, base) + end + if (bigint.compare(exp, bigint.new(1), "==")) then + break + else + exp = bigint.divide(exp, bigint.new(2)) + base = bigint.multiply(base, base) + end + end + + return result + end + +end + +-- BACKEND: Divide two bigs (decimals not supported), returning big result and +-- big remainder +-- WARNING: Only supports positive integers +function bigint.divide_raw(big1, big2) + -- Type checking done by bigint.compare + if (bigint.compare(big1, big2, "==")) then + return bigint.new(1), bigint.new(0) + elseif (bigint.compare(big1, big2, "<")) then + return bigint.new(0), big1:clone() + else + assert(bigint.compare(big2, bigint.new(0), "!="), "error: divide by zero") + assert(big1.sign == "+", "error: big1 is not positive") + assert(big2.sign == "+", "error: big2 is not positive") + + local result = bigint.new() + + local dividend = bigint.new() -- Dividend of a single operation + + local neg_zero = bigint.new(0) + neg_zero.sign = "-" + + for i = 1, #big1.digits do + -- Fixes a negative zero bug + if (#dividend.digits ~= 0) and (bigint.compare(dividend, neg_zero, "==")) then + dividend = bigint.new() + end + + table.insert(dividend.digits, big1.digits[i]) + + local factor = bigint.new(0) + while bigint.compare(dividend, big2, ">=") do + dividend = bigint.subtract(dividend, big2) + factor = bigint.add(factor, bigint.new(1)) + end + + for i = 0, #factor.digits - 1 do + result.digits[#result.digits + 1 - i] = factor.digits[i + 1] + end + end + + -- Remove leading zeros from result + while (result.digits[1] == 0) do + table.remove(result.digits, 1) + end + + return result, dividend + end +end + +-- FRONTEND: Divide two bigs (decimals not supported), returning big result and +-- big remainder, accounting for signs +function bigint.divide(big1, big2) + local result, remainder = bigint.divide_raw(bigint.abs(big1), + bigint.abs(big2)) + if (big1.sign == big2.sign) then + result.sign = "+" + else + result.sign = "-" + end + + return result, remainder +end + +-- FRONTEND: Return only the remainder from bigint.divide +function bigint.modulus(big1, big2) + local result, remainder = bigint.divide(big1, big2) + + -- Remainder will always have the same sign as the dividend per C standard + -- https://en.wikipedia.org/wiki/Modulo_operation#Remainder_calculation_for_the_modulo_operation + remainder.sign = big1.sign + return remainder +end + +return bigint diff --git a/libs/bigint/named-powers-of-ten.lua b/libs/bigint/named-powers-of-ten.lua new file mode 100644 index 0000000..aaa81ef --- /dev/null +++ b/libs/bigint/named-powers-of-ten.lua @@ -0,0 +1,3340 @@ +-- Generated by util/isthe.com-number-names.sh + +number_names = {} + +number_names[2] = "hundred" +number_names[3] = "thousand" +number_names[6] = "million" +number_names[9] = "billion" +number_names[12] = "trillion" +number_names[15] = "quadrillion" +number_names[18] = "quintillion" +number_names[21] = "sextillion" +number_names[24] = "septillion" +number_names[27] = "octillion" +number_names[30] = "nonillion" +number_names[33] = "decillion" +number_names[36] = "undecillion" +number_names[39] = "duodecillion" +number_names[42] = "tredecillion" +number_names[45] = "quattuordecillion" +number_names[48] = "quindecillion" +number_names[51] = "sexdecillion" +number_names[54] = "septendecillion" +number_names[57] = "octadecillion" +number_names[60] = "novemdecillion" +number_names[63] = "vigintillion" +number_names[66] = "unvigintillion" +number_names[69] = "duovigintillion" +number_names[72] = "trevigintillion" +number_names[75] = "quattuorvigintillion" +number_names[78] = "quinvigintillion" +number_names[81] = "sexvigintillion" +number_names[84] = "septenvigintillion" +number_names[87] = "octavigintillion" +number_names[90] = "novemvigintillion" +number_names[93] = "trigintillion" +number_names[96] = "untrigintillion" +number_names[99] = "duotrigintillion" +number_names[102] = "tretrigintillion" +number_names[105] = "quattuortrigintillion" +number_names[108] = "quintrigintillion" +number_names[111] = "sextrigintillion" +number_names[114] = "septentrigintillion" +number_names[117] = "octatrigintillion" +number_names[120] = "novemtrigintillion" +number_names[123] = "quadragintillion" +number_names[126] = "unquadragintillion" +number_names[129] = "duoquadragintillion" +number_names[132] = "trequadragintillion" +number_names[135] = "quattuorquadragintillion" +number_names[138] = "quinquadragintillion" +number_names[141] = "sexquadragintillion" +number_names[144] = "septenquadragintillion" +number_names[147] = "octaquadragintillion" +number_names[150] = "novemquadragintillion" +number_names[153] = "quinquagintillion" +number_names[156] = "unquinquagintillion" +number_names[159] = "duoquinquagintillion" +number_names[162] = "trequinquagintillion" +number_names[165] = "quattuorquinquagintillion" +number_names[168] = "quinquinquagintillion" +number_names[171] = "sexquinquagintillion" +number_names[174] = "septenquinquagintillion" +number_names[177] = "octaquinquagintillion" +number_names[180] = "novemquinquagintillion" +number_names[183] = "sexagintillion" +number_names[186] = "unsexagintillion" +number_names[189] = "duosexagintillion" +number_names[192] = "tresexagintillion" +number_names[195] = "quattuorsexagintillion" +number_names[198] = "quinsexagintillion" +number_names[201] = "sexsexagintillion" +number_names[204] = "septensexagintillion" +number_names[207] = "octasexagintillion" +number_names[210] = "novemsexagintillion" +number_names[213] = "septuagintillion" +number_names[216] = "unseptuagintillion" +number_names[219] = "duoseptuagintillion" +number_names[222] = "treseptuagintillion" +number_names[225] = "quattuorseptuagintillion" +number_names[228] = "quinseptuagintillion" +number_names[231] = "sexseptuagintillion" +number_names[234] = "septenseptuagintillion" +number_names[237] = "octaseptuagintillion" +number_names[240] = "novemseptuagintillion" +number_names[243] = "octagintillion" +number_names[246] = "unoctogintillion" +number_names[249] = "duooctogintillion" +number_names[252] = "treoctogintillion" +number_names[255] = "quattuoroctogintillion" +number_names[258] = "quinoctogintillion" +number_names[261] = "sexoctogintillion" +number_names[264] = "septenoctogintillion" +number_names[267] = "octaoctogintillion" +number_names[270] = "novemoctogintillion" +number_names[273] = "nonagintillion" +number_names[276] = "unnonagintillion" +number_names[279] = "duononagintillion" +number_names[282] = "trenonagintillion" +number_names[285] = "quattuornonagintillion" +number_names[288] = "quinnonagintillion" +number_names[291] = "sexnonagintillion" +number_names[294] = "septennonagintillion" +number_names[297] = "octanonagintillion" +number_names[300] = "novemnonagintillion" +number_names[303] = "centillion" +number_names[306] = "cenuntillion" +number_names[309] = "cendotillion" +number_names[312] = "centretillion" +number_names[315] = "cenquattuortillion" +number_names[318] = "cenquintillion" +number_names[321] = "censextillion" +number_names[324] = "censeptentillion" +number_names[327] = "cenoctotillion" +number_names[330] = "cennovemtillion" +number_names[333] = "cendecillion" +number_names[336] = "cenundecillion" +number_names[339] = "cendodecillion" +number_names[342] = "centredecillion" +number_names[345] = "cenquattuordecillion" +number_names[348] = "cenquindecillion" +number_names[351] = "censexdecillion" +number_names[354] = "censeptendecillion" +number_names[357] = "cenoctodecillion" +number_names[360] = "cennovemdecillion" +number_names[363] = "cenvigintillion" +number_names[366] = "cenunvigintillion" +number_names[369] = "cendovigintillion" +number_names[372] = "centrevigintillion" +number_names[375] = "cenquattuorvigintillion" +number_names[378] = "cenquinvigintillion" +number_names[381] = "censexvigintillion" +number_names[384] = "censeptenvigintillion" +number_names[387] = "cenoctovigintillion" +number_names[390] = "cennovemvigintillion" +number_names[393] = "centrigintillion" +number_names[396] = "cenuntrigintillion" +number_names[399] = "cendotrigintillion" +number_names[402] = "centretrigintillion" +number_names[405] = "cenquattuortrigintillion" +number_names[408] = "cenquintrigintillion" +number_names[411] = "censextrigintillion" +number_names[414] = "censeptentrigintillion" +number_names[417] = "cenoctotrigintillion" +number_names[420] = "cennovemtrigintillion" +number_names[423] = "cenquadragintillion" +number_names[426] = "cenunquadragintillion" +number_names[429] = "cendoquadragintillion" +number_names[432] = "centrequadragintillion" +number_names[435] = "cenquattuorquadragintillion" +number_names[438] = "cenquinquadragintillion" +number_names[441] = "censexquadragintillion" +number_names[444] = "censeptenquadragintillion" +number_names[447] = "cenoctoquadragintillion" +number_names[450] = "cennovemquadragintillion" +number_names[453] = "cenquinquagintillion" +number_names[456] = "cenunquinquagintillion" +number_names[459] = "cendoquinquagintillion" +number_names[462] = "centrequinquagintillion" +number_names[465] = "cenquattuorquinquagintillion" +number_names[468] = "cenquinquinquagintillion" +number_names[471] = "censexquinquagintillion" +number_names[474] = "censeptenquinquagintillion" +number_names[477] = "cenoctoquinquagintillion" +number_names[480] = "cennovemquinquagintillion" +number_names[483] = "censexagintillion" +number_names[486] = "cenunsexagintillion" +number_names[489] = "cendosexagintillion" +number_names[492] = "centresexagintillion" +number_names[495] = "cenquattuorsexagintillion" +number_names[498] = "cenquinsexagintillion" +number_names[501] = "censexsexagintillion" +number_names[504] = "censeptensexagintillion" +number_names[507] = "cenoctosexagintillion" +number_names[510] = "cennovemsexagintillion" +number_names[513] = "censeptuagintillion" +number_names[516] = "cenunseptuagintillion" +number_names[519] = "cendoseptuagintillion" +number_names[522] = "centreseptuagintillion" +number_names[525] = "cenquattuorseptuagintillion" +number_names[528] = "cenquinseptuagintillion" +number_names[531] = "censexseptuagintillion" +number_names[534] = "censeptenseptuagintillion" +number_names[537] = "cenoctoseptuagintillion" +number_names[540] = "cennovemseptuagintillion" +number_names[543] = "cenoctogintillion" +number_names[546] = "cenunoctogintillion" +number_names[549] = "cendooctogintillion" +number_names[552] = "centreoctogintillion" +number_names[555] = "cenquattuoroctogintillion" +number_names[558] = "cenquinoctogintillion" +number_names[561] = "censexoctogintillion" +number_names[564] = "censeptenoctogintillion" +number_names[567] = "cenoctooctogintillion" +number_names[570] = "cennovemoctogintillion" +number_names[573] = "cennonagintillion" +number_names[576] = "cenunnonagintillion" +number_names[579] = "cendononagintillion" +number_names[582] = "centrenonagintillion" +number_names[585] = "cenquattuornonagintillion" +number_names[588] = "cenquinnonagintillion" +number_names[591] = "censexnonagintillion" +number_names[594] = "censeptennonagintillion" +number_names[597] = "cenoctononagintillion" +number_names[600] = "cennovemnonagintillion" +number_names[603] = "duocentillion" +number_names[606] = "duocenuntillion" +number_names[609] = "duocendotillion" +number_names[612] = "duocentretillion" +number_names[615] = "duocenquattuortillion" +number_names[618] = "duocenquintillion" +number_names[621] = "duocensextillion" +number_names[624] = "duocenseptentillion" +number_names[627] = "duocenoctotillion" +number_names[630] = "duocennovemtillion" +number_names[633] = "duocendecillion" +number_names[636] = "duocenundecillion" +number_names[639] = "duocendodecillion" +number_names[642] = "duocentredecillion" +number_names[645] = "duocenquattuordecillion" +number_names[648] = "duocenquindecillion" +number_names[651] = "duocensexdecillion" +number_names[654] = "duocenseptendecillion" +number_names[657] = "duocenoctodecillion" +number_names[660] = "duocennovemdecillion" +number_names[663] = "duocenvigintillion" +number_names[666] = "duocenunvigintillion" +number_names[669] = "duocendovigintillion" +number_names[672] = "duocentrevigintillion" +number_names[675] = "duocenquattuorvigintillion" +number_names[678] = "duocenquinvigintillion" +number_names[681] = "duocensexvigintillion" +number_names[684] = "duocenseptenvigintillion" +number_names[687] = "duocenoctovigintillion" +number_names[690] = "duocennovemvigintillion" +number_names[693] = "duocentrigintillion" +number_names[696] = "duocenuntrigintillion" +number_names[699] = "duocendotrigintillion" +number_names[702] = "duocentretrigintillion" +number_names[705] = "duocenquattuortrigintillion" +number_names[708] = "duocenquintrigintillion" +number_names[711] = "duocensextrigintillion" +number_names[714] = "duocenseptentrigintillion" +number_names[717] = "duocenoctotrigintillion" +number_names[720] = "duocennovemtrigintillion" +number_names[723] = "duocenquadragintillion" +number_names[726] = "duocenunquadragintillion" +number_names[729] = "duocendoquadragintillion" +number_names[732] = "duocentrequadragintillion" +number_names[735] = "duocenquattuorquadragintillion" +number_names[738] = "duocenquinquadragintillion" +number_names[741] = "duocensexquadragintillion" +number_names[744] = "duocenseptenquadragintillion" +number_names[747] = "duocenoctoquadragintillion" +number_names[750] = "duocennovemquadragintillion" +number_names[753] = "duocenquinquagintillion" +number_names[756] = "duocenunquinquagintillion" +number_names[759] = "duocendoquinquagintillion" +number_names[762] = "duocentrequinquagintillion" +number_names[765] = "duocenquattuorquinquagintillion" +number_names[768] = "duocenquinquinquagintillion" +number_names[771] = "duocensexquinquagintillion" +number_names[774] = "duocenseptenquinquagintillion" +number_names[777] = "duocenoctoquinquagintillion" +number_names[780] = "duocennovemquinquagintillion" +number_names[783] = "duocensexagintillion" +number_names[786] = "duocenunsexagintillion" +number_names[789] = "duocendosexagintillion" +number_names[792] = "duocentresexagintillion" +number_names[795] = "duocenquattuorsexagintillion" +number_names[798] = "duocenquinsexagintillion" +number_names[801] = "duocensexsexagintillion" +number_names[804] = "duocenseptensexagintillion" +number_names[807] = "duocenoctosexagintillion" +number_names[810] = "duocennovemsexagintillion" +number_names[813] = "duocenseptuagintillion" +number_names[816] = "duocenunseptuagintillion" +number_names[819] = "duocendoseptuagintillion" +number_names[822] = "duocentreseptuagintillion" +number_names[825] = "duocenquattuorseptuagintillion" +number_names[828] = "duocenquinseptuagintillion" +number_names[831] = "duocensexseptuagintillion" +number_names[834] = "duocenseptenseptuagintillion" +number_names[837] = "duocenoctoseptuagintillion" +number_names[840] = "duocennovemseptuagintillion" +number_names[843] = "duocenoctogintillion" +number_names[846] = "duocenunoctogintillion" +number_names[849] = "duocendooctogintillion" +number_names[852] = "duocentreoctogintillion" +number_names[855] = "duocenquattuoroctogintillion" +number_names[858] = "duocenquinoctogintillion" +number_names[861] = "duocensexoctogintillion" +number_names[864] = "duocenseptenoctogintillion" +number_names[867] = "duocenoctooctogintillion" +number_names[870] = "duocennovemoctogintillion" +number_names[873] = "duocennonagintillion" +number_names[876] = "duocenunnonagintillion" +number_names[879] = "duocendononagintillion" +number_names[882] = "duocentrenonagintillion" +number_names[885] = "duocenquattuornonagintillion" +number_names[888] = "duocenquinnonagintillion" +number_names[891] = "duocensexnonagintillion" +number_names[894] = "duocenseptennonagintillion" +number_names[897] = "duocenoctononagintillion" +number_names[900] = "duocennovemnonagintillion" +number_names[903] = "trecentillion" +number_names[906] = "trecenuntillion" +number_names[909] = "trecendotillion" +number_names[912] = "trecentretillion" +number_names[915] = "trecenquattuortillion" +number_names[918] = "trecenquintillion" +number_names[921] = "trecensextillion" +number_names[924] = "trecenseptentillion" +number_names[927] = "trecenoctotillion" +number_names[930] = "trecennovemtillion" +number_names[933] = "trecendecillion" +number_names[936] = "trecenundecillion" +number_names[939] = "trecendodecillion" +number_names[942] = "trecentredecillion" +number_names[945] = "trecenquattuordecillion" +number_names[948] = "trecenquindecillion" +number_names[951] = "trecensexdecillion" +number_names[954] = "trecenseptendecillion" +number_names[957] = "trecenoctodecillion" +number_names[960] = "trecennovemdecillion" +number_names[963] = "trecenvigintillion" +number_names[966] = "trecenunvigintillion" +number_names[969] = "trecendovigintillion" +number_names[972] = "trecentrevigintillion" +number_names[975] = "trecenquattuorvigintillion" +number_names[978] = "trecenquinvigintillion" +number_names[981] = "trecensexvigintillion" +number_names[984] = "trecenseptenvigintillion" +number_names[987] = "trecenoctovigintillion" +number_names[990] = "trecennovemvigintillion" +number_names[993] = "trecentrigintillion" +number_names[996] = "trecenuntrigintillion" +number_names[999] = "trecendotrigintillion" +number_names[1002] = "trecentretrigintillion" +number_names[1005] = "trecenquattuortrigintillion" +number_names[1008] = "trecenquintrigintillion" +number_names[1011] = "trecensextrigintillion" +number_names[1014] = "trecenseptentrigintillion" +number_names[1017] = "trecenoctotrigintillion" +number_names[1020] = "trecennovemtrigintillion" +number_names[1023] = "trecenquadragintillion" +number_names[1026] = "trecenunquadragintillion" +number_names[1029] = "trecendoquadragintillion" +number_names[1032] = "trecentrequadragintillion" +number_names[1035] = "trecenquattuorquadragintillion" +number_names[1038] = "trecenquinquadragintillion" +number_names[1041] = "trecensexquadragintillion" +number_names[1044] = "trecenseptenquadragintillion" +number_names[1047] = "trecenoctoquadragintillion" +number_names[1050] = "trecennovemquadragintillion" +number_names[1053] = "trecenquinquagintillion" +number_names[1056] = "trecenunquinquagintillion" +number_names[1059] = "trecendoquinquagintillion" +number_names[1062] = "trecentrequinquagintillion" +number_names[1065] = "trecenquattuorquinquagintillion" +number_names[1068] = "trecenquinquinquagintillion" +number_names[1071] = "trecensexquinquagintillion" +number_names[1074] = "trecenseptenquinquagintillion" +number_names[1077] = "trecenoctoquinquagintillion" +number_names[1080] = "trecennovemquinquagintillion" +number_names[1083] = "trecensexagintillion" +number_names[1086] = "trecenunsexagintillion" +number_names[1089] = "trecendosexagintillion" +number_names[1092] = "trecentresexagintillion" +number_names[1095] = "trecenquattuorsexagintillion" +number_names[1098] = "trecenquinsexagintillion" +number_names[1101] = "trecensexsexagintillion" +number_names[1104] = "trecenseptensexagintillion" +number_names[1107] = "trecenoctosexagintillion" +number_names[1110] = "trecennovemsexagintillion" +number_names[1113] = "trecenseptuagintillion" +number_names[1116] = "trecenunseptuagintillion" +number_names[1119] = "trecendoseptuagintillion" +number_names[1122] = "trecentreseptuagintillion" +number_names[1125] = "trecenquattuorseptuagintillion" +number_names[1128] = "trecenquinseptuagintillion" +number_names[1131] = "trecensexseptuagintillion" +number_names[1134] = "trecenseptenseptuagintillion" +number_names[1137] = "trecenoctoseptuagintillion" +number_names[1140] = "trecennovemseptuagintillion" +number_names[1143] = "trecenoctogintillion" +number_names[1146] = "trecenunoctogintillion" +number_names[1149] = "trecendooctogintillion" +number_names[1152] = "trecentreoctogintillion" +number_names[1155] = "trecenquattuoroctogintillion" +number_names[1158] = "trecenquinoctogintillion" +number_names[1161] = "trecensexoctogintillion" +number_names[1164] = "trecenseptenoctogintillion" +number_names[1167] = "trecenoctooctogintillion" +number_names[1170] = "trecennovemoctogintillion" +number_names[1173] = "trecennonagintillion" +number_names[1176] = "trecenunnonagintillion" +number_names[1179] = "trecendononagintillion" +number_names[1182] = "trecentrenonagintillion" +number_names[1185] = "trecenquattuornonagintillion" +number_names[1188] = "trecenquinnonagintillion" +number_names[1191] = "trecensexnonagintillion" +number_names[1194] = "trecenseptennonagintillion" +number_names[1197] = "trecenoctononagintillion" +number_names[1200] = "trecennovemnonagintillion" +number_names[1203] = "quadringentillion" +number_names[1206] = "quadringenuntillion" +number_names[1209] = "quadringendotillion" +number_names[1212] = "quadringentretillion" +number_names[1215] = "quadringenquattuortillion" +number_names[1218] = "quadringenquintillion" +number_names[1221] = "quadringensextillion" +number_names[1224] = "quadringenseptentillion" +number_names[1227] = "quadringenoctotillion" +number_names[1230] = "quadringennovemtillion" +number_names[1233] = "quadringendecillion" +number_names[1236] = "quadringenundecillion" +number_names[1239] = "quadringendodecillion" +number_names[1242] = "quadringentredecillion" +number_names[1245] = "quadringenquattuordecillion" +number_names[1248] = "quadringenquindecillion" +number_names[1251] = "quadringensexdecillion" +number_names[1254] = "quadringenseptendecillion" +number_names[1257] = "quadringenoctodecillion" +number_names[1260] = "quadringennovemdecillion" +number_names[1263] = "quadringenvigintillion" +number_names[1266] = "quadringenunvigintillion" +number_names[1269] = "quadringendovigintillion" +number_names[1272] = "quadringentrevigintillion" +number_names[1275] = "quadringenquattuorvigintillion" +number_names[1278] = "quadringenquinvigintillion" +number_names[1281] = "quadringensexvigintillion" +number_names[1284] = "quadringenseptenvigintillion" +number_names[1287] = "quadringenoctovigintillion" +number_names[1290] = "quadringennovemvigintillion" +number_names[1293] = "quadringentrigintillion" +number_names[1296] = "quadringenuntrigintillion" +number_names[1299] = "quadringendotrigintillion" +number_names[1302] = "quadringentretrigintillion" +number_names[1305] = "quadringenquattuortrigintillion" +number_names[1308] = "quadringenquintrigintillion" +number_names[1311] = "quadringensextrigintillion" +number_names[1314] = "quadringenseptentrigintillion" +number_names[1317] = "quadringenoctotrigintillion" +number_names[1320] = "quadringennovemtrigintillion" +number_names[1323] = "quadringenquadragintillion" +number_names[1326] = "quadringenunquadragintillion" +number_names[1329] = "quadringendoquadragintillion" +number_names[1332] = "quadringentrequadragintillion" +number_names[1335] = "quadringenquattuorquadragintillion" +number_names[1338] = "quadringenquinquadragintillion" +number_names[1341] = "quadringensexquadragintillion" +number_names[1344] = "quadringenseptenquadragintillion" +number_names[1347] = "quadringenoctoquadragintillion" +number_names[1350] = "quadringennovemquadragintillion" +number_names[1353] = "quadringenquinquagintillion" +number_names[1356] = "quadringenunquinquagintillion" +number_names[1359] = "quadringendoquinquagintillion" +number_names[1362] = "quadringentrequinquagintillion" +number_names[1365] = "quadringenquattuorquinquagintillion" +number_names[1368] = "quadringenquinquinquagintillion" +number_names[1371] = "quadringensexquinquagintillion" +number_names[1374] = "quadringenseptenquinquagintillion" +number_names[1377] = "quadringenoctoquinquagintillion" +number_names[1380] = "quadringennovemquinquagintillion" +number_names[1383] = "quadringensexagintillion" +number_names[1386] = "quadringenunsexagintillion" +number_names[1389] = "quadringendosexagintillion" +number_names[1392] = "quadringentresexagintillion" +number_names[1395] = "quadringenquattuorsexagintillion" +number_names[1398] = "quadringenquinsexagintillion" +number_names[1401] = "quadringensexsexagintillion" +number_names[1404] = "quadringenseptensexagintillion" +number_names[1407] = "quadringenoctosexagintillion" +number_names[1410] = "quadringennovemsexagintillion" +number_names[1413] = "quadringenseptuagintillion" +number_names[1416] = "quadringenunseptuagintillion" +number_names[1419] = "quadringendoseptuagintillion" +number_names[1422] = "quadringentreseptuagintillion" +number_names[1425] = "quadringenquattuorseptuagintillion" +number_names[1428] = "quadringenquinseptuagintillion" +number_names[1431] = "quadringensexseptuagintillion" +number_names[1434] = "quadringenseptenseptuagintillion" +number_names[1437] = "quadringenoctoseptuagintillion" +number_names[1440] = "quadringennovemseptuagintillion" +number_names[1443] = "quadringenoctogintillion" +number_names[1446] = "quadringenunoctogintillion" +number_names[1449] = "quadringendooctogintillion" +number_names[1452] = "quadringentreoctogintillion" +number_names[1455] = "quadringenquattuoroctogintillion" +number_names[1458] = "quadringenquinoctogintillion" +number_names[1461] = "quadringensexoctogintillion" +number_names[1464] = "quadringenseptenoctogintillion" +number_names[1467] = "quadringenoctooctogintillion" +number_names[1470] = "quadringennovemoctogintillion" +number_names[1473] = "quadringennonagintillion" +number_names[1476] = "quadringenunnonagintillion" +number_names[1479] = "quadringendononagintillion" +number_names[1482] = "quadringentrenonagintillion" +number_names[1485] = "quadringenquattuornonagintillion" +number_names[1488] = "quadringenquinnonagintillion" +number_names[1491] = "quadringensexnonagintillion" +number_names[1494] = "quadringenseptennonagintillion" +number_names[1497] = "quadringenoctononagintillion" +number_names[1500] = "quadringennovemnonagintillion" +number_names[1503] = "quingentillion" +number_names[1506] = "quingenuntillion" +number_names[1509] = "quingendotillion" +number_names[1512] = "quingentretillion" +number_names[1515] = "quingenquattuortillion" +number_names[1518] = "quingenquintillion" +number_names[1521] = "quingensextillion" +number_names[1524] = "quingenseptentillion" +number_names[1527] = "quingenoctotillion" +number_names[1530] = "quingennovemtillion" +number_names[1533] = "quingendecillion" +number_names[1536] = "quingenundecillion" +number_names[1539] = "quingendodecillion" +number_names[1542] = "quingentredecillion" +number_names[1545] = "quingenquattuordecillion" +number_names[1548] = "quingenquindecillion" +number_names[1551] = "quingensexdecillion" +number_names[1554] = "quingenseptendecillion" +number_names[1557] = "quingenoctodecillion" +number_names[1560] = "quingennovemdecillion" +number_names[1563] = "quingenvigintillion" +number_names[1566] = "quingenunvigintillion" +number_names[1569] = "quingendovigintillion" +number_names[1572] = "quingentrevigintillion" +number_names[1575] = "quingenquattuorvigintillion" +number_names[1578] = "quingenquinvigintillion" +number_names[1581] = "quingensexvigintillion" +number_names[1584] = "quingenseptenvigintillion" +number_names[1587] = "quingenoctovigintillion" +number_names[1590] = "quingennovemvigintillion" +number_names[1593] = "quingentrigintillion" +number_names[1596] = "quingenuntrigintillion" +number_names[1599] = "quingendotrigintillion" +number_names[1602] = "quingentretrigintillion" +number_names[1605] = "quingenquattuortrigintillion" +number_names[1608] = "quingenquintrigintillion" +number_names[1611] = "quingensextrigintillion" +number_names[1614] = "quingenseptentrigintillion" +number_names[1617] = "quingenoctotrigintillion" +number_names[1620] = "quingennovemtrigintillion" +number_names[1623] = "quingenquadragintillion" +number_names[1626] = "quingenunquadragintillion" +number_names[1629] = "quingendoquadragintillion" +number_names[1632] = "quingentrequadragintillion" +number_names[1635] = "quingenquattuorquadragintillion" +number_names[1638] = "quingenquinquadragintillion" +number_names[1641] = "quingensexquadragintillion" +number_names[1644] = "quingenseptenquadragintillion" +number_names[1647] = "quingenoctoquadragintillion" +number_names[1650] = "quingennovemquadragintillion" +number_names[1653] = "quingenquinquagintillion" +number_names[1656] = "quingenunquinquagintillion" +number_names[1659] = "quingendoquinquagintillion" +number_names[1662] = "quingentrequinquagintillion" +number_names[1665] = "quingenquattuorquinquagintillion" +number_names[1668] = "quingenquinquinquagintillion" +number_names[1671] = "quingensexquinquagintillion" +number_names[1674] = "quingenseptenquinquagintillion" +number_names[1677] = "quingenoctoquinquagintillion" +number_names[1680] = "quingennovemquinquagintillion" +number_names[1683] = "quingensexagintillion" +number_names[1686] = "quingenunsexagintillion" +number_names[1689] = "quingendosexagintillion" +number_names[1692] = "quingentresexagintillion" +number_names[1695] = "quingenquattuorsexagintillion" +number_names[1698] = "quingenquinsexagintillion" +number_names[1701] = "quingensexsexagintillion" +number_names[1704] = "quingenseptensexagintillion" +number_names[1707] = "quingenoctosexagintillion" +number_names[1710] = "quingennovemsexagintillion" +number_names[1713] = "quingenseptuagintillion" +number_names[1716] = "quingenunseptuagintillion" +number_names[1719] = "quingendoseptuagintillion" +number_names[1722] = "quingentreseptuagintillion" +number_names[1725] = "quingenquattuorseptuagintillion" +number_names[1728] = "quingenquinseptuagintillion" +number_names[1731] = "quingensexseptuagintillion" +number_names[1734] = "quingenseptenseptuagintillion" +number_names[1737] = "quingenoctoseptuagintillion" +number_names[1740] = "quingennovemseptuagintillion" +number_names[1743] = "quingenoctogintillion" +number_names[1746] = "quingenunoctogintillion" +number_names[1749] = "quingendooctogintillion" +number_names[1752] = "quingentreoctogintillion" +number_names[1755] = "quingenquattuoroctogintillion" +number_names[1758] = "quingenquinoctogintillion" +number_names[1761] = "quingensexoctogintillion" +number_names[1764] = "quingenseptenoctogintillion" +number_names[1767] = "quingenoctooctogintillion" +number_names[1770] = "quingennovemoctogintillion" +number_names[1773] = "quingennonagintillion" +number_names[1776] = "quingenunnonagintillion" +number_names[1779] = "quingendononagintillion" +number_names[1782] = "quingentrenonagintillion" +number_names[1785] = "quingenquattuornonagintillion" +number_names[1788] = "quingenquinnonagintillion" +number_names[1791] = "quingensexnonagintillion" +number_names[1794] = "quingenseptennonagintillion" +number_names[1797] = "quingenoctononagintillion" +number_names[1800] = "quingennovemnonagintillion" +number_names[1803] = "sescentillion" +number_names[1806] = "sescenuntillion" +number_names[1809] = "sescendotillion" +number_names[1812] = "sescentretillion" +number_names[1815] = "sescenquattuortillion" +number_names[1818] = "sescenquintillion" +number_names[1821] = "sescensextillion" +number_names[1824] = "sescenseptentillion" +number_names[1827] = "sescenoctotillion" +number_names[1830] = "sescennovemtillion" +number_names[1833] = "sescendecillion" +number_names[1836] = "sescenundecillion" +number_names[1839] = "sescendodecillion" +number_names[1842] = "sescentredecillion" +number_names[1845] = "sescenquattuordecillion" +number_names[1848] = "sescenquindecillion" +number_names[1851] = "sescensexdecillion" +number_names[1854] = "sescenseptendecillion" +number_names[1857] = "sescenoctodecillion" +number_names[1860] = "sescennovemdecillion" +number_names[1863] = "sescenvigintillion" +number_names[1866] = "sescenunvigintillion" +number_names[1869] = "sescendovigintillion" +number_names[1872] = "sescentrevigintillion" +number_names[1875] = "sescenquattuorvigintillion" +number_names[1878] = "sescenquinvigintillion" +number_names[1881] = "sescensexvigintillion" +number_names[1884] = "sescenseptenvigintillion" +number_names[1887] = "sescenoctovigintillion" +number_names[1890] = "sescennovemvigintillion" +number_names[1893] = "sescentrigintillion" +number_names[1896] = "sescenuntrigintillion" +number_names[1899] = "sescendotrigintillion" +number_names[1902] = "sescentretrigintillion" +number_names[1905] = "sescenquattuortrigintillion" +number_names[1908] = "sescenquintrigintillion" +number_names[1911] = "sescensextrigintillion" +number_names[1914] = "sescenseptentrigintillion" +number_names[1917] = "sescenoctotrigintillion" +number_names[1920] = "sescennovemtrigintillion" +number_names[1923] = "sescenquadragintillion" +number_names[1926] = "sescenunquadragintillion" +number_names[1929] = "sescendoquadragintillion" +number_names[1932] = "sescentrequadragintillion" +number_names[1935] = "sescenquattuorquadragintillion" +number_names[1938] = "sescenquinquadragintillion" +number_names[1941] = "sescensexquadragintillion" +number_names[1944] = "sescenseptenquadragintillion" +number_names[1947] = "sescenoctoquadragintillion" +number_names[1950] = "sescennovemquadragintillion" +number_names[1953] = "sescenquinquagintillion" +number_names[1956] = "sescenunquinquagintillion" +number_names[1959] = "sescendoquinquagintillion" +number_names[1962] = "sescentrequinquagintillion" +number_names[1965] = "sescenquattuorquinquagintillion" +number_names[1968] = "sescenquinquinquagintillion" +number_names[1971] = "sescensexquinquagintillion" +number_names[1974] = "sescenseptenquinquagintillion" +number_names[1977] = "sescenoctoquinquagintillion" +number_names[1980] = "sescennovemquinquagintillion" +number_names[1983] = "sescensexagintillion" +number_names[1986] = "sescenunsexagintillion" +number_names[1989] = "sescendosexagintillion" +number_names[1992] = "sescentresexagintillion" +number_names[1995] = "sescenquattuorsexagintillion" +number_names[1998] = "sescenquinsexagintillion" +number_names[2001] = "sescensexsexagintillion" +number_names[2004] = "sescenseptensexagintillion" +number_names[2007] = "sescenoctosexagintillion" +number_names[2010] = "sescennovemsexagintillion" +number_names[2013] = "sescenseptuagintillion" +number_names[2016] = "sescenunseptuagintillion" +number_names[2019] = "sescendoseptuagintillion" +number_names[2022] = "sescentreseptuagintillion" +number_names[2025] = "sescenquattuorseptuagintillion" +number_names[2028] = "sescenquinseptuagintillion" +number_names[2031] = "sescensexseptuagintillion" +number_names[2034] = "sescenseptenseptuagintillion" +number_names[2037] = "sescenoctoseptuagintillion" +number_names[2040] = "sescennovemseptuagintillion" +number_names[2043] = "sescenoctogintillion" +number_names[2046] = "sescenunoctogintillion" +number_names[2049] = "sescendooctogintillion" +number_names[2052] = "sescentreoctogintillion" +number_names[2055] = "sescenquattuoroctogintillion" +number_names[2058] = "sescenquinoctogintillion" +number_names[2061] = "sescensexoctogintillion" +number_names[2064] = "sescenseptenoctogintillion" +number_names[2067] = "sescenoctooctogintillion" +number_names[2070] = "sescennovemoctogintillion" +number_names[2073] = "sescennonagintillion" +number_names[2076] = "sescenunnonagintillion" +number_names[2079] = "sescendononagintillion" +number_names[2082] = "sescentrenonagintillion" +number_names[2085] = "sescenquattuornonagintillion" +number_names[2088] = "sescenquinnonagintillion" +number_names[2091] = "sescensexnonagintillion" +number_names[2094] = "sescenseptennonagintillion" +number_names[2097] = "sescenoctononagintillion" +number_names[2100] = "sescennovemnonagintillion" +number_names[2103] = "septingentillion" +number_names[2106] = "septingenuntillion" +number_names[2109] = "septingendotillion" +number_names[2112] = "septingentretillion" +number_names[2115] = "septingenquattuortillion" +number_names[2118] = "septingenquintillion" +number_names[2121] = "septingensextillion" +number_names[2124] = "septingenseptentillion" +number_names[2127] = "septingenoctotillion" +number_names[2130] = "septingennovemtillion" +number_names[2133] = "septingendecillion" +number_names[2136] = "septingenundecillion" +number_names[2139] = "septingendodecillion" +number_names[2142] = "septingentredecillion" +number_names[2145] = "septingenquattuordecillion" +number_names[2148] = "septingenquindecillion" +number_names[2151] = "septingensexdecillion" +number_names[2154] = "septingenseptendecillion" +number_names[2157] = "septingenoctodecillion" +number_names[2160] = "septingennovemdecillion" +number_names[2163] = "septingenvigintillion" +number_names[2166] = "septingenunvigintillion" +number_names[2169] = "septingendovigintillion" +number_names[2172] = "septingentrevigintillion" +number_names[2175] = "septingenquattuorvigintillion" +number_names[2178] = "septingenquinvigintillion" +number_names[2181] = "septingensexvigintillion" +number_names[2184] = "septingenseptenvigintillion" +number_names[2187] = "septingenoctovigintillion" +number_names[2190] = "septingennovemvigintillion" +number_names[2193] = "septingentrigintillion" +number_names[2196] = "septingenuntrigintillion" +number_names[2199] = "septingendotrigintillion" +number_names[2202] = "septingentretrigintillion" +number_names[2205] = "septingenquattuortrigintillion" +number_names[2208] = "septingenquintrigintillion" +number_names[2211] = "septingensextrigintillion" +number_names[2214] = "septingenseptentrigintillion" +number_names[2217] = "septingenoctotrigintillion" +number_names[2220] = "septingennovemtrigintillion" +number_names[2223] = "septingenquadragintillion" +number_names[2226] = "septingenunquadragintillion" +number_names[2229] = "septingendoquadragintillion" +number_names[2232] = "septingentrequadragintillion" +number_names[2235] = "septingenquattuorquadragintillion" +number_names[2238] = "septingenquinquadragintillion" +number_names[2241] = "septingensexquadragintillion" +number_names[2244] = "septingenseptenquadragintillion" +number_names[2247] = "septingenoctoquadragintillion" +number_names[2250] = "septingennovemquadragintillion" +number_names[2253] = "septingenquinquagintillion" +number_names[2256] = "septingenunquinquagintillion" +number_names[2259] = "septingendoquinquagintillion" +number_names[2262] = "septingentrequinquagintillion" +number_names[2265] = "septingenquattuorquinquagintillion" +number_names[2268] = "septingenquinquinquagintillion" +number_names[2271] = "septingensexquinquagintillion" +number_names[2274] = "septingenseptenquinquagintillion" +number_names[2277] = "septingenoctoquinquagintillion" +number_names[2280] = "septingennovemquinquagintillion" +number_names[2283] = "septingensexagintillion" +number_names[2286] = "septingenunsexagintillion" +number_names[2289] = "septingendosexagintillion" +number_names[2292] = "septingentresexagintillion" +number_names[2295] = "septingenquattuorsexagintillion" +number_names[2298] = "septingenquinsexagintillion" +number_names[2301] = "septingensexsexagintillion" +number_names[2304] = "septingenseptensexagintillion" +number_names[2307] = "septingenoctosexagintillion" +number_names[2310] = "septingennovemsexagintillion" +number_names[2313] = "septingenseptuagintillion" +number_names[2316] = "septingenunseptuagintillion" +number_names[2319] = "septingendoseptuagintillion" +number_names[2322] = "septingentreseptuagintillion" +number_names[2325] = "septingenquattuorseptuagintillion" +number_names[2328] = "septingenquinseptuagintillion" +number_names[2331] = "septingensexseptuagintillion" +number_names[2334] = "septingenseptenseptuagintillion" +number_names[2337] = "septingenoctoseptuagintillion" +number_names[2340] = "septingennovemseptuagintillion" +number_names[2343] = "septingenoctogintillion" +number_names[2346] = "septingenunoctogintillion" +number_names[2349] = "septingendooctogintillion" +number_names[2352] = "septingentreoctogintillion" +number_names[2355] = "septingenquattuoroctogintillion" +number_names[2358] = "septingenquinoctogintillion" +number_names[2361] = "septingensexoctogintillion" +number_names[2364] = "septingenseptenoctogintillion" +number_names[2367] = "septingenoctooctogintillion" +number_names[2370] = "septingennovemoctogintillion" +number_names[2373] = "septingennonagintillion" +number_names[2376] = "septingenunnonagintillion" +number_names[2379] = "septingendononagintillion" +number_names[2382] = "septingentrenonagintillion" +number_names[2385] = "septingenquattuornonagintillion" +number_names[2388] = "septingenquinnonagintillion" +number_names[2391] = "septingensexnonagintillion" +number_names[2394] = "septingenseptennonagintillion" +number_names[2397] = "septingenoctononagintillion" +number_names[2400] = "septingennovemnonagintillion" +number_names[2403] = "octingentillion" +number_names[2406] = "octingenuntillion" +number_names[2409] = "octingendotillion" +number_names[2412] = "octingentretillion" +number_names[2415] = "octingenquattuortillion" +number_names[2418] = "octingenquintillion" +number_names[2421] = "octingensextillion" +number_names[2424] = "octingenseptentillion" +number_names[2427] = "octingenoctotillion" +number_names[2430] = "octingennovemtillion" +number_names[2433] = "octingendecillion" +number_names[2436] = "octingenundecillion" +number_names[2439] = "octingendodecillion" +number_names[2442] = "octingentredecillion" +number_names[2445] = "octingenquattuordecillion" +number_names[2448] = "octingenquindecillion" +number_names[2451] = "octingensexdecillion" +number_names[2454] = "octingenseptendecillion" +number_names[2457] = "octingenoctodecillion" +number_names[2460] = "octingennovemdecillion" +number_names[2463] = "octingenvigintillion" +number_names[2466] = "octingenunvigintillion" +number_names[2469] = "octingendovigintillion" +number_names[2472] = "octingentrevigintillion" +number_names[2475] = "octingenquattuorvigintillion" +number_names[2478] = "octingenquinvigintillion" +number_names[2481] = "octingensexvigintillion" +number_names[2484] = "octingenseptenvigintillion" +number_names[2487] = "octingenoctovigintillion" +number_names[2490] = "octingennovemvigintillion" +number_names[2493] = "octingentrigintillion" +number_names[2496] = "octingenuntrigintillion" +number_names[2499] = "octingendotrigintillion" +number_names[2502] = "octingentretrigintillion" +number_names[2505] = "octingenquattuortrigintillion" +number_names[2508] = "octingenquintrigintillion" +number_names[2511] = "octingensextrigintillion" +number_names[2514] = "octingenseptentrigintillion" +number_names[2517] = "octingenoctotrigintillion" +number_names[2520] = "octingennovemtrigintillion" +number_names[2523] = "octingenquadragintillion" +number_names[2526] = "octingenunquadragintillion" +number_names[2529] = "octingendoquadragintillion" +number_names[2532] = "octingentrequadragintillion" +number_names[2535] = "octingenquattuorquadragintillion" +number_names[2538] = "octingenquinquadragintillion" +number_names[2541] = "octingensexquadragintillion" +number_names[2544] = "octingenseptenquadragintillion" +number_names[2547] = "octingenoctoquadragintillion" +number_names[2550] = "octingennovemquadragintillion" +number_names[2553] = "octingenquinquagintillion" +number_names[2556] = "octingenunquinquagintillion" +number_names[2559] = "octingendoquinquagintillion" +number_names[2562] = "octingentrequinquagintillion" +number_names[2565] = "octingenquattuorquinquagintillion" +number_names[2568] = "octingenquinquinquagintillion" +number_names[2571] = "octingensexquinquagintillion" +number_names[2574] = "octingenseptenquinquagintillion" +number_names[2577] = "octingenoctoquinquagintillion" +number_names[2580] = "octingennovemquinquagintillion" +number_names[2583] = "octingensexagintillion" +number_names[2586] = "octingenunsexagintillion" +number_names[2589] = "octingendosexagintillion" +number_names[2592] = "octingentresexagintillion" +number_names[2595] = "octingenquattuorsexagintillion" +number_names[2598] = "octingenquinsexagintillion" +number_names[2601] = "octingensexsexagintillion" +number_names[2604] = "octingenseptensexagintillion" +number_names[2607] = "octingenoctosexagintillion" +number_names[2610] = "octingennovemsexagintillion" +number_names[2613] = "octingenseptuagintillion" +number_names[2616] = "octingenunseptuagintillion" +number_names[2619] = "octingendoseptuagintillion" +number_names[2622] = "octingentreseptuagintillion" +number_names[2625] = "octingenquattuorseptuagintillion" +number_names[2628] = "octingenquinseptuagintillion" +number_names[2631] = "octingensexseptuagintillion" +number_names[2634] = "octingenseptenseptuagintillion" +number_names[2637] = "octingenoctoseptuagintillion" +number_names[2640] = "octingennovemseptuagintillion" +number_names[2643] = "octingenoctogintillion" +number_names[2646] = "octingenunoctogintillion" +number_names[2649] = "octingendooctogintillion" +number_names[2652] = "octingentreoctogintillion" +number_names[2655] = "octingenquattuoroctogintillion" +number_names[2658] = "octingenquinoctogintillion" +number_names[2661] = "octingensexoctogintillion" +number_names[2664] = "octingenseptenoctogintillion" +number_names[2667] = "octingenoctooctogintillion" +number_names[2670] = "octingennovemoctogintillion" +number_names[2673] = "octingennonagintillion" +number_names[2676] = "octingenunnonagintillion" +number_names[2679] = "octingendononagintillion" +number_names[2682] = "octingentrenonagintillion" +number_names[2685] = "octingenquattuornonagintillion" +number_names[2688] = "octingenquinnonagintillion" +number_names[2691] = "octingensexnonagintillion" +number_names[2694] = "octingenseptennonagintillion" +number_names[2697] = "octingenoctononagintillion" +number_names[2700] = "octingennovemnonagintillion" +number_names[2703] = "nongentillion" +number_names[2706] = "nongenuntillion" +number_names[2709] = "nongendotillion" +number_names[2712] = "nongentretillion" +number_names[2715] = "nongenquattuortillion" +number_names[2718] = "nongenquintillion" +number_names[2721] = "nongensextillion" +number_names[2724] = "nongenseptentillion" +number_names[2727] = "nongenoctotillion" +number_names[2730] = "nongennovemtillion" +number_names[2733] = "nongendecillion" +number_names[2736] = "nongenundecillion" +number_names[2739] = "nongendodecillion" +number_names[2742] = "nongentredecillion" +number_names[2745] = "nongenquattuordecillion" +number_names[2748] = "nongenquindecillion" +number_names[2751] = "nongensexdecillion" +number_names[2754] = "nongenseptendecillion" +number_names[2757] = "nongenoctodecillion" +number_names[2760] = "nongennovemdecillion" +number_names[2763] = "nongenvigintillion" +number_names[2766] = "nongenunvigintillion" +number_names[2769] = "nongendovigintillion" +number_names[2772] = "nongentrevigintillion" +number_names[2775] = "nongenquattuorvigintillion" +number_names[2778] = "nongenquinvigintillion" +number_names[2781] = "nongensexvigintillion" +number_names[2784] = "nongenseptenvigintillion" +number_names[2787] = "nongenoctovigintillion" +number_names[2790] = "nongennovemvigintillion" +number_names[2793] = "nongentrigintillion" +number_names[2796] = "nongenuntrigintillion" +number_names[2799] = "nongendotrigintillion" +number_names[2802] = "nongentretrigintillion" +number_names[2805] = "nongenquattuortrigintillion" +number_names[2808] = "nongenquintrigintillion" +number_names[2811] = "nongensextrigintillion" +number_names[2814] = "nongenseptentrigintillion" +number_names[2817] = "nongenoctotrigintillion" +number_names[2820] = "nongennovemtrigintillion" +number_names[2823] = "nongenquadragintillion" +number_names[2826] = "nongenunquadragintillion" +number_names[2829] = "nongendoquadragintillion" +number_names[2832] = "nongentrequadragintillion" +number_names[2835] = "nongenquattuorquadragintillion" +number_names[2838] = "nongenquinquadragintillion" +number_names[2841] = "nongensexquadragintillion" +number_names[2844] = "nongenseptenquadragintillion" +number_names[2847] = "nongenoctoquadragintillion" +number_names[2850] = "nongennovemquadragintillion" +number_names[2853] = "nongenquinquagintillion" +number_names[2856] = "nongenunquinquagintillion" +number_names[2859] = "nongendoquinquagintillion" +number_names[2862] = "nongentrequinquagintillion" +number_names[2865] = "nongenquattuorquinquagintillion" +number_names[2868] = "nongenquinquinquagintillion" +number_names[2871] = "nongensexquinquagintillion" +number_names[2874] = "nongenseptenquinquagintillion" +number_names[2877] = "nongenoctoquinquagintillion" +number_names[2880] = "nongennovemquinquagintillion" +number_names[2883] = "nongensexagintillion" +number_names[2886] = "nongenunsexagintillion" +number_names[2889] = "nongendosexagintillion" +number_names[2892] = "nongentresexagintillion" +number_names[2895] = "nongenquattuorsexagintillion" +number_names[2898] = "nongenquinsexagintillion" +number_names[2901] = "nongensexsexagintillion" +number_names[2904] = "nongenseptensexagintillion" +number_names[2907] = "nongenoctosexagintillion" +number_names[2910] = "nongennovemsexagintillion" +number_names[2913] = "nongenseptuagintillion" +number_names[2916] = "nongenunseptuagintillion" +number_names[2919] = "nongendoseptuagintillion" +number_names[2922] = "nongentreseptuagintillion" +number_names[2925] = "nongenquattuorseptuagintillion" +number_names[2928] = "nongenquinseptuagintillion" +number_names[2931] = "nongensexseptuagintillion" +number_names[2934] = "nongenseptenseptuagintillion" +number_names[2937] = "nongenoctoseptuagintillion" +number_names[2940] = "nongennovemseptuagintillion" +number_names[2943] = "nongenoctogintillion" +number_names[2946] = "nongenunoctogintillion" +number_names[2949] = "nongendooctogintillion" +number_names[2952] = "nongentreoctogintillion" +number_names[2955] = "nongenquattuoroctogintillion" +number_names[2958] = "nongenquinoctogintillion" +number_names[2961] = "nongensexoctogintillion" +number_names[2964] = "nongenseptenoctogintillion" +number_names[2967] = "nongenoctooctogintillion" +number_names[2970] = "nongennovemoctogintillion" +number_names[2973] = "nongennonagintillion" +number_names[2976] = "nongenunnonagintillion" +number_names[2979] = "nongendononagintillion" +number_names[2982] = "nongentrenonagintillion" +number_names[2985] = "nongenquattuornonagintillion" +number_names[2988] = "nongenquinnonagintillion" +number_names[2991] = "nongensexnonagintillion" +number_names[2994] = "nongenseptennonagintillion" +number_names[2997] = "nongenoctononagintillion" +number_names[3000] = "nongennovemnonagintillion" +number_names[3003] = "milliatillion" +number_names[3006] = "milliauntillion" +number_names[3009] = "milliadotillion" +number_names[3012] = "milliatretillion" +number_names[3015] = "milliaquattuortillion" +number_names[3018] = "milliaquintillion" +number_names[3021] = "milliasextillion" +number_names[3024] = "milliaseptentillion" +number_names[3027] = "milliaoctotillion" +number_names[3030] = "millianovemtillion" +number_names[3033] = "milliadecillion" +number_names[3036] = "milliaundecillion" +number_names[3039] = "milliadodecillion" +number_names[3042] = "milliatredecillion" +number_names[3045] = "milliaquattuordecillion" +number_names[3048] = "milliaquindecillion" +number_names[3051] = "milliasexdecillion" +number_names[3054] = "milliaseptendecillion" +number_names[3057] = "milliaoctodecillion" +number_names[3060] = "millianovemdecillion" +number_names[3063] = "milliavigintillion" +number_names[3066] = "milliaunvigintillion" +number_names[3069] = "milliadovigintillion" +number_names[3072] = "milliatrevigintillion" +number_names[3075] = "milliaquattuorvigintillion" +number_names[3078] = "milliaquinvigintillion" +number_names[3081] = "milliasexvigintillion" +number_names[3084] = "milliaseptenvigintillion" +number_names[3087] = "milliaoctovigintillion" +number_names[3090] = "millianovemvigintillion" +number_names[3093] = "milliatrigintillion" +number_names[3096] = "milliauntrigintillion" +number_names[3099] = "milliadotrigintillion" +number_names[3102] = "milliatretrigintillion" +number_names[3105] = "milliaquattuortrigintillion" +number_names[3108] = "milliaquintrigintillion" +number_names[3111] = "milliasextrigintillion" +number_names[3114] = "milliaseptentrigintillion" +number_names[3117] = "milliaoctotrigintillion" +number_names[3120] = "millianovemtrigintillion" +number_names[3123] = "milliaquadragintillion" +number_names[3126] = "milliaunquadragintillion" +number_names[3129] = "milliadoquadragintillion" +number_names[3132] = "milliatrequadragintillion" +number_names[3135] = "milliaquattuorquadragintillion" +number_names[3138] = "milliaquinquadragintillion" +number_names[3141] = "milliasexquadragintillion" +number_names[3144] = "milliaseptenquadragintillion" +number_names[3147] = "milliaoctoquadragintillion" +number_names[3150] = "millianovemquadragintillion" +number_names[3153] = "milliaquinquagintillion" +number_names[3156] = "milliaunquinquagintillion" +number_names[3159] = "milliadoquinquagintillion" +number_names[3162] = "milliatrequinquagintillion" +number_names[3165] = "milliaquattuorquinquagintillion" +number_names[3168] = "milliaquinquinquagintillion" +number_names[3171] = "milliasexquinquagintillion" +number_names[3174] = "milliaseptenquinquagintillion" +number_names[3177] = "milliaoctoquinquagintillion" +number_names[3180] = "millianovemquinquagintillion" +number_names[3183] = "milliasexagintillion" +number_names[3186] = "milliaunsexagintillion" +number_names[3189] = "milliadosexagintillion" +number_names[3192] = "milliatresexagintillion" +number_names[3195] = "milliaquattuorsexagintillion" +number_names[3198] = "milliaquinsexagintillion" +number_names[3201] = "milliasexsexagintillion" +number_names[3204] = "milliaseptensexagintillion" +number_names[3207] = "milliaoctosexagintillion" +number_names[3210] = "millianovemsexagintillion" +number_names[3213] = "milliaseptuagintillion" +number_names[3216] = "milliaunseptuagintillion" +number_names[3219] = "milliadoseptuagintillion" +number_names[3222] = "milliatreseptuagintillion" +number_names[3225] = "milliaquattuorseptuagintillion" +number_names[3228] = "milliaquinseptuagintillion" +number_names[3231] = "milliasexseptuagintillion" +number_names[3234] = "milliaseptenseptuagintillion" +number_names[3237] = "milliaoctoseptuagintillion" +number_names[3240] = "millianovemseptuagintillion" +number_names[3243] = "milliaoctogintillion" +number_names[3246] = "milliaunoctogintillion" +number_names[3249] = "milliadooctogintillion" +number_names[3252] = "milliatreoctogintillion" +number_names[3255] = "milliaquattuoroctogintillion" +number_names[3258] = "milliaquinoctogintillion" +number_names[3261] = "milliasexoctogintillion" +number_names[3264] = "milliaseptenoctogintillion" +number_names[3267] = "milliaoctooctogintillion" +number_names[3270] = "millianovemoctogintillion" +number_names[3273] = "millianonagintillion" +number_names[3276] = "milliaunnonagintillion" +number_names[3279] = "milliadononagintillion" +number_names[3282] = "milliatrenonagintillion" +number_names[3285] = "milliaquattuornonagintillion" +number_names[3288] = "milliaquinnonagintillion" +number_names[3291] = "milliasexnonagintillion" +number_names[3294] = "milliaseptennonagintillion" +number_names[3297] = "milliaoctononagintillion" +number_names[3300] = "millianovemnonagintillion" +number_names[3303] = "milliacentillion" +number_names[3306] = "milliacenuntillion" +number_names[3309] = "milliacendotillion" +number_names[3312] = "milliacentretillion" +number_names[3315] = "milliacenquattuortillion" +number_names[3318] = "milliacenquintillion" +number_names[3321] = "milliacensextillion" +number_names[3324] = "milliacenseptentillion" +number_names[3327] = "milliacenoctotillion" +number_names[3330] = "milliacennovemtillion" +number_names[3333] = "milliacendecillion" +number_names[3336] = "milliacenundecillion" +number_names[3339] = "milliacendodecillion" +number_names[3342] = "milliacentredecillion" +number_names[3345] = "milliacenquattuordecillion" +number_names[3348] = "milliacenquindecillion" +number_names[3351] = "milliacensexdecillion" +number_names[3354] = "milliacenseptendecillion" +number_names[3357] = "milliacenoctodecillion" +number_names[3360] = "milliacennovemdecillion" +number_names[3363] = "milliacenvigintillion" +number_names[3366] = "milliacenunvigintillion" +number_names[3369] = "milliacendovigintillion" +number_names[3372] = "milliacentrevigintillion" +number_names[3375] = "milliacenquattuorvigintillion" +number_names[3378] = "milliacenquinvigintillion" +number_names[3381] = "milliacensexvigintillion" +number_names[3384] = "milliacenseptenvigintillion" +number_names[3387] = "milliacenoctovigintillion" +number_names[3390] = "milliacennovemvigintillion" +number_names[3393] = "milliacentrigintillion" +number_names[3396] = "milliacenuntrigintillion" +number_names[3399] = "milliacendotrigintillion" +number_names[3402] = "milliacentretrigintillion" +number_names[3405] = "milliacenquattuortrigintillion" +number_names[3408] = "milliacenquintrigintillion" +number_names[3411] = "milliacensextrigintillion" +number_names[3414] = "milliacenseptentrigintillion" +number_names[3417] = "milliacenoctotrigintillion" +number_names[3420] = "milliacennovemtrigintillion" +number_names[3423] = "milliacenquadragintillion" +number_names[3426] = "milliacenunquadragintillion" +number_names[3429] = "milliacendoquadragintillion" +number_names[3432] = "milliacentrequadragintillion" +number_names[3435] = "milliacenquattuorquadragintillion" +number_names[3438] = "milliacenquinquadragintillion" +number_names[3441] = "milliacensexquadragintillion" +number_names[3444] = "milliacenseptenquadragintillion" +number_names[3447] = "milliacenoctoquadragintillion" +number_names[3450] = "milliacennovemquadragintillion" +number_names[3453] = "milliacenquinquagintillion" +number_names[3456] = "milliacenunquinquagintillion" +number_names[3459] = "milliacendoquinquagintillion" +number_names[3462] = "milliacentrequinquagintillion" +number_names[3465] = "milliacenquattuorquinquagintillion" +number_names[3468] = "milliacenquinquinquagintillion" +number_names[3471] = "milliacensexquinquagintillion" +number_names[3474] = "milliacenseptenquinquagintillion" +number_names[3477] = "milliacenoctoquinquagintillion" +number_names[3480] = "milliacennovemquinquagintillion" +number_names[3483] = "milliacensexagintillion" +number_names[3486] = "milliacenunsexagintillion" +number_names[3489] = "milliacendosexagintillion" +number_names[3492] = "milliacentresexagintillion" +number_names[3495] = "milliacenquattuorsexagintillion" +number_names[3498] = "milliacenquinsexagintillion" +number_names[3501] = "milliacensexsexagintillion" +number_names[3504] = "milliacenseptensexagintillion" +number_names[3507] = "milliacenoctosexagintillion" +number_names[3510] = "milliacennovemsexagintillion" +number_names[3513] = "milliacenseptuagintillion" +number_names[3516] = "milliacenunseptuagintillion" +number_names[3519] = "milliacendoseptuagintillion" +number_names[3522] = "milliacentreseptuagintillion" +number_names[3525] = "milliacenquattuorseptuagintillion" +number_names[3528] = "milliacenquinseptuagintillion" +number_names[3531] = "milliacensexseptuagintillion" +number_names[3534] = "milliacenseptenseptuagintillion" +number_names[3537] = "milliacenoctoseptuagintillion" +number_names[3540] = "milliacennovemseptuagintillion" +number_names[3543] = "milliacenoctogintillion" +number_names[3546] = "milliacenunoctogintillion" +number_names[3549] = "milliacendooctogintillion" +number_names[3552] = "milliacentreoctogintillion" +number_names[3555] = "milliacenquattuoroctogintillion" +number_names[3558] = "milliacenquinoctogintillion" +number_names[3561] = "milliacensexoctogintillion" +number_names[3564] = "milliacenseptenoctogintillion" +number_names[3567] = "milliacenoctooctogintillion" +number_names[3570] = "milliacennovemoctogintillion" +number_names[3573] = "milliacennonagintillion" +number_names[3576] = "milliacenunnonagintillion" +number_names[3579] = "milliacendononagintillion" +number_names[3582] = "milliacentrenonagintillion" +number_names[3585] = "milliacenquattuornonagintillion" +number_names[3588] = "milliacenquinnonagintillion" +number_names[3591] = "milliacensexnonagintillion" +number_names[3594] = "milliacenseptennonagintillion" +number_names[3597] = "milliacenoctononagintillion" +number_names[3600] = "milliacennovemnonagintillion" +number_names[3603] = "milliaducentillion" +number_names[3606] = "milliaducenuntillion" +number_names[3609] = "milliaducendotillion" +number_names[3612] = "milliaducentretillion" +number_names[3615] = "milliaducenquattuortillion" +number_names[3618] = "milliaducenquintillion" +number_names[3621] = "milliaducensextillion" +number_names[3624] = "milliaducenseptentillion" +number_names[3627] = "milliaducenoctotillion" +number_names[3630] = "milliaducennovemtillion" +number_names[3633] = "milliaducendecillion" +number_names[3636] = "milliaducenundecillion" +number_names[3639] = "milliaducendodecillion" +number_names[3642] = "milliaducentredecillion" +number_names[3645] = "milliaducenquattuordecillion" +number_names[3648] = "milliaducenquindecillion" +number_names[3651] = "milliaducensexdecillion" +number_names[3654] = "milliaducenseptendecillion" +number_names[3657] = "milliaducenoctodecillion" +number_names[3660] = "milliaducennovemdecillion" +number_names[3663] = "milliaducenvigintillion" +number_names[3666] = "milliaducenunvigintillion" +number_names[3669] = "milliaducendovigintillion" +number_names[3672] = "milliaducentrevigintillion" +number_names[3675] = "milliaducenquattuorvigintillion" +number_names[3678] = "milliaducenquinvigintillion" +number_names[3681] = "milliaducensexvigintillion" +number_names[3684] = "milliaducenseptenvigintillion" +number_names[3687] = "milliaducenoctovigintillion" +number_names[3690] = "milliaducennovemvigintillion" +number_names[3693] = "milliaducentrigintillion" +number_names[3696] = "milliaducenuntrigintillion" +number_names[3699] = "milliaducendotrigintillion" +number_names[3702] = "milliaducentretrigintillion" +number_names[3705] = "milliaducenquattuortrigintillion" +number_names[3708] = "milliaducenquintrigintillion" +number_names[3711] = "milliaducensextrigintillion" +number_names[3714] = "milliaducenseptentrigintillion" +number_names[3717] = "milliaducenoctotrigintillion" +number_names[3720] = "milliaducennovemtrigintillion" +number_names[3723] = "milliaducenquadragintillion" +number_names[3726] = "milliaducenunquadragintillion" +number_names[3729] = "milliaducendoquadragintillion" +number_names[3732] = "milliaducentrequadragintillion" +number_names[3735] = "milliaducenquattuorquadragintillion" +number_names[3738] = "milliaducenquinquadragintillion" +number_names[3741] = "milliaducensexquadragintillion" +number_names[3744] = "milliaducenseptenquadragintillion" +number_names[3747] = "milliaducenoctoquadragintillion" +number_names[3750] = "milliaducennovemquadragintillion" +number_names[3753] = "milliaducenquinquagintillion" +number_names[3756] = "milliaducenunquinquagintillion" +number_names[3759] = "milliaducendoquinquagintillion" +number_names[3762] = "milliaducentrequinquagintillion" +number_names[3765] = "milliaducenquattuorquinquagintillion" +number_names[3768] = "milliaducenquinquinquagintillion" +number_names[3771] = "milliaducensexquinquagintillion" +number_names[3774] = "milliaducenseptenquinquagintillion" +number_names[3777] = "milliaducenoctoquinquagintillion" +number_names[3780] = "milliaducennovemquinquagintillion" +number_names[3783] = "milliaducensexagintillion" +number_names[3786] = "milliaducenunsexagintillion" +number_names[3789] = "milliaducendosexagintillion" +number_names[3792] = "milliaducentresexagintillion" +number_names[3795] = "milliaducenquattuorsexagintillion" +number_names[3798] = "milliaducenquinsexagintillion" +number_names[3801] = "milliaducensexsexagintillion" +number_names[3804] = "milliaducenseptensexagintillion" +number_names[3807] = "milliaducenoctosexagintillion" +number_names[3810] = "milliaducennovemsexagintillion" +number_names[3813] = "milliaducenseptuagintillion" +number_names[3816] = "milliaducenunseptuagintillion" +number_names[3819] = "milliaducendoseptuagintillion" +number_names[3822] = "milliaducentreseptuagintillion" +number_names[3825] = "milliaducenquattuorseptuagintillion" +number_names[3828] = "milliaducenquinseptuagintillion" +number_names[3831] = "milliaducensexseptuagintillion" +number_names[3834] = "milliaducenseptenseptuagintillion" +number_names[3837] = "milliaducenoctoseptuagintillion" +number_names[3840] = "milliaducennovemseptuagintillion" +number_names[3843] = "milliaducenoctogintillion" +number_names[3846] = "milliaducenunoctogintillion" +number_names[3849] = "milliaducendooctogintillion" +number_names[3852] = "milliaducentreoctogintillion" +number_names[3855] = "milliaducenquattuoroctogintillion" +number_names[3858] = "milliaducenquinoctogintillion" +number_names[3861] = "milliaducensexoctogintillion" +number_names[3864] = "milliaducenseptenoctogintillion" +number_names[3867] = "milliaducenoctooctogintillion" +number_names[3870] = "milliaducennovemoctogintillion" +number_names[3873] = "milliaducennonagintillion" +number_names[3876] = "milliaducenunnonagintillion" +number_names[3879] = "milliaducendononagintillion" +number_names[3882] = "milliaducentrenonagintillion" +number_names[3885] = "milliaducenquattuornonagintillion" +number_names[3888] = "milliaducenquinnonagintillion" +number_names[3891] = "milliaducensexnonagintillion" +number_names[3894] = "milliaducenseptennonagintillion" +number_names[3897] = "milliaducenoctononagintillion" +number_names[3900] = "milliaducennovemnonagintillion" +number_names[3903] = "milliatrecentillion" +number_names[3906] = "milliatrecenuntillion" +number_names[3909] = "milliatrecendotillion" +number_names[3912] = "milliatrecentretillion" +number_names[3915] = "milliatrecenquattuortillion" +number_names[3918] = "milliatrecenquintillion" +number_names[3921] = "milliatrecensextillion" +number_names[3924] = "milliatrecenseptentillion" +number_names[3927] = "milliatrecenoctotillion" +number_names[3930] = "milliatrecennovemtillion" +number_names[3933] = "milliatrecendecillion" +number_names[3936] = "milliatrecenundecillion" +number_names[3939] = "milliatrecendodecillion" +number_names[3942] = "milliatrecentredecillion" +number_names[3945] = "milliatrecenquattuordecillion" +number_names[3948] = "milliatrecenquindecillion" +number_names[3951] = "milliatrecensexdecillion" +number_names[3954] = "milliatrecenseptendecillion" +number_names[3957] = "milliatrecenoctodecillion" +number_names[3960] = "milliatrecennovemdecillion" +number_names[3963] = "milliatrecenvigintillion" +number_names[3966] = "milliatrecenunvigintillion" +number_names[3969] = "milliatrecendovigintillion" +number_names[3972] = "milliatrecentrevigintillion" +number_names[3975] = "milliatrecenquattuorvigintillion" +number_names[3978] = "milliatrecenquinvigintillion" +number_names[3981] = "milliatrecensexvigintillion" +number_names[3984] = "milliatrecenseptenvigintillion" +number_names[3987] = "milliatrecenoctovigintillion" +number_names[3990] = "milliatrecennovemvigintillion" +number_names[3993] = "milliatrecentrigintillion" +number_names[3996] = "milliatrecenuntrigintillion" +number_names[3999] = "milliatrecendotrigintillion" +number_names[4002] = "milliatrecentretrigintillion" +number_names[4005] = "milliatrecenquattuortrigintillion" +number_names[4008] = "milliatrecenquintrigintillion" +number_names[4011] = "milliatrecensextrigintillion" +number_names[4014] = "milliatrecenseptentrigintillion" +number_names[4017] = "milliatrecenoctotrigintillion" +number_names[4020] = "milliatrecennovemtrigintillion" +number_names[4023] = "milliatrecenquadragintillion" +number_names[4026] = "milliatrecenunquadragintillion" +number_names[4029] = "milliatrecendoquadragintillion" +number_names[4032] = "milliatrecentrequadragintillion" +number_names[4035] = "milliatrecenquattuorquadragintillion" +number_names[4038] = "milliatrecenquinquadragintillion" +number_names[4041] = "milliatrecensexquadragintillion" +number_names[4044] = "milliatrecenseptenquadragintillion" +number_names[4047] = "milliatrecenoctoquadragintillion" +number_names[4050] = "milliatrecennovemquadragintillion" +number_names[4053] = "milliatrecenquinquagintillion" +number_names[4056] = "milliatrecenunquinquagintillion" +number_names[4059] = "milliatrecendoquinquagintillion" +number_names[4062] = "milliatrecentrequinquagintillion" +number_names[4065] = "milliatrecenquattuorquinquagintillion" +number_names[4068] = "milliatrecenquinquinquagintillion" +number_names[4071] = "milliatrecensexquinquagintillion" +number_names[4074] = "milliatrecenseptenquinquagintillion" +number_names[4077] = "milliatrecenoctoquinquagintillion" +number_names[4080] = "milliatrecennovemquinquagintillion" +number_names[4083] = "milliatrecensexagintillion" +number_names[4086] = "milliatrecenunsexagintillion" +number_names[4089] = "milliatrecendosexagintillion" +number_names[4092] = "milliatrecentresexagintillion" +number_names[4095] = "milliatrecenquattuorsexagintillion" +number_names[4098] = "milliatrecenquinsexagintillion" +number_names[4101] = "milliatrecensexsexagintillion" +number_names[4104] = "milliatrecenseptensexagintillion" +number_names[4107] = "milliatrecenoctosexagintillion" +number_names[4110] = "milliatrecennovemsexagintillion" +number_names[4113] = "milliatrecenseptuagintillion" +number_names[4116] = "milliatrecenunseptuagintillion" +number_names[4119] = "milliatrecendoseptuagintillion" +number_names[4122] = "milliatrecentreseptuagintillion" +number_names[4125] = "milliatrecenquattuorseptuagintillion" +number_names[4128] = "milliatrecenquinseptuagintillion" +number_names[4131] = "milliatrecensexseptuagintillion" +number_names[4134] = "milliatrecenseptenseptuagintillion" +number_names[4137] = "milliatrecenoctoseptuagintillion" +number_names[4140] = "milliatrecennovemseptuagintillion" +number_names[4143] = "milliatrecenoctogintillion" +number_names[4146] = "milliatrecenunoctogintillion" +number_names[4149] = "milliatrecendooctogintillion" +number_names[4152] = "milliatrecentreoctogintillion" +number_names[4155] = "milliatrecenquattuoroctogintillion" +number_names[4158] = "milliatrecenquinoctogintillion" +number_names[4161] = "milliatrecensexoctogintillion" +number_names[4164] = "milliatrecenseptenoctogintillion" +number_names[4167] = "milliatrecenoctooctogintillion" +number_names[4170] = "milliatrecennovemoctogintillion" +number_names[4173] = "milliatrecennonagintillion" +number_names[4176] = "milliatrecenunnonagintillion" +number_names[4179] = "milliatrecendononagintillion" +number_names[4182] = "milliatrecentrenonagintillion" +number_names[4185] = "milliatrecenquattuornonagintillion" +number_names[4188] = "milliatrecenquinnonagintillion" +number_names[4191] = "milliatrecensexnonagintillion" +number_names[4194] = "milliatrecenseptennonagintillion" +number_names[4197] = "milliatrecenoctononagintillion" +number_names[4200] = "milliatrecennovemnonagintillion" +number_names[4203] = "milliaquadringentillion" +number_names[4206] = "milliaquadringenuntillion" +number_names[4209] = "milliaquadringendotillion" +number_names[4212] = "milliaquadringentretillion" +number_names[4215] = "milliaquadringenquattuortillion" +number_names[4218] = "milliaquadringenquintillion" +number_names[4221] = "milliaquadringensextillion" +number_names[4224] = "milliaquadringenseptentillion" +number_names[4227] = "milliaquadringenoctotillion" +number_names[4230] = "milliaquadringennovemtillion" +number_names[4233] = "milliaquadringendecillion" +number_names[4236] = "milliaquadringenundecillion" +number_names[4239] = "milliaquadringendodecillion" +number_names[4242] = "milliaquadringentredecillion" +number_names[4245] = "milliaquadringenquattuordecillion" +number_names[4248] = "milliaquadringenquindecillion" +number_names[4251] = "milliaquadringensexdecillion" +number_names[4254] = "milliaquadringenseptendecillion" +number_names[4257] = "milliaquadringenoctodecillion" +number_names[4260] = "milliaquadringennovemdecillion" +number_names[4263] = "milliaquadringenvigintillion" +number_names[4266] = "milliaquadringenunvigintillion" +number_names[4269] = "milliaquadringendovigintillion" +number_names[4272] = "milliaquadringentrevigintillion" +number_names[4275] = "milliaquadringenquattuorvigintillion" +number_names[4278] = "milliaquadringenquinvigintillion" +number_names[4281] = "milliaquadringensexvigintillion" +number_names[4284] = "milliaquadringenseptenvigintillion" +number_names[4287] = "milliaquadringenoctovigintillion" +number_names[4290] = "milliaquadringennovemvigintillion" +number_names[4293] = "milliaquadringentrigintillion" +number_names[4296] = "milliaquadringenuntrigintillion" +number_names[4299] = "milliaquadringendotrigintillion" +number_names[4302] = "milliaquadringentretrigintillion" +number_names[4305] = "milliaquadringenquattuortrigintillion" +number_names[4308] = "milliaquadringenquintrigintillion" +number_names[4311] = "milliaquadringensextrigintillion" +number_names[4314] = "milliaquadringenseptentrigintillion" +number_names[4317] = "milliaquadringenoctotrigintillion" +number_names[4320] = "milliaquadringennovemtrigintillion" +number_names[4323] = "milliaquadringenquadragintillion" +number_names[4326] = "milliaquadringenunquadragintillion" +number_names[4329] = "milliaquadringendoquadragintillion" +number_names[4332] = "milliaquadringentrequadragintillion" +number_names[4335] = "milliaquadringenquattuorquadragintillion" +number_names[4338] = "milliaquadringenquinquadragintillion" +number_names[4341] = "milliaquadringensexquadragintillion" +number_names[4344] = "milliaquadringenseptenquadragintillion" +number_names[4347] = "milliaquadringenoctoquadragintillion" +number_names[4350] = "milliaquadringennovemquadragintillion" +number_names[4353] = "milliaquadringenquinquagintillion" +number_names[4356] = "milliaquadringenunquinquagintillion" +number_names[4359] = "milliaquadringendoquinquagintillion" +number_names[4362] = "milliaquadringentrequinquagintillion" +number_names[4365] = "milliaquadringenquattuorquinquagintillion" +number_names[4368] = "milliaquadringenquinquinquagintillion" +number_names[4371] = "milliaquadringensexquinquagintillion" +number_names[4374] = "milliaquadringenseptenquinquagintillion" +number_names[4377] = "milliaquadringenoctoquinquagintillion" +number_names[4380] = "milliaquadringennovemquinquagintillion" +number_names[4383] = "milliaquadringensexagintillion" +number_names[4386] = "milliaquadringenunsexagintillion" +number_names[4389] = "milliaquadringendosexagintillion" +number_names[4392] = "milliaquadringentresexagintillion" +number_names[4395] = "milliaquadringenquattuorsexagintillion" +number_names[4398] = "milliaquadringenquinsexagintillion" +number_names[4401] = "milliaquadringensexsexagintillion" +number_names[4404] = "milliaquadringenseptensexagintillion" +number_names[4407] = "milliaquadringenoctosexagintillion" +number_names[4410] = "milliaquadringennovemsexagintillion" +number_names[4413] = "milliaquadringenseptuagintillion" +number_names[4416] = "milliaquadringenunseptuagintillion" +number_names[4419] = "milliaquadringendoseptuagintillion" +number_names[4422] = "milliaquadringentreseptuagintillion" +number_names[4425] = "milliaquadringenquattuorseptuagintillion" +number_names[4428] = "milliaquadringenquinseptuagintillion" +number_names[4431] = "milliaquadringensexseptuagintillion" +number_names[4434] = "milliaquadringenseptenseptuagintillion" +number_names[4437] = "milliaquadringenoctoseptuagintillion" +number_names[4440] = "milliaquadringennovemseptuagintillion" +number_names[4443] = "milliaquadringenoctogintillion" +number_names[4446] = "milliaquadringenunoctogintillion" +number_names[4449] = "milliaquadringendooctogintillion" +number_names[4452] = "milliaquadringentreoctogintillion" +number_names[4455] = "milliaquadringenquattuoroctogintillion" +number_names[4458] = "milliaquadringenquinoctogintillion" +number_names[4461] = "milliaquadringensexoctogintillion" +number_names[4464] = "milliaquadringenseptenoctogintillion" +number_names[4467] = "milliaquadringenoctooctogintillion" +number_names[4470] = "milliaquadringennovemoctogintillion" +number_names[4473] = "milliaquadringennonagintillion" +number_names[4476] = "milliaquadringenunnonagintillion" +number_names[4479] = "milliaquadringendononagintillion" +number_names[4482] = "milliaquadringentrenonagintillion" +number_names[4485] = "milliaquadringenquattuornonagintillion" +number_names[4488] = "milliaquadringenquinnonagintillion" +number_names[4491] = "milliaquadringensexnonagintillion" +number_names[4494] = "milliaquadringenseptennonagintillion" +number_names[4497] = "milliaquadringenoctononagintillion" +number_names[4500] = "milliaquadringennovemnonagintillion" +number_names[4503] = "milliaquingentillion" +number_names[4506] = "milliaquingenuntillion" +number_names[4509] = "milliaquingendotillion" +number_names[4512] = "milliaquingentretillion" +number_names[4515] = "milliaquingenquattuortillion" +number_names[4518] = "milliaquingenquintillion" +number_names[4521] = "milliaquingensextillion" +number_names[4524] = "milliaquingenseptentillion" +number_names[4527] = "milliaquingenoctotillion" +number_names[4530] = "milliaquingennovemtillion" +number_names[4533] = "milliaquingendecillion" +number_names[4536] = "milliaquingenundecillion" +number_names[4539] = "milliaquingendodecillion" +number_names[4542] = "milliaquingentredecillion" +number_names[4545] = "milliaquingenquattuordecillion" +number_names[4548] = "milliaquingenquindecillion" +number_names[4551] = "milliaquingensexdecillion" +number_names[4554] = "milliaquingenseptendecillion" +number_names[4557] = "milliaquingenoctodecillion" +number_names[4560] = "milliaquingennovemdecillion" +number_names[4563] = "milliaquingenvigintillion" +number_names[4566] = "milliaquingenunvigintillion" +number_names[4569] = "milliaquingendovigintillion" +number_names[4572] = "milliaquingentrevigintillion" +number_names[4575] = "milliaquingenquattuorvigintillion" +number_names[4578] = "milliaquingenquinvigintillion" +number_names[4581] = "milliaquingensexvigintillion" +number_names[4584] = "milliaquingenseptenvigintillion" +number_names[4587] = "milliaquingenoctovigintillion" +number_names[4590] = "milliaquingennovemvigintillion" +number_names[4593] = "milliaquingentrigintillion" +number_names[4596] = "milliaquingenuntrigintillion" +number_names[4599] = "milliaquingendotrigintillion" +number_names[4602] = "milliaquingentretrigintillion" +number_names[4605] = "milliaquingenquattuortrigintillion" +number_names[4608] = "milliaquingenquintrigintillion" +number_names[4611] = "milliaquingensextrigintillion" +number_names[4614] = "milliaquingenseptentrigintillion" +number_names[4617] = "milliaquingenoctotrigintillion" +number_names[4620] = "milliaquingennovemtrigintillion" +number_names[4623] = "milliaquingenquadragintillion" +number_names[4626] = "milliaquingenunquadragintillion" +number_names[4629] = "milliaquingendoquadragintillion" +number_names[4632] = "milliaquingentrequadragintillion" +number_names[4635] = "milliaquingenquattuorquadragintillion" +number_names[4638] = "milliaquingenquinquadragintillion" +number_names[4641] = "milliaquingensexquadragintillion" +number_names[4644] = "milliaquingenseptenquadragintillion" +number_names[4647] = "milliaquingenoctoquadragintillion" +number_names[4650] = "milliaquingennovemquadragintillion" +number_names[4653] = "milliaquingenquinquagintillion" +number_names[4656] = "milliaquingenunquinquagintillion" +number_names[4659] = "milliaquingendoquinquagintillion" +number_names[4662] = "milliaquingentrequinquagintillion" +number_names[4665] = "milliaquingenquattuorquinquagintillion" +number_names[4668] = "milliaquingenquinquinquagintillion" +number_names[4671] = "milliaquingensexquinquagintillion" +number_names[4674] = "milliaquingenseptenquinquagintillion" +number_names[4677] = "milliaquingenoctoquinquagintillion" +number_names[4680] = "milliaquingennovemquinquagintillion" +number_names[4683] = "milliaquingensexagintillion" +number_names[4686] = "milliaquingenunsexagintillion" +number_names[4689] = "milliaquingendosexagintillion" +number_names[4692] = "milliaquingentresexagintillion" +number_names[4695] = "milliaquingenquattuorsexagintillion" +number_names[4698] = "milliaquingenquinsexagintillion" +number_names[4701] = "milliaquingensexsexagintillion" +number_names[4704] = "milliaquingenseptensexagintillion" +number_names[4707] = "milliaquingenoctosexagintillion" +number_names[4710] = "milliaquingennovemsexagintillion" +number_names[4713] = "milliaquingenseptuagintillion" +number_names[4716] = "milliaquingenunseptuagintillion" +number_names[4719] = "milliaquingendoseptuagintillion" +number_names[4722] = "milliaquingentreseptuagintillion" +number_names[4725] = "milliaquingenquattuorseptuagintillion" +number_names[4728] = "milliaquingenquinseptuagintillion" +number_names[4731] = "milliaquingensexseptuagintillion" +number_names[4734] = "milliaquingenseptenseptuagintillion" +number_names[4737] = "milliaquingenoctoseptuagintillion" +number_names[4740] = "milliaquingennovemseptuagintillion" +number_names[4743] = "milliaquingenoctogintillion" +number_names[4746] = "milliaquingenunoctogintillion" +number_names[4749] = "milliaquingendooctogintillion" +number_names[4752] = "milliaquingentreoctogintillion" +number_names[4755] = "milliaquingenquattuoroctogintillion" +number_names[4758] = "milliaquingenquinoctogintillion" +number_names[4761] = "milliaquingensexoctogintillion" +number_names[4764] = "milliaquingenseptenoctogintillion" +number_names[4767] = "milliaquingenoctooctogintillion" +number_names[4770] = "milliaquingennovemoctogintillion" +number_names[4773] = "milliaquingennonagintillion" +number_names[4776] = "milliaquingenunnonagintillion" +number_names[4779] = "milliaquingendononagintillion" +number_names[4782] = "milliaquingentrenonagintillion" +number_names[4785] = "milliaquingenquattuornonagintillion" +number_names[4788] = "milliaquingenquinnonagintillion" +number_names[4791] = "milliaquingensexnonagintillion" +number_names[4794] = "milliaquingenseptennonagintillion" +number_names[4797] = "milliaquingenoctononagintillion" +number_names[4800] = "milliaquingennovemnonagintillion" +number_names[4803] = "milliasescentillion" +number_names[4806] = "milliasescenuntillion" +number_names[4809] = "milliasescendotillion" +number_names[4812] = "milliasescentretillion" +number_names[4815] = "milliasescenquattuortillion" +number_names[4818] = "milliasescenquintillion" +number_names[4821] = "milliasescensextillion" +number_names[4824] = "milliasescenseptentillion" +number_names[4827] = "milliasescenoctotillion" +number_names[4830] = "milliasescennovemtillion" +number_names[4833] = "milliasescendecillion" +number_names[4836] = "milliasescenundecillion" +number_names[4839] = "milliasescendodecillion" +number_names[4842] = "milliasescentredecillion" +number_names[4845] = "milliasescenquattuordecillion" +number_names[4848] = "milliasescenquindecillion" +number_names[4851] = "milliasescensexdecillion" +number_names[4854] = "milliasescenseptendecillion" +number_names[4857] = "milliasescenoctodecillion" +number_names[4860] = "milliasescennovemdecillion" +number_names[4863] = "milliasescenvigintillion" +number_names[4866] = "milliasescenunvigintillion" +number_names[4869] = "milliasescendovigintillion" +number_names[4872] = "milliasescentrevigintillion" +number_names[4875] = "milliasescenquattuorvigintillion" +number_names[4878] = "milliasescenquinvigintillion" +number_names[4881] = "milliasescensexvigintillion" +number_names[4884] = "milliasescenseptenvigintillion" +number_names[4887] = "milliasescenoctovigintillion" +number_names[4890] = "milliasescennovemvigintillion" +number_names[4893] = "milliasescentrigintillion" +number_names[4896] = "milliasescenuntrigintillion" +number_names[4899] = "milliasescendotrigintillion" +number_names[4902] = "milliasescentretrigintillion" +number_names[4905] = "milliasescenquattuortrigintillion" +number_names[4908] = "milliasescenquintrigintillion" +number_names[4911] = "milliasescensextrigintillion" +number_names[4914] = "milliasescenseptentrigintillion" +number_names[4917] = "milliasescenoctotrigintillion" +number_names[4920] = "milliasescennovemtrigintillion" +number_names[4923] = "milliasescenquadragintillion" +number_names[4926] = "milliasescenunquadragintillion" +number_names[4929] = "milliasescendoquadragintillion" +number_names[4932] = "milliasescentrequadragintillion" +number_names[4935] = "milliasescenquattuorquadragintillion" +number_names[4938] = "milliasescenquinquadragintillion" +number_names[4941] = "milliasescensexquadragintillion" +number_names[4944] = "milliasescenseptenquadragintillion" +number_names[4947] = "milliasescenoctoquadragintillion" +number_names[4950] = "milliasescennovemquadragintillion" +number_names[4953] = "milliasescenquinquagintillion" +number_names[4956] = "milliasescenunquinquagintillion" +number_names[4959] = "milliasescendoquinquagintillion" +number_names[4962] = "milliasescentrequinquagintillion" +number_names[4965] = "milliasescenquattuorquinquagintillion" +number_names[4968] = "milliasescenquinquinquagintillion" +number_names[4971] = "milliasescensexquinquagintillion" +number_names[4974] = "milliasescenseptenquinquagintillion" +number_names[4977] = "milliasescenoctoquinquagintillion" +number_names[4980] = "milliasescennovemquinquagintillion" +number_names[4983] = "milliasescensexagintillion" +number_names[4986] = "milliasescenunsexagintillion" +number_names[4989] = "milliasescendosexagintillion" +number_names[4992] = "milliasescentresexagintillion" +number_names[4995] = "milliasescenquattuorsexagintillion" +number_names[4998] = "milliasescenquinsexagintillion" +number_names[5001] = "milliasescensexsexagintillion" +number_names[5004] = "milliasescenseptensexagintillion" +number_names[5007] = "milliasescenoctosexagintillion" +number_names[5010] = "milliasescennovemsexagintillion" +number_names[5013] = "milliasescenseptuagintillion" +number_names[5016] = "milliasescenunseptuagintillion" +number_names[5019] = "milliasescendoseptuagintillion" +number_names[5022] = "milliasescentreseptuagintillion" +number_names[5025] = "milliasescenquattuorseptuagintillion" +number_names[5028] = "milliasescenquinseptuagintillion" +number_names[5031] = "milliasescensexseptuagintillion" +number_names[5034] = "milliasescenseptenseptuagintillion" +number_names[5037] = "milliasescenoctoseptuagintillion" +number_names[5040] = "milliasescennovemseptuagintillion" +number_names[5043] = "milliasescenoctogintillion" +number_names[5046] = "milliasescenunoctogintillion" +number_names[5049] = "milliasescendooctogintillion" +number_names[5052] = "milliasescentreoctogintillion" +number_names[5055] = "milliasescenquattuoroctogintillion" +number_names[5058] = "milliasescenquinoctogintillion" +number_names[5061] = "milliasescensexoctogintillion" +number_names[5064] = "milliasescenseptenoctogintillion" +number_names[5067] = "milliasescenoctooctogintillion" +number_names[5070] = "milliasescennovemoctogintillion" +number_names[5073] = "milliasescennonagintillion" +number_names[5076] = "milliasescenunnonagintillion" +number_names[5079] = "milliasescendononagintillion" +number_names[5082] = "milliasescentrenonagintillion" +number_names[5085] = "milliasescenquattuornonagintillion" +number_names[5088] = "milliasescenquinnonagintillion" +number_names[5091] = "milliasescensexnonagintillion" +number_names[5094] = "milliasescenseptennonagintillion" +number_names[5097] = "milliasescenoctononagintillion" +number_names[5100] = "milliasescennovemnonagintillion" +number_names[5103] = "milliaseptingentillion" +number_names[5106] = "milliaseptingenuntillion" +number_names[5109] = "milliaseptingendotillion" +number_names[5112] = "milliaseptingentretillion" +number_names[5115] = "milliaseptingenquattuortillion" +number_names[5118] = "milliaseptingenquintillion" +number_names[5121] = "milliaseptingensextillion" +number_names[5124] = "milliaseptingenseptentillion" +number_names[5127] = "milliaseptingenoctotillion" +number_names[5130] = "milliaseptingennovemtillion" +number_names[5133] = "milliaseptingendecillion" +number_names[5136] = "milliaseptingenundecillion" +number_names[5139] = "milliaseptingendodecillion" +number_names[5142] = "milliaseptingentredecillion" +number_names[5145] = "milliaseptingenquattuordecillion" +number_names[5148] = "milliaseptingenquindecillion" +number_names[5151] = "milliaseptingensexdecillion" +number_names[5154] = "milliaseptingenseptendecillion" +number_names[5157] = "milliaseptingenoctodecillion" +number_names[5160] = "milliaseptingennovemdecillion" +number_names[5163] = "milliaseptingenvigintillion" +number_names[5166] = "milliaseptingenunvigintillion" +number_names[5169] = "milliaseptingendovigintillion" +number_names[5172] = "milliaseptingentrevigintillion" +number_names[5175] = "milliaseptingenquattuorvigintillion" +number_names[5178] = "milliaseptingenquinvigintillion" +number_names[5181] = "milliaseptingensexvigintillion" +number_names[5184] = "milliaseptingenseptenvigintillion" +number_names[5187] = "milliaseptingenoctovigintillion" +number_names[5190] = "milliaseptingennovemvigintillion" +number_names[5193] = "milliaseptingentrigintillion" +number_names[5196] = "milliaseptingenuntrigintillion" +number_names[5199] = "milliaseptingendotrigintillion" +number_names[5202] = "milliaseptingentretrigintillion" +number_names[5205] = "milliaseptingenquattuortrigintillion" +number_names[5208] = "milliaseptingenquintrigintillion" +number_names[5211] = "milliaseptingensextrigintillion" +number_names[5214] = "milliaseptingenseptentrigintillion" +number_names[5217] = "milliaseptingenoctotrigintillion" +number_names[5220] = "milliaseptingennovemtrigintillion" +number_names[5223] = "milliaseptingenquadragintillion" +number_names[5226] = "milliaseptingenunquadragintillion" +number_names[5229] = "milliaseptingendoquadragintillion" +number_names[5232] = "milliaseptingentrequadragintillion" +number_names[5235] = "milliaseptingenquattuorquadragintillion" +number_names[5238] = "milliaseptingenquinquadragintillion" +number_names[5241] = "milliaseptingensexquadragintillion" +number_names[5244] = "milliaseptingenseptenquadragintillion" +number_names[5247] = "milliaseptingenoctoquadragintillion" +number_names[5250] = "milliaseptingennovemquadragintillion" +number_names[5253] = "milliaseptingenquinquagintillion" +number_names[5256] = "milliaseptingenunquinquagintillion" +number_names[5259] = "milliaseptingendoquinquagintillion" +number_names[5262] = "milliaseptingentrequinquagintillion" +number_names[5265] = "milliaseptingenquattuorquinquagintillion" +number_names[5268] = "milliaseptingenquinquinquagintillion" +number_names[5271] = "milliaseptingensexquinquagintillion" +number_names[5274] = "milliaseptingenseptenquinquagintillion" +number_names[5277] = "milliaseptingenoctoquinquagintillion" +number_names[5280] = "milliaseptingennovemquinquagintillion" +number_names[5283] = "milliaseptingensexagintillion" +number_names[5286] = "milliaseptingenunsexagintillion" +number_names[5289] = "milliaseptingendosexagintillion" +number_names[5292] = "milliaseptingentresexagintillion" +number_names[5295] = "milliaseptingenquattuorsexagintillion" +number_names[5298] = "milliaseptingenquinsexagintillion" +number_names[5301] = "milliaseptingensexsexagintillion" +number_names[5304] = "milliaseptingenseptensexagintillion" +number_names[5307] = "milliaseptingenoctosexagintillion" +number_names[5310] = "milliaseptingennovemsexagintillion" +number_names[5313] = "milliaseptingenseptuagintillion" +number_names[5316] = "milliaseptingenunseptuagintillion" +number_names[5319] = "milliaseptingendoseptuagintillion" +number_names[5322] = "milliaseptingentreseptuagintillion" +number_names[5325] = "milliaseptingenquattuorseptuagintillion" +number_names[5328] = "milliaseptingenquinseptuagintillion" +number_names[5331] = "milliaseptingensexseptuagintillion" +number_names[5334] = "milliaseptingenseptenseptuagintillion" +number_names[5337] = "milliaseptingenoctoseptuagintillion" +number_names[5340] = "milliaseptingennovemseptuagintillion" +number_names[5343] = "milliaseptingenoctogintillion" +number_names[5346] = "milliaseptingenunoctogintillion" +number_names[5349] = "milliaseptingendooctogintillion" +number_names[5352] = "milliaseptingentreoctogintillion" +number_names[5355] = "milliaseptingenquattuoroctogintillion" +number_names[5358] = "milliaseptingenquinoctogintillion" +number_names[5361] = "milliaseptingensexoctogintillion" +number_names[5364] = "milliaseptingenseptenoctogintillion" +number_names[5367] = "milliaseptingenoctooctogintillion" +number_names[5370] = "milliaseptingennovemoctogintillion" +number_names[5373] = "milliaseptingennonagintillion" +number_names[5376] = "milliaseptingenunnonagintillion" +number_names[5379] = "milliaseptingendononagintillion" +number_names[5382] = "milliaseptingentrenonagintillion" +number_names[5385] = "milliaseptingenquattuornonagintillion" +number_names[5388] = "milliaseptingenquinnonagintillion" +number_names[5391] = "milliaseptingensexnonagintillion" +number_names[5394] = "milliaseptingenseptennonagintillion" +number_names[5397] = "milliaseptingenoctononagintillion" +number_names[5400] = "milliaseptingennovemnonagintillion" +number_names[5403] = "milliaoctingentillion" +number_names[5406] = "milliaoctingenuntillion" +number_names[5409] = "milliaoctingendotillion" +number_names[5412] = "milliaoctingentretillion" +number_names[5415] = "milliaoctingenquattuortillion" +number_names[5418] = "milliaoctingenquintillion" +number_names[5421] = "milliaoctingensextillion" +number_names[5424] = "milliaoctingenseptentillion" +number_names[5427] = "milliaoctingenoctotillion" +number_names[5430] = "milliaoctingennovemtillion" +number_names[5433] = "milliaoctingendecillion" +number_names[5436] = "milliaoctingenundecillion" +number_names[5439] = "milliaoctingendodecillion" +number_names[5442] = "milliaoctingentredecillion" +number_names[5445] = "milliaoctingenquattuordecillion" +number_names[5448] = "milliaoctingenquindecillion" +number_names[5451] = "milliaoctingensexdecillion" +number_names[5454] = "milliaoctingenseptendecillion" +number_names[5457] = "milliaoctingenoctodecillion" +number_names[5460] = "milliaoctingennovemdecillion" +number_names[5463] = "milliaoctingenvigintillion" +number_names[5466] = "milliaoctingenunvigintillion" +number_names[5469] = "milliaoctingendovigintillion" +number_names[5472] = "milliaoctingentrevigintillion" +number_names[5475] = "milliaoctingenquattuorvigintillion" +number_names[5478] = "milliaoctingenquinvigintillion" +number_names[5481] = "milliaoctingensexvigintillion" +number_names[5484] = "milliaoctingenseptenvigintillion" +number_names[5487] = "milliaoctingenoctovigintillion" +number_names[5490] = "milliaoctingennovemvigintillion" +number_names[5493] = "milliaoctingentrigintillion" +number_names[5496] = "milliaoctingenuntrigintillion" +number_names[5499] = "milliaoctingendotrigintillion" +number_names[5502] = "milliaoctingentretrigintillion" +number_names[5505] = "milliaoctingenquattuortrigintillion" +number_names[5508] = "milliaoctingenquintrigintillion" +number_names[5511] = "milliaoctingensextrigintillion" +number_names[5514] = "milliaoctingenseptentrigintillion" +number_names[5517] = "milliaoctingenoctotrigintillion" +number_names[5520] = "milliaoctingennovemtrigintillion" +number_names[5523] = "milliaoctingenquadragintillion" +number_names[5526] = "milliaoctingenunquadragintillion" +number_names[5529] = "milliaoctingendoquadragintillion" +number_names[5532] = "milliaoctingentrequadragintillion" +number_names[5535] = "milliaoctingenquattuorquadragintillion" +number_names[5538] = "milliaoctingenquinquadragintillion" +number_names[5541] = "milliaoctingensexquadragintillion" +number_names[5544] = "milliaoctingenseptenquadragintillion" +number_names[5547] = "milliaoctingenoctoquadragintillion" +number_names[5550] = "milliaoctingennovemquadragintillion" +number_names[5553] = "milliaoctingenquinquagintillion" +number_names[5556] = "milliaoctingenunquinquagintillion" +number_names[5559] = "milliaoctingendoquinquagintillion" +number_names[5562] = "milliaoctingentrequinquagintillion" +number_names[5565] = "milliaoctingenquattuorquinquagintillion" +number_names[5568] = "milliaoctingenquinquinquagintillion" +number_names[5571] = "milliaoctingensexquinquagintillion" +number_names[5574] = "milliaoctingenseptenquinquagintillion" +number_names[5577] = "milliaoctingenoctoquinquagintillion" +number_names[5580] = "milliaoctingennovemquinquagintillion" +number_names[5583] = "milliaoctingensexagintillion" +number_names[5586] = "milliaoctingenunsexagintillion" +number_names[5589] = "milliaoctingendosexagintillion" +number_names[5592] = "milliaoctingentresexagintillion" +number_names[5595] = "milliaoctingenquattuorsexagintillion" +number_names[5598] = "milliaoctingenquinsexagintillion" +number_names[5601] = "milliaoctingensexsexagintillion" +number_names[5604] = "milliaoctingenseptensexagintillion" +number_names[5607] = "milliaoctingenoctosexagintillion" +number_names[5610] = "milliaoctingennovemsexagintillion" +number_names[5613] = "milliaoctingenseptuagintillion" +number_names[5616] = "milliaoctingenunseptuagintillion" +number_names[5619] = "milliaoctingendoseptuagintillion" +number_names[5622] = "milliaoctingentreseptuagintillion" +number_names[5625] = "milliaoctingenquattuorseptuagintillion" +number_names[5628] = "milliaoctingenquinseptuagintillion" +number_names[5631] = "milliaoctingensexseptuagintillion" +number_names[5634] = "milliaoctingenseptenseptuagintillion" +number_names[5637] = "milliaoctingenoctoseptuagintillion" +number_names[5640] = "milliaoctingennovemseptuagintillion" +number_names[5643] = "milliaoctingenoctogintillion" +number_names[5646] = "milliaoctingenunoctogintillion" +number_names[5649] = "milliaoctingendooctogintillion" +number_names[5652] = "milliaoctingentreoctogintillion" +number_names[5655] = "milliaoctingenquattuoroctogintillion" +number_names[5658] = "milliaoctingenquinoctogintillion" +number_names[5661] = "milliaoctingensexoctogintillion" +number_names[5664] = "milliaoctingenseptenoctogintillion" +number_names[5667] = "milliaoctingenoctooctogintillion" +number_names[5670] = "milliaoctingennovemoctogintillion" +number_names[5673] = "milliaoctingennonagintillion" +number_names[5676] = "milliaoctingenunnonagintillion" +number_names[5679] = "milliaoctingendononagintillion" +number_names[5682] = "milliaoctingentrenonagintillion" +number_names[5685] = "milliaoctingenquattuornonagintillion" +number_names[5688] = "milliaoctingenquinnonagintillion" +number_names[5691] = "milliaoctingensexnonagintillion" +number_names[5694] = "milliaoctingenseptennonagintillion" +number_names[5697] = "milliaoctingenoctononagintillion" +number_names[5700] = "milliaoctingennovemnonagintillion" +number_names[5703] = "millianongentillion" +number_names[5706] = "millianongenuntillion" +number_names[5709] = "millianongendotillion" +number_names[5712] = "millianongentretillion" +number_names[5715] = "millianongenquattuortillion" +number_names[5718] = "millianongenquintillion" +number_names[5721] = "millianongensextillion" +number_names[5724] = "millianongenseptentillion" +number_names[5727] = "millianongenoctotillion" +number_names[5730] = "millianongennovemtillion" +number_names[5733] = "millianongendecillion" +number_names[5736] = "millianongenundecillion" +number_names[5739] = "millianongendodecillion" +number_names[5742] = "millianongentredecillion" +number_names[5745] = "millianongenquattuordecillion" +number_names[5748] = "millianongenquindecillion" +number_names[5751] = "millianongensexdecillion" +number_names[5754] = "millianongenseptendecillion" +number_names[5757] = "millianongenoctodecillion" +number_names[5760] = "millianongennovemdecillion" +number_names[5763] = "millianongenvigintillion" +number_names[5766] = "millianongenunvigintillion" +number_names[5769] = "millianongendovigintillion" +number_names[5772] = "millianongentrevigintillion" +number_names[5775] = "millianongenquattuorvigintillion" +number_names[5778] = "millianongenquinvigintillion" +number_names[5781] = "millianongensexvigintillion" +number_names[5784] = "millianongenseptenvigintillion" +number_names[5787] = "millianongenoctovigintillion" +number_names[5790] = "millianongennovemvigintillion" +number_names[5793] = "millianongentrigintillion" +number_names[5796] = "millianongenuntrigintillion" +number_names[5799] = "millianongendotrigintillion" +number_names[5802] = "millianongentretrigintillion" +number_names[5805] = "millianongenquattuortrigintillion" +number_names[5808] = "millianongenquintrigintillion" +number_names[5811] = "millianongensextrigintillion" +number_names[5814] = "millianongenseptentrigintillion" +number_names[5817] = "millianongenoctotrigintillion" +number_names[5820] = "millianongennovemtrigintillion" +number_names[5823] = "millianongenquadragintillion" +number_names[5826] = "millianongenunquadragintillion" +number_names[5829] = "millianongendoquadragintillion" +number_names[5832] = "millianongentrequadragintillion" +number_names[5835] = "millianongenquattuorquadragintillion" +number_names[5838] = "millianongenquinquadragintillion" +number_names[5841] = "millianongensexquadragintillion" +number_names[5844] = "millianongenseptenquadragintillion" +number_names[5847] = "millianongenoctoquadragintillion" +number_names[5850] = "millianongennovemquadragintillion" +number_names[5853] = "millianongenquinquagintillion" +number_names[5856] = "millianongenunquinquagintillion" +number_names[5859] = "millianongendoquinquagintillion" +number_names[5862] = "millianongentrequinquagintillion" +number_names[5865] = "millianongenquattuorquinquagintillion" +number_names[5868] = "millianongenquinquinquagintillion" +number_names[5871] = "millianongensexquinquagintillion" +number_names[5874] = "millianongenseptenquinquagintillion" +number_names[5877] = "millianongenoctoquinquagintillion" +number_names[5880] = "millianongennovemquinquagintillion" +number_names[5883] = "millianongensexagintillion" +number_names[5886] = "millianongenunsexagintillion" +number_names[5889] = "millianongendosexagintillion" +number_names[5892] = "millianongentresexagintillion" +number_names[5895] = "millianongenquattuorsexagintillion" +number_names[5898] = "millianongenquinsexagintillion" +number_names[5901] = "millianongensexsexagintillion" +number_names[5904] = "millianongenseptensexagintillion" +number_names[5907] = "millianongenoctosexagintillion" +number_names[5910] = "millianongennovemsexagintillion" +number_names[5913] = "millianongenseptuagintillion" +number_names[5916] = "millianongenunseptuagintillion" +number_names[5919] = "millianongendoseptuagintillion" +number_names[5922] = "millianongentreseptuagintillion" +number_names[5925] = "millianongenquattuorseptuagintillion" +number_names[5928] = "millianongenquinseptuagintillion" +number_names[5931] = "millianongensexseptuagintillion" +number_names[5934] = "millianongenseptenseptuagintillion" +number_names[5937] = "millianongenoctoseptuagintillion" +number_names[5940] = "millianongennovemseptuagintillion" +number_names[5943] = "millianongenoctogintillion" +number_names[5946] = "millianongenunoctogintillion" +number_names[5949] = "millianongendooctogintillion" +number_names[5952] = "millianongentreoctogintillion" +number_names[5955] = "millianongenquattuoroctogintillion" +number_names[5958] = "millianongenquinoctogintillion" +number_names[5961] = "millianongensexoctogintillion" +number_names[5964] = "millianongenseptenoctogintillion" +number_names[5967] = "millianongenoctooctogintillion" +number_names[5970] = "millianongennovemoctogintillion" +number_names[5973] = "millianongennonagintillion" +number_names[5976] = "millianongenunnonagintillion" +number_names[5979] = "millianongendononagintillion" +number_names[5982] = "millianongentrenonagintillion" +number_names[5985] = "millianongenquattuornonagintillion" +number_names[5988] = "millianongenquinnonagintillion" +number_names[5991] = "millianongensexnonagintillion" +number_names[5994] = "millianongenseptennonagintillion" +number_names[5997] = "millianongenoctononagintillion" +number_names[6000] = "millianongennovemnonagintillion" +number_names[6003] = "duomilliatillion" +number_names[6006] = "duomilliauntillion" +number_names[6009] = "duomilliadotillion" +number_names[6012] = "duomilliatretillion" +number_names[6015] = "duomilliaquattuortillion" +number_names[6018] = "duomilliaquintillion" +number_names[6021] = "duomilliasextillion" +number_names[6024] = "duomilliaseptentillion" +number_names[6027] = "duomilliaoctotillion" +number_names[6030] = "duomillianovemtillion" +number_names[6033] = "duomilliadecillion" +number_names[6036] = "duomilliaundecillion" +number_names[6039] = "duomilliadodecillion" +number_names[6042] = "duomilliatredecillion" +number_names[6045] = "duomilliaquattuordecillion" +number_names[6048] = "duomilliaquindecillion" +number_names[6051] = "duomilliasexdecillion" +number_names[6054] = "duomilliaseptendecillion" +number_names[6057] = "duomilliaoctodecillion" +number_names[6060] = "duomillianovemdecillion" +number_names[6063] = "duomilliavigintillion" +number_names[6066] = "duomilliaunvigintillion" +number_names[6069] = "duomilliadovigintillion" +number_names[6072] = "duomilliatrevigintillion" +number_names[6075] = "duomilliaquattuorvigintillion" +number_names[6078] = "duomilliaquinvigintillion" +number_names[6081] = "duomilliasexvigintillion" +number_names[6084] = "duomilliaseptenvigintillion" +number_names[6087] = "duomilliaoctovigintillion" +number_names[6090] = "duomillianovemvigintillion" +number_names[6093] = "duomilliatrigintillion" +number_names[6096] = "duomilliauntrigintillion" +number_names[6099] = "duomilliadotrigintillion" +number_names[6102] = "duomilliatretrigintillion" +number_names[6105] = "duomilliaquattuortrigintillion" +number_names[6108] = "duomilliaquintrigintillion" +number_names[6111] = "duomilliasextrigintillion" +number_names[6114] = "duomilliaseptentrigintillion" +number_names[6117] = "duomilliaoctotrigintillion" +number_names[6120] = "duomillianovemtrigintillion" +number_names[6123] = "duomilliaquadragintillion" +number_names[6126] = "duomilliaunquadragintillion" +number_names[6129] = "duomilliadoquadragintillion" +number_names[6132] = "duomilliatrequadragintillion" +number_names[6135] = "duomilliaquattuorquadragintillion" +number_names[6138] = "duomilliaquinquadragintillion" +number_names[6141] = "duomilliasexquadragintillion" +number_names[6144] = "duomilliaseptenquadragintillion" +number_names[6147] = "duomilliaoctoquadragintillion" +number_names[6150] = "duomillianovemquadragintillion" +number_names[6153] = "duomilliaquinquagintillion" +number_names[6156] = "duomilliaunquinquagintillion" +number_names[6159] = "duomilliadoquinquagintillion" +number_names[6162] = "duomilliatrequinquagintillion" +number_names[6165] = "duomilliaquattuorquinquagintillion" +number_names[6168] = "duomilliaquinquinquagintillion" +number_names[6171] = "duomilliasexquinquagintillion" +number_names[6174] = "duomilliaseptenquinquagintillion" +number_names[6177] = "duomilliaoctoquinquagintillion" +number_names[6180] = "duomillianovemquinquagintillion" +number_names[6183] = "duomilliasexagintillion" +number_names[6186] = "duomilliaunsexagintillion" +number_names[6189] = "duomilliadosexagintillion" +number_names[6192] = "duomilliatresexagintillion" +number_names[6195] = "duomilliaquattuorsexagintillion" +number_names[6198] = "duomilliaquinsexagintillion" +number_names[6201] = "duomilliasexsexagintillion" +number_names[6204] = "duomilliaseptensexagintillion" +number_names[6207] = "duomilliaoctosexagintillion" +number_names[6210] = "duomillianovemsexagintillion" +number_names[6213] = "duomilliaseptuagintillion" +number_names[6216] = "duomilliaunseptuagintillion" +number_names[6219] = "duomilliadoseptuagintillion" +number_names[6222] = "duomilliatreseptuagintillion" +number_names[6225] = "duomilliaquattuorseptuagintillion" +number_names[6228] = "duomilliaquinseptuagintillion" +number_names[6231] = "duomilliasexseptuagintillion" +number_names[6234] = "duomilliaseptenseptuagintillion" +number_names[6237] = "duomilliaoctoseptuagintillion" +number_names[6240] = "duomillianovemseptuagintillion" +number_names[6243] = "duomilliaoctogintillion" +number_names[6246] = "duomilliaunoctogintillion" +number_names[6249] = "duomilliadooctogintillion" +number_names[6252] = "duomilliatreoctogintillion" +number_names[6255] = "duomilliaquattuoroctogintillion" +number_names[6258] = "duomilliaquinoctogintillion" +number_names[6261] = "duomilliasexoctogintillion" +number_names[6264] = "duomilliaseptenoctogintillion" +number_names[6267] = "duomilliaoctooctogintillion" +number_names[6270] = "duomillianovemoctogintillion" +number_names[6273] = "duomillianonagintillion" +number_names[6276] = "duomilliaunnonagintillion" +number_names[6279] = "duomilliadononagintillion" +number_names[6282] = "duomilliatrenonagintillion" +number_names[6285] = "duomilliaquattuornonagintillion" +number_names[6288] = "duomilliaquinnonagintillion" +number_names[6291] = "duomilliasexnonagintillion" +number_names[6294] = "duomilliaseptennonagintillion" +number_names[6297] = "duomilliaoctononagintillion" +number_names[6300] = "duomillianovemnonagintillion" +number_names[6303] = "duomilliacentillion" +number_names[6306] = "duomilliacenuntillion" +number_names[6309] = "duomilliacendotillion" +number_names[6312] = "duomilliacentretillion" +number_names[6315] = "duomilliacenquattuortillion" +number_names[6318] = "duomilliacenquintillion" +number_names[6321] = "duomilliacensextillion" +number_names[6324] = "duomilliacenseptentillion" +number_names[6327] = "duomilliacenoctotillion" +number_names[6330] = "duomilliacennovemtillion" +number_names[6333] = "duomilliacendecillion" +number_names[6336] = "duomilliacenundecillion" +number_names[6339] = "duomilliacendodecillion" +number_names[6342] = "duomilliacentredecillion" +number_names[6345] = "duomilliacenquattuordecillion" +number_names[6348] = "duomilliacenquindecillion" +number_names[6351] = "duomilliacensexdecillion" +number_names[6354] = "duomilliacenseptendecillion" +number_names[6357] = "duomilliacenoctodecillion" +number_names[6360] = "duomilliacennovemdecillion" +number_names[6363] = "duomilliacenvigintillion" +number_names[6366] = "duomilliacenunvigintillion" +number_names[6369] = "duomilliacendovigintillion" +number_names[6372] = "duomilliacentrevigintillion" +number_names[6375] = "duomilliacenquattuorvigintillion" +number_names[6378] = "duomilliacenquinvigintillion" +number_names[6381] = "duomilliacensexvigintillion" +number_names[6384] = "duomilliacenseptenvigintillion" +number_names[6387] = "duomilliacenoctovigintillion" +number_names[6390] = "duomilliacennovemvigintillion" +number_names[6393] = "duomilliacentrigintillion" +number_names[6396] = "duomilliacenuntrigintillion" +number_names[6399] = "duomilliacendotrigintillion" +number_names[6402] = "duomilliacentretrigintillion" +number_names[6405] = "duomilliacenquattuortrigintillion" +number_names[6408] = "duomilliacenquintrigintillion" +number_names[6411] = "duomilliacensextrigintillion" +number_names[6414] = "duomilliacenseptentrigintillion" +number_names[6417] = "duomilliacenoctotrigintillion" +number_names[6420] = "duomilliacennovemtrigintillion" +number_names[6423] = "duomilliacenquadragintillion" +number_names[6426] = "duomilliacenunquadragintillion" +number_names[6429] = "duomilliacendoquadragintillion" +number_names[6432] = "duomilliacentrequadragintillion" +number_names[6435] = "duomilliacenquattuorquadragintillion" +number_names[6438] = "duomilliacenquinquadragintillion" +number_names[6441] = "duomilliacensexquadragintillion" +number_names[6444] = "duomilliacenseptenquadragintillion" +number_names[6447] = "duomilliacenoctoquadragintillion" +number_names[6450] = "duomilliacennovemquadragintillion" +number_names[6453] = "duomilliacenquinquagintillion" +number_names[6456] = "duomilliacenunquinquagintillion" +number_names[6459] = "duomilliacendoquinquagintillion" +number_names[6462] = "duomilliacentrequinquagintillion" +number_names[6465] = "duomilliacenquattuorquinquagintillion" +number_names[6468] = "duomilliacenquinquinquagintillion" +number_names[6471] = "duomilliacensexquinquagintillion" +number_names[6474] = "duomilliacenseptenquinquagintillion" +number_names[6477] = "duomilliacenoctoquinquagintillion" +number_names[6480] = "duomilliacennovemquinquagintillion" +number_names[6483] = "duomilliacensexagintillion" +number_names[6486] = "duomilliacenunsexagintillion" +number_names[6489] = "duomilliacendosexagintillion" +number_names[6492] = "duomilliacentresexagintillion" +number_names[6495] = "duomilliacenquattuorsexagintillion" +number_names[6498] = "duomilliacenquinsexagintillion" +number_names[6501] = "duomilliacensexsexagintillion" +number_names[6504] = "duomilliacenseptensexagintillion" +number_names[6507] = "duomilliacenoctosexagintillion" +number_names[6510] = "duomilliacennovemsexagintillion" +number_names[6513] = "duomilliacenseptuagintillion" +number_names[6516] = "duomilliacenunseptuagintillion" +number_names[6519] = "duomilliacendoseptuagintillion" +number_names[6522] = "duomilliacentreseptuagintillion" +number_names[6525] = "duomilliacenquattuorseptuagintillion" +number_names[6528] = "duomilliacenquinseptuagintillion" +number_names[6531] = "duomilliacensexseptuagintillion" +number_names[6534] = "duomilliacenseptenseptuagintillion" +number_names[6537] = "duomilliacenoctoseptuagintillion" +number_names[6540] = "duomilliacennovemseptuagintillion" +number_names[6543] = "duomilliacenoctogintillion" +number_names[6546] = "duomilliacenunoctogintillion" +number_names[6549] = "duomilliacendooctogintillion" +number_names[6552] = "duomilliacentreoctogintillion" +number_names[6555] = "duomilliacenquattuoroctogintillion" +number_names[6558] = "duomilliacenquinoctogintillion" +number_names[6561] = "duomilliacensexoctogintillion" +number_names[6564] = "duomilliacenseptenoctogintillion" +number_names[6567] = "duomilliacenoctooctogintillion" +number_names[6570] = "duomilliacennovemoctogintillion" +number_names[6573] = "duomilliacennonagintillion" +number_names[6576] = "duomilliacenunnonagintillion" +number_names[6579] = "duomilliacendononagintillion" +number_names[6582] = "duomilliacentrenonagintillion" +number_names[6585] = "duomilliacenquattuornonagintillion" +number_names[6588] = "duomilliacenquinnonagintillion" +number_names[6591] = "duomilliacensexnonagintillion" +number_names[6594] = "duomilliacenseptennonagintillion" +number_names[6597] = "duomilliacenoctononagintillion" +number_names[6600] = "duomilliacennovemnonagintillion" +number_names[6603] = "duomilliaducentillion" +number_names[6606] = "duomilliaducenuntillion" +number_names[6609] = "duomilliaducendotillion" +number_names[6612] = "duomilliaducentretillion" +number_names[6615] = "duomilliaducenquattuortillion" +number_names[6618] = "duomilliaducenquintillion" +number_names[6621] = "duomilliaducensextillion" +number_names[6624] = "duomilliaducenseptentillion" +number_names[6627] = "duomilliaducenoctotillion" +number_names[6630] = "duomilliaducennovemtillion" +number_names[6633] = "duomilliaducendecillion" +number_names[6636] = "duomilliaducenundecillion" +number_names[6639] = "duomilliaducendodecillion" +number_names[6642] = "duomilliaducentredecillion" +number_names[6645] = "duomilliaducenquattuordecillion" +number_names[6648] = "duomilliaducenquindecillion" +number_names[6651] = "duomilliaducensexdecillion" +number_names[6654] = "duomilliaducenseptendecillion" +number_names[6657] = "duomilliaducenoctodecillion" +number_names[6660] = "duomilliaducennovemdecillion" +number_names[6663] = "duomilliaducenvigintillion" +number_names[6666] = "duomilliaducenunvigintillion" +number_names[6669] = "duomilliaducendovigintillion" +number_names[6672] = "duomilliaducentrevigintillion" +number_names[6675] = "duomilliaducenquattuorvigintillion" +number_names[6678] = "duomilliaducenquinvigintillion" +number_names[6681] = "duomilliaducensexvigintillion" +number_names[6684] = "duomilliaducenseptenvigintillion" +number_names[6687] = "duomilliaducenoctovigintillion" +number_names[6690] = "duomilliaducennovemvigintillion" +number_names[6693] = "duomilliaducentrigintillion" +number_names[6696] = "duomilliaducenuntrigintillion" +number_names[6699] = "duomilliaducendotrigintillion" +number_names[6702] = "duomilliaducentretrigintillion" +number_names[6705] = "duomilliaducenquattuortrigintillion" +number_names[6708] = "duomilliaducenquintrigintillion" +number_names[6711] = "duomilliaducensextrigintillion" +number_names[6714] = "duomilliaducenseptentrigintillion" +number_names[6717] = "duomilliaducenoctotrigintillion" +number_names[6720] = "duomilliaducennovemtrigintillion" +number_names[6723] = "duomilliaducenquadragintillion" +number_names[6726] = "duomilliaducenunquadragintillion" +number_names[6729] = "duomilliaducendoquadragintillion" +number_names[6732] = "duomilliaducentrequadragintillion" +number_names[6735] = "duomilliaducenquattuorquadragintillion" +number_names[6738] = "duomilliaducenquinquadragintillion" +number_names[6741] = "duomilliaducensexquadragintillion" +number_names[6744] = "duomilliaducenseptenquadragintillion" +number_names[6747] = "duomilliaducenoctoquadragintillion" +number_names[6750] = "duomilliaducennovemquadragintillion" +number_names[6753] = "duomilliaducenquinquagintillion" +number_names[6756] = "duomilliaducenunquinquagintillion" +number_names[6759] = "duomilliaducendoquinquagintillion" +number_names[6762] = "duomilliaducentrequinquagintillion" +number_names[6765] = "duomilliaducenquattuorquinquagintillion" +number_names[6768] = "duomilliaducenquinquinquagintillion" +number_names[6771] = "duomilliaducensexquinquagintillion" +number_names[6774] = "duomilliaducenseptenquinquagintillion" +number_names[6777] = "duomilliaducenoctoquinquagintillion" +number_names[6780] = "duomilliaducennovemquinquagintillion" +number_names[6783] = "duomilliaducensexagintillion" +number_names[6786] = "duomilliaducenunsexagintillion" +number_names[6789] = "duomilliaducendosexagintillion" +number_names[6792] = "duomilliaducentresexagintillion" +number_names[6795] = "duomilliaducenquattuorsexagintillion" +number_names[6798] = "duomilliaducenquinsexagintillion" +number_names[6801] = "duomilliaducensexsexagintillion" +number_names[6804] = "duomilliaducenseptensexagintillion" +number_names[6807] = "duomilliaducenoctosexagintillion" +number_names[6810] = "duomilliaducennovemsexagintillion" +number_names[6813] = "duomilliaducenseptuagintillion" +number_names[6816] = "duomilliaducenunseptuagintillion" +number_names[6819] = "duomilliaducendoseptuagintillion" +number_names[6822] = "duomilliaducentreseptuagintillion" +number_names[6825] = "duomilliaducenquattuorseptuagintillion" +number_names[6828] = "duomilliaducenquinseptuagintillion" +number_names[6831] = "duomilliaducensexseptuagintillion" +number_names[6834] = "duomilliaducenseptenseptuagintillion" +number_names[6837] = "duomilliaducenoctoseptuagintillion" +number_names[6840] = "duomilliaducennovemseptuagintillion" +number_names[6843] = "duomilliaducenoctogintillion" +number_names[6846] = "duomilliaducenunoctogintillion" +number_names[6849] = "duomilliaducendooctogintillion" +number_names[6852] = "duomilliaducentreoctogintillion" +number_names[6855] = "duomilliaducenquattuoroctogintillion" +number_names[6858] = "duomilliaducenquinoctogintillion" +number_names[6861] = "duomilliaducensexoctogintillion" +number_names[6864] = "duomilliaducenseptenoctogintillion" +number_names[6867] = "duomilliaducenoctooctogintillion" +number_names[6870] = "duomilliaducennovemoctogintillion" +number_names[6873] = "duomilliaducennonagintillion" +number_names[6876] = "duomilliaducenunnonagintillion" +number_names[6879] = "duomilliaducendononagintillion" +number_names[6882] = "duomilliaducentrenonagintillion" +number_names[6885] = "duomilliaducenquattuornonagintillion" +number_names[6888] = "duomilliaducenquinnonagintillion" +number_names[6891] = "duomilliaducensexnonagintillion" +number_names[6894] = "duomilliaducenseptennonagintillion" +number_names[6897] = "duomilliaducenoctononagintillion" +number_names[6900] = "duomilliaducennovemnonagintillion" +number_names[6903] = "duomilliatrecentillion" +number_names[6906] = "duomilliatrecenuntillion" +number_names[6909] = "duomilliatrecendotillion" +number_names[6912] = "duomilliatrecentretillion" +number_names[6915] = "duomilliatrecenquattuortillion" +number_names[6918] = "duomilliatrecenquintillion" +number_names[6921] = "duomilliatrecensextillion" +number_names[6924] = "duomilliatrecenseptentillion" +number_names[6927] = "duomilliatrecenoctotillion" +number_names[6930] = "duomilliatrecennovemtillion" +number_names[6933] = "duomilliatrecendecillion" +number_names[6936] = "duomilliatrecenundecillion" +number_names[6939] = "duomilliatrecendodecillion" +number_names[6942] = "duomilliatrecentredecillion" +number_names[6945] = "duomilliatrecenquattuordecillion" +number_names[6948] = "duomilliatrecenquindecillion" +number_names[6951] = "duomilliatrecensexdecillion" +number_names[6954] = "duomilliatrecenseptendecillion" +number_names[6957] = "duomilliatrecenoctodecillion" +number_names[6960] = "duomilliatrecennovemdecillion" +number_names[6963] = "duomilliatrecenvigintillion" +number_names[6966] = "duomilliatrecenunvigintillion" +number_names[6969] = "duomilliatrecendovigintillion" +number_names[6972] = "duomilliatrecentrevigintillion" +number_names[6975] = "duomilliatrecenquattuorvigintillion" +number_names[6978] = "duomilliatrecenquinvigintillion" +number_names[6981] = "duomilliatrecensexvigintillion" +number_names[6984] = "duomilliatrecenseptenvigintillion" +number_names[6987] = "duomilliatrecenoctovigintillion" +number_names[6990] = "duomilliatrecennovemvigintillion" +number_names[6993] = "duomilliatrecentrigintillion" +number_names[6996] = "duomilliatrecenuntrigintillion" +number_names[6999] = "duomilliatrecendotrigintillion" +number_names[7002] = "duomilliatrecentretrigintillion" +number_names[7005] = "duomilliatrecenquattuortrigintillion" +number_names[7008] = "duomilliatrecenquintrigintillion" +number_names[7011] = "duomilliatrecensextrigintillion" +number_names[7014] = "duomilliatrecenseptentrigintillion" +number_names[7017] = "duomilliatrecenoctotrigintillion" +number_names[7020] = "duomilliatrecennovemtrigintillion" +number_names[7023] = "duomilliatrecenquadragintillion" +number_names[7026] = "duomilliatrecenunquadragintillion" +number_names[7029] = "duomilliatrecendoquadragintillion" +number_names[7032] = "duomilliatrecentrequadragintillion" +number_names[7035] = "duomilliatrecenquattuorquadragintillion" +number_names[7038] = "duomilliatrecenquinquadragintillion" +number_names[7041] = "duomilliatrecensexquadragintillion" +number_names[7044] = "duomilliatrecenseptenquadragintillion" +number_names[7047] = "duomilliatrecenoctoquadragintillion" +number_names[7050] = "duomilliatrecennovemquadragintillion" +number_names[7053] = "duomilliatrecenquinquagintillion" +number_names[7056] = "duomilliatrecenunquinquagintillion" +number_names[7059] = "duomilliatrecendoquinquagintillion" +number_names[7062] = "duomilliatrecentrequinquagintillion" +number_names[7065] = "duomilliatrecenquattuorquinquagintillion" +number_names[7068] = "duomilliatrecenquinquinquagintillion" +number_names[7071] = "duomilliatrecensexquinquagintillion" +number_names[7074] = "duomilliatrecenseptenquinquagintillion" +number_names[7077] = "duomilliatrecenoctoquinquagintillion" +number_names[7080] = "duomilliatrecennovemquinquagintillion" +number_names[7083] = "duomilliatrecensexagintillion" +number_names[7086] = "duomilliatrecenunsexagintillion" +number_names[7089] = "duomilliatrecendosexagintillion" +number_names[7092] = "duomilliatrecentresexagintillion" +number_names[7095] = "duomilliatrecenquattuorsexagintillion" +number_names[7098] = "duomilliatrecenquinsexagintillion" +number_names[7101] = "duomilliatrecensexsexagintillion" +number_names[7104] = "duomilliatrecenseptensexagintillion" +number_names[7107] = "duomilliatrecenoctosexagintillion" +number_names[7110] = "duomilliatrecennovemsexagintillion" +number_names[7113] = "duomilliatrecenseptuagintillion" +number_names[7116] = "duomilliatrecenunseptuagintillion" +number_names[7119] = "duomilliatrecendoseptuagintillion" +number_names[7122] = "duomilliatrecentreseptuagintillion" +number_names[7125] = "duomilliatrecenquattuorseptuagintillion" +number_names[7128] = "duomilliatrecenquinseptuagintillion" +number_names[7131] = "duomilliatrecensexseptuagintillion" +number_names[7134] = "duomilliatrecenseptenseptuagintillion" +number_names[7137] = "duomilliatrecenoctoseptuagintillion" +number_names[7140] = "duomilliatrecennovemseptuagintillion" +number_names[7143] = "duomilliatrecenoctogintillion" +number_names[7146] = "duomilliatrecenunoctogintillion" +number_names[7149] = "duomilliatrecendooctogintillion" +number_names[7152] = "duomilliatrecentreoctogintillion" +number_names[7155] = "duomilliatrecenquattuoroctogintillion" +number_names[7158] = "duomilliatrecenquinoctogintillion" +number_names[7161] = "duomilliatrecensexoctogintillion" +number_names[7164] = "duomilliatrecenseptenoctogintillion" +number_names[7167] = "duomilliatrecenoctooctogintillion" +number_names[7170] = "duomilliatrecennovemoctogintillion" +number_names[7173] = "duomilliatrecennonagintillion" +number_names[7176] = "duomilliatrecenunnonagintillion" +number_names[7179] = "duomilliatrecendononagintillion" +number_names[7182] = "duomilliatrecentrenonagintillion" +number_names[7185] = "duomilliatrecenquattuornonagintillion" +number_names[7188] = "duomilliatrecenquinnonagintillion" +number_names[7191] = "duomilliatrecensexnonagintillion" +number_names[7194] = "duomilliatrecenseptennonagintillion" +number_names[7197] = "duomilliatrecenoctononagintillion" +number_names[7200] = "duomilliatrecennovemnonagintillion" +number_names[7203] = "duomilliaquadringentillion" +number_names[7206] = "duomilliaquadringenuntillion" +number_names[7209] = "duomilliaquadringendotillion" +number_names[7212] = "duomilliaquadringentretillion" +number_names[7215] = "duomilliaquadringenquattuortillion" +number_names[7218] = "duomilliaquadringenquintillion" +number_names[7221] = "duomilliaquadringensextillion" +number_names[7224] = "duomilliaquadringenseptentillion" +number_names[7227] = "duomilliaquadringenoctotillion" +number_names[7230] = "duomilliaquadringennovemtillion" +number_names[7233] = "duomilliaquadringendecillion" +number_names[7236] = "duomilliaquadringenundecillion" +number_names[7239] = "duomilliaquadringendodecillion" +number_names[7242] = "duomilliaquadringentredecillion" +number_names[7245] = "duomilliaquadringenquattuordecillion" +number_names[7248] = "duomilliaquadringenquindecillion" +number_names[7251] = "duomilliaquadringensexdecillion" +number_names[7254] = "duomilliaquadringenseptendecillion" +number_names[7257] = "duomilliaquadringenoctodecillion" +number_names[7260] = "duomilliaquadringennovemdecillion" +number_names[7263] = "duomilliaquadringenvigintillion" +number_names[7266] = "duomilliaquadringenunvigintillion" +number_names[7269] = "duomilliaquadringendovigintillion" +number_names[7272] = "duomilliaquadringentrevigintillion" +number_names[7275] = "duomilliaquadringenquattuorvigintillion" +number_names[7278] = "duomilliaquadringenquinvigintillion" +number_names[7281] = "duomilliaquadringensexvigintillion" +number_names[7284] = "duomilliaquadringenseptenvigintillion" +number_names[7287] = "duomilliaquadringenoctovigintillion" +number_names[7290] = "duomilliaquadringennovemvigintillion" +number_names[7293] = "duomilliaquadringentrigintillion" +number_names[7296] = "duomilliaquadringenuntrigintillion" +number_names[7299] = "duomilliaquadringendotrigintillion" +number_names[7302] = "duomilliaquadringentretrigintillion" +number_names[7305] = "duomilliaquadringenquattuortrigintillion" +number_names[7308] = "duomilliaquadringenquintrigintillion" +number_names[7311] = "duomilliaquadringensextrigintillion" +number_names[7314] = "duomilliaquadringenseptentrigintillion" +number_names[7317] = "duomilliaquadringenoctotrigintillion" +number_names[7320] = "duomilliaquadringennovemtrigintillion" +number_names[7323] = "duomilliaquadringenquadragintillion" +number_names[7326] = "duomilliaquadringenunquadragintillion" +number_names[7329] = "duomilliaquadringendoquadragintillion" +number_names[7332] = "duomilliaquadringentrequadragintillion" +number_names[7335] = "duomilliaquadringenquattuorquadragintillion" +number_names[7338] = "duomilliaquadringenquinquadragintillion" +number_names[7341] = "duomilliaquadringensexquadragintillion" +number_names[7344] = "duomilliaquadringenseptenquadragintillion" +number_names[7347] = "duomilliaquadringenoctoquadragintillion" +number_names[7350] = "duomilliaquadringennovemquadragintillion" +number_names[7353] = "duomilliaquadringenquinquagintillion" +number_names[7356] = "duomilliaquadringenunquinquagintillion" +number_names[7359] = "duomilliaquadringendoquinquagintillion" +number_names[7362] = "duomilliaquadringentrequinquagintillion" +number_names[7365] = "duomilliaquadringenquattuorquinquagintillion" +number_names[7368] = "duomilliaquadringenquinquinquagintillion" +number_names[7371] = "duomilliaquadringensexquinquagintillion" +number_names[7374] = "duomilliaquadringenseptenquinquagintillion" +number_names[7377] = "duomilliaquadringenoctoquinquagintillion" +number_names[7380] = "duomilliaquadringennovemquinquagintillion" +number_names[7383] = "duomilliaquadringensexagintillion" +number_names[7386] = "duomilliaquadringenunsexagintillion" +number_names[7389] = "duomilliaquadringendosexagintillion" +number_names[7392] = "duomilliaquadringentresexagintillion" +number_names[7395] = "duomilliaquadringenquattuorsexagintillion" +number_names[7398] = "duomilliaquadringenquinsexagintillion" +number_names[7401] = "duomilliaquadringensexsexagintillion" +number_names[7404] = "duomilliaquadringenseptensexagintillion" +number_names[7407] = "duomilliaquadringenoctosexagintillion" +number_names[7410] = "duomilliaquadringennovemsexagintillion" +number_names[7413] = "duomilliaquadringenseptuagintillion" +number_names[7416] = "duomilliaquadringenunseptuagintillion" +number_names[7419] = "duomilliaquadringendoseptuagintillion" +number_names[7422] = "duomilliaquadringentreseptuagintillion" +number_names[7425] = "duomilliaquadringenquattuorseptuagintillion" +number_names[7428] = "duomilliaquadringenquinseptuagintillion" +number_names[7431] = "duomilliaquadringensexseptuagintillion" +number_names[7434] = "duomilliaquadringenseptenseptuagintillion" +number_names[7437] = "duomilliaquadringenoctoseptuagintillion" +number_names[7440] = "duomilliaquadringennovemseptuagintillion" +number_names[7443] = "duomilliaquadringenoctogintillion" +number_names[7446] = "duomilliaquadringenunoctogintillion" +number_names[7449] = "duomilliaquadringendooctogintillion" +number_names[7452] = "duomilliaquadringentreoctogintillion" +number_names[7455] = "duomilliaquadringenquattuoroctogintillion" +number_names[7458] = "duomilliaquadringenquinoctogintillion" +number_names[7461] = "duomilliaquadringensexoctogintillion" +number_names[7464] = "duomilliaquadringenseptenoctogintillion" +number_names[7467] = "duomilliaquadringenoctooctogintillion" +number_names[7470] = "duomilliaquadringennovemoctogintillion" +number_names[7473] = "duomilliaquadringennonagintillion" +number_names[7476] = "duomilliaquadringenunnonagintillion" +number_names[7479] = "duomilliaquadringendononagintillion" +number_names[7482] = "duomilliaquadringentrenonagintillion" +number_names[7485] = "duomilliaquadringenquattuornonagintillion" +number_names[7488] = "duomilliaquadringenquinnonagintillion" +number_names[7491] = "duomilliaquadringensexnonagintillion" +number_names[7494] = "duomilliaquadringenseptennonagintillion" +number_names[7497] = "duomilliaquadringenoctononagintillion" +number_names[7500] = "duomilliaquadringennovemnonagintillion" +number_names[7503] = "duomilliaquingentillion" +number_names[7506] = "duomilliaquingenuntillion" +number_names[7509] = "duomilliaquingendotillion" +number_names[7512] = "duomilliaquingentretillion" +number_names[7515] = "duomilliaquingenquattuortillion" +number_names[7518] = "duomilliaquingenquintillion" +number_names[7521] = "duomilliaquingensextillion" +number_names[7524] = "duomilliaquingenseptentillion" +number_names[7527] = "duomilliaquingenoctotillion" +number_names[7530] = "duomilliaquingennovemtillion" +number_names[7533] = "duomilliaquingendecillion" +number_names[7536] = "duomilliaquingenundecillion" +number_names[7539] = "duomilliaquingendodecillion" +number_names[7542] = "duomilliaquingentredecillion" +number_names[7545] = "duomilliaquingenquattuordecillion" +number_names[7548] = "duomilliaquingenquindecillion" +number_names[7551] = "duomilliaquingensexdecillion" +number_names[7554] = "duomilliaquingenseptendecillion" +number_names[7557] = "duomilliaquingenoctodecillion" +number_names[7560] = "duomilliaquingennovemdecillion" +number_names[7563] = "duomilliaquingenvigintillion" +number_names[7566] = "duomilliaquingenunvigintillion" +number_names[7569] = "duomilliaquingendovigintillion" +number_names[7572] = "duomilliaquingentrevigintillion" +number_names[7575] = "duomilliaquingenquattuorvigintillion" +number_names[7578] = "duomilliaquingenquinvigintillion" +number_names[7581] = "duomilliaquingensexvigintillion" +number_names[7584] = "duomilliaquingenseptenvigintillion" +number_names[7587] = "duomilliaquingenoctovigintillion" +number_names[7590] = "duomilliaquingennovemvigintillion" +number_names[7593] = "duomilliaquingentrigintillion" +number_names[7596] = "duomilliaquingenuntrigintillion" +number_names[7599] = "duomilliaquingendotrigintillion" +number_names[7602] = "duomilliaquingentretrigintillion" +number_names[7605] = "duomilliaquingenquattuortrigintillion" +number_names[7608] = "duomilliaquingenquintrigintillion" +number_names[7611] = "duomilliaquingensextrigintillion" +number_names[7614] = "duomilliaquingenseptentrigintillion" +number_names[7617] = "duomilliaquingenoctotrigintillion" +number_names[7620] = "duomilliaquingennovemtrigintillion" +number_names[7623] = "duomilliaquingenquadragintillion" +number_names[7626] = "duomilliaquingenunquadragintillion" +number_names[7629] = "duomilliaquingendoquadragintillion" +number_names[7632] = "duomilliaquingentrequadragintillion" +number_names[7635] = "duomilliaquingenquattuorquadragintillion" +number_names[7638] = "duomilliaquingenquinquadragintillion" +number_names[7641] = "duomilliaquingensexquadragintillion" +number_names[7644] = "duomilliaquingenseptenquadragintillion" +number_names[7647] = "duomilliaquingenoctoquadragintillion" +number_names[7650] = "duomilliaquingennovemquadragintillion" +number_names[7653] = "duomilliaquingenquinquagintillion" +number_names[7656] = "duomilliaquingenunquinquagintillion" +number_names[7659] = "duomilliaquingendoquinquagintillion" +number_names[7662] = "duomilliaquingentrequinquagintillion" +number_names[7665] = "duomilliaquingenquattuorquinquagintillion" +number_names[7668] = "duomilliaquingenquinquinquagintillion" +number_names[7671] = "duomilliaquingensexquinquagintillion" +number_names[7674] = "duomilliaquingenseptenquinquagintillion" +number_names[7677] = "duomilliaquingenoctoquinquagintillion" +number_names[7680] = "duomilliaquingennovemquinquagintillion" +number_names[7683] = "duomilliaquingensexagintillion" +number_names[7686] = "duomilliaquingenunsexagintillion" +number_names[7689] = "duomilliaquingendosexagintillion" +number_names[7692] = "duomilliaquingentresexagintillion" +number_names[7695] = "duomilliaquingenquattuorsexagintillion" +number_names[7698] = "duomilliaquingenquinsexagintillion" +number_names[7701] = "duomilliaquingensexsexagintillion" +number_names[7704] = "duomilliaquingenseptensexagintillion" +number_names[7707] = "duomilliaquingenoctosexagintillion" +number_names[7710] = "duomilliaquingennovemsexagintillion" +number_names[7713] = "duomilliaquingenseptuagintillion" +number_names[7716] = "duomilliaquingenunseptuagintillion" +number_names[7719] = "duomilliaquingendoseptuagintillion" +number_names[7722] = "duomilliaquingentreseptuagintillion" +number_names[7725] = "duomilliaquingenquattuorseptuagintillion" +number_names[7728] = "duomilliaquingenquinseptuagintillion" +number_names[7731] = "duomilliaquingensexseptuagintillion" +number_names[7734] = "duomilliaquingenseptenseptuagintillion" +number_names[7737] = "duomilliaquingenoctoseptuagintillion" +number_names[7740] = "duomilliaquingennovemseptuagintillion" +number_names[7743] = "duomilliaquingenoctogintillion" +number_names[7746] = "duomilliaquingenunoctogintillion" +number_names[7749] = "duomilliaquingendooctogintillion" +number_names[7752] = "duomilliaquingentreoctogintillion" +number_names[7755] = "duomilliaquingenquattuoroctogintillion" +number_names[7758] = "duomilliaquingenquinoctogintillion" +number_names[7761] = "duomilliaquingensexoctogintillion" +number_names[7764] = "duomilliaquingenseptenoctogintillion" +number_names[7767] = "duomilliaquingenoctooctogintillion" +number_names[7770] = "duomilliaquingennovemoctogintillion" +number_names[7773] = "duomilliaquingennonagintillion" +number_names[7776] = "duomilliaquingenunnonagintillion" +number_names[7779] = "duomilliaquingendononagintillion" +number_names[7782] = "duomilliaquingentrenonagintillion" +number_names[7785] = "duomilliaquingenquattuornonagintillion" +number_names[7788] = "duomilliaquingenquinnonagintillion" +number_names[7791] = "duomilliaquingensexnonagintillion" +number_names[7794] = "duomilliaquingenseptennonagintillion" +number_names[7797] = "duomilliaquingenoctononagintillion" +number_names[7800] = "duomilliaquingennovemnonagintillion" +number_names[7803] = "duomilliasescentillion" +number_names[7806] = "duomilliasescenuntillion" +number_names[7809] = "duomilliasescendotillion" +number_names[7812] = "duomilliasescentretillion" +number_names[7815] = "duomilliasescenquattuortillion" +number_names[7818] = "duomilliasescenquintillion" +number_names[7821] = "duomilliasescensextillion" +number_names[7824] = "duomilliasescenseptentillion" +number_names[7827] = "duomilliasescenoctotillion" +number_names[7830] = "duomilliasescennovemtillion" +number_names[7833] = "duomilliasescendecillion" +number_names[7836] = "duomilliasescenundecillion" +number_names[7839] = "duomilliasescendodecillion" +number_names[7842] = "duomilliasescentredecillion" +number_names[7845] = "duomilliasescenquattuordecillion" +number_names[7848] = "duomilliasescenquindecillion" +number_names[7851] = "duomilliasescensexdecillion" +number_names[7854] = "duomilliasescenseptendecillion" +number_names[7857] = "duomilliasescenoctodecillion" +number_names[7860] = "duomilliasescennovemdecillion" +number_names[7863] = "duomilliasescenvigintillion" +number_names[7866] = "duomilliasescenunvigintillion" +number_names[7869] = "duomilliasescendovigintillion" +number_names[7872] = "duomilliasescentrevigintillion" +number_names[7875] = "duomilliasescenquattuorvigintillion" +number_names[7878] = "duomilliasescenquinvigintillion" +number_names[7881] = "duomilliasescensexvigintillion" +number_names[7884] = "duomilliasescenseptenvigintillion" +number_names[7887] = "duomilliasescenoctovigintillion" +number_names[7890] = "duomilliasescennovemvigintillion" +number_names[7893] = "duomilliasescentrigintillion" +number_names[7896] = "duomilliasescenuntrigintillion" +number_names[7899] = "duomilliasescendotrigintillion" +number_names[7902] = "duomilliasescentretrigintillion" +number_names[7905] = "duomilliasescenquattuortrigintillion" +number_names[7908] = "duomilliasescenquintrigintillion" +number_names[7911] = "duomilliasescensextrigintillion" +number_names[7914] = "duomilliasescenseptentrigintillion" +number_names[7917] = "duomilliasescenoctotrigintillion" +number_names[7920] = "duomilliasescennovemtrigintillion" +number_names[7923] = "duomilliasescenquadragintillion" +number_names[7926] = "duomilliasescenunquadragintillion" +number_names[7929] = "duomilliasescendoquadragintillion" +number_names[7932] = "duomilliasescentrequadragintillion" +number_names[7935] = "duomilliasescenquattuorquadragintillion" +number_names[7938] = "duomilliasescenquinquadragintillion" +number_names[7941] = "duomilliasescensexquadragintillion" +number_names[7944] = "duomilliasescenseptenquadragintillion" +number_names[7947] = "duomilliasescenoctoquadragintillion" +number_names[7950] = "duomilliasescennovemquadragintillion" +number_names[7953] = "duomilliasescenquinquagintillion" +number_names[7956] = "duomilliasescenunquinquagintillion" +number_names[7959] = "duomilliasescendoquinquagintillion" +number_names[7962] = "duomilliasescentrequinquagintillion" +number_names[7965] = "duomilliasescenquattuorquinquagintillion" +number_names[7968] = "duomilliasescenquinquinquagintillion" +number_names[7971] = "duomilliasescensexquinquagintillion" +number_names[7974] = "duomilliasescenseptenquinquagintillion" +number_names[7977] = "duomilliasescenoctoquinquagintillion" +number_names[7980] = "duomilliasescennovemquinquagintillion" +number_names[7983] = "duomilliasescensexagintillion" +number_names[7986] = "duomilliasescenunsexagintillion" +number_names[7989] = "duomilliasescendosexagintillion" +number_names[7992] = "duomilliasescentresexagintillion" +number_names[7995] = "duomilliasescenquattuorsexagintillion" +number_names[7998] = "duomilliasescenquinsexagintillion" +number_names[8001] = "duomilliasescensexsexagintillion" +number_names[8004] = "duomilliasescenseptensexagintillion" +number_names[8007] = "duomilliasescenoctosexagintillion" +number_names[8010] = "duomilliasescennovemsexagintillion" +number_names[8013] = "duomilliasescenseptuagintillion" +number_names[8016] = "duomilliasescenunseptuagintillion" +number_names[8019] = "duomilliasescendoseptuagintillion" +number_names[8022] = "duomilliasescentreseptuagintillion" +number_names[8025] = "duomilliasescenquattuorseptuagintillion" +number_names[8028] = "duomilliasescenquinseptuagintillion" +number_names[8031] = "duomilliasescensexseptuagintillion" +number_names[8034] = "duomilliasescenseptenseptuagintillion" +number_names[8037] = "duomilliasescenoctoseptuagintillion" +number_names[8040] = "duomilliasescennovemseptuagintillion" +number_names[8043] = "duomilliasescenoctogintillion" +number_names[8046] = "duomilliasescenunoctogintillion" +number_names[8049] = "duomilliasescendooctogintillion" +number_names[8052] = "duomilliasescentreoctogintillion" +number_names[8055] = "duomilliasescenquattuoroctogintillion" +number_names[8058] = "duomilliasescenquinoctogintillion" +number_names[8061] = "duomilliasescensexoctogintillion" +number_names[8064] = "duomilliasescenseptenoctogintillion" +number_names[8067] = "duomilliasescenoctooctogintillion" +number_names[8070] = "duomilliasescennovemoctogintillion" +number_names[8073] = "duomilliasescennonagintillion" +number_names[8076] = "duomilliasescenunnonagintillion" +number_names[8079] = "duomilliasescendononagintillion" +number_names[8082] = "duomilliasescentrenonagintillion" +number_names[8085] = "duomilliasescenquattuornonagintillion" +number_names[8088] = "duomilliasescenquinnonagintillion" +number_names[8091] = "duomilliasescensexnonagintillion" +number_names[8094] = "duomilliasescenseptennonagintillion" +number_names[8097] = "duomilliasescenoctononagintillion" +number_names[8100] = "duomilliasescennovemnonagintillion" +number_names[8103] = "duomilliaseptingentillion" +number_names[8106] = "duomilliaseptingenuntillion" +number_names[8109] = "duomilliaseptingendotillion" +number_names[8112] = "duomilliaseptingentretillion" +number_names[8115] = "duomilliaseptingenquattuortillion" +number_names[8118] = "duomilliaseptingenquintillion" +number_names[8121] = "duomilliaseptingensextillion" +number_names[8124] = "duomilliaseptingenseptentillion" +number_names[8127] = "duomilliaseptingenoctotillion" +number_names[8130] = "duomilliaseptingennovemtillion" +number_names[8133] = "duomilliaseptingendecillion" +number_names[8136] = "duomilliaseptingenundecillion" +number_names[8139] = "duomilliaseptingendodecillion" +number_names[8142] = "duomilliaseptingentredecillion" +number_names[8145] = "duomilliaseptingenquattuordecillion" +number_names[8148] = "duomilliaseptingenquindecillion" +number_names[8151] = "duomilliaseptingensexdecillion" +number_names[8154] = "duomilliaseptingenseptendecillion" +number_names[8157] = "duomilliaseptingenoctodecillion" +number_names[8160] = "duomilliaseptingennovemdecillion" +number_names[8163] = "duomilliaseptingenvigintillion" +number_names[8166] = "duomilliaseptingenunvigintillion" +number_names[8169] = "duomilliaseptingendovigintillion" +number_names[8172] = "duomilliaseptingentrevigintillion" +number_names[8175] = "duomilliaseptingenquattuorvigintillion" +number_names[8178] = "duomilliaseptingenquinvigintillion" +number_names[8181] = "duomilliaseptingensexvigintillion" +number_names[8184] = "duomilliaseptingenseptenvigintillion" +number_names[8187] = "duomilliaseptingenoctovigintillion" +number_names[8190] = "duomilliaseptingennovemvigintillion" +number_names[8193] = "duomilliaseptingentrigintillion" +number_names[8196] = "duomilliaseptingenuntrigintillion" +number_names[8199] = "duomilliaseptingendotrigintillion" +number_names[8202] = "duomilliaseptingentretrigintillion" +number_names[8205] = "duomilliaseptingenquattuortrigintillion" +number_names[8208] = "duomilliaseptingenquintrigintillion" +number_names[8211] = "duomilliaseptingensextrigintillion" +number_names[8214] = "duomilliaseptingenseptentrigintillion" +number_names[8217] = "duomilliaseptingenoctotrigintillion" +number_names[8220] = "duomilliaseptingennovemtrigintillion" +number_names[8223] = "duomilliaseptingenquadragintillion" +number_names[8226] = "duomilliaseptingenunquadragintillion" +number_names[8229] = "duomilliaseptingendoquadragintillion" +number_names[8232] = "duomilliaseptingentrequadragintillion" +number_names[8235] = "duomilliaseptingenquattuorquadragintillion" +number_names[8238] = "duomilliaseptingenquinquadragintillion" +number_names[8241] = "duomilliaseptingensexquadragintillion" +number_names[8244] = "duomilliaseptingenseptenquadragintillion" +number_names[8247] = "duomilliaseptingenoctoquadragintillion" +number_names[8250] = "duomilliaseptingennovemquadragintillion" +number_names[8253] = "duomilliaseptingenquinquagintillion" +number_names[8256] = "duomilliaseptingenunquinquagintillion" +number_names[8259] = "duomilliaseptingendoquinquagintillion" +number_names[8262] = "duomilliaseptingentrequinquagintillion" +number_names[8265] = "duomilliaseptingenquattuorquinquagintillion" +number_names[8268] = "duomilliaseptingenquinquinquagintillion" +number_names[8271] = "duomilliaseptingensexquinquagintillion" +number_names[8274] = "duomilliaseptingenseptenquinquagintillion" +number_names[8277] = "duomilliaseptingenoctoquinquagintillion" +number_names[8280] = "duomilliaseptingennovemquinquagintillion" +number_names[8283] = "duomilliaseptingensexagintillion" +number_names[8286] = "duomilliaseptingenunsexagintillion" +number_names[8289] = "duomilliaseptingendosexagintillion" +number_names[8292] = "duomilliaseptingentresexagintillion" +number_names[8295] = "duomilliaseptingenquattuorsexagintillion" +number_names[8298] = "duomilliaseptingenquinsexagintillion" +number_names[8301] = "duomilliaseptingensexsexagintillion" +number_names[8304] = "duomilliaseptingenseptensexagintillion" +number_names[8307] = "duomilliaseptingenoctosexagintillion" +number_names[8310] = "duomilliaseptingennovemsexagintillion" +number_names[8313] = "duomilliaseptingenseptuagintillion" +number_names[8316] = "duomilliaseptingenunseptuagintillion" +number_names[8319] = "duomilliaseptingendoseptuagintillion" +number_names[8322] = "duomilliaseptingentreseptuagintillion" +number_names[8325] = "duomilliaseptingenquattuorseptuagintillion" +number_names[8328] = "duomilliaseptingenquinseptuagintillion" +number_names[8331] = "duomilliaseptingensexseptuagintillion" +number_names[8334] = "duomilliaseptingenseptenseptuagintillion" +number_names[8337] = "duomilliaseptingenoctoseptuagintillion" +number_names[8340] = "duomilliaseptingennovemseptuagintillion" +number_names[8343] = "duomilliaseptingenoctogintillion" +number_names[8346] = "duomilliaseptingenunoctogintillion" +number_names[8349] = "duomilliaseptingendooctogintillion" +number_names[8352] = "duomilliaseptingentreoctogintillion" +number_names[8355] = "duomilliaseptingenquattuoroctogintillion" +number_names[8358] = "duomilliaseptingenquinoctogintillion" +number_names[8361] = "duomilliaseptingensexoctogintillion" +number_names[8364] = "duomilliaseptingenseptenoctogintillion" +number_names[8367] = "duomilliaseptingenoctooctogintillion" +number_names[8370] = "duomilliaseptingennovemoctogintillion" +number_names[8373] = "duomilliaseptingennonagintillion" +number_names[8376] = "duomilliaseptingenunnonagintillion" +number_names[8379] = "duomilliaseptingendononagintillion" +number_names[8382] = "duomilliaseptingentrenonagintillion" +number_names[8385] = "duomilliaseptingenquattuornonagintillion" +number_names[8388] = "duomilliaseptingenquinnonagintillion" +number_names[8391] = "duomilliaseptingensexnonagintillion" +number_names[8394] = "duomilliaseptingenseptennonagintillion" +number_names[8397] = "duomilliaseptingenoctononagintillion" +number_names[8400] = "duomilliaseptingennovemnonagintillion" +number_names[8403] = "duomilliaoctingentillion" +number_names[8406] = "duomilliaoctingenuntillion" +number_names[8409] = "duomilliaoctingendotillion" +number_names[8412] = "duomilliaoctingentretillion" +number_names[8415] = "duomilliaoctingenquattuortillion" +number_names[8418] = "duomilliaoctingenquintillion" +number_names[8421] = "duomilliaoctingensextillion" +number_names[8424] = "duomilliaoctingenseptentillion" +number_names[8427] = "duomilliaoctingenoctotillion" +number_names[8430] = "duomilliaoctingennovemtillion" +number_names[8433] = "duomilliaoctingendecillion" +number_names[8436] = "duomilliaoctingenundecillion" +number_names[8439] = "duomilliaoctingendodecillion" +number_names[8442] = "duomilliaoctingentredecillion" +number_names[8445] = "duomilliaoctingenquattuordecillion" +number_names[8448] = "duomilliaoctingenquindecillion" +number_names[8451] = "duomilliaoctingensexdecillion" +number_names[8454] = "duomilliaoctingenseptendecillion" +number_names[8457] = "duomilliaoctingenoctodecillion" +number_names[8460] = "duomilliaoctingennovemdecillion" +number_names[8463] = "duomilliaoctingenvigintillion" +number_names[8466] = "duomilliaoctingenunvigintillion" +number_names[8469] = "duomilliaoctingendovigintillion" +number_names[8472] = "duomilliaoctingentrevigintillion" +number_names[8475] = "duomilliaoctingenquattuorvigintillion" +number_names[8478] = "duomilliaoctingenquinvigintillion" +number_names[8481] = "duomilliaoctingensexvigintillion" +number_names[8484] = "duomilliaoctingenseptenvigintillion" +number_names[8487] = "duomilliaoctingenoctovigintillion" +number_names[8490] = "duomilliaoctingennovemvigintillion" +number_names[8493] = "duomilliaoctingentrigintillion" +number_names[8496] = "duomilliaoctingenuntrigintillion" +number_names[8499] = "duomilliaoctingendotrigintillion" +number_names[8502] = "duomilliaoctingentretrigintillion" +number_names[8505] = "duomilliaoctingenquattuortrigintillion" +number_names[8508] = "duomilliaoctingenquintrigintillion" +number_names[8511] = "duomilliaoctingensextrigintillion" +number_names[8514] = "duomilliaoctingenseptentrigintillion" +number_names[8517] = "duomilliaoctingenoctotrigintillion" +number_names[8520] = "duomilliaoctingennovemtrigintillion" +number_names[8523] = "duomilliaoctingenquadragintillion" +number_names[8526] = "duomilliaoctingenunquadragintillion" +number_names[8529] = "duomilliaoctingendoquadragintillion" +number_names[8532] = "duomilliaoctingentrequadragintillion" +number_names[8535] = "duomilliaoctingenquattuorquadragintillion" +number_names[8538] = "duomilliaoctingenquinquadragintillion" +number_names[8541] = "duomilliaoctingensexquadragintillion" +number_names[8544] = "duomilliaoctingenseptenquadragintillion" +number_names[8547] = "duomilliaoctingenoctoquadragintillion" +number_names[8550] = "duomilliaoctingennovemquadragintillion" +number_names[8553] = "duomilliaoctingenquinquagintillion" +number_names[8556] = "duomilliaoctingenunquinquagintillion" +number_names[8559] = "duomilliaoctingendoquinquagintillion" +number_names[8562] = "duomilliaoctingentrequinquagintillion" +number_names[8565] = "duomilliaoctingenquattuorquinquagintillion" +number_names[8568] = "duomilliaoctingenquinquinquagintillion" +number_names[8571] = "duomilliaoctingensexquinquagintillion" +number_names[8574] = "duomilliaoctingenseptenquinquagintillion" +number_names[8577] = "duomilliaoctingenoctoquinquagintillion" +number_names[8580] = "duomilliaoctingennovemquinquagintillion" +number_names[8583] = "duomilliaoctingensexagintillion" +number_names[8586] = "duomilliaoctingenunsexagintillion" +number_names[8589] = "duomilliaoctingendosexagintillion" +number_names[8592] = "duomilliaoctingentresexagintillion" +number_names[8595] = "duomilliaoctingenquattuorsexagintillion" +number_names[8598] = "duomilliaoctingenquinsexagintillion" +number_names[8601] = "duomilliaoctingensexsexagintillion" +number_names[8604] = "duomilliaoctingenseptensexagintillion" +number_names[8607] = "duomilliaoctingenoctosexagintillion" +number_names[8610] = "duomilliaoctingennovemsexagintillion" +number_names[8613] = "duomilliaoctingenseptuagintillion" +number_names[8616] = "duomilliaoctingenunseptuagintillion" +number_names[8619] = "duomilliaoctingendoseptuagintillion" +number_names[8622] = "duomilliaoctingentreseptuagintillion" +number_names[8625] = "duomilliaoctingenquattuorseptuagintillion" +number_names[8628] = "duomilliaoctingenquinseptuagintillion" +number_names[8631] = "duomilliaoctingensexseptuagintillion" +number_names[8634] = "duomilliaoctingenseptenseptuagintillion" +number_names[8637] = "duomilliaoctingenoctoseptuagintillion" +number_names[8640] = "duomilliaoctingennovemseptuagintillion" +number_names[8643] = "duomilliaoctingenoctogintillion" +number_names[8646] = "duomilliaoctingenunoctogintillion" +number_names[8649] = "duomilliaoctingendooctogintillion" +number_names[8652] = "duomilliaoctingentreoctogintillion" +number_names[8655] = "duomilliaoctingenquattuoroctogintillion" +number_names[8658] = "duomilliaoctingenquinoctogintillion" +number_names[8661] = "duomilliaoctingensexoctogintillion" +number_names[8664] = "duomilliaoctingenseptenoctogintillion" +number_names[8667] = "duomilliaoctingenoctooctogintillion" +number_names[8670] = "duomilliaoctingennovemoctogintillion" +number_names[8673] = "duomilliaoctingennonagintillion" +number_names[8676] = "duomilliaoctingenunnonagintillion" +number_names[8679] = "duomilliaoctingendononagintillion" +number_names[8682] = "duomilliaoctingentrenonagintillion" +number_names[8685] = "duomilliaoctingenquattuornonagintillion" +number_names[8688] = "duomilliaoctingenquinnonagintillion" +number_names[8691] = "duomilliaoctingensexnonagintillion" +number_names[8694] = "duomilliaoctingenseptennonagintillion" +number_names[8697] = "duomilliaoctingenoctononagintillion" +number_names[8700] = "duomilliaoctingennovemnonagintillion" +number_names[8703] = "duomillianongentillion" +number_names[8706] = "duomillianongenuntillion" +number_names[8709] = "duomillianongendotillion" +number_names[8712] = "duomillianongentretillion" +number_names[8715] = "duomillianongenquattuortillion" +number_names[8718] = "duomillianongenquintillion" +number_names[8721] = "duomillianongensextillion" +number_names[8724] = "duomillianongenseptentillion" +number_names[8727] = "duomillianongenoctotillion" +number_names[8730] = "duomillianongennovemtillion" +number_names[8733] = "duomillianongendecillion" +number_names[8736] = "duomillianongenundecillion" +number_names[8739] = "duomillianongendodecillion" +number_names[8742] = "duomillianongentredecillion" +number_names[8745] = "duomillianongenquattuordecillion" +number_names[8748] = "duomillianongenquindecillion" +number_names[8751] = "duomillianongensexdecillion" +number_names[8754] = "duomillianongenseptendecillion" +number_names[8757] = "duomillianongenoctodecillion" +number_names[8760] = "duomillianongennovemdecillion" +number_names[8763] = "duomillianongenvigintillion" +number_names[8766] = "duomillianongenunvigintillion" +number_names[8769] = "duomillianongendovigintillion" +number_names[8772] = "duomillianongentrevigintillion" +number_names[8775] = "duomillianongenquattuorvigintillion" +number_names[8778] = "duomillianongenquinvigintillion" +number_names[8781] = "duomillianongensexvigintillion" +number_names[8784] = "duomillianongenseptenvigintillion" +number_names[8787] = "duomillianongenoctovigintillion" +number_names[8790] = "duomillianongennovemvigintillion" +number_names[8793] = "duomillianongentrigintillion" +number_names[8796] = "duomillianongenuntrigintillion" +number_names[8799] = "duomillianongendotrigintillion" +number_names[8802] = "duomillianongentretrigintillion" +number_names[8805] = "duomillianongenquattuortrigintillion" +number_names[8808] = "duomillianongenquintrigintillion" +number_names[8811] = "duomillianongensextrigintillion" +number_names[8814] = "duomillianongenseptentrigintillion" +number_names[8817] = "duomillianongenoctotrigintillion" +number_names[8820] = "duomillianongennovemtrigintillion" +number_names[8823] = "duomillianongenquadragintillion" +number_names[8826] = "duomillianongenunquadragintillion" +number_names[8829] = "duomillianongendoquadragintillion" +number_names[8832] = "duomillianongentrequadragintillion" +number_names[8835] = "duomillianongenquattuorquadragintillion" +number_names[8838] = "duomillianongenquinquadragintillion" +number_names[8841] = "duomillianongensexquadragintillion" +number_names[8844] = "duomillianongenseptenquadragintillion" +number_names[8847] = "duomillianongenoctoquadragintillion" +number_names[8850] = "duomillianongennovemquadragintillion" +number_names[8853] = "duomillianongenquinquagintillion" +number_names[8856] = "duomillianongenunquinquagintillion" +number_names[8859] = "duomillianongendoquinquagintillion" +number_names[8862] = "duomillianongentrequinquagintillion" +number_names[8865] = "duomillianongenquattuorquinquagintillion" +number_names[8868] = "duomillianongenquinquinquagintillion" +number_names[8871] = "duomillianongensexquinquagintillion" +number_names[8874] = "duomillianongenseptenquinquagintillion" +number_names[8877] = "duomillianongenoctoquinquagintillion" +number_names[8880] = "duomillianongennovemquinquagintillion" +number_names[8883] = "duomillianongensexagintillion" +number_names[8886] = "duomillianongenunsexagintillion" +number_names[8889] = "duomillianongendosexagintillion" +number_names[8892] = "duomillianongentresexagintillion" +number_names[8895] = "duomillianongenquattuorsexagintillion" +number_names[8898] = "duomillianongenquinsexagintillion" +number_names[8901] = "duomillianongensexsexagintillion" +number_names[8904] = "duomillianongenseptensexagintillion" +number_names[8907] = "duomillianongenoctosexagintillion" +number_names[8910] = "duomillianongennovemsexagintillion" +number_names[8913] = "duomillianongenseptuagintillion" +number_names[8916] = "duomillianongenunseptuagintillion" +number_names[8919] = "duomillianongendoseptuagintillion" +number_names[8922] = "duomillianongentreseptuagintillion" +number_names[8925] = "duomillianongenquattuorseptuagintillion" +number_names[8928] = "duomillianongenquinseptuagintillion" +number_names[8931] = "duomillianongensexseptuagintillion" +number_names[8934] = "duomillianongenseptenseptuagintillion" +number_names[8937] = "duomillianongenoctoseptuagintillion" +number_names[8940] = "duomillianongennovemseptuagintillion" +number_names[8943] = "duomillianongenoctogintillion" +number_names[8946] = "duomillianongenunoctogintillion" +number_names[8949] = "duomillianongendooctogintillion" +number_names[8952] = "duomillianongentreoctogintillion" +number_names[8955] = "duomillianongenquattuoroctogintillion" +number_names[8958] = "duomillianongenquinoctogintillion" +number_names[8961] = "duomillianongensexoctogintillion" +number_names[8964] = "duomillianongenseptenoctogintillion" +number_names[8967] = "duomillianongenoctooctogintillion" +number_names[8970] = "duomillianongennovemoctogintillion" +number_names[8973] = "duomillianongennonagintillion" +number_names[8976] = "duomillianongenunnonagintillion" +number_names[8979] = "duomillianongendononagintillion" +number_names[8982] = "duomillianongentrenonagintillion" +number_names[8985] = "duomillianongenquattuornonagintillion" +number_names[8988] = "duomillianongenquinnonagintillion" +number_names[8991] = "duomillianongensexnonagintillion" +number_names[8994] = "duomillianongenseptennonagintillion" +number_names[8997] = "duomillianongenoctononagintillion" +number_names[9000] = "duomillianongennovemnonagintillion" +number_names[9003] = "tremilliatillion" +number_names[9006] = "tremilliauntillion" +number_names[9009] = "tremilliadotillion" +number_names[9012] = "tremilliatretillion" +number_names[9015] = "tremilliaquattuortillion" +number_names[9018] = "tremilliaquintillion" +number_names[9021] = "tremilliasextillion" +number_names[9024] = "tremilliaseptentillion" +number_names[9027] = "tremilliaoctotillion" +number_names[9030] = "tremillianovemtillion" +number_names[9033] = "tremilliadecillion" +number_names[9036] = "tremilliaundecillion" +number_names[9039] = "tremilliadodecillion" +number_names[9042] = "tremilliatredecillion" +number_names[9045] = "tremilliaquattuordecillion" +number_names[9048] = "tremilliaquindecillion" +number_names[9051] = "tremilliasexdecillion" +number_names[9054] = "tremilliaseptendecillion" +number_names[9057] = "tremilliaoctodecillion" +number_names[9060] = "tremillianovemdecillion" +number_names[9063] = "tremilliavigintillion" +number_names[9066] = "tremilliaunvigintillion" +number_names[9069] = "tremilliadovigintillion" +number_names[9072] = "tremilliatrevigintillion" +number_names[9075] = "tremilliaquattuorvigintillion" +number_names[9078] = "tremilliaquinvigintillion" +number_names[9081] = "tremilliasexvigintillion" +number_names[9084] = "tremilliaseptenvigintillion" +number_names[9087] = "tremilliaoctovigintillion" +number_names[9090] = "tremillianovemvigintillion" +number_names[9093] = "tremilliatrigintillion" +number_names[9096] = "tremilliauntrigintillion" +number_names[9099] = "tremilliadotrigintillion" +number_names[9102] = "tremilliatretrigintillion" +number_names[9105] = "tremilliaquattuortrigintillion" +number_names[9108] = "tremilliaquintrigintillion" +number_names[9111] = "tremilliasextrigintillion" +number_names[9114] = "tremilliaseptentrigintillion" +number_names[9117] = "tremilliaoctotrigintillion" +number_names[9120] = "tremillianovemtrigintillion" +number_names[9123] = "tremilliaquadragintillion" +number_names[9126] = "tremilliaunquadragintillion" +number_names[9129] = "tremilliadoquadragintillion" +number_names[9132] = "tremilliatrequadragintillion" +number_names[9135] = "tremilliaquattuorquadragintillion" +number_names[9138] = "tremilliaquinquadragintillion" +number_names[9141] = "tremilliasexquadragintillion" +number_names[9144] = "tremilliaseptenquadragintillion" +number_names[9147] = "tremilliaoctoquadragintillion" +number_names[9150] = "tremillianovemquadragintillion" +number_names[9153] = "tremilliaquinquagintillion" +number_names[9156] = "tremilliaunquinquagintillion" +number_names[9159] = "tremilliadoquinquagintillion" +number_names[9162] = "tremilliatrequinquagintillion" +number_names[9165] = "tremilliaquattuorquinquagintillion" +number_names[9168] = "tremilliaquinquinquagintillion" +number_names[9171] = "tremilliasexquinquagintillion" +number_names[9174] = "tremilliaseptenquinquagintillion" +number_names[9177] = "tremilliaoctoquinquagintillion" +number_names[9180] = "tremillianovemquinquagintillion" +number_names[9183] = "tremilliasexagintillion" +number_names[9186] = "tremilliaunsexagintillion" +number_names[9189] = "tremilliadosexagintillion" +number_names[9192] = "tremilliatresexagintillion" +number_names[9195] = "tremilliaquattuorsexagintillion" +number_names[9198] = "tremilliaquinsexagintillion" +number_names[9201] = "tremilliasexsexagintillion" +number_names[9204] = "tremilliaseptensexagintillion" +number_names[9207] = "tremilliaoctosexagintillion" +number_names[9210] = "tremillianovemsexagintillion" +number_names[9213] = "tremilliaseptuagintillion" +number_names[9216] = "tremilliaunseptuagintillion" +number_names[9219] = "tremilliadoseptuagintillion" +number_names[9222] = "tremilliatreseptuagintillion" +number_names[9225] = "tremilliaquattuorseptuagintillion" +number_names[9228] = "tremilliaquinseptuagintillion" +number_names[9231] = "tremilliasexseptuagintillion" +number_names[9234] = "tremilliaseptenseptuagintillion" +number_names[9237] = "tremilliaoctoseptuagintillion" +number_names[9240] = "tremillianovemseptuagintillion" +number_names[9243] = "tremilliaoctogintillion" +number_names[9246] = "tremilliaunoctogintillion" +number_names[9249] = "tremilliadooctogintillion" +number_names[9252] = "tremilliatreoctogintillion" +number_names[9255] = "tremilliaquattuoroctogintillion" +number_names[9258] = "tremilliaquinoctogintillion" +number_names[9261] = "tremilliasexoctogintillion" +number_names[9264] = "tremilliaseptenoctogintillion" +number_names[9267] = "tremilliaoctooctogintillion" +number_names[9270] = "tremillianovemoctogintillion" +number_names[9273] = "tremillianonagintillion" +number_names[9276] = "tremilliaunnonagintillion" +number_names[9279] = "tremilliadononagintillion" +number_names[9282] = "tremilliatrenonagintillion" +number_names[9285] = "tremilliaquattuornonagintillion" +number_names[9288] = "tremilliaquinnonagintillion" +number_names[9291] = "tremilliasexnonagintillion" +number_names[9294] = "tremilliaseptennonagintillion" +number_names[9297] = "tremilliaoctononagintillion" +number_names[9300] = "tremillianovemnonagintillion" +number_names[9303] = "tremilliacentillion" +number_names[9306] = "tremilliacenuntillion" +number_names[9309] = "tremilliacendotillion" +number_names[9312] = "tremilliacentretillion" +number_names[9315] = "tremilliacenquattuortillion" +number_names[9318] = "tremilliacenquintillion" +number_names[9321] = "tremilliacensextillion" +number_names[9324] = "tremilliacenseptentillion" +number_names[9327] = "tremilliacenoctotillion" +number_names[9330] = "tremilliacennovemtillion" +number_names[9333] = "tremilliacendecillion" +number_names[9336] = "tremilliacenundecillion" +number_names[9339] = "tremilliacendodecillion" +number_names[9342] = "tremilliacentredecillion" +number_names[9345] = "tremilliacenquattuordecillion" +number_names[9348] = "tremilliacenquindecillion" +number_names[9351] = "tremilliacensexdecillion" +number_names[9354] = "tremilliacenseptendecillion" +number_names[9357] = "tremilliacenoctodecillion" +number_names[9360] = "tremilliacennovemdecillion" +number_names[9363] = "tremilliacenvigintillion" +number_names[9366] = "tremilliacenunvigintillion" +number_names[9369] = "tremilliacendovigintillion" +number_names[9372] = "tremilliacentrevigintillion" +number_names[9375] = "tremilliacenquattuorvigintillion" +number_names[9378] = "tremilliacenquinvigintillion" +number_names[9381] = "tremilliacensexvigintillion" +number_names[9384] = "tremilliacenseptenvigintillion" +number_names[9387] = "tremilliacenoctovigintillion" +number_names[9390] = "tremilliacennovemvigintillion" +number_names[9393] = "tremilliacentrigintillion" +number_names[9396] = "tremilliacenuntrigintillion" +number_names[9399] = "tremilliacendotrigintillion" +number_names[9402] = "tremilliacentretrigintillion" +number_names[9405] = "tremilliacenquattuortrigintillion" +number_names[9408] = "tremilliacenquintrigintillion" +number_names[9411] = "tremilliacensextrigintillion" +number_names[9414] = "tremilliacenseptentrigintillion" +number_names[9417] = "tremilliacenoctotrigintillion" +number_names[9420] = "tremilliacennovemtrigintillion" +number_names[9423] = "tremilliacenquadragintillion" +number_names[9426] = "tremilliacenunquadragintillion" +number_names[9429] = "tremilliacendoquadragintillion" +number_names[9432] = "tremilliacentrequadragintillion" +number_names[9435] = "tremilliacenquattuorquadragintillion" +number_names[9438] = "tremilliacenquinquadragintillion" +number_names[9441] = "tremilliacensexquadragintillion" +number_names[9444] = "tremilliacenseptenquadragintillion" +number_names[9447] = "tremilliacenoctoquadragintillion" +number_names[9450] = "tremilliacennovemquadragintillion" +number_names[9453] = "tremilliacenquinquagintillion" +number_names[9456] = "tremilliacenunquinquagintillion" +number_names[9459] = "tremilliacendoquinquagintillion" +number_names[9462] = "tremilliacentrequinquagintillion" +number_names[9465] = "tremilliacenquattuorquinquagintillion" +number_names[9468] = "tremilliacenquinquinquagintillion" +number_names[9471] = "tremilliacensexquinquagintillion" +number_names[9474] = "tremilliacenseptenquinquagintillion" +number_names[9477] = "tremilliacenoctoquinquagintillion" +number_names[9480] = "tremilliacennovemquinquagintillion" +number_names[9483] = "tremilliacensexagintillion" +number_names[9486] = "tremilliacenunsexagintillion" +number_names[9489] = "tremilliacendosexagintillion" +number_names[9492] = "tremilliacentresexagintillion" +number_names[9495] = "tremilliacenquattuorsexagintillion" +number_names[9498] = "tremilliacenquinsexagintillion" +number_names[9501] = "tremilliacensexsexagintillion" +number_names[9504] = "tremilliacenseptensexagintillion" +number_names[9507] = "tremilliacenoctosexagintillion" +number_names[9510] = "tremilliacennovemsexagintillion" +number_names[9513] = "tremilliacenseptuagintillion" +number_names[9516] = "tremilliacenunseptuagintillion" +number_names[9519] = "tremilliacendoseptuagintillion" +number_names[9522] = "tremilliacentreseptuagintillion" +number_names[9525] = "tremilliacenquattuorseptuagintillion" +number_names[9528] = "tremilliacenquinseptuagintillion" +number_names[9531] = "tremilliacensexseptuagintillion" +number_names[9534] = "tremilliacenseptenseptuagintillion" +number_names[9537] = "tremilliacenoctoseptuagintillion" +number_names[9540] = "tremilliacennovemseptuagintillion" +number_names[9543] = "tremilliacenoctogintillion" +number_names[9546] = "tremilliacenunoctogintillion" +number_names[9549] = "tremilliacendooctogintillion" +number_names[9552] = "tremilliacentreoctogintillion" +number_names[9555] = "tremilliacenquattuoroctogintillion" +number_names[9558] = "tremilliacenquinoctogintillion" +number_names[9561] = "tremilliacensexoctogintillion" +number_names[9564] = "tremilliacenseptenoctogintillion" +number_names[9567] = "tremilliacenoctooctogintillion" +number_names[9570] = "tremilliacennovemoctogintillion" +number_names[9573] = "tremilliacennonagintillion" +number_names[9576] = "tremilliacenunnonagintillion" +number_names[9579] = "tremilliacendononagintillion" +number_names[9582] = "tremilliacentrenonagintillion" +number_names[9585] = "tremilliacenquattuornonagintillion" +number_names[9588] = "tremilliacenquinnonagintillion" +number_names[9591] = "tremilliacensexnonagintillion" +number_names[9594] = "tremilliacenseptennonagintillion" +number_names[9597] = "tremilliacenoctononagintillion" +number_names[9600] = "tremilliacennovemnonagintillion" +number_names[9603] = "tremilliaducentillion" +number_names[9606] = "tremilliaducenuntillion" +number_names[9609] = "tremilliaducendotillion" +number_names[9612] = "tremilliaducentretillion" +number_names[9615] = "tremilliaducenquattuortillion" +number_names[9618] = "tremilliaducenquintillion" +number_names[9621] = "tremilliaducensextillion" +number_names[9624] = "tremilliaducenseptentillion" +number_names[9627] = "tremilliaducenoctotillion" +number_names[9630] = "tremilliaducennovemtillion" +number_names[9633] = "tremilliaducendecillion" +number_names[9636] = "tremilliaducenundecillion" +number_names[9639] = "tremilliaducendodecillion" +number_names[9642] = "tremilliaducentredecillion" +number_names[9645] = "tremilliaducenquattuordecillion" +number_names[9648] = "tremilliaducenquindecillion" +number_names[9651] = "tremilliaducensexdecillion" +number_names[9654] = "tremilliaducenseptendecillion" +number_names[9657] = "tremilliaducenoctodecillion" +number_names[9660] = "tremilliaducennovemdecillion" +number_names[9663] = "tremilliaducenvigintillion" +number_names[9666] = "tremilliaducenunvigintillion" +number_names[9669] = "tremilliaducendovigintillion" +number_names[9672] = "tremilliaducentrevigintillion" +number_names[9675] = "tremilliaducenquattuorvigintillion" +number_names[9678] = "tremilliaducenquinvigintillion" +number_names[9681] = "tremilliaducensexvigintillion" +number_names[9684] = "tremilliaducenseptenvigintillion" +number_names[9687] = "tremilliaducenoctovigintillion" +number_names[9690] = "tremilliaducennovemvigintillion" +number_names[9693] = "tremilliaducentrigintillion" +number_names[9696] = "tremilliaducenuntrigintillion" +number_names[9699] = "tremilliaducendotrigintillion" +number_names[9702] = "tremilliaducentretrigintillion" +number_names[9705] = "tremilliaducenquattuortrigintillion" +number_names[9708] = "tremilliaducenquintrigintillion" +number_names[9711] = "tremilliaducensextrigintillion" +number_names[9714] = "tremilliaducenseptentrigintillion" +number_names[9717] = "tremilliaducenoctotrigintillion" +number_names[9720] = "tremilliaducennovemtrigintillion" +number_names[9723] = "tremilliaducenquadragintillion" +number_names[9726] = "tremilliaducenunquadragintillion" +number_names[9729] = "tremilliaducendoquadragintillion" +number_names[9732] = "tremilliaducentrequadragintillion" +number_names[9735] = "tremilliaducenquattuorquadragintillion" +number_names[9738] = "tremilliaducenquinquadragintillion" +number_names[9741] = "tremilliaducensexquadragintillion" +number_names[9744] = "tremilliaducenseptenquadragintillion" +number_names[9747] = "tremilliaducenoctoquadragintillion" +number_names[9750] = "tremilliaducennovemquadragintillion" +number_names[9753] = "tremilliaducenquinquagintillion" +number_names[9756] = "tremilliaducenunquinquagintillion" +number_names[9759] = "tremilliaducendoquinquagintillion" +number_names[9762] = "tremilliaducentrequinquagintillion" +number_names[9765] = "tremilliaducenquattuorquinquagintillion" +number_names[9768] = "tremilliaducenquinquinquagintillion" +number_names[9771] = "tremilliaducensexquinquagintillion" +number_names[9774] = "tremilliaducenseptenquinquagintillion" +number_names[9777] = "tremilliaducenoctoquinquagintillion" +number_names[9780] = "tremilliaducennovemquinquagintillion" +number_names[9783] = "tremilliaducensexagintillion" +number_names[9786] = "tremilliaducenunsexagintillion" +number_names[9789] = "tremilliaducendosexagintillion" +number_names[9792] = "tremilliaducentresexagintillion" +number_names[9795] = "tremilliaducenquattuorsexagintillion" +number_names[9798] = "tremilliaducenquinsexagintillion" +number_names[9801] = "tremilliaducensexsexagintillion" +number_names[9804] = "tremilliaducenseptensexagintillion" +number_names[9807] = "tremilliaducenoctosexagintillion" +number_names[9810] = "tremilliaducennovemsexagintillion" +number_names[9813] = "tremilliaducenseptuagintillion" +number_names[9816] = "tremilliaducenunseptuagintillion" +number_names[9819] = "tremilliaducendoseptuagintillion" +number_names[9822] = "tremilliaducentreseptuagintillion" +number_names[9825] = "tremilliaducenquattuorseptuagintillion" +number_names[9828] = "tremilliaducenquinseptuagintillion" +number_names[9831] = "tremilliaducensexseptuagintillion" +number_names[9834] = "tremilliaducenseptenseptuagintillion" +number_names[9837] = "tremilliaducenoctoseptuagintillion" +number_names[9840] = "tremilliaducennovemseptuagintillion" +number_names[9843] = "tremilliaducenoctogintillion" +number_names[9846] = "tremilliaducenunoctogintillion" +number_names[9849] = "tremilliaducendooctogintillion" +number_names[9852] = "tremilliaducentreoctogintillion" +number_names[9855] = "tremilliaducenquattuoroctogintillion" +number_names[9858] = "tremilliaducenquinoctogintillion" +number_names[9861] = "tremilliaducensexoctogintillion" +number_names[9864] = "tremilliaducenseptenoctogintillion" +number_names[9867] = "tremilliaducenoctooctogintillion" +number_names[9870] = "tremilliaducennovemoctogintillion" +number_names[9873] = "tremilliaducennonagintillion" +number_names[9876] = "tremilliaducenunnonagintillion" +number_names[9879] = "tremilliaducendononagintillion" +number_names[9882] = "tremilliaducentrenonagintillion" +number_names[9885] = "tremilliaducenquattuornonagintillion" +number_names[9888] = "tremilliaducenquinnonagintillion" +number_names[9891] = "tremilliaducensexnonagintillion" +number_names[9894] = "tremilliaducenseptennonagintillion" +number_names[9897] = "tremilliaducenoctononagintillion" +number_names[9900] = "tremilliaducennovemnonagintillion" +number_names[9903] = "tremilliatrecentillion" +number_names[9906] = "tremilliatrecenuntillion" +number_names[9909] = "tremilliatrecendotillion" +number_names[9912] = "tremilliatrecentretillion" +number_names[9915] = "tremilliatrecenquattuortillion" +number_names[9918] = "tremilliatrecenquintillion" +number_names[9921] = "tremilliatrecensextillion" +number_names[9924] = "tremilliatrecenseptentillion" +number_names[9927] = "tremilliatrecenoctotillion" +number_names[9930] = "tremilliatrecennovemtillion" +number_names[9933] = "tremilliatrecendecillion" +number_names[9936] = "tremilliatrecenundecillion" +number_names[9939] = "tremilliatrecendodecillion" +number_names[9942] = "tremilliatrecentredecillion" +number_names[9945] = "tremilliatrecenquattuordecillion" +number_names[9948] = "tremilliatrecenquindecillion" +number_names[9951] = "tremilliatrecensexdecillion" +number_names[9954] = "tremilliatrecenseptendecillion" +number_names[9957] = "tremilliatrecenoctodecillion" +number_names[9960] = "tremilliatrecennovemdecillion" +number_names[9963] = "tremilliatrecenvigintillion" +number_names[9966] = "tremilliatrecenunvigintillion" +number_names[9969] = "tremilliatrecendovigintillion" +number_names[9972] = "tremilliatrecentrevigintillion" +number_names[9975] = "tremilliatrecenquattuorvigintillion" +number_names[9978] = "tremilliatrecenquinvigintillion" +number_names[9981] = "tremilliatrecensexvigintillion" +number_names[9984] = "tremilliatrecenseptenvigintillion" +number_names[9987] = "tremilliatrecenoctovigintillion" +number_names[9990] = "tremilliatrecennovemvigintillion" +number_names[9993] = "tremilliatrecentrigintillion" +number_names[9996] = "tremilliatrecenuntrigintillion" +number_names[9999] = "tremilliatrecendotrigintillion" + +return number_names diff --git a/libs/binser.lua b/libs/binser.lua new file mode 100644 index 0000000..421da6e --- /dev/null +++ b/libs/binser.lua @@ -0,0 +1,689 @@ +-- binser.lua + +--[[ +Copyright (c) 2016 Calvin Rose + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local assert = assert +local error = error +local select = select +local pairs = pairs +local getmetatable = getmetatable +local setmetatable = setmetatable +local tonumber = tonumber +local type = type +local loadstring = loadstring or load +local concat = table.concat +local char = string.char +local byte = string.byte +local format = string.format +local sub = string.sub +local dump = string.dump +local floor = math.floor +local frexp = math.frexp +local unpack = unpack or table.unpack + +-- Lua 5.3 frexp polyfill +-- From https://github.com/excessive/cpml/blob/master/modules/utils.lua +if not frexp then + local log, abs, floor = math.log, math.abs, math.floor + local log2 = log(2) + frexp = function(x) + if x == 0 then return 0, 0 end + local e = floor(log(abs(x)) / log2 + 1) + return x / 2 ^ e, e + end +end + +-- NIL = 202 +-- FLOAT = 203 +-- TRUE = 204 +-- FALSE = 205 +-- STRING = 206 +-- TABLE = 207 +-- REFERENCE = 208 +-- CONSTRUCTOR = 209 +-- FUNCTION = 210 +-- RESOURCE = 211 +-- INT64 = 212 + +local mts = {} +local ids = {} +local serializers = {} +local deserializers = {} +local resources = {} +local resources_by_name = {} + +local function pack(...) + return {...}, select("#", ...) +end + +local function not_array_index(x, len) + return type(x) ~= "number" or x < 1 or x > len or x ~= floor(x) +end + +local function type_check(x, tp, name) + assert(type(x) == tp, + format("Expected parameter %q to be of type %q.", name, tp)) +end + +local bigIntSupport = false +local isInteger +if math.type then -- Detect Lua 5.3 + local mtype = math.type + bigIntSupport = loadstring[[ + local char = string.char + return function(n) + local nn = n < 0 and -(n + 1) or n + local b1 = nn // 0x100000000000000 + local b2 = nn // 0x1000000000000 % 0x100 + local b3 = nn // 0x10000000000 % 0x100 + local b4 = nn // 0x100000000 % 0x100 + local b5 = nn // 0x1000000 % 0x100 + local b6 = nn // 0x10000 % 0x100 + local b7 = nn // 0x100 % 0x100 + local b8 = nn % 0x100 + if n < 0 then + b1, b2, b3, b4 = 0xFF - b1, 0xFF - b2, 0xFF - b3, 0xFF - b4 + b5, b6, b7, b8 = 0xFF - b5, 0xFF - b6, 0xFF - b7, 0xFF - b8 + end + return char(212, b1, b2, b3, b4, b5, b6, b7, b8) + end]]() + isInteger = function(x) + return mtype(x) == 'integer' + end +else + isInteger = function(x) + return floor(x) == x + end +end + +-- Copyright (C) 2012-2015 Francois Perrad. +-- number serialization code modified from https://github.com/fperrad/lua-MessagePack +-- Encode a number as a big-endian ieee-754 double, big-endian signed 64 bit integer, or a small integer +local function number_to_str(n) + if isInteger(n) then -- int + if n <= 100 and n >= -27 then -- 1 byte, 7 bits of data + return char(n + 27) + elseif n <= 8191 and n >= -8192 then -- 2 bytes, 14 bits of data + n = n + 8192 + return char(128 + (floor(n / 0x100) % 0x100), n % 0x100) + elseif bigIntSupport then + return bigIntSupport(n) + end + end + local sign = 0 + if n < 0.0 then + sign = 0x80 + n = -n + end + local m, e = frexp(n) -- mantissa, exponent + if m ~= m then + return char(203, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + elseif m == 1/0 then + if sign == 0 then + return char(203, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + else + return char(203, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + end + end + e = e + 0x3FE + if e < 1 then -- denormalized numbers + m = m * 2 ^ (52 + e) + e = 0 + else + m = (m * 2 - 1) * 2 ^ 52 + end + return char(203, + sign + floor(e / 0x10), + (e % 0x10) * 0x10 + floor(m / 0x1000000000000), + floor(m / 0x10000000000) % 0x100, + floor(m / 0x100000000) % 0x100, + floor(m / 0x1000000) % 0x100, + floor(m / 0x10000) % 0x100, + floor(m / 0x100) % 0x100, + m % 0x100) +end + +-- Copyright (C) 2012-2015 Francois Perrad. +-- number deserialization code also modified from https://github.com/fperrad/lua-MessagePack +local function number_from_str(str, index) + local b = byte(str, index) + if b < 128 then + return b - 27, index + 1 + elseif b < 192 then + return byte(str, index + 1) + 0x100 * (b - 128) - 8192, index + 2 + end + local b1, b2, b3, b4, b5, b6, b7, b8 = byte(str, index + 1, index + 8) + if b == 212 then + local flip = b1 >= 128 + if flip then -- negative + b1, b2, b3, b4 = 0xFF - b1, 0xFF - b2, 0xFF - b3, 0xFF - b4 + b5, b6, b7, b8 = 0xFF - b5, 0xFF - b6, 0xFF - b7, 0xFF - b8 + end + local n = ((((((b1 * 0x100 + b2) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8 + if flip then + return (-n) - 1, index + 9 + else + return n, index + 9 + end + end + local sign = b1 > 0x7F and -1 or 1 + local e = (b1 % 0x80) * 0x10 + floor(b2 / 0x10) + local m = ((((((b2 % 0x10) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8 + local n + if e == 0 then + if m == 0 then + n = sign * 0.0 + else + n = sign * (m / 2 ^ 52) * 2 ^ -1022 + end + elseif e == 0x7FF then + if m == 0 then + n = sign * (1/0) + else + n = 0.0/0.0 + end + else + n = sign * (1.0 + m / 2 ^ 52) * 2 ^ (e - 0x3FF) + end + return n, index + 9 +end + +local types = {} + +types["nil"] = function(x, visited, accum) + accum[#accum + 1] = "\202" +end + +function types.number(x, visited, accum) + accum[#accum + 1] = number_to_str(x) +end + +function types.boolean(x, visited, accum) + accum[#accum + 1] = x and "\204" or "\205" +end + +function types.string(x, visited, accum) + local alen = #accum + if visited[x] then + accum[alen + 1] = "\208" + accum[alen + 2] = number_to_str(visited[x]) + else + visited[x] = visited.next + visited.next = visited.next + 1 + accum[alen + 1] = "\206" + accum[alen + 2] = number_to_str(#x) + accum[alen + 3] = x + end +end + +local function check_custom_type(x, visited, accum) + local res = resources[x] + if res then + accum[#accum + 1] = "\211" + types[type(res)](res, visited, accum) + return true + end + local mt = getmetatable(x) + local id = mt and ids[mt] + if id then + if x == visited.temp then + error("Infinite loop in constructor.") + end + visited.temp = x + accum[#accum + 1] = "\209" + types[type(id)](id, visited, accum) + local args, len = pack(serializers[id](x)) + accum[#accum + 1] = number_to_str(len) + for i = 1, len do + local arg = args[i] + types[type(arg)](arg, visited, accum) + end + visited[x] = visited.next + visited.next = visited.next + 1 + return true + end +end + +function types.userdata(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, accum) then return end + error("Cannot serialize this userdata.") + end +end + +function types.table(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, accum) then return end + visited[x] = visited.next + visited.next = visited.next + 1 + local xlen = #x + accum[#accum + 1] = "\207" + accum[#accum + 1] = number_to_str(xlen) + for i = 1, xlen do + local v = x[i] + types[type(v)](v, visited, accum) + end + local key_count = 0 + for k in pairs(x) do + if not_array_index(k, xlen) then + key_count = key_count + 1 + end + end + accum[#accum + 1] = number_to_str(key_count) + for k, v in pairs(x) do + if not_array_index(k, xlen) then + types[type(k)](k, visited, accum) + types[type(v)](v, visited, accum) + end + end + end +end + +types["function"] = function(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, accum) then return end + visited[x] = visited.next + visited.next = visited.next + 1 + local str = dump(x) + accum[#accum + 1] = "\210" + accum[#accum + 1] = number_to_str(#str) + accum[#accum + 1] = str + end +end + +types.cdata = function(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, #accum) then return end + error("Cannot serialize this cdata.") + end +end + +types.thread = function() error("Cannot serialize threads.") end + +local function deserialize_value(str, index, visited) + local t = byte(str, index) + if not t then return end + if t < 128 then + return t - 27, index + 1 + elseif t < 192 then + return byte(str, index + 1) + 0x100 * (t - 128) - 8192, index + 2 + elseif t == 202 then + return nil, index + 1 + elseif t == 203 then + return number_from_str(str, index) + elseif t == 204 then + return true, index + 1 + elseif t == 205 then + return false, index + 1 + elseif t == 206 then + local length, dataindex = deserialize_value(str, index + 1, visited) + local nextindex = dataindex + length + local substr = sub(str, dataindex, nextindex - 1) + visited[#visited + 1] = substr + return substr, nextindex + elseif t == 207 then + local count, nextindex = number_from_str(str, index + 1) + local ret = {} + visited[#visited + 1] = ret + for i = 1, count do + ret[i], nextindex = deserialize_value(str, nextindex, visited) + end + count, nextindex = number_from_str(str, nextindex) + for i = 1, count do + local k, v + k, nextindex = deserialize_value(str, nextindex, visited) + v, nextindex = deserialize_value(str, nextindex, visited) + ret[k] = v + end + return ret, nextindex + elseif t == 208 then + local ref, nextindex = number_from_str(str, index + 1) + return visited[ref], nextindex + elseif t == 209 then + local count + local name, nextindex = deserialize_value(str, index + 1, visited) + count, nextindex = number_from_str(str, nextindex) + local args = {} + for i = 1, count do + args[i], nextindex = deserialize_value(str, nextindex, visited) + end + local ret = deserializers[name](unpack(args)) + visited[#visited + 1] = ret + return ret, nextindex + elseif t == 210 then + local length, dataindex = deserialize_value(str, index + 1, visited) + local nextindex = dataindex + length + local ret = loadstring(sub(str, dataindex, nextindex - 1)) + visited[#visited + 1] = ret + return ret, nextindex + elseif t == 211 then + local res, nextindex = deserialize_value(str, index + 1, visited) + return resources_by_name[res], nextindex + elseif t == 212 then + return number_from_str(str, index) + else + error("Could not deserialize type byte " .. t .. ".") + end +end + +local function serialize(...) + local visited = {next = 1} + local accum = {} + for i = 1, select("#", ...) do + local x = select(i, ...) + types[type(x)](x, visited, accum) + end + return concat(accum) +end + +local function make_file_writer(file) + return setmetatable({}, { + __newindex = function(_, _, v) + file:write(v) + end + }) +end + +local function serialize_to_file(path, mode, ...) + local file, err = io.open(path, mode) + assert(file, err) + local visited = {next = 1} + local accum = make_file_writer(file) + for i = 1, select("#", ...) do + local x = select(i, ...) + types[type(x)](x, visited, accum) + end + -- flush the writer + file:flush() + file:close() +end + +local function writeFile(path, ...) + return serialize_to_file(path, "wb", ...) +end + +local function appendFile(path, ...) + return serialize_to_file(path, "ab", ...) +end + +local function deserialize(str, index) + assert(type(str) == "string", "Expected string to deserialize.") + local vals = {} + index = index or 1 + local visited = {} + local len = 0 + local val + while index do + val, index = deserialize_value(str, index, visited) + if index then + len = len + 1 + vals[len] = val + end + end + return vals, len +end + +local function deserializeN(str, n, index) + assert(type(str) == "string", "Expected string to deserialize.") + n = n or 1 + assert(type(n) == "number", "Expected a number for parameter n.") + assert(n > 0 and floor(n) == n, "N must be a poitive integer.") + local vals = {} + index = index or 1 + local visited = {} + local len = 0 + local val + while index and len < n do + val, index = deserialize_value(str, index, visited) + if index then + len = len + 1 + vals[len] = val + end + end + vals[len + 1] = index + return unpack(vals, 1, n + 1) +end + +local function readFile(path) + local file, err = io.open(path, "rb") + if file == nil then + return nil, 0 + end + local str = file:read("*all") + file:close() + return deserialize(str) +end + +local function default_deserialize(metatable) + return function(...) + local ret = {} + for i = 1, select("#", ...), 2 do + ret[select(i, ...)] = select(i + 1, ...) + end + return setmetatable(ret, metatable) + end +end + +local function default_serialize(x) + assert(type(x) == "table", + "Default serialization for custom types only works for tables.") + local args = {} + local len = 0 + for k, v in pairs(x) do + args[len + 1], args[len + 2] = k, v + len = len + 2 + end + return unpack(args, 1, len) +end + +-- Templating + +local function normalize_template(template) + local ret = {} + for i = 1, #template do + ret[i] = template[i] + end + local non_array_part = {} + -- The non-array part of the template (nested templates) have to be deterministic, so they are sorted. + -- This means that inherently non deterministicly sortable keys (tables, functions) should NOT be used + -- in templates. Looking for way around this. + for k in pairs(template) do + if not_array_index(k, #template) then + non_array_part[#non_array_part + 1] = k + end + end + table.sort(non_array_part) + for i = 1, #non_array_part do + local name = non_array_part[i] + ret[#ret + 1] = {name, normalize_template(template[name])} + end + return ret +end + +local function templatepart_serialize(part, argaccum, x, len) + local extras = {} + local extracount = 0 + for k, v in pairs(x) do + extras[k] = v + extracount = extracount + 1 + end + for i = 1, #part do + extracount = extracount - 1 + if type(part[i]) == "table" then + extras[part[i][1]] = nil + len = templatepart_serialize(part[i][2], argaccum, x[part[i][1]], len) + else + extras[part[i]] = nil + len = len + 1 + argaccum[len] = x[part[i]] + end + end + if extracount > 0 then + argaccum[len + 1] = extras + else + argaccum[len + 1] = nil + end + return len + 1 +end + +local function templatepart_deserialize(ret, part, values, vindex) + for i = 1, #part do + local name = part[i] + if type(name) == "table" then + local newret = {} + ret[name[1]] = newret + vindex = templatepart_deserialize(newret, name[2], values, vindex) + else + ret[name] = values[vindex] + vindex = vindex + 1 + end + end + local extras = values[vindex] + if extras then + for k, v in pairs(extras) do + ret[k] = v + end + end + return vindex + 1 +end + +local function template_serializer_and_deserializer(metatable, template) + return function(x) + argaccum = {} + local len = templatepart_serialize(template, argaccum, x, 0) + return unpack(argaccum, 1, len) + end, function(...) + local ret = {} + local len = select("#", ...) + local args = {...} + templatepart_deserialize(ret, template, args, 1) + return setmetatable(ret, metatable) + end +end + +local function register(metatable, name, serialize, deserialize) + name = name or metatable.name + serialize = serialize or metatable._serialize + deserialize = deserialize or metatable._deserialize + if not serialize then + if metatable._template then + local t = normalize_template(metatable._template) + serialize, deserialize = template_serializer_and_deserializer(metatable, t) + elseif not deserialize then + serialize = default_serialize + deserialize = default_deserialize(metatable) + else + serialize = metatable + end + end + type_check(metatable, "table", "metatable") + type_check(name, "string", "name") + type_check(serialize, "function", "serialize") + type_check(deserialize, "function", "deserialize") + assert(not ids[metatable], "Metatable already registered.") + assert(not mts[name], ("Name %q already registered."):format(name)) + mts[name] = metatable + ids[metatable] = name + serializers[name] = serialize + deserializers[name] = deserialize + return metatable +end + +local function unregister(item) + local name, metatable + if type(item) == "string" then -- assume name + name, metatable = item, mts[item] + else -- assume metatable + name, metatable = ids[item], item + end + type_check(name, "string", "name") + type_check(metatable, "table", "metatable") + mts[name] = nil + ids[metatable] = nil + serializers[name] = nil + deserializers[name] = nil + return metatable +end + +local function registerClass(class, name) + name = name or class.name + if class.__instanceDict then -- middleclass + register(class.__instanceDict, name) + else -- assume 30log or similar library + register(class, name) + end + return class +end + +local function registerResource(resource, name) + type_check(name, "string", "name") + assert(not resources[resource], + "Resource already registered.") + assert(not resources_by_name[name], + format("Resource %q already exists.", name)) + resources_by_name[name] = resource + resources[resource] = name + return resource +end + +local function unregisterResource(name) + type_check(name, "string", "name") + assert(resources_by_name[name], format("Resource %q does not exist.", name)) + local resource = resources_by_name[name] + resources_by_name[name] = nil + resources[resource] = nil + return resource +end + +return { + -- aliases + s = serialize, + d = deserialize, + dn = deserializeN, + r = readFile, + w = writeFile, + a = appendFile, + + serialize = serialize, + deserialize = deserialize, + deserializeN = deserializeN, + readFile = readFile, + writeFile = writeFile, + appendFile = appendFile, + register = register, + unregister = unregister, + registerResource = registerResource, + unregisterResource = unregisterResource, + registerClass = registerClass +} diff --git a/libs/classic.lua b/libs/classic.lua new file mode 100644 index 0000000..cbd6f81 --- /dev/null +++ b/libs/classic.lua @@ -0,0 +1,68 @@ +-- +-- classic +-- +-- Copyright (c) 2014, rxi +-- +-- This module is free software; you can redistribute it and/or modify it under +-- the terms of the MIT license. See LICENSE for details. +-- + + +local Object = {} +Object.__index = Object + + +function Object:new() +end + + +function Object:extend() + local cls = {} + for k, v in pairs(self) do + if k:find("__") == 1 then + cls[k] = v + end + end + cls.__index = cls + cls.super = self + setmetatable(cls, self) + return cls +end + + +function Object:implement(...) + for _, cls in pairs({...}) do + for k, v in pairs(cls) do + if self[k] == nil and type(v) == "function" then + self[k] = v + end + end + end +end + + +function Object:is(T) + local mt = getmetatable(self) + while mt do + if mt == T then + return true + end + mt = getmetatable(mt) + end + return false +end + + +function Object:__tostring() + return "Object" +end + + +function Object:__call(...) + local obj = setmetatable({}, self) + obj:new(...) + return obj +end + + +return Object diff --git a/libs/lualzw.lua b/libs/lualzw.lua new file mode 100644 index 0000000..e8f00d6 --- /dev/null +++ b/libs/lualzw.lua @@ -0,0 +1,165 @@ +--[[ +MIT License + +Copyright (c) 2016 Rochet2 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] + +local char = string.char +local type = type +local select = select +local sub = string.sub +local tconcat = table.concat + +local basedictcompress = {} +local basedictdecompress = {} +for i = 0, 255 do + local ic, iic = char(i), char(i, 0) + basedictcompress[ic] = iic + basedictdecompress[iic] = ic +end + +local function dictAddA(str, dict, a, b) + if a >= 256 then + a, b = 0, b+1 + if b >= 256 then + dict = {} + b = 1 + end + end + dict[str] = char(a,b) + a = a+1 + return dict, a, b +end + +local function compress(input) + if type(input) ~= "string" then + return nil, "string expected, got "..type(input) + end + local len = #input + if len <= 1 then + return "u"..input + end + + local dict = {} + local a, b = 0, 1 + + local result = {"c"} + local resultlen = 1 + local n = 2 + local word = "" + for i = 1, len do + local c = sub(input, i, i) + local wc = word..c + if not (basedictcompress[wc] or dict[wc]) then + local write = basedictcompress[word] or dict[word] + if not write then + return nil, "algorithm error, could not fetch word" + end + result[n] = write + resultlen = resultlen + #write + n = n+1 + if len <= resultlen then + return "u"..input + end + dict, a, b = dictAddA(wc, dict, a, b) + word = c + else + word = wc + end + end + result[n] = basedictcompress[word] or dict[word] + resultlen = resultlen+#result[n] + n = n+1 + if len <= resultlen then + return "u"..input + end + return tconcat(result) +end + +local function dictAddB(str, dict, a, b) + if a >= 256 then + a, b = 0, b+1 + if b >= 256 then + dict = {} + b = 1 + end + end + dict[char(a,b)] = str + a = a+1 + return dict, a, b +end + +local function decompress(input) + if type(input) ~= "string" then + return nil, "string expected, got "..type(input) + end + + if #input < 1 then + return nil, "invalid input - not a compressed string" + end + + local control = sub(input, 1, 1) + if control == "u" then + return sub(input, 2) + elseif control ~= "c" then + return nil, "invalid input - not a compressed string" + end + input = sub(input, 2) + local len = #input + + if len < 2 then + return nil, "invalid input - not a compressed string" + end + + local dict = {} + local a, b = 0, 1 + + local result = {} + local n = 1 + local last = sub(input, 1, 2) + result[n] = basedictdecompress[last] or dict[last] + n = n+1 + for i = 3, len, 2 do + local code = sub(input, i, i+1) + local lastStr = basedictdecompress[last] or dict[last] + if not lastStr then + return nil, "could not find last from dict. Invalid input?" + end + local toAdd = basedictdecompress[code] or dict[code] + if toAdd then + result[n] = toAdd + n = n+1 + dict, a, b = dictAddB(lastStr..sub(toAdd, 1, 1), dict, a, b) + else + local tmp = lastStr..sub(lastStr, 1, 1) + result[n] = tmp + n = n+1 + dict, a, b = dictAddB(tmp, dict, a, b) + end + last = code + end + return tconcat(result) +end + +return { + compress = compress, + decompress = decompress, +} diff --git a/libs/simple-slider.lua b/libs/simple-slider.lua new file mode 100644 index 0000000..d234d99 --- /dev/null +++ b/libs/simple-slider.lua @@ -0,0 +1,138 @@ +--[[ +Copyright (c) 2016 George Prosser + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +]] + +local slider = {} +slider.__index = slider + +function newSlider(x, y, length, value, min, max, setter, style) + local s = {} + s.value = (value - min) / (max - min) + s.min = min + s.max = max + s.setter = setter + s.x = x + s.y = y + s.length = length + + local p = style or {} + s.width = p.width or length * 0.1 + s.orientation = p.orientation or 'horizontal' + s.track = p.track or 'rectangle' + s.knob = p.knob or 'rectangle' + + s.grabbed = false + s.wasDown = true + s.ox = 0 + s.oy = 0 + + return setmetatable(s, slider) +end + +function slider:update(mouseX, mouseY, mouseDown) + local x = mouseX or love.mouse.getX() + local y = mouseY or love.mouse.getY() + local down = love.mouse.isDown(1) + if mouseDown ~= nil then + down = mouseDown + end + + local knobX = self.x + local knobY = self.y + if self.orientation == 'horizontal' then + knobX = self.x - self.length/2 + self.length * self.value + elseif self.orientation == 'vertical' then + knobY = self.y + self.length/2 - self.length * self.value + end + + local ox = x - knobX + local oy = y - knobY + + local dx = ox - self.ox + local dy = oy - self.oy + + if down then + if self.grabbed then + if self.orientation == 'horizontal' then + self.value = self.value + dx / self.length + elseif self.orientation == 'vertical' then + self.value = self.value - dy / self.length + end + elseif (x > knobX - self.width/2 and x < knobX + self.width/2 and y > knobY - self.width/2 and y < knobY + self.width/2) and not self.wasDown then + self.ox = ox + self.oy = oy + self.grabbed = true + end + else + self.grabbed = false + end + + self.value = math.max(0, math.min(1, self.value)) + + if self.setter ~= nil then + self.setter(self.min + self.value * (self.max - self.min)) + end + + self.wasDown = down +end + +function slider:draw() + if self.track == 'rectangle' then + if self.orientation == 'horizontal' then + love.graphics.rectangle('line', self.x - self.length/2 - self.width/2, self.y - self.width/2, self.length + self.width, self.width) + elseif self.orientation == 'vertical' then + love.graphics.rectangle('line', self.x - self.width/2, self.y - self.length/2 - self.width/2, self.width, self.length + self.width) + end + elseif self.track == 'line' then + if self.orientation == 'horizontal' then + love.graphics.line(self.x - self.length/2, self.y, self.x + self.length/2, self.y) + elseif self.orientation == 'vertical' then + love.graphics.line(self.x, self.y - self.length/2, self.x, self.y + self.length/2) + end + elseif self.track == 'roundrect' then + if self.orientation == 'horizontal' then + love.graphics.rectangle('line', self.x - self.length/2 - self.width/2, self.y - self.width/2, self.length + self.width, self.width, self.width/2, self.width) + elseif self.orientation == 'vertical' then + love.graphics.rectangle('line', self.x - self.width/2, self.y - self.length/2 - self.width/2, self.width, self.length + self.width, self.width, self.width/2) + end + end + + local knobX = self.x + local knobY = self.y + if self.orientation == 'horizontal' then + knobX = self.x - self.length/2 + self.length * self.value + elseif self.orientation == 'vertical' then + knobY = self.y + self.length/2 - self.length * self.value + end + + if self.knob == 'rectangle' then + love.graphics.rectangle('fill', knobX - self.width/2, knobY - self.width/2, self.width, self.width) + elseif self.knob == 'circle' then + love.graphics.circle('fill', knobX, knobY, self.width/2) + end +end + +function slider:getValue() + return self.min + self.value * (self.max - self.min) +end \ No newline at end of file diff --git a/load/bigint.lua b/load/bigint.lua new file mode 100644 index 0000000..c7f7207 --- /dev/null +++ b/load/bigint.lua @@ -0,0 +1,2 @@ +bigint = require "libs.bigint.bigint" +number_names = require "libs.bigint.named-powers-of-ten" \ No newline at end of file diff --git a/load/fonts.lua b/load/fonts.lua new file mode 100644 index 0000000..226731e --- /dev/null +++ b/load/fonts.lua @@ -0,0 +1,2 @@ +tromi_font = love.graphics.newFont('res/fonts/monofonto rg.otf', 28) +big_font = love.graphics.newFont('res/fonts/monofonto rg.otf', 56) diff --git a/load/graphics.lua b/load/graphics.lua new file mode 100644 index 0000000..4227eac --- /dev/null +++ b/load/graphics.lua @@ -0,0 +1,48 @@ +backgrounds = { + [0] = love.graphics.newVideo("res/backgrounds/green_waterfall.ogv", {audio=false}), + love.graphics.newVideo("res/backgrounds/water.ogv", {audio=false}), + love.graphics.newVideo("res/backgrounds/green_streams.ogv", {audio=false}), + love.graphics.newVideo("res/backgrounds/streams.ogv", {audio=false}), + love.graphics.newVideo("res/backgrounds/red_forest_waterfall.ogv", {audio=false}), + love.graphics.newVideo("res/backgrounds/flowers_rain.ogv", {audio=false}), + love.graphics.newVideo("res/backgrounds/moonlight_tree.ogv", {audio=false}), + love.graphics.newVideo("res/backgrounds/lisa_frank.ogv", {audio=false}), + love.graphics.newVideo("res/backgrounds/snowy_trees.ogv", {audio=false}), + love.graphics.newVideo("res/backgrounds/snowy_cabin.ogv", {audio=false}), +} + + +blocks = { + ["2tie"] = { + R = love.graphics.newImage("res/img/r.png"), + O = love.graphics.newImage("res/img/o.png"), + Y = love.graphics.newImage("res/img/y.png"), + G = love.graphics.newImage("res/img/g.png"), + C = love.graphics.newImage("res/img/b.png"), + B = love.graphics.newImage("res/img/i.png"), + M = love.graphics.newImage("res/img/v.png"), + F = love.graphics.newImage("res/img/bl.png"), + A = love.graphics.newImage("res/img/bl.png"), + X = love.graphics.newImage("res/img/t.png"), + W = love.graphics.newImage("res/img/w.png"), + R_d = love.graphics.newImage("res/img/r_d.png"), + O_d = love.graphics.newImage("res/img/o_d.png"), + Y_d = love.graphics.newImage("res/img/y_d.png"), + G_d = love.graphics.newImage("res/img/g_d.png"), + C_d = love.graphics.newImage("res/img/b_d.png"), + B_d = love.graphics.newImage("res/img/i_d.png"), + M_d = love.graphics.newImage("res/img/v_d.png"), + } +} + +ColourSchemes = { + Arika = { + I = "R", + L = "O", + J = "B", + S = "M", + Z = "G", + O = "Y", + T = "C", + } +} diff --git a/load/save.lua b/load/save.lua new file mode 100644 index 0000000..50c1bfa --- /dev/null +++ b/load/save.lua @@ -0,0 +1,29 @@ +local binser = require 'libs.binser' +local fs = love.filesystem + +function loadSave() + config = loadFromFile(CONFIG_FILE) +end + +function loadFromFile(filename) + local save_data = fs.read(filename) + if save_data == nil then + return {} -- new object + end + return binser.deserialize(save_data)[1] +end + +function initConfig() + if config.fullscreen == nil then config.fullscreen = false end + if config.music == nil then config.music = true end + if not config.input then + scene = InputConfigScene(true) + else + scene = TitleScene() + end + +end + +function saveConfig() + fs.write(CONFIG_FILE,binser.serialize(config)) +end diff --git a/load/sounds.lua b/load/sounds.lua new file mode 100644 index 0000000..37e4d1b --- /dev/null +++ b/load/sounds.lua @@ -0,0 +1,49 @@ +sounds = { + bottom = love.audio.newSource("res/se/bottom.wav", "static"), + lock = love.audio.newSource("res/se/lock.wav", "static"), + erase = love.audio.newSource("res/se/erase.wav", "static"), + fall = love.audio.newSource("res/se/fall.wav", "static"), + ready = love.audio.newSource("res/se/ready.wav", "static"), + promote = love.audio.newSource("res/se/promote.wav", "static"), + demote = love.audio.newSource("res/se/demote.wav", "static"), + autopromote = love.audio.newSource("res/se/autopromote.wav", "static"), + bgm_firsthalf = love.audio.newSource("res/bgm/firsthalf.flac", "static"), + bgm_secondhalf = love.audio.newSource("res/bgm/secondhalf.flac", "static"), + bgm_title = love.audio.newSource("res/bgm/title.flac", "static") +} + +function playSE(sound, subsound) + if sound ~= nil then + if subsound ~= nil then + sounds[sound][subsound]:setVolume(0.4) + if sounds[sound][subsound]:isPlaying() then + sounds[sound][subsound]:stop() + end + sounds[sound][subsound]:play() + else + sounds[sound]:setVolume(0.4) + if sounds[sound]:isPlaying() then + sounds[sound]:stop() + end + sounds[sound]:play() + end + end +end + +function playSEOnce(sound, subsound) + if sound ~= nil then + if subsound ~= nil then + sounds[sound][subsound]:setVolume(0.4) + if sounds[sound][subsound]:isPlaying() then + return + end + sounds[sound][subsound]:play() + else + sounds[sound]:setVolume(0.4) + if sounds[sound]:isPlaying() then + return + end + sounds[sound]:play() + end + end +end diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..2da1b23 --- /dev/null +++ b/main.lua @@ -0,0 +1,389 @@ +require 'funcs' +-- savedir = love.filesystem.getSaveDirectory() +-- if love.system.getOS() == 'Windows' then +-- local test_for_separator = string.find(savedir, '/') +-- if test_for_separator ~= nil then savedir = table.concat(split_string(savedir, '/'), '\\') end +-- savedir = savedir..'\\saves\\' +-- configfile = savedir..'config.sav' +-- replaydir = savedir..'replays\\' +-- hiscorefile = savedir..'hiscores.sav' +-- else +-- savedir = savedir..'/saves/' +-- configfile = savedir..'config.sav' +-- replaydir = savedir..'replays/' +-- hiscorefile = savedir..'hiscores.sav' +-- end +SAVE_DIR = '/saves/' +CONFIG_FILE = 'config.sav' +REPLAY_DIR = 'replays/' +HIscoreFILE = 'hiscores.sav' + +PENTO_MODE = false + + +function love.load() + math.randomseed(os.time()) + highscores = {} + require "load.graphics" + require "load.fonts" + require "load.sounds" + require "load.save" + require "load.bigint" + loadSave() + require "scene" + + love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true}); + + love.mouse.setVisible(false) + love.keyboard.setKeyRepeat(true) + love.keyboard.setTextInput(true) + + -- used for screenshots + GLOBAL_CANVAS = love.graphics.newCanvas() + + -- init config + initConfig() + + love.window.setFullscreen(config["fullscreen"]) + +end + +function love.draw() + love.graphics.setCanvas(GLOBAL_CANVAS) + love.graphics.clear() + love.graphics.push() + + -- get offset matrix + local width = love.graphics.getWidth() + local height = love.graphics.getHeight() + local scale_factor = math.min(width / 640, height / 480) + love.graphics.translate( + (width - scale_factor * 640) / 2, + (height - scale_factor * 480) / 2 + ) + love.graphics.scale(scale_factor) + + scene:render() + love.graphics.pop() + + drawText("Pressed: "..(lastPressedKey or '[NONE]').." | Released key: "..(lastReleasedKey or '[NONE]'),0,0,1000,"left") + + love.graphics.setCanvas() + love.graphics.setColor(1,1,1,1) + love.graphics.draw(GLOBAL_CANVAS) +end + +function love.keypressed(key, scancode) + local input_pressed=nil + + -- global hotkeys + if scancode == "f4" then + config["fullscreen"] = not config["fullscreen"] + saveConfig() + love.window.setFullscreen(config["fullscreen"]) + elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then + scene = InputConfigScene() + -- function keys are reserved + elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then + return + -- escape is reserved for menu_back + elseif scancode == "escape" then + scene:onInputPress({input="menu_back", type="key", key=key, scancode=scancode}) + -- pass any other key to the scene, with its configured mapping + else + if config.input and config.input.keys then + input_pressed = config.input.keys[scancode] + end + scene:onInputPress({input=input_pressed, type="key", key=key, scancode=scancode}) + end + + lastPressedKey = input_pressed or scancode +end + +function love.keyreleased(key, scancode) + local input_released = nil + + -- escape is reserved for menu_back + if scancode == "escape" then + scene:onInputRelease({input="menu_back", type="key", key=key, scancode=scancode}) + -- function keys are reserved + elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then + return + -- handle all other keys; tab is reserved, but the input config scene keeps it from getting configured as a game input, so pass tab to the scene here + else + if config.input and config.input.keys then + input_released = config.input.keys[scancode] + end + scene:onInputRelease({input=input_released, type="key", key=key, scancode=scancode}) + end + + lastReleasedKey = input_released or scancode +end + +function love.joystickpressed(joystick, button) + local input_pressed = nil + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].buttons + then + input_pressed = config.input.joysticks[joystick:getName()].buttons[button] + end + scene:onInputPress({input=input_pressed, type="joybutton", name=joystick:getName(), button=button}) +end + +function love.joystickreleased(joystick, button) + local input_released = nil + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].buttons + then + input_released = config.input.joysticks[joystick:getName()].buttons[button] + end + scene:onInputRelease({input=input_released, type="joybutton", name=joystick:getName(), button=button}) +end + +function love.joystickaxis(joystick, axis, value) + local input_pressed = nil + local positive_released = nil + local negative_released = nil + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].axes and + config.input.joysticks[joystick:getName()].axes[axis] + then + if math.abs(value) >= 1 then + input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 1 and "positive" or "negative"] + end + positive_released = config.input.joysticks[joystick:getName()].axes[axis].positive + negative_released = config.input.joysticks[joystick:getName()].axes[axis].negative + end + if math.abs(value) >= 1 then + scene:onInputPress({input=input_pressed, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) + else + scene:onInputRelease({input=positive_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) + scene:onInputRelease({input=negative_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) + end +end + +function love.touchPressed() + love.keyboard.setKeyRepeat(true) + love.keyboard.setTextInput(false) + love.keyboard.setTextInput(true) +end + +local last_hat_direction = "" +local directions = { + ["u"] = "up", + ["d"] = "down", + ["l"] = "left", + ["r"] = "right", +} + +function love.joystickhat(joystick, hat, direction) + local input_pressed = nil + local has_hat = false + if + config.input and + config.input.joysticks and + config.input.joysticks[joystick:getName()] and + config.input.joysticks[joystick:getName()].hats and + config.input.joysticks[joystick:getName()].hats[hat] + then + if direction ~= "c" then + input_pressed = config.input.joysticks[joystick:getName()].hats[hat][direction] + end + has_hat = true + end + if input_pressed then + for i = 1, #direction do + local char = direction:sub(i, i) + local _, count = last_hat_direction:gsub(char, char) + if count == 0 then + scene:onInputPress({input=config.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char}) + end + end + for i = 1, #last_hat_direction do + local char = last_hat_direction:sub(i, i) + local _, count = direction:gsub(char, char) + if count == 0 then + scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char}) + end + end + last_hat_direction = direction + elseif has_hat then + for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do + scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][direction], type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) + end + last_hat_direction = "" + elseif direction ~= "c" then + for i = 1, #direction do + local char = direction:sub(i, i) + local _, count = last_hat_direction:gsub(char, char) + if count == 0 then + scene:onInputPress({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char}) + end + end + for i = 1, #last_hat_direction do + local char = last_hat_direction:sub(i, i) + local _, count = direction:gsub(char, char) + if count == 0 then + scene:onInputRelease({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char}) + end + end + last_hat_direction = direction + else + for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do + scene:onInputRelease({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) + end + last_hat_direction = "" + end +end + +function love.focus(f) + return +end + +function love.resize(w, h) + GLOBAL_CANVAS:release() + GLOBAL_CANVAS = love.graphics.newCanvas(w, h) +end + +local TARGET_FPS = 60 + +function love.run() + if love.load then love.load(love.arg.parseGameArguments(arg), arg) end + + if love.timer then love.timer.step() end + + local dt = 0 + + local last_time = love.timer.getTime() + local time_accumulator = 0 + return function() + if love.event then + love.event.pump() + for name, a,b,c,d,e,f in love.event.poll() do + if name == "quit" then + if not love.quit or not love.quit() then + return a or 0 + end + end + love.handlers[name](a,b,c,d,e,f) + end + end + + if scene and scene.update and love.timer then + scene:update() + + local frame_duration = 1.0 / TARGET_FPS + if time_accumulator < frame_duration then + if love.graphics and love.graphics.isActive() and love.draw then + love.graphics.origin() + love.graphics.clear(love.graphics.getBackgroundColor()) + love.draw() + love.graphics.present() + end + local end_time = last_time + frame_duration + local time = love.timer.getTime() + while time < end_time do + love.timer.sleep(0.001) + time = love.timer.getTime() + end + time_accumulator = time_accumulator + time - last_time + end + time_accumulator = time_accumulator - frame_duration + end + last_time = love.timer.getTime() + end +end + +minos = {'R_d', 'O_d', 'Y_d', 'G_d', 'C_d', 'B_d', 'M_d'} +main_bg_grid = {} +for x=1, 40 do + main_bg_grid[x] = {} + for y=1, 30 do + main_bg_grid[x][y] = 0 + end +end +main_bg_cur_pos = {20,6} +main_bg_cur_color = minos[love.math.random(1,7)] +main_bg_cur_mino = 1 +main_bg_draw_frame = 0 +main_bg_last_color = nil + +function mainBackground() + if config["music"] and not sounds["bgm_title"]:isPlaying() then + sounds["bgm_title"]:setVolume(0.3) + sounds["bgm_title"]:play() + end + local y = 40 + if main_bg_draw_frame >= 16 then + while y > 1 do + for x = 1, 40 do + main_bg_grid[x][y] = main_bg_grid[x][y-1] + end + y = y - 1 + end + for x=1, 40 do + main_bg_grid[x][1] = 0 + end + main_bg_draw_frame = 0 + main_bg_cur_pos[2] = main_bg_cur_pos[2] + 1 + end + local directions = { {0,-1},{1,0}, {-1,0}} + local test_dir = directions[love.math.random(1,3)] + main_bg_cur_pos[1] = main_bg_cur_pos[1] + test_dir[1] + main_bg_cur_pos[2] = main_bg_cur_pos[2] + test_dir[2] + if main_bg_cur_pos[1] > 40 then main_bg_cur_pos[1] = 40 end + if main_bg_cur_pos[1] < 1 then main_bg_cur_pos[1] = 1 end + if main_bg_cur_pos[2] > 30 then main_bg_cur_pos[2] = 30 end + if main_bg_cur_pos[2] < 1 then main_bg_cur_pos[2] = 1 end + if main_bg_grid[main_bg_cur_pos[1]][main_bg_cur_pos[2]] == 0 then + main_bg_grid[main_bg_cur_pos[1]][main_bg_cur_pos[2]] = main_bg_cur_color + main_bg_cur_mino = main_bg_cur_mino + 1 + end + for x=1,40 do + for y=1,30 do + if main_bg_grid[x][y] ~= 0 then + love.graphics.setColor(1, 1, 1, 0.4) + if ((x-1)*48)-560 > 0 and ((x-1)*48)-560 < 640 then love.graphics.draw(blocks["2tie"][main_bg_grid[x][y]], ((x-1)*48)-570, (((y+2)*48)+main_bg_draw_frame*3)-480,0, 3) end + love.graphics.setColor(1, 1, 1, 1) + end + end + end + for x=1,40 do + for y=1,30 do + if main_bg_grid[x][y] ~= 0 then + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(blocks["2tie"][main_bg_grid[x][y]], (x-1)*16, ((y-1)*16)+main_bg_draw_frame) + end + end + end + for x=1,40 do + for y=1,30 do + if main_bg_grid[x][y] ~= 0 then + love.graphics.setColor(1, 1, 1, 0.6) + if ((x-1)*32)-320 > 0 and ((x-1)*32)-320 < 640 then love.graphics.draw(blocks["2tie"][main_bg_grid[x][y]], ((x-1)*32)-320, (((y+1)*32)+main_bg_draw_frame*2)-320,0, 2) end + love.graphics.setColor(1, 1, 1, 1) + end + end + end + if main_bg_cur_mino == 5 then + --if main_bg_cur_pos[2] < 4 then + -- main_bg_cur_pos[2] = 4 + -- main_bg_cur_pos[1] = love.math.random(4, 36) + --end + main_bg_cur_pos = {love.math.random(16,24),6} + main_bg_last_color = main_bg_cur_color + while main_bg_cur_color == main_bg_last_color do main_bg_cur_color = minos[love.math.random(1,7)] end + main_bg_cur_mino = 1 + end + main_bg_placed = false + main_bg_draw_frame = main_bg_draw_frame + 1 +end diff --git a/res/backgrounds/flowers_rain.ogv b/res/backgrounds/flowers_rain.ogv new file mode 100644 index 0000000..8c632b2 Binary files /dev/null and b/res/backgrounds/flowers_rain.ogv differ diff --git a/res/backgrounds/green_streams.ogv b/res/backgrounds/green_streams.ogv new file mode 100644 index 0000000..2460075 Binary files /dev/null and b/res/backgrounds/green_streams.ogv differ diff --git a/res/backgrounds/green_waterfall.ogv b/res/backgrounds/green_waterfall.ogv new file mode 100644 index 0000000..a38d5b1 Binary files /dev/null and b/res/backgrounds/green_waterfall.ogv differ diff --git a/res/backgrounds/lisa_frank.ogv b/res/backgrounds/lisa_frank.ogv new file mode 100644 index 0000000..1d588fa Binary files /dev/null and b/res/backgrounds/lisa_frank.ogv differ diff --git a/res/backgrounds/moonlight_tree.ogv b/res/backgrounds/moonlight_tree.ogv new file mode 100644 index 0000000..be4dbd5 Binary files /dev/null and b/res/backgrounds/moonlight_tree.ogv differ diff --git a/res/backgrounds/red_forest_waterfall.ogv b/res/backgrounds/red_forest_waterfall.ogv new file mode 100644 index 0000000..6e3669f Binary files /dev/null and b/res/backgrounds/red_forest_waterfall.ogv differ diff --git a/res/backgrounds/snowy_cabin.ogv b/res/backgrounds/snowy_cabin.ogv new file mode 100644 index 0000000..eedc6b0 Binary files /dev/null and b/res/backgrounds/snowy_cabin.ogv differ diff --git a/res/backgrounds/snowy_trees.ogv b/res/backgrounds/snowy_trees.ogv new file mode 100644 index 0000000..846e641 Binary files /dev/null and b/res/backgrounds/snowy_trees.ogv differ diff --git a/res/backgrounds/streams.ogv b/res/backgrounds/streams.ogv new file mode 100644 index 0000000..df31634 Binary files /dev/null and b/res/backgrounds/streams.ogv differ diff --git a/res/backgrounds/water.ogv b/res/backgrounds/water.ogv new file mode 100644 index 0000000..4d1ebbe Binary files /dev/null and b/res/backgrounds/water.ogv differ diff --git a/res/bgm/firsthalf.flac b/res/bgm/firsthalf.flac new file mode 100644 index 0000000..742e36f Binary files /dev/null and b/res/bgm/firsthalf.flac differ diff --git a/res/bgm/secondhalf.flac b/res/bgm/secondhalf.flac new file mode 100644 index 0000000..37ae4c3 Binary files /dev/null and b/res/bgm/secondhalf.flac differ diff --git a/res/bgm/title.flac b/res/bgm/title.flac new file mode 100644 index 0000000..f5fd02a Binary files /dev/null and b/res/bgm/title.flac differ diff --git a/res/fonts/monofonto rg.otf b/res/fonts/monofonto rg.otf new file mode 100644 index 0000000..bca1ad6 Binary files /dev/null and b/res/fonts/monofonto rg.otf differ diff --git a/res/img/b.png b/res/img/b.png new file mode 100644 index 0000000..84b9efa Binary files /dev/null and b/res/img/b.png differ diff --git a/res/img/b_d.png b/res/img/b_d.png new file mode 100644 index 0000000..7230e74 Binary files /dev/null and b/res/img/b_d.png differ diff --git a/res/img/bl.png b/res/img/bl.png new file mode 100644 index 0000000..be7f0cc Binary files /dev/null and b/res/img/bl.png differ diff --git a/res/img/g.png b/res/img/g.png new file mode 100644 index 0000000..503245e Binary files /dev/null and b/res/img/g.png differ diff --git a/res/img/g_d.png b/res/img/g_d.png new file mode 100644 index 0000000..b2daad3 Binary files /dev/null and b/res/img/g_d.png differ diff --git a/res/img/i.png b/res/img/i.png new file mode 100644 index 0000000..f2e70bf Binary files /dev/null and b/res/img/i.png differ diff --git a/res/img/i_d.png b/res/img/i_d.png new file mode 100644 index 0000000..03a28f7 Binary files /dev/null and b/res/img/i_d.png differ diff --git a/res/img/o.png b/res/img/o.png new file mode 100644 index 0000000..736fa8a Binary files /dev/null and b/res/img/o.png differ diff --git a/res/img/o_d.png b/res/img/o_d.png new file mode 100644 index 0000000..9e75359 Binary files /dev/null and b/res/img/o_d.png differ diff --git a/res/img/r.png b/res/img/r.png new file mode 100644 index 0000000..ba724dc Binary files /dev/null and b/res/img/r.png differ diff --git a/res/img/r_d.png b/res/img/r_d.png new file mode 100644 index 0000000..ca73a52 Binary files /dev/null and b/res/img/r_d.png differ diff --git a/res/img/t.png b/res/img/t.png new file mode 100644 index 0000000..6d3d184 Binary files /dev/null and b/res/img/t.png differ diff --git a/res/img/v.png b/res/img/v.png new file mode 100644 index 0000000..930b7ac Binary files /dev/null and b/res/img/v.png differ diff --git a/res/img/v_d.png b/res/img/v_d.png new file mode 100644 index 0000000..371fc24 Binary files /dev/null and b/res/img/v_d.png differ diff --git a/res/img/w.png b/res/img/w.png new file mode 100644 index 0000000..b536f5d Binary files /dev/null and b/res/img/w.png differ diff --git a/res/img/y.png b/res/img/y.png new file mode 100644 index 0000000..0a4de8d Binary files /dev/null and b/res/img/y.png differ diff --git a/res/img/y_d.png b/res/img/y_d.png new file mode 100644 index 0000000..66d19af Binary files /dev/null and b/res/img/y_d.png differ diff --git a/res/se/autopromote.wav b/res/se/autopromote.wav new file mode 100644 index 0000000..d017fb9 Binary files /dev/null and b/res/se/autopromote.wav differ diff --git a/res/se/bottom.wav b/res/se/bottom.wav new file mode 100644 index 0000000..688accb Binary files /dev/null and b/res/se/bottom.wav differ diff --git a/res/se/demote.wav b/res/se/demote.wav new file mode 100644 index 0000000..7cdc306 Binary files /dev/null and b/res/se/demote.wav differ diff --git a/res/se/erase.wav b/res/se/erase.wav new file mode 100644 index 0000000..da7f99b Binary files /dev/null and b/res/se/erase.wav differ diff --git a/res/se/fall.wav b/res/se/fall.wav new file mode 100644 index 0000000..2ba1cd4 Binary files /dev/null and b/res/se/fall.wav differ diff --git a/res/se/lock.wav b/res/se/lock.wav new file mode 100644 index 0000000..c34682c Binary files /dev/null and b/res/se/lock.wav differ diff --git a/res/se/promote.wav b/res/se/promote.wav new file mode 100644 index 0000000..8261581 Binary files /dev/null and b/res/se/promote.wav differ diff --git a/res/se/ready.wav b/res/se/ready.wav new file mode 100644 index 0000000..f38758d Binary files /dev/null and b/res/se/ready.wav differ diff --git a/scene.lua b/scene.lua new file mode 100644 index 0000000..b6ae4bb --- /dev/null +++ b/scene.lua @@ -0,0 +1,21 @@ +local Object = require "libs.classic" + +Scene = Object:extend() + +function Scene:new() end +function Scene:update() end +function Scene:render() end +function Scene:onInputPress() end +function Scene:onInputRelease() end + +ExitScene = require "scene.exit" +GameScene = require "scene.game" +NameEntryScene = require "scene.name_entry" +KeyConfigScene = require "scene.key_config" +StickConfigScene = require "scene.stick_config" +InputConfigScene = require "scene.input_config" +ReplaySelectScene = require "scene.replay" +FullscreenScene = require "scene.fullscreen" +MusicToggleScene = require "scene.music_toggle" +TrainingScene = require "scene.training" +TitleScene = require "scene.title" diff --git a/scene/exit.lua b/scene/exit.lua new file mode 100644 index 0000000..bd1fd16 --- /dev/null +++ b/scene/exit.lua @@ -0,0 +1,23 @@ +local ExitScene = Scene:extend() +require 'load.save' + +ExitScene.title = "Exit Game" + +function ExitScene:new() +end + +function ExitScene:update() + love.event.quit() +end + +function ExitScene:render() +end + +function ExitScene:changeOption(rel) +end + +function ExitScene:onInputPress(e) +end + +return ExitScene + diff --git a/scene/fullscreen.lua b/scene/fullscreen.lua new file mode 100644 index 0000000..0dc9b78 --- /dev/null +++ b/scene/fullscreen.lua @@ -0,0 +1,25 @@ +local FullscreenScene = Scene:extend() +require 'load.save' + +FullscreenScene.title = "Fullscreen" + +function FullscreenScene:new() +end + +function FullscreenScene:update() + config["fullscreen"] = not config["fullscreen"] + saveConfig() + love.window.setFullscreen(config["fullscreen"]) + scene = TitleScene() +end + +function FullscreenScene:render() +end + +function FullscreenScene:changeOption(rel) +end + +function FullscreenScene:onInputPress(e) +end + +return FullscreenScene diff --git a/scene/game.lua b/scene/game.lua new file mode 100644 index 0000000..96d2dbf --- /dev/null +++ b/scene/game.lua @@ -0,0 +1,115 @@ +local GameScene = Scene:extend() +local binser = require 'libs.binser' + +GameScene.title = "Game" +local tas = false +require 'load.save' + +function GameScene:new(player_name, replay_file, replay_grade) + game_mode = require 'game.gamemode' + if PENTO_MODE then + ruleset = require 'game.rotation_pent' + else + ruleset = require 'game.rotation' + end + self.retry_mode = game_mode + self.retry_ruleset = ruleset + self.secret_inputs = inputs + self.reset_stuff = {player_name, replay_file, replay_grade} + self.game = game_mode(player_name, replay_file, replay_grade) + self.ruleset = ruleset(self.game) + self.grace_frames = 0 + self.normal_volume = love.audio.getVolume() + self.game:initialize(self.ruleset) + self.inputs = { + left=false, + right=false, + up=false, + down=false, + rotate_left=false, + rotate_left2=false, + rotate_right=false, + rotate_right2=false, + rotate_180=false, + hold=false, + } + self.paused = false +end + +function GameScene:update(nosound, tas_update) + local inputs = {} + if tas then + while self.game.are > 2 do + self.game:update(inputs, self.ruleset) + end + end + for input, value in pairs(self.inputs) do + inputs[input] = value + end + if tas and tas_update then + self.paused = false + self.game:update(inputs, self.ruleset) + self.paused = true + return + end + if nosound then + love.audio.setVolume(0) + end + if not nosound and self.grace_frames > 0 then + self.grace_frames = self.grace_frames - 1 + if self.grace_frames == 1 then love.audio.setVolume(self.normal_volume) end + end + if not self.paused then + self.game:update(inputs, self.ruleset) + end +end + +function GameScene:render() + self.game:draw(self.paused) +end + +function GameScene:onInputPress(e) + if (self.game.game_over or self.game.completed) and (e.input == "menu_decide" or e.input == "menu_back" or e.input == "rotate_right") and self.game.game_over_frames > 50 then + scene = TitleScene() + elseif tas and e.input == "menu_decide" then + self:update(false, true) + elseif self.game.input_playback and (e.input == "menu_back") then + scene = TitleScene() + elseif self.game.input_playback and e.input == "rotate_left" then + self.paused = false + self:update() + self.paused = true + elseif self.game.input_playback and e.input == "rotate_right" then + self.paused = false + elseif self.game.input_playback and not self.paused and e.input == 'left' then + local target = self.game.frames - 300 + if target < 1 then target = 1 end + self.game = game_mode(self.reset_stuff[1], self.reset_stuff[2], self.reset_stuff[3]) + self.ruleset = ruleset(self.game) + self.game:initialize(self.ruleset) + while self.game.frames < (target) do + self:update(true) + end + self.grace_frames = 90 + elseif self.game.input_playback and not self.paused and e.input == 'right' then + local target = self.game.frames + 600 + if target > #self.game.replay_inputs then target = #self.game.replay_inputs-10 end + self.game = game_mode(self.reset_stuff[1], self.reset_stuff[2], self.reset_stuff[3]) + self.ruleset = ruleset(self.game) + self.game:initialize(self.ruleset) + while self.game.frames < (target) do + self:update(true) + end + self.grace_frames = 90 + elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then + self.inputs[e.input] = true + end +end + +function GameScene:onInputRelease(e) + if e.input and string.sub(e.input, 1, 5) ~= "menu_" then + self.inputs[e.input] = false + end +end + +return GameScene diff --git a/scene/input_config.lua b/scene/input_config.lua new file mode 100644 index 0000000..db73477 --- /dev/null +++ b/scene/input_config.lua @@ -0,0 +1,60 @@ +local ConfigScene = Scene:extend() + +ConfigScene.title = "Input Config" + +local minos = {'R_d', 'O_d', 'Y_d', 'G_d', 'C_d', 'B_d', 'M_d'} + +local menu_screens = { + KeyConfigScene, + StickConfigScene +} + +function ConfigScene:new(first_time) + self.menu_state = 1 + if first_time then + self.first_time = true + else + self.first_time = false + end +end + +function ConfigScene:update() end + +function ConfigScene:render() + mainBackground() + if not self.first_time then + drawText("Which controls do you want to configure?", 80, 70, 1000) + else + drawText("Thanks for playing Tromi!", 80, 40, 1000) + drawText("Please begin by configuring your controls:", 80, 70, 1000) + end + + love.graphics.setColor(1, 1, 1, 0.5) + love.graphics.rectangle("fill", 75, 118 + 50 * self.menu_state, 200, 33) + + love.graphics.setColor(1, 1, 1, 1) + for i, screen in pairs(menu_screens) do + drawText(screen.title, 80, 120 + 50 * i, 200, "left") + end +end + +function ConfigScene:changeOption(rel) + local len = table.getn(menu_screens) + self.menu_state = (self.menu_state + len + rel - 1) % len + 1 +end + +function ConfigScene:onInputPress(e) + if e.input == "menu_decide" or e.input == "rotate_left" or e.scancode == "return" then + scene = menu_screens[self.menu_state]() + elseif e.input == "up" or e.scancode == "up" then + self:changeOption(-1) + elseif e.input == "down" or e.scancode == "down" then + self:changeOption(1) + elseif config.input and ( + e.input == "menu_back" or e.input == "rotate_right" or e.scancode == "backspace" or e.scancode == "delete" + ) then + scene = TitleScene() + end +end + +return ConfigScene diff --git a/scene/key_config.lua b/scene/key_config.lua new file mode 100644 index 0000000..74d24cb --- /dev/null +++ b/scene/key_config.lua @@ -0,0 +1,100 @@ +local KeyConfigScene = Scene:extend() + +KeyConfigScene.title = "Key Config" + +require 'load.save' + +local minos = {'R_d', 'O_d', 'Y_d', 'G_d', 'C_d', 'B_d', 'M_d'} + +local configurable_inputs = { + "menu_decide", + "menu_back", + "left", + "right", + "up", + "down", + "rotate_left", + "rotate_left2", + "rotate_right", + "rotate_right2", +} + +local input_names = { + menu_decide='Confirm Selection', + menu_back = 'Go Back', + left='Left', + right='Right', + up='Up', + down='Down', + rotate_left='Rotate Counter-clockwise', + rotate_left2='Rotate Counter-clockwise (2)', + rotate_right='Rotate Clockwise', + rotate_right2='Rotate Clockwise (2)' +} + + +local function newSetInputs() + local set_inputs = {} + for i, input in ipairs(configurable_inputs) do + set_inputs[input] = false + end + return set_inputs +end + +function KeyConfigScene:new() + self.input_state = 1 + self.set_inputs = newSetInputs() + self.new_input = {} +end + +function KeyConfigScene:update() +end + +function KeyConfigScene:render() + mainBackground() + for i, input in ipairs(configurable_inputs) do + drawText(input_names[input], 40, 50 + i * 20, 200, "left") + if self.set_inputs[input] then + drawText(self.set_inputs[input], 240, 50 + i * 20, 300, "left") + end + end + if self.input_state > table.getn(configurable_inputs) then + drawText("Press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""),0,0,1000) + else + drawText("Press key input for " .. input_names[configurable_inputs[self.input_state]] .. ", tab to skip, escape to cancel",0,0,1000) + drawText("Function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20,1000) + end +end + +function KeyConfigScene:onInputPress(e) + if e.type == "key" then + -- function keys, escape, and tab are reserved and can't be remapped + if e.scancode == "escape" then + scene = InputConfigScene() + elseif self.input_state > table.getn(configurable_inputs) then + if e.scancode == "return" then + -- save new input, then load next scene + local had_config = config.input ~= nil + if not config.input then config.input = {} end + config.input.keys = self.new_input + saveConfig() + scene = had_config and InputConfigScene() or TitleScene() + elseif e.scancode == "delete" or e.scancode == "backspace" then + -- retry + self.input_state = 1 + self.set_inputs = newSetInputs() + self.new_input = {} + end + elseif e.scancode == "tab" then + self.set_inputs[configurable_inputs[self.input_state]] = "skipped" + self.input_state = self.input_state + 1 + elseif e.scancode ~= "escape" and not self.new_input[e.scancode] then + -- all other keys can be configured + self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")" + self.new_input[e.scancode] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + end + end +end + +return KeyConfigScene diff --git a/scene/music_toggle.lua b/scene/music_toggle.lua new file mode 100644 index 0000000..33163df --- /dev/null +++ b/scene/music_toggle.lua @@ -0,0 +1,24 @@ +local MusicToggleScene = Scene:extend() +require 'load.save' + +MusicToggleScene.title = "Play music during game:" + +function MusicToggleScene:new() +end + +function MusicToggleScene:update() + config["music"] = not config["music"] + saveConfig() + scene = TitleScene() +end + +function MusicToggleScene:render() +end + +function MusicToggleScene:changeOption(rel) +end + +function MusicToggleScene:onInputPress(e) +end + +return MusicToggleScene diff --git a/scene/name_entry.lua b/scene/name_entry.lua new file mode 100644 index 0000000..187c87a --- /dev/null +++ b/scene/name_entry.lua @@ -0,0 +1,191 @@ +local NameEntryScene = Scene:extend() +local Grid = require 'game.grid' +local binser = require 'libs.binser' +require 'load.save' + +NameEntryScene.title = "Game Start" + + +function NameEntryScene:new() + self.chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890." + self.char_pos = 1 + self.name_entry = {'A','A','A'} + self.entry_pos = 1 + self.entry_chars = self.name_entry[1]..self.name_entry[2]..self.name_entry[3] + self.grid = Grid(10, 20) + self.repeat_limit = 10 + self.repeat_counter = self.repeat_limit-1 + self.direction = nil + self.grade = 0 + self.wins = 0 + self.plays = 0 + self.delete_confirm = false + self.delete_input_count = 0 + self.gradeNames = { + "19k", "18k", "17k", "16k", "15k", "14k", "13k", "12k", "11k", + "10k", "9k", "8k", "7k", "6k", "5k", "4k", "3k", "2k", "1k", + "1D", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D" + } + if config['last_entry'] ~= nil then + self.name_entry = {config['last_entry']:sub(1,1),config['last_entry']:sub(2,2),config['last_entry']:sub(3,3)} + self.entry_pos = 3 + end + score_file = io.open(HIscoreFILE, 'rb') + if score_file ~= nil then + self.hi_scores = binser.deserialize(score_file:read('a'))[1] + else + self.hi_scores = {"TRO",0,"MIT",0,"ROM",0,"ITR",0,"OMI",0} + end +end + +function NameEntryScene:drawGradeList(left, top) + love.graphics.setColor(0,0,0,0.5) + love.graphics.rectangle("fill", left+3, top+3, 200, 240, 10, 10) + love.graphics.setColor(0.05,0.05,0.05,1) + love.graphics.rectangle("fill", left, top, 200, 240, 10, 10) + drawText("Grade list:", left+15, top+10, 1000, "left") + drawText("Beginner\n19 kyu\n18 kyu\n17 kyu\n16 kyu\n15 kyu\n14 kyu\n13 kyu\n12 kyu\n11 kyu\n10 kyu", left+15, top+25, 1000, "left") + drawText("Intermed.\n9 kyu\n8 kyu\n7 kyu\n6 kyu\n5 kyu\n4 kyu\n3 kyu\n2 kyu\n1 kyu", left+80, top+25, 1000, "left") + drawText("Expert\n1 Dan\n2 Dan\n3 Dan\n4 Dan\n5 Dan\n6 Dan\n7 Dan\n8 Dan\n9 Dan", left+145, top+25, 1000, "left") +end + +function NameEntryScene:render() + mainBackground() + love.graphics.setColor(1, 1, 1, 1) + love.graphics.line(216,80,216,80+(16*self.grid.height)) + love.graphics.line(216+(16*self.grid.width),80,216+(16*self.grid.width),80+(16*self.grid.height)) + love.graphics.line(216,80+(16*self.grid.height),216+(16*self.grid.width),80+(16*self.grid.height)) + love.graphics.line(216,80,216+(16*self.grid.width),80) + love.graphics.setColor(0, 0, 0, 1) + love.graphics.rectangle( + "fill", 216, 80, + 16 * self.grid.width, 16 * self.grid.height + ) + love.graphics.setColor(1, 1, 1, 1) + drawText('Enter your initials:', 227, 180, 200, "left") + drawBigText(self.entry_chars, 272, 200, 200, "left") + drawText('o', 262+(self.entry_pos*14), 225, 200, "left") + self:drawGradeList(397, 40) + love.graphics.setColor(0,0,0,0.5) + love.graphics.rectangle("fill", 400, 295, 130, 130, 10, 10) + love.graphics.setColor(0.05,0.05,0.05,1) + love.graphics.rectangle("fill", 397, 292, 130, 130, 10, 10) + drawText("Best scores:", 410, 297, 1000, "left") + i = 2 + while i <= 10 do + drawText(self.hi_scores[i-1]..' - '..self.hi_scores[i], 410, 297+(i*10), 1000, "left") + i = i + 2 + end + if self.entry_pos == 4 then + drawText('Press confirm\nto play', 255, 290, 1000) + end + if self.grade > 0 then + drawText(string.format('Games: %s', self.plays), 255, 250, 1000) + drawText(string.format('Grade: %s', self.gradeNames[self.grade]), 255, 270, 1000) + --if not self.delete_confirm then + -- drawText('Press up\nthree times\nto delete', 255, 330, 1000) + --else + -- drawText('Are you sure?\nPress down\nthree times\nto confirm', 255, 330, 1000) + --end + end +end + +function NameEntryScene:update() + if self.direction == "left" then + if self.repeat_counter >= self.repeat_limit then + self.char_pos = self.char_pos - 1 + if self.char_pos < 1 then self.char_pos = 37 end + self.name_entry[self.entry_pos] = self.chars:sub(self.char_pos, self.char_pos) + self.repeat_counter = 0 + end + self.repeat_counter = self.repeat_counter + 1 + elseif self.direction == "right" then + if self.repeat_counter >= self.repeat_limit then + self.char_pos = self.char_pos + 1 + if self.char_pos > 37 then self.char_pos = 1 end + self.name_entry[self.entry_pos] = self.chars:sub(self.char_pos, self.char_pos) + self.repeat_counter = 0 + end + self.repeat_counter = self.repeat_counter + 1 + end + self.entry_chars = self.name_entry[1]..self.name_entry[2]..self.name_entry[3] +end + +function NameEntryScene:onInputPress(e) + if e.input == "menu_decide" or e.input == "rotate_left" or e.scancode == "return" then + self.delete_confirm = false + self.delete_input_count = 0 + if self.entry_pos == 4 then + config['last_entry'] = name:upper() + saveConfig() + scene = GameScene(name:lower()) + else + if self.entry_pos == 3 then + name = string.lower(self.name_entry[1]..self.name_entry[2]..self.name_entry[3]) + grade_history = io.open(SAVE_DIR..name.."_grade_history.sav", 'rb') + if grade_history ~= nil then + grade_history = binser.deserialize(grade_history:read())[1] + self.grade = grade_history[1] + self.wins = grade_history[2] + self.plays = grade_history[4] + end + end + if self.entry_pos < 3 then + self.name_entry[self.entry_pos] = self.chars:sub(self.char_pos, self.char_pos) + self.name_entry[self.entry_pos+1] = self.chars:sub(self.char_pos, self.char_pos) + end + self.entry_pos = self.entry_pos + 1 + end + elseif e.input == "left" or e.scancode == "left" then + self.delete_confirm = false + self.delete_input_count = 0 + self.direction = "left" + elseif e.input == "right" or e.scancode == "right" then + self.delete_confirm = false + self.delete_input_count = 0 + self.direction = "right" + elseif e.input == "menu_back" or e.input == "rotate_right" or e.scancode == "delete" or e.scancode == "backspace" then + self.delete_confirm = false + self.delete_input_count = 0 + if self.entry_pos == 1 then + scene = TitleScene() + else + self.name_entry[self.entry_pos] = 'A' + self.name_entry[self.entry_pos-1] = 'A' + self.char_pos = 1 + self.entry_pos = self.entry_pos - 1 + self.grade = 0 + end + end + --elseif e.input == "up" or e.scancode == "up" then + -- if self.delete_confirm then + -- self.delete_confirm = false + -- self.delete_input_count = 0 + -- end + -- if self.entry_pos == 4 and self.grade > 0 and not self.delete_confirm then + -- self.delete_input_count = self.delete_input_count + 1 + -- if self.delete_input_count >= 3 then + -- self.delete_input_count = 0 + -- self.delete_confirm = true + -- end + -- end + --elseif e.input == "down" or e.scancode == "down" then + -- if not self.delete_confirm then self.delete_input_count = 0 end + -- if self.entry_pos == 4 and self.delete_confirm then + -- self.delete_input_count = self.delete_input_count + 1 + -- if self.delete_input_count >= 3 then + -- love.filesystem.remove(string.lower(self.name_entry[1]..self.name_entry[2]..self.name_entry[3]).."_grade_history.sav") + -- scene = TitleScene() + -- end + -- end + --end +end + +function NameEntryScene:onInputRelease(e) + if e.input == "left" or e.scancode == "left" or e.input == "right" or e.scancode == "right" then + self.direction = nil + self.repeat_counter = self.repeat_limit-1 + end +end + +return NameEntryScene diff --git a/scene/replay.lua b/scene/replay.lua new file mode 100644 index 0000000..84d2083 --- /dev/null +++ b/scene/replay.lua @@ -0,0 +1,150 @@ +require 'funcs' +local ReplaySelectScene = Scene:extend() + +ReplaySelectScene.title = "Replay" + +local minos = {'R_d', 'O_d', 'Y_d', 'G_d', 'C_d', 'B_d', 'M_d'} + +function ReplaySelectScene:new() + self:initList() + PENTO_MODE = false +end + +function ReplaySelectScene:initList() + self.replays = {} + replay_list = love.filesystem.getDirectoryItems('saves/replays/') + table.sort(replay_list, function(a,b) return a > b end) + self.replay_text = {} + self.page_flip = 16 + self.page = 1 + gradeNames = { + "19k", "18k", "17k", "16k", "15k", "14k", "13k", "12k", "11k", + "10k", "9k", "8k", "7k", "6k", "5k", "4k", "3k", "2k", "1k", + "1D", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D" + } + for i=1, #replay_list do + replay_found = string.find(replay_list[i], "_replay.sav") + if replay_found ~= nil then + table.insert(self.replays, replay_list[i]) + line_components = {} + for str in string.gmatch(replay_list[i], "([^".."_".."]+)") do + table.insert(line_components, str) + end + player_name = line_components[2] + player_grade = gradeNames[tonumber(line_components[3])] + player_score = line_components[4] + if #player_grade == 2 then player_grade = ' '..player_grade end + table.insert(self.replay_text, player_name..' - '..player_grade..' - '..string.format('%6d',player_score)) + end + end + self.dialog = false + self.dialog_select = 1 + self.replay_select = 1 +end + +function ReplaySelectScene:render() + mainBackground() + love.graphics.setColor(0.4, 1, 1, 0.5) + love.graphics.rectangle("fill", 0, 20 + 20 * self.replay_select, 640, 22) + + drawText('Name - Grade - Score', 40, 20, 1000, "left") + drawText(string.format('Page %s', self.page), 20, 440, 1000, "left") + j = 1 + i = 1 + while i <= #self.replay_text do + if j > self.page_flip then j = 1 + elseif j < 1 then j = self.page_flip + end + if i > (self.page-1) * self.page_flip and i <= self.page * self.page_flip then + drawText(self.replay_text[i], 40, 20 + 20 * j, 1000, "left") + end + j = j + 1 + i = i + 1 + end + if self.dialog then + love.graphics.setColor(0, 0, 0, 0.5) + love.graphics.rectangle("fill", 23, 43 + 20 * self.replay_select, 65, 40, 5, 5) + love.graphics.setColor(0.3, 0.8, 0.8, 1) + love.graphics.rectangle("fill", 20, 40 + 20 * self.replay_select, 65, 40, 5, 5) + drawText("Play", 30, 40 + 20 * self.replay_select, 1000, "left") + drawText("Delete", 30, 60 + 20 * self.replay_select, 1000, "left") + drawText("o", 20, 40+((self.dialog_select-1) * 20) + (20 * self.replay_select), 1000, "left") + + end + if self.replays[1] == nil then + drawText('No replays yet!', 40, 40, 1000, "left") + end +end + +function ReplaySelectScene:changeOption(rel) + local len = table.getn(self.replays) + self.replay_select = self.replay_select + rel + if self.replay_select + ((self.page-1) * self.page_flip) > len then + self.page = 1 + self.replay_select = 1 + elseif self.replay_select < 1 and self.page == 1 then + self.page = 1+(math.floor(len / self.page_flip)) + self.replay_select = len - ((self.page-1) * self.page_flip) + end + if self.replay_select > self.page_flip then + self.page = self.page + 1 + self.replay_select = 1 + elseif self.replay_select < 1 then + self.page = self.page - 1 + self.replay_select = self.page_flip + end +end + +function ReplaySelectScene:changeDialog(rel) + self.dialog_select = self.dialog_select + rel + if self.dialog_select > 2 then self.dialog_select = 1 + elseif self.dialog_select < 1 then self.dialog_select = 2 + end +end + +function ReplaySelectScene:onInputPress(e) + selected_replay = self.replays[self.replay_select + ((self.page-1) * self.page_flip)] + selected_replay_text = self.replay_text[self.replay_select + ((self.page-1) * self.page_flip)] + if e.input == "menu_decide" or e.input == "rotate_left" or e.scancode == "return" then + if self.replays[1] == nil then + scene = TitleScene() + --if not self.dialog then + -- self.dialog_select = 1 + -- self.dialog = true + --elseif self.dialog_select == 2 then + -- love.filesystem.remove(selected_replay) + -- self:initList() + --elseif self.dialog_select == 1 then + -- line_components = {} + -- for str in string.gmatch(selected_replay_text, "([^".."-".."]+)") do + -- table.insert(line_components, str) + -- end + -- player_name = line_components[1] + -- player_grade = string.gsub(line_components[2], " ", "") + -- scene = GameScene(player_name, selected_replay, player_grade) + --end + else + line_components = {} + for str in string.gmatch(selected_replay_text, "([^".."-".."]+)") do + table.insert(line_components, str) + end + player_name = line_components[1] + player_grade = string.gsub(line_components[2], " ", "") + scene = GameScene(player_name, selected_replay, player_grade) + end + elseif e.input == "up" or e.scancode == "up" then + if self.replays[1] == nil then scene = TitleScene() end + if not self.dialog then self:changeOption(-1) + else self:changeDialog(-1) end + elseif e.input == "down" or e.scancode == "down" then + if self.replays[1] == nil then scene = TitleScene() end + if not self.dialog then self:changeOption(1) + else self:changeDialog(1) end + elseif e.input == "menu_back" or e.input == "rotate_right" or e.scancode == "backspace" or e.scancode == "delete" then + if self.replays[1] == nil then scene = TitleScene() end + if not self.dialog then scene = TitleScene() + else self.dialog = false end + end +end + +return ReplaySelectScene diff --git a/scene/stick_config.lua b/scene/stick_config.lua new file mode 100644 index 0000000..a548603 --- /dev/null +++ b/scene/stick_config.lua @@ -0,0 +1,158 @@ +local StickConfigScene = Scene:extend() + +StickConfigScene.title = "Controller Config" + +require 'load.save' + +local minos = {'R_d', 'O_d', 'Y_d', 'G_d', 'C_d', 'B_d', 'M_d'} + +local configurable_inputs = { + "menu_decide", + "menu_back", + "left", + "right", + "up", + "down", + "rotate_left", + "rotate_left2", + "rotate_right", + "rotate_right2", +} + +local input_names = { + menu_decide='Confirm Selection', + menu_back = 'Go Back', + left='Left', + right='Right', + up='Up', + down='Down', + rotate_left='Rotate Counter-clockwise', + rotate_left2='Rotate Counter-clockwise (2)', + rotate_right='Rotate Clockwise', + rotate_right2='Rotate Clockwise (2)' +} + +local function newSetInputs() + local set_inputs = {} + for i, input in ipairs(configurable_inputs) do + set_inputs[input] = false + end + return set_inputs +end + +function StickConfigScene:new() + self.input_state = 1 + self.set_inputs = newSetInputs() + self.new_input = {} + self.axis_timer = 0 +end + +function StickConfigScene:update() +end + +function StickConfigScene:render() + mainBackground() + for i, input in ipairs(configurable_inputs) do + drawText(input_names[input], 40, 50 + i * 20, 200, "left") + if self.set_inputs[input] then + drawText(self.set_inputs[input], 240, 50 + i * 20, 300, "left") + end + end + if self.input_state > table.getn(configurable_inputs) then + drawText("Press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""), 0, 0, 1000) + else + drawText("Press joystick input for " .. input_names[configurable_inputs[self.input_state]] .. ", tab to skip, escape to cancel", 0, 0, 1000) + end + + self.axis_timer = self.axis_timer + 1 +end + +local function addJoystick(input, name) + if not input[name] then + input[name] = {} + end +end + +function StickConfigScene:onInputPress(e) + if e.type == "key" then + -- function keys, escape, and tab are reserved and can't be remapped + if e.scancode == "escape" then + scene = InputConfigScene() + elseif self.input_state > table.getn(configurable_inputs) then + if e.scancode == "return" then + -- save new input, then load next scene + local had_config = config.input ~= nil + if not config.input then config.input = {} end + config.input.joysticks = self.new_input + saveConfig() + scene = had_config and InputConfigScene() or TitleScene() + elseif e.scancode == "delete" or e.scancode == "backspace" then + -- retry + self.input_state = 1 + self.set_inputs = newSetInputs() + self.new_input = {} + end + elseif e.scancode == "tab" then + self.set_inputs[configurable_inputs[self.input_state]] = "skipped" + self.input_state = self.input_state + 1 + end + elseif string.sub(e.type, 1, 3) == "joy" then + if self.input_state <= table.getn(configurable_inputs) then + if e.type == "joybutton" then + addJoystick(self.new_input, e.name) + if not self.new_input[e.name].buttons then + self.new_input[e.name].buttons = {} + end + if self.new_input[e.name].buttons[e.button] then return end + self.set_inputs[configurable_inputs[self.input_state]] = + "jbtn " .. + e.button .. + " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") + self.new_input[e.name].buttons[e.button] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + elseif e.type == "joyaxis" then + if (e.axis ~= self.last_axis or self.axis_timer > 30) and math.abs(e.value) >= 1 then + addJoystick(self.new_input, e.name) + if not self.new_input[e.name].axes then + self.new_input[e.name].axes = {} + end + if not self.new_input[e.name].axes[e.axis] then + self.new_input[e.name].axes[e.axis] = {} + end + if ( + self.new_input[e.name].axes[e.axis][e.value >= 1 and "positive" or "negative"] + ) then return end + self.set_inputs[configurable_inputs[self.input_state]] = + "jaxis " .. + (e.value >= 1 and "+" or "-") .. e.axis .. + " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") + self.new_input[e.name].axes[e.axis][e.value >= 1 and "positive" or "negative"] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + self.last_axis = e.axis + self.axis_timer = 0 + end + elseif e.type == "joyhat" then + if e.direction ~= "c" then + addJoystick(self.new_input, e.name) + if not self.new_input[e.name].hats then + self.new_input[e.name].hats = {} + end + if not self.new_input[e.name].hats[e.hat] then + self.new_input[e.name].hats[e.hat] = {} + end + if self.new_input[e.name].hats[e.hat][e.direction] then + return + end + self.set_inputs[configurable_inputs[self.input_state]] = + "jhat " .. + e.hat .. " " .. e.direction .. + " " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") + self.new_input[e.name].hats[e.hat][e.direction] = configurable_inputs[self.input_state] + self.input_state = self.input_state + 1 + end + end + end + end +end + +return StickConfigScene diff --git a/scene/title.lua b/scene/title.lua new file mode 100644 index 0000000..82d5e09 --- /dev/null +++ b/scene/title.lua @@ -0,0 +1,106 @@ +local TitleScene = Scene:extend() +require 'load.save' +require 'funcs' + +TitleScene.title = "Title" +TitleScene.restart_message = false + +local main_menu_screens = { + NameEntryScene, + ReplaySelectScene, + TrainingScene, + InputConfigScene, + FullscreenScene, + MusicToggleScene, + ExitScene, +} + +function TitleScene:new() + if sounds['bgm_firsthalf']:isPlaying() or sounds['bgm_secondhalf']:isPlaying() or not config["music"] then + love.audio.stop() + end + self.main_menu_state = 1 + PENTO_MODE = false + self.code = {0,0,0,0,0,0,0,0} +end + +function TitleScene:update() +end + +function TitleScene:drawCredits(top, left) + love.graphics.setColor(0,0,0,0.7) + love.graphics.rectangle("fill", top, left, 335, 345, 10, 10) + drawText("Design & Programming mycophobia ", 6+top, 6+left, 1000, "left") + drawText("Programming Cambridge contributors", 6+top, 21+left, 1000, "left") + drawText("Music Jerry Martin", 6+top, 36+left, 1000, "left") + drawText(" Juraj Stanik", 6+top, 51+left, 1000, "left") + drawText("RNG Consultant colour_thief", 6+top, 66+left, 1000, "left") + drawText("Mac Launcher nightmareci", 6+top, 81+left, 1000, "left") + drawText("People Who Tested switchpalacecorner", 6+top, 106+left, 1000, "left") + drawText("and/or Offered esquatre", 6+top, 121+left, 1000, "left") + drawText("Cool Suggestions Kirby703", 6+top, 136+left, 1000, "left") + drawText(" netdoll", 6+top, 151+left, 1000, "left") + drawText(" lindtobias", 6+top, 166+left, 1000, "left") + drawText(" zaphod77", 6+top, 181+left, 1000, "left") + drawText(" Arch Nemesis", 6+top, 196+left, 1000, "left") + drawText(" dtet_enjoyer", 6+top, 211+left, 1000, "left") + drawText(" woozy", 6+top, 226+left, 1000, "left") + drawText(" AgentBasey", 6+top, 241+left, 1000, "left") + drawText(" Zircean", 6+top, 256+left, 1000, "left") + drawText(" Eden GT", 6+top, 271+left, 1000, "left") + drawText("Special Thanks theabsolute.plus", 6+top, 291+left, 1000, "left") + drawText(" FYAD/Imp Zone Collective", 6+top, 306+left, 1000, "left") + drawText(" All Version 1 Players", 6+top, 321+left, 1000, "left") +end + +function TitleScene:render() + mainBackground() + love.graphics.setColor(0,0,0,0.7) + love.graphics.rectangle("fill", 14, 174, 260, 200, 10, 10) + love.graphics.setColor(0,0,0,0.7) + love.graphics.rectangle("fill", 14, 400, 605, 75, 10, 10) + love.graphics.setColor(0.4, 1, 1, 0.5) + love.graphics.rectangle("fill", 20, 198 + 20 * self.main_menu_state, 240, 22) + drawBigText('Tromi', 30, 180, 120, "left") + drawText('version 2', 110, 193, 120, "left") + self:drawCredits(300, 40) + drawText("mycophobia.org", 20, 405, 1000) + drawText("Based on Cambridge - t-sp.in/cambridge", 20, 420, 1000) + drawText("Music for Tromi by Jerry Martin, all rights reserved - jerrymartinmusic.com", 20, 435, 1000) + drawText("Game backgrounds by Pixabay users Joe_hackney, yokim, Favorisxp, Any_Ann, VisualSkyFX ", 20, 450, 1000) + if config["music"] == true then + drawText("On", 230, 320, 1000) + else + drawText("Off", 230, 320, 1000) + end + for i, screen in pairs(main_menu_screens) do + drawText(screen.title, 40, 200 + 20 * i, 1200, "left") + end + if table.concat(self.code, ',') == '1,1,1,1,-1,-1,-1,-1' then PENTO_MODE = true end + if PENTO_MODE then + drawBigText('PENT MODE', 30, 100, 120, "left") + end +end + +function TitleScene:changeOption(rel) + local len = table.getn(main_menu_screens) + self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1 +end + +function TitleScene:onInputPress(e) + if e.input == "menu_decide" or e.input == "rotate_left" or e.scancode == "return" then + scene = main_menu_screens[self.main_menu_state]() + elseif e.input == "up" or e.scancode == "up" then + self:changeOption(-1) + elseif e.input == "down" or e.scancode == "down" then + self:changeOption(1) + elseif e.input == "left" or e.scancode == "left" then + table.remove(self.code, 8) + table.insert(self.code, 1, -1) + elseif e.input == "right" or e.scancode == "right" then + table.remove(self.code, 8) + table.insert(self.code, 1, 1) + end +end + +return TitleScene diff --git a/scene/training.lua b/scene/training.lua new file mode 100644 index 0000000..bc7c6f5 --- /dev/null +++ b/scene/training.lua @@ -0,0 +1,64 @@ +local TrainingScene = Scene:extend() + +TrainingScene.title = "Max Gravity Training" + +require 'load.save' + +function TrainingScene:new() + game_mode = require 'game.gamemode' + if PENTO_MODE then + ruleset = require 'game.rotation_pent' + else + ruleset = require 'game.rotation' + end + self.retry_mode = game_mode + self.retry_ruleset = ruleset + self.secret_inputs = inputs + self.game = game_mode() + self.ruleset = ruleset(self.game) + self.game:initialize(self.ruleset) + self.inputs = { + left=false, + right=false, + up=false, + down=false, + rotate_left=false, + rotate_left2=false, + rotate_right=false, + rotate_right2=false, + rotate_180=false, + hold=false, + } + self.paused = false +end + +function TrainingScene:update() + local inputs = {} + for input, value in pairs(self.inputs) do + inputs[input] = value + end + self.game:update(inputs, self.ruleset) + self.game.grid:update() +end + +function TrainingScene:render() + self.game:draw(self.paused) +end + +function TrainingScene:onInputPress(e) + if (self.game.game_over or self.game.completed) and (e.input == "menu_decide" or e.input == "menu_back" or e.input == "rotate_right") and self.game.game_over_frames > 50 then + scene = TitleScene() + elseif (e.input == "menu_back") then + scene = TitleScene() + elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then + self.inputs[e.input] = true + end +end + +function TrainingScene:onInputRelease(e) + if e.input and string.sub(e.input, 1, 5) ~= "menu_" then + self.inputs[e.input] = false + end +end + +return TrainingScene