diff --git a/lib/gui.lua b/lib/gui.lua index 6d7203b..b2cfe98 100644 --- a/lib/gui.lua +++ b/lib/gui.lua @@ -216,6 +216,7 @@ function gui_make_textfield( if self"text".text:len() ~= 0 then self"text".text = self"text".text:sub(1, self"text".text:len() - 1) self"cursor".position2d = self"cursor".position2d - vec2(9 * 2, 0) + self"cursor".hidden = false end elseif k == "tab" then -- @TODO @@ -230,9 +231,13 @@ function gui_make_textfield( for _,c in pairs(chars) do if validate(self"text".text .. c) then - if self"text".text:len() <= max then + local len = self"text".text:len() + if len <= max then self"text".text = self"text".text .. c self"cursor".position2d = self"cursor".position2d + vec2(9 * 2, 0) + if len == max then + self"cursor".hidden = true + end end end end diff --git a/lib/random.lua b/lib/random.lua index 11282a8..18908dc 100644 --- a/lib/random.lua +++ b/lib/random.lua @@ -1,4 +1,6 @@ +RANDOM_CALLS_COUNT = 0 + -- https://stackoverflow.com/a/32387452/12464892 local function bitwise_and(a, b) local result = 0 @@ -26,39 +28,46 @@ local function rand() X2 = V - X1*D20 return V/D40 end -local SEED_BOUNDS = 2^20 - 1 -math.randomseed = function(seed) - RANDOM_CALLS_COUNT = 0 +local SEED_BOUNDS = 2^20 - 1 +local function randomseed2(seed) -- 0 <= X1 <= 2^20-1, 1 <= X2 <= 2^20-1 (must be odd!) - -- ensure the number is odd, and within the bounds of + -- ensure the number is odd, and within bounds of the generator local seed = bitwise_and(seed, 1) local v = math.clamp(math.abs(seed), 0, SEED_BOUNDS) X1 = v X2 = v + 1 end -RANDOM_CALLS_COUNT = 0 + +local RS = math.randomseed +math.randomseed = function(seed) + RANDOM_CALLS_COUNT = 0 + RS(seed) +end local R = math.random local function random(n, m) RANDOM_CALLS_COUNT = RANDOM_CALLS_COUNT + 1 + local r if n then if m then - return (rand() + n) * m + r = R(n, m) else - return rand() * n + r = R(n) end else - return rand() + r = R() end + + return r end -- whenever we refer to math.random, actually use the function 'random' above math.random = random function g_octave_noise(x, y, num_octaves, seed) - local seed = seed or os.clock() + local seed = seed or os.time() local noise = 0 for oct = 1, num_octaves do @@ -71,21 +80,21 @@ function g_octave_noise(x, y, num_octaves, seed) return noise end ----- @TODO test, fix ---function poisson_knuth(lambda) --- local e = 2.71828 --- --- local L = e^-lambda --- local k = 0 --- local p = 1 --- --- while p > L do --- k = k + 1 --- p = p * math.random() --- end --- --- return k - 1 ---end +-- @TODO test, fix +function poisson_knuth(lambda) + local e = 2.71828 + + local L = e^-lambda + local k = 0 + local p = 1 + + while p > L do + k = k + 1 + p = p * math.random() + end + + return k - 1 +end -- seed the random number generator with the current time -- os.clock() is better if the program has been running for a little bit. diff --git a/lib/texture.lua b/lib/texture.lua index 36d528d..0628236 100644 --- a/lib/texture.lua +++ b/lib/texture.lua @@ -30,6 +30,8 @@ TEXTURES = { UNPAUSE_HEX = load_texture("unpausehex.png"), MAIN_MENU_HEX = load_texture("mainmenuhex.png"), + SEED_COLON_TEXT = load_texture("seed_colon_text.png"), + CURTAIN = load_texture("curtain1.png"), SOUND_ON1 = load_texture("sound-on.png"), diff --git a/main.lua b/main.lua index d45bc37..9ae35f6 100644 --- a/main.lua +++ b/main.lua @@ -151,9 +151,9 @@ function main_scene(do_backdrop, do_logo) end local seed_textfield, get_seed_textfield_value = gui_make_textfield{ - position = vec2(win.left + 150, 50), - dimensions = vec2(200, 40), - max = 9, + position = vec2(win.left + 500, 50), + dimensions = vec2(90, 40), + max = math.ceil(math.log(HEX_GRID_WIDTH * HEX_GRID_HEIGHT, 10)), validate = function(string) return not string.match(string, "%D") end, @@ -161,6 +161,9 @@ function main_scene(do_backdrop, do_logo) group:append( seed_textfield ) + group:append( + am.translate(win.left + 220, 50) ^ pack_texture_into_sprite(TEXTURES.SEED_COLON_TEXT) + ) local main_scene_options = { false, @@ -213,7 +216,7 @@ function main_scene(do_backdrop, do_logo) return group end -function make_scene_menu(scene_options, tag) +function make_scene_menu(scene_options, tag, do_curtain) -- calculate the dimensions of the whole grid local spacing = 150 local grid_width = 6 @@ -227,6 +230,11 @@ function make_scene_menu(scene_options, tag) -- generate a map of hexagons (the menu is made up of two rows of hexes) and populate their locations with buttons from the provided options local map = hex_rectangular_map(grid_width, grid_height, HEX_ORIENTATION.POINTY) local group = am.group():tag(tag or "menu") + if do_curtain then + group:append(pack_texture_into_sprite(TEXTURES.CURTAIN, win.width, win.height)) + end + + local menu = am.group() local option_index = 1 for i,_ in pairs(map) do for j,_ in pairs(map[i]) do @@ -250,6 +258,14 @@ function make_scene_menu(scene_options, tag) local hex_ = pixel_to_hex(mouse - pixel_offset, vec2(spacing), HEX_ORIENTATION.POINTY) if tile.option then + if tile.option.keys and tile.option.action then + + for _,key in pairs(win:keys_pressed()) do + if table.find(tile.option.keys, function(_key) return _key == key end) then + tile.option.action() + end + end + end if hex == hex_ then if not selected then play_sfx(SOUNDS.SELECT1) @@ -267,12 +283,13 @@ function make_scene_menu(scene_options, tag) end end) - group:append(node) + menu:append(node) option_index = option_index + 1 end end + group:append(am.translate(pixel_offset) ^ menu) - return am.translate(pixel_offset) ^ group + return group end function switch_context(scene, action) diff --git a/res/img/seed_colon_text.png b/res/img/seed_colon_text.png new file mode 100644 index 0000000..2c48dd5 Binary files /dev/null and b/res/img/seed_colon_text.png differ diff --git a/src/game.lua b/src/game.lua index 9bf38da..5219b03 100644 --- a/src/game.lua +++ b/src/game.lua @@ -42,7 +42,10 @@ local game_scene_menu_options = { action = function() win.scene("context").paused = false win.scene:remove("menu") - end + end, + keys = { + "escape" + } }, { texture = TEXTURES.SETTINGS_HEX, @@ -149,12 +152,11 @@ end local function game_pause() win.scene("context").paused = true - win.scene:append(make_scene_menu(game_scene_menu_options)) + win.scene:append(make_scene_menu(game_scene_menu_options, nil, true)) end local function game_deserialize(json_string) local new_game_state = am.parse_json(json_string) - log(new_game_state.RANDOM_CALLS_COUNT) if new_game_state.version ~= version then gui_alert("loading incompatible old save data.\nstarting a fresh game instead.", nil, 10) @@ -167,10 +169,11 @@ local function game_deserialize(json_string) -- in order to restore the state of the random number generator on game deserialize, we first -- seed it with the same seed used in the original state. then, we discard N calls, where N -- is the number of calls we counted since seeding the generator last time. - for i = 0, new_game_state.RANDOM_CALLS_COUNT do + -- + -- this means it's important that deserializing the rest of the game state doesn't cause any math.random() calls. + for i = 1, new_game_state.RANDOM_CALLS_COUNT do math.random() end - log(RANDOM_CALLS_COUNT) new_game_state.world = make_hex_grid_scene(new_game_state.map, true) new_game_state.seed = nil diff --git a/src/hexyz.lua b/src/hexyz.lua index d5260a3..a121483 100644 --- a/src/hexyz.lua +++ b/src/hexyz.lua @@ -384,7 +384,7 @@ end -- Returns Unordered Hexagonal Map of |radius| with Simplex Noise function hex_hexagonal_map(radius, seed) - local seed = seed or os.time() + local seed = seed or math.floor(math.random() * (2 * math.pi * radius^2)) local size = 0 local map = {} @@ -435,7 +435,7 @@ end -- Returns Unordered Rectangular Map of |width| and |height| with Simplex Noise function hex_rectangular_map(width, height, orientation, seed, do_generate_noise) local orientation = orientation or HEX_DEFAULT_ORIENTATION - local seed = seed or os.time() + local seed = seed or math.floor(math.random() * (width * height)) local map = {} if orientation == HEX_ORIENTATION.FLAT then diff --git a/src/map-editor.lua b/src/map-editor.lua index 4c9a0f4..faad31d 100644 --- a/src/map-editor.lua +++ b/src/map-editor.lua @@ -81,7 +81,7 @@ function map_editor_action() if win:key_pressed"escape" then win.scene("map_editor").paused = true - win.scene:append(make_scene_menu(map_editor_scene_menu_options)) + win.scene:append(make_scene_menu(map_editor_scene_menu_options, nil, true)) end if win:mouse_down"left" then