local Interburbulator = {} --[[ -- have 4 shield projectors. -- have 1 laser turet. -- have n input addon? A group of 3 bots are on a planet. Antikythera / Aigilia / Eunomia Tritan Aurum 1.6180339 Tritan Argent 2.41421356 Tritan Brontion 3.3027756 Plectrum Princeps 2.4450076 Plectrum Aurum 0.6180339 Plectrum Argent 1.41421356 Plectrum Brontion 2.3027756 Brontion Burble 33027756 The bots ask for numbers. The bots move into a triangle and project a hololographic grid. Interburbulator bots move to intersection points. Hovering an Interburbulator makes them say their numbers. -- The grid resolution is controlled by A coordinate interface. -- need an associated ruin. ]] Interburbulator.display_width_tiles = 16 Interburbulator.threshold = 0.000000000000001 Interburbulator.name_interburbulator_gui_root = mod_prefix.."interburbulator-control" Interburbulator.robot_color = {r=1, g=1, b=1, a=0.1} Interburbulator.attempts_locked_timeout = 60*15 -- 15 seconds, claimed to reset after 20s but assume lower UPS Interburbulator.challenges = { { -- 1 grid = 3, target = {2,2}, set = { {1,0,0}, {1,1,0}, {1,0,1}}, prize = {name = "raw-fish", count = 1}, attempts = 7, success_text_prize = {"space-exploration.interburbulator_success_prize_1"} }, { -- 2 grid = 4, target = {2,3}, set = { {1,0,0}, {0,1,0}, {0,0,1}}, prize = {name = mod_prefix.."machine-learning-data", count = 100}, attempts = 6, success_text_prize = {"space-exploration.interburbulator_success_prize_2"} }, { -- 3 grid = 5, target = {3,1}, set = { {1,1,1}, {0,1,0}, {0,0,1}}, prize = {name = mod_prefix.."significant-data", count = 100}, attempts = 6, success_text_prize = {"space-exploration.interburbulator_success_prize_3"} }, { -- 4 grid = 6, target = {4,4}, set = { {-1,0,0}, {0,1,0}, {0,0,1}}, prize = {name = "spidertron", count = 1}, attempts = 5, success_text_prize = {"space-exploration.interburbulator_success_prize_4"} }, { -- 5 grid = 7, target = {2,4}, set = { {1,0,0}, {0,2,0}, {0,0,7}}, attempts = 5, prize = {name = "effectivity-module-9", count = 1}, success_text_prize = {"space-exploration.interburbulator_success_prize_5"} }, { -- 6 grid = 8, target = {7,7}, set = { {1,6,1}, {8,0,3}, {3,9,8}}, prize = {name = "speed-module-9", count = 1}, attempts = 4, success_text_prize = {"space-exploration.interburbulator_success_prize_6"} }, { -- 7 grid = 10, target = {3,6}, set = { {0.1,0.6,0.1}, {0.8,-0.1,0.3}, {0.3,0.9,0.8}}, prize = {name = "productivity-module-9", count = 1}, attempts = 4, success_text_prize = {"space-exploration.interburbulator_success_prize_7"} }, { -- 8 grid = 15, target = {13,15}, set = { {0.87,0.49,0.89}, {0.48,0.48,0.2}, {0.45,0.86,0.83}}, prize = {name = mod_prefix.."wide-beacon-2", count = 4}, attempts = 3, success_text_prize = {"space-exploration.interburbulator_success_prize_8"} }, { -- 9 grid = 20, target = {17,2}, set = { {-436,563,-811}, {772,30,917}, {980,576,286}}, prize = {name = mod_prefix.."naquium-processor", count = 8}, attempts = 3, success_text_prize = {"space-exploration.interburbulator_success_prize_9"} }, { -- 10 grid = 50, target = {33,44}, set = { {1.618033,0.9887498,0.48204586}, {2.414213,0.5623730,0.9504880}, {3.302775,0.6377319,0.9464655}}, prize = {name = mod_prefix.."arcosphere", count = 10}, attempts = 2, success_text_prize = {"space-exploration.interburbulator_success_prize_10"} }, } Interburbulator.success_freeplay = {} for i = 1, 5 do table.insert(Interburbulator.success_freeplay, "interburbulator_success_freeplay_"..i) end Interburbulator.success_repeat = {} for i = 1, 6 do table.insert(Interburbulator.success_repeat, "interburbulator_success_repeat_"..i) end Interburbulator.fail_text = {} Interburbulator.fail_bad_text = {} for i = 1, 39 do table.insert(Interburbulator.fail_text, "interburbulator_fail_easy_"..i) end for i = 1, 10 do table.insert(Interburbulator.fail_bad_text, "interburbulator_fail_offgrid_"..i) end for i = 1, 9 do table.insert(Interburbulator.fail_text, "interburbulator_fail_mixed_"..i) table.insert(Interburbulator.fail_bad_text, "interburbulator_fail_mixed_"..i) end Interburbulator.locked_text = {} for i = 1, 6 do table.insert(Interburbulator.locked_text, "interburbulator_challenge_locked_"..i) end function Interburbulator.message(player, text) player.print({"space-exploration.interburbulator_speak", text}) end function Interburbulator.make_interburbulator(zone, position) if global.interburbulator then return end -- don't make 2 global.interburbulator = { zone = zone, position = position or {x=0, y=0}, challenge_index = 1, challenge_set = nil, -- only used when you set a custom/random challenge. challenge_grid_size = nil, -- only used when you set a custom/random challenge. challenge_cell = nil, -- only used when you set a custom/random challenge. guessed_vector = nil, -- shown after a guess guessed_position = nil, -- shown after a guess guessed_cell = nil, -- shown after a guess guessed_player_index = nil, shape_ids = {}, prizes_won = {}, -- could be indexed by player-challenge but for now just challenge freeplay_unlocked = false } zone.interburbulator = global.interburbulator Interburbulator.build_platform() end function Interburbulator.build_platform() if global.interburbulator.robot and global.interburbulator.robot.valid and global.interburbulator.interface and global.interburbulator.interface.valid then return end local surface = Zone.get_surface(global.interburbulator.zone) if surface then surface.request_to_generate_chunks(global.interburbulator.position) surface.force_generate_chunk_requests() Ruin.build({ruin_name = "interburbulator-platform", surface_index = surface.index, position = global.interburbulator.position}) global.interburbulator.light = rendering.draw_light{ sprite = mod_prefix.."interburbulator-light", surface = surface, target = global.interburbulator.position, intesity = 2, } global.interburbulator.grid = rendering.draw_sprite{ sprite = mod_prefix.."interburbulator-grid", surface = surface, target = global.interburbulator.position, tint = {r=0.5,b=0.5,g=0.5}, draw_on_ground = true, alignment = "center" } global.interburbulator.robot = surface.find_entities_filtered{name=mod_prefix.."burbulator"}[1] global.interburbulator.interface = surface.find_entities_filtered{name=mod_prefix.."interburbulator-control"}[1] global.interburbulator.robot.color = Interburbulator.robot_color global.interburbulator.robot_text = rendering.draw_text{ surface = surface, target = global.interburbulator.robot, text = {"space-exploration.interburbulator_robot_name"}, color = {r=0.6,g=0,b=0}, alignment = "center", target_offset = {0, -3.5} } game.print({"space-exploration.interburbulator_speak", {"space-exploration.interburbulator_greeting", global.interburbulator.zone.name, Zone.get_star_from_child( global.interburbulator.zone).name}}) end end function Interburbulator.on_nth_tick_300() if global.interburbulator and global.interburbulator.robot and global.interburbulator.robot.valid then local orientation = Util.orientation_from_to(global.interburbulator.position, global.interburbulator.robot.position) + 0.25 -- why is this 0.25 off? if orientation > 0.5 then orientation = orientation - 1 end -- -0.5 to 0.5 orientation = orientation * 0.8 - 0.2 + 0.4 * math.random() local pos = Util.orientation_to_vector(orientation, math.random(12,15)) global.interburbulator.robot.autopilot_destination = Util.vectors_add(global.interburbulator.position, pos) if math.random() < 0.1 then global.interburbulator.robot.autopilot_destination = Util.vectors_add(global.interburbulator.position, {x = 0, y = -10}) end global.interburbulator.robot.insert({name="rocket", count = 10}) global.interburbulator.robot.color = Interburbulator.robot_color end end Event.addListener("on_nth_tick_300", Interburbulator.on_nth_tick_300) -- 5s function Interburbulator.clear_display() if global.interburbulator.shape_ids then for _, shape_id in pairs(global.interburbulator.shape_ids) do if rendering.is_valid(shape_id) then rendering.destroy(shape_id) end end end global.interburbulator.shape_ids = {} end function Interburbulator.get_attempts(challenge_index) global.interburbulator.challenge_attempts = global.interburbulator.challenge_attempts or {} global.interburbulator.challenge_attempts[challenge_index] = global.interburbulator.challenge_attempts[challenge_index] or { attempts = 0, tick = game.tick } -- reset if global.interburbulator.challenge_attempts[challenge_index].attempts >= Interburbulator.challenges[challenge_index].attempts and game.tick > global.interburbulator.challenge_attempts[challenge_index].tick + Interburbulator.attempts_locked_timeout then global.interburbulator.challenge_attempts[challenge_index].attempts = 0 global.interburbulator.challenge_attempts[challenge_index].tick = game.tick end return global.interburbulator.challenge_attempts[challenge_index] end function Interburbulator.increase_attempts(challenge_index) Interburbulator.get_attempts(challenge_index) global.interburbulator.challenge_attempts[challenge_index].attempts = global.interburbulator.challenge_attempts[challenge_index].attempts + 1 global.interburbulator.challenge_attempts[challenge_index].tick = game.tick end function Interburbulator.update(player) if not global.interburbulator then return end Interburbulator.clear_display() local surface = Zone.get_surface(global.interburbulator.zone) if not surface then return end local vs_abc = global.interburbulator.challenge_set -- vector set: points a, b, and c. Point d is inferred to complete the square local cells_w = global.interburbulator.challenge_grid_size local target_cell = global.interburbulator.challenge_cell local width if global.interburbulator.challenge_index then vs_abc = Interburbulator.challenges[global.interburbulator.challenge_index].set cells_w = Interburbulator.challenges[global.interburbulator.challenge_index].grid target_cell = Interburbulator.challenges[global.interburbulator.challenge_index].target end if cells_w then Interburbulator.draw_grid(surface, cells_w) width = Interburbulator.display_width_tiles * cells_w/(cells_w+2) if target_cell then local box = { {(target_cell[1]-1)/cells_w, (target_cell[2]-1)/cells_w}, {target_cell[1]/cells_w, target_cell[2]/cells_w} } table.insert(global.interburbulator.shape_ids, rendering.draw_rectangle{ surface = surface, color = {r=0.4,b=0,g=0,a=0.4}, filled = true, left_top = { x = global.interburbulator.position.x -width/2 + box[1][1] * width, y = global.interburbulator.position.y -width/2 + box[1][2] * width }, right_bottom = { x = global.interburbulator.position.x -width/2 + box[2][1] * width, y = global.interburbulator.position.y -width/2 + box[2][2] * width }, draw_on_ground = true, }) end else return end local v_e = global.interburbulator.guessed_vector if v_e and v_e[1] == 0 and v_e[2] == 0 and v_e[3] == 0 then v_e = nil end if not (vs_abc and v_e) then return end local v_a2b = {} -- a to b local v_a2c = {} -- a to c local n_e = Util.nvector_normalise(v_e) -- the normal of point e local v_bc = {} -- the bc midpoint local v_abc = {} -- the abc midpoint for i = 1, #v_e do v_bc[i] = (vs_abc[2][i]+vs_abc[3][i])/2 v_a2b[i] = vs_abc[2][i]-vs_abc[1][i] v_a2c[i] = vs_abc[3][i]-vs_abc[1][i] v_abc[i] = (vs_abc[1][i] + vs_abc[2][i] + vs_abc[3][i]) / 3 end local n_abc = Util.nvector_normalise(v_abc) -- the normal of the abc mid point local n_abc_cross = Util.vector_cross(v_a2b, v_a2c) local n_abc_cross = {n_abc_cross.x, n_abc_cross.y, n_abc_cross.z} -- m_i: the magnitude multiplier for vector e where it would intersect with the abc plane local m_i = Util.nvector_dot(n_abc_cross, Util.nvector_multiply(vs_abc[1], -1)) / Util.nvector_dot(Util.nvector_multiply(v_e, -1), n_abc_cross) local v_i = Util.nvector_multiply(v_e, m_i) -- i, the point on the abc plane where e intersects local v_a2i = {} -- bc_mid to a local v_bc2a = {} -- bc_mid to a local v_bc2b = {} -- bc_mid to b (to c is negative this vector) local v_bc2i = {} -- bc_mid to the i intersection for i = 1, #v_e do v_a2i[i] = v_i[i]-vs_abc[1][i] v_bc2a[i] = vs_abc[1][i]-v_bc[i] v_bc2b[i] = vs_abc[2][i]-v_bc[i] v_bc2i[i] = v_i[i]-v_bc[i] end -- need to de-skew the space local sets = {{1,2},{1,3},{2,3}} local mi_a2b local mi_a2c for _, set in pairs(sets) do local u = set[1] local v = set[2] if mi_a2b == nil or tostring(mi_a2b) == "nan" then mi_a2b = (v_a2i[v]*v_a2c[u]-v_a2i[u]*v_a2c[v])/(v_a2c[u]*v_a2b[v]-v_a2c[v]*v_a2b[u]) end if mi_a2c == nil or tostring(mi_a2c) == "nan" then mi_a2c = (v_a2i[v]*v_a2b[u]-v_a2i[u]*v_a2b[v])/(v_a2b[u]*v_a2c[v]-v_a2b[v]*v_a2c[u]) end end local cursor_point_2d = { mi_a2b, mi_a2c, } -- handle innacuracy if cursor_point_2d[1] < 0 and cursor_point_2d[1] > -Interburbulator.threshold then cursor_point_2d[1] = 0 end if cursor_point_2d[2] < 0 and cursor_point_2d[2] > -Interburbulator.threshold then cursor_point_2d[2] = 0 end local best_box local best_cell for k = 0, cells_w do for j = 0, cells_w do local box if not best_box then box = {{k/cells_w, j/cells_w}, {(k+1)/cells_w, (j+1)/cells_w}} if cursor_point_2d[1] >= box[1][1] and cursor_point_2d[1] <= box[2][1] and cursor_point_2d[2] >= box[1][2] and cursor_point_2d[2] <= box[2][2] then best_box = box best_cell = {k+1, j+1} end end end end local challenge_index = global.interburbulator.challenge_index local attempts = 0 local allow = true if challenge_index then attempts = Interburbulator.get_attempts(challenge_index).attempts if attempts >= Interburbulator.challenges[challenge_index].attempts then allow = false if player then Interburbulator.message(player, {"space-exploration."..Interburbulator.locked_text[math.random(#Interburbulator.locked_text)]}) end end end if allow then if cursor_point_2d and cursor_point_2d[1] > -0.1 and cursor_point_2d[1] < 1.1 and cursor_point_2d[2] > -0.1 and cursor_point_2d[2] < 1.1 then table.insert(global.interburbulator.shape_ids, rendering.draw_circle{ surface = surface, color = {r=1,b=0,g=1}, filled = true, radius = 0.2, target = {x = global.interburbulator.position.x -width/2 + width * cursor_point_2d[1], y = global.interburbulator.position.y -width/2 + width * cursor_point_2d[2]}, draw_on_ground = true, }) end if best_box then table.insert(global.interburbulator.shape_ids, rendering.draw_rectangle{ surface = surface, color = {r=0.4,b=0,g=0.4,a=0.4}, filled = true, left_top = { x = global.interburbulator.position.x -width/2 + best_box[1][1] * width, y = global.interburbulator.position.y -width/2 + best_box[1][2] * width }, right_bottom = { x = global.interburbulator.position.x -width/2 + best_box[2][1] * width, y = global.interburbulator.position.y -width/2 + best_box[2][2] * width }, draw_on_ground = true, }) table.insert(global.interburbulator.shape_ids, rendering.draw_rectangle{ surface = surface, color = {r=1,b=0,g=1,a=0.4}, filled = false, left_top = { x = global.interburbulator.position.x -width/2 + best_box[1][1] * width, y = global.interburbulator.position.y -width/2 + best_box[1][2] * width }, right_bottom = { x = global.interburbulator.position.x -width/2 + best_box[2][1] * width, y = global.interburbulator.position.y -width/2 + best_box[2][2] * width }, draw_on_ground = true, }) end if player and global.interburbulator.challenge_index then if best_cell and target_cell and best_cell[1] == target_cell[1] and best_cell[2] == target_cell[2] then global.interburbulator.prizes_won = global.interburbulator.prizes_won or {} if not global.interburbulator.prizes_won[global.interburbulator.challenge_index] then global.interburbulator.prizes_won[global.interburbulator.challenge_index] = player.index local prize = Interburbulator.challenges[global.interburbulator.challenge_index].prize local inserted = 0 if player.character and player.character.surface == surface then inserted = player.insert(prize) end local remain = (prize.count or 1) - inserted if remain > 0 then surface.spill_item_stack( Util.vectors_add({x=0,y=2.25}, global.interburbulator.interface.position), {name = prize.name, count = remain}, true, player.force, false) end Interburbulator.message(player, { "space-exploration.simple-a-b-space", Interburbulator.challenges[global.interburbulator.challenge_index].success_text_prize or Interburbulator.success_text_prize, {"space-exploration.simple-a-b-space", (prize.count or 1) .." [img=item/"..prize.name.."] ", {"item-name."..prize.name}} }) else Interburbulator.message(player, {"space-exploration."..Interburbulator.success_repeat[math.random(#Interburbulator.success_repeat)]}) end if table_size(global.interburbulator.prizes_won) >= 5 and not global.interburbulator.freeplay_unlocked then global.interburbulator.freeplay_unlocked = true Interburbulator.message(player, {"space-exploration.interburbulator_freeplay_unlocked"}) end else Interburbulator.increase_attempts(global.interburbulator.challenge_index) if best_box then Interburbulator.message(player, {"space-exploration."..Interburbulator.fail_text[math.random(#Interburbulator.fail_text)]}) else Interburbulator.message(player, {"space-exploration."..Interburbulator.fail_bad_text[math.random(#Interburbulator.fail_bad_text)]}) end if player and challenge_index then attempts = Interburbulator.get_attempts(challenge_index).attempts if attempts >= Interburbulator.challenges[challenge_index].attempts then Interburbulator.message(player, {"space-exploration."..Interburbulator.locked_text[math.random(#Interburbulator.locked_text)]}) end end end end end end function Interburbulator.draw_grid(surface, cells_w) local pos = global.interburbulator.position local width = Interburbulator.display_width_tiles * cells_w/(cells_w+2) for i = 1, cells_w+1 do local p = (i-1)/(cells_w) table.insert(global.interburbulator.shape_ids, rendering.draw_line{ surface = surface, from = {x = pos.x - width/2, y = pos.y - width/2 + p * width}, to = {x = pos.x + width/2, y = pos.y - width/2 + p * width}, color = {r=0.5,b=0,g=0,a=0.5}, width = 1, draw_on_ground = true }) table.insert(global.interburbulator.shape_ids, rendering.draw_line{ surface = surface, from = {x = pos.x - width/2 + p * width, y = pos.y - width/2}, to = {x = pos.x - width/2 + p * width, y = pos.y + width/2}, color = {r=0.5,b=0,g=0,a=0.5}, width = 1, draw_on_ground = true }) end end function Interburbulator.gui_close(player) local gui = player.gui.screen local root = gui[Interburbulator.name_interburbulator_gui_root] if root then root.destroy() end end function Interburbulator.gui_update(player) local root = player.gui.screen[Interburbulator.name_interburbulator_gui_root] if not root then return end local vs_abc = global.interburbulator.challenge_set local cells_w = global.interburbulator.challenge_grid_size local target_cell = global.interburbulator.challenge_cell if global.interburbulator.challenge_index then vs_abc = Interburbulator.challenges[global.interburbulator.challenge_index].set cells_w = Interburbulator.challenges[global.interburbulator.challenge_index].grid target_cell = Interburbulator.challenges[global.interburbulator.challenge_index].target end if target_cell then target_cell = target_cell[1]..","..target_cell[2] end local challenge = util.find_first_descendant_by_name(root, "challenges") local active_name --if global.interburbulator.challenge_set then active_name = "challenge_random" end -- need to be able to click multiple times if global.interburbulator.challenge_index then active_name = "challenge_"..global.interburbulator.challenge_index end for _, button in pairs(challenge.children) do button.enabled = true if button.name == active_name then button.enabled = false end end if cells_w then util.find_first_descendant_by_name(root, "grid_textbox").text = ""..cells_w end if target_cell then util.find_first_descendant_by_name(root, "target_textbox").text = ""..target_cell end local prize_lab = util.find_first_descendant_by_name(root, "prize_lab") if prize_lab then if global.interburbulator.challenge_index then local prize = Interburbulator.challenges[global.interburbulator.challenge_index].prize local claimed = global.interburbulator.prizes_won and global.interburbulator.prizes_won[global.interburbulator.challenge_index] local caption = { "space-exploration.interburbulator_caption_prize", (prize.count or 1), "[img=item/"..prize.name.."]", {"item-name."..prize.name}, claimed and {"space-exploration.interburbulator_caption_claimed"} or "" } prize_lab.caption = caption else prize_lab.caption = "" end end if vs_abc then local top_left = util.find_first_descendant_by_name(root, "top_left") top_left.x.textbox.text = ""..vs_abc[1][1] top_left.y.textbox.text = ""..vs_abc[1][2] top_left.z.textbox.text = ""..vs_abc[1][3] local top_right = util.find_first_descendant_by_name(root, "top_right") top_right.x.textbox.text = ""..vs_abc[2][1] top_right.y.textbox.text = ""..vs_abc[2][2] top_right.z.textbox.text = ""..vs_abc[2][3] local bottom_left = util.find_first_descendant_by_name(root, "bottom_left") bottom_left.x.textbox.text = ""..vs_abc[3][1] bottom_left.y.textbox.text = ""..vs_abc[3][2] bottom_left.z.textbox.text = ""..vs_abc[3][3] end if global.interburbulator.challenge_index then local attempts = Interburbulator.get_attempts(global.interburbulator.challenge_index).attempts local attempts_max = Interburbulator.challenges[global.interburbulator.challenge_index].attempts if attempts < attempts_max then util.find_first_descendant_by_name(root, "attempt").caption = {"space-exploration.interburbulator_attempt_limited", attempts, attempts_max } else util.find_first_descendant_by_name(root, "attempt").caption = {"space-exploration.interburbulator_attempt_locked"} end else util.find_first_descendant_by_name(root, "attempt").caption = {"space-exploration.interburbulator_attempt"} end if global.interburbulator.guessed_vector then local attempt = util.find_first_descendant_by_name(root, "attempt") if attempt.x.textbox.text == "" then attempt.x.textbox.text = ""..global.interburbulator.guessed_vector[1] end if attempt.y.textbox.text == "" then attempt.y.textbox.text = ""..global.interburbulator.guessed_vector[2] end if attempt.z.textbox.text == "" then attempt.z.textbox.text = ""..global.interburbulator.guessed_vector[3] end end local challenge_random = util.find_first_descendant_by_name(root, "challenge_random") if challenge_random then challenge_random.caption = {global.interburbulator.freeplay_unlocked and "space-exploration.interburbulator_freeplay" or "space-exploration.interburbulator_random"} end end function Interburbulator.enable_textfields(element, enabled) if element.type == "textfield" then element.enabled = enabled else for _, child in pairs(element.children) do if child.name ~= "attempt" then Interburbulator.enable_textfields(child, enabled) end end end end function Interburbulator.gui_open(player) Interburbulator.gui_close(player) local gui = player.gui.screen local container = gui.add{ type = "frame", name = Interburbulator.name_interburbulator_gui_root, direction="vertical"} player.opened = container local title_flow = container.add{ type="flow", name="unit_number", direction="horizontal"} local title = title_flow.add{ type="label", name="title", caption={"space-exploration.interburbulator_game_title"}, style="heading_1_label"} title.ignored_by_interaction = true if gui_name == "screen" then title_flow.drag_target = container end -- Trying to make the fancy "Drag me" vertical bars... local drag_handle = title_flow.add{type = "empty-widget", style = "draggable_space_header", direction="horizontal"} drag_handle.drag_target = container drag_handle.style.minimal_width = 20 drag_handle.style.horizontally_stretchable = true drag_handle.style.vertically_stretchable = true local close = title_flow.add{type="sprite-button", name=mod_prefix .. "-interburbulator-close", sprite = "utility/close_white", style="informatron_close_button"} close.style.width = 28 close.style.height = 28 close.style.top_margin = 0 local intro = container.add{type="label", name="intro", caption={"space-exploration.interburbulator_introduction"}} intro.style.single_line = false intro.style.width = 500 intro.style.top_margin = 10 intro.style.bottom_margin = 10 local challenges = container.add{type="flow", name="challenges", direction="horizontal"} challenges.style.bottom_margin = 10 for i = 1, 10 do local button = challenges.add{type = "button", name = "challenge_"..i, caption = i} button.style.minimal_width = 32 end local button = challenges.add{type = "button", name = "challenge_random", caption = { global.interburbulator.freeplay_unlocked and "space-exploration.interburbulator_freeplay" or "space-exploration.interburbulator_random" }} local grid = container.add{type="flow", name="grid_target", direction="horizontal"} grid.style.vertical_align = "center" local grid_lab = grid.add{type="label", name="grid_lab", caption={"space-exploration.interburbulator_grid_size"}} local grid_textbox = grid.add{type="textfield", name="grid_textbox", numeric = true, allow_decimal = false, allow_negative = false} grid_textbox.style.width = 100 local target_lab = grid.add{type="label", name="target_lab", caption={"space-exploration.interburbulator_target_cell"}} target_lab.style.left_margin = 10 local target_textbox = grid.add{type="textfield", name="target_textbox"} target_textbox.style.width = 100 local settings_flow1 = container.add{type = "flow", name="settings_flow1", direction = "horizontal"} settings_flow1.style.top_margin = 10 local settings_flow2 = container.add{type = "flow", name="settings_flow2", direction = "horizontal"} local top_left = settings_flow1.add{type = "frame", name="top_left", direction="vertical", caption = {"space-exploration.interburbulator_top_left"}} top_left.style.width = 250 local top_right = settings_flow1.add{type = "frame", name="top_right", direction="vertical", caption = {"space-exploration.interburbulator_top_right"}} top_right.style.width = 250 local bottom_left = settings_flow2.add{type = "frame", name="bottom_left", direction="vertical", caption = {"space-exploration.interburbulator_bottom_left"}} bottom_left.style.width = 250 local attempt = settings_flow2.add{type = "frame", name="attempt", direction="vertical", caption = {"space-exploration.interburbulator_attempt"}} attempt.style.width = 250 for _, frame in pairs({top_left, top_right, bottom_left, attempt}) do local x = frame.add{type="flow", name="x", direction="horizontal"} x.add{type="label", name="lab", caption="X: "} x.add{type="textfield", name="textbox", numeric = true, allow_decimal = true, allow_negative = true} local y = frame.add{type="flow", name="y", direction="horizontal"} y.add{type="label", name="lab", caption="Y: "} y.add{type="textfield", name="textbox", numeric = true, allow_decimal = true, allow_negative = true} local z = frame.add{type="flow", name="z", direction="horizontal"} z.add{type="label", name="lab", caption="Z: "} z.add{type="textfield", name="textbox", numeric = true, allow_decimal = true, allow_negative = true} end local bottom_table = container.add{ type="table", name="bottom_table", column_count=2, draw_horizontal_lines=false} bottom_table.style.horizontally_stretchable = true bottom_table.style.vertical_align = "bottom" bottom_table.style.column_alignments[1] = "left" -- title, search, zone list table bottom_table.style.column_alignments[2] = "right" -- starmap, close, selected zone info local prize_lab = bottom_table.add{type="label", name="prize_lab"} prize_lab.style.horizontally_stretchable = true local submit = bottom_table.add{type="button", name=mod_prefix .. "-interburbulator-submit", style="confirm_button", caption={"space-exploration.interburbulator_submit"}} submit.style.top_margin = 10 --Interburbulator.enable_textfields(container, false) Interburbulator.gui_update(player) --container.force_auto_center() end function Interburbulator.submit(player, skip_warnings) local root = player.gui.screen[Interburbulator.name_interburbulator_gui_root] if not root then return end if global.interburbulator.freeplay_unlocked and not global.interburbulator.challenge_index then Interburbulator.challenge_from_gui(player) end local attempt = util.find_first_descendant_by_name(root, "attempt") local attempt_x = tonumber(attempt.x.textbox.text) local attempt_y = tonumber(attempt.y.textbox.text) local attempt_z = tonumber(attempt.z.textbox.text) if attempt_x and attempt_y and attempt_z and not(attempt_x==0 and attempt_y==0 and attempt_z==0) then global.interburbulator.guessed_vector = {attempt_x,attempt_y,attempt_z} -- shown after a guess else if not skip_warnings then Interburbulator.message(player, "Invalid attempt vector") end end global.interburbulator.guessed_player_index = player.index Interburbulator.update(player) Interburbulator.gui_update(player) end function Interburbulator.activate_challenge(challenge_index, player) global.interburbulator.guessed_vector = nil global.interburbulator.guessed_position = nil global.interburbulator.guessed_cell = nil global.interburbulator.guessed_player_index = nil if Interburbulator.challenges[challenge_index] then global.interburbulator.challenge_index = challenge_index global.interburbulator.challenge_set = nil global.interburbulator.challenge_grid_size = nil global.interburbulator.challenge_cell = nil else -- assume random global.interburbulator.challenge_index = nil global.interburbulator.challenge_grid_size = math.random(5,50) global.interburbulator.challenge_cell = {math.random(2,global.interburbulator.challenge_grid_size-1), math.random(2,global.interburbulator.challenge_grid_size-1)} local multiplier = 1 if math.random() < 0.23 then multiplier = math.random() * 1000 end global.interburbulator.challenge_set = { {(-1+math.random()*2) *multiplier,(-1+math.random()*2) *multiplier,(-1+math.random()*2) *multiplier}, {(-1+math.random()*2) *multiplier,(-1+math.random()*2) *multiplier,(-1+math.random()*2) *multiplier}, {(-1+math.random()*2) *multiplier,(-1+math.random()*2) *multiplier,(-1+math.random()*2) *multiplier}, } end Interburbulator.update(player) Interburbulator.gui_update(player) end function Interburbulator.challenge_from_gui(player) local root = player.gui.screen[Interburbulator.name_interburbulator_gui_root] if not root then return end local grid_textbox = util.find_first_descendant_by_name(root, "grid_textbox") local target_textbox = util.find_first_descendant_by_name(root, "target_textbox") local top_left = util.find_first_descendant_by_name(root, "top_left") local top_right = util.find_first_descendant_by_name(root, "top_right") local bottom_left = util.find_first_descendant_by_name(root, "bottom_left") local function number_or_random(inp) return tonumber(inp) or math.random() end global.interburbulator.challenge_set = { {number_or_random(top_left.x.textbox.text),number_or_random(top_left.y.textbox.text),number_or_random(top_left.z.textbox.text)}, {number_or_random(top_right.x.textbox.text),number_or_random(top_right.y.textbox.text),number_or_random(top_right.z.textbox.text)}, {number_or_random(bottom_left.x.textbox.text),number_or_random(bottom_left.y.textbox.text),number_or_random(bottom_left.z.textbox.text)}, } local cells_w = tonumber(grid_textbox.text) or 5 cells_w = math.min(50, math.max(5, cells_w)) global.interburbulator.challenge_grid_size = cells_w local target_cell = target_textbox.text local parts = Util.split(target_cell, ",") local x = 2 local y = 2 if #parts == 2 then x = math.min(cells_w, math.max(1, Util.string_to_number(parts[1]) or 2)) y = math.min(cells_w, math.max(1, Util.string_to_number(parts[2]) or 2)) end global.interburbulator.challenge_cell = {x, y} end function Interburbulator.on_gui_click(event) if not (event.element and event.element.valid) then return end local element = event.element local player = game.players[event.player_index] root = gui_element_or_parent(element, Interburbulator.name_interburbulator_gui_root) if element.parent and element.parent.name == "challenges" then if element.name == "challenge_random" then Interburbulator.activate_challenge("random", player) else local challenge_index = Util.string_to_number(Util.replace(element.name, "challenge_", "")) Interburbulator.activate_challenge(challenge_index, player) end elseif element.name == mod_prefix .. "-interburbulator-close" then Interburbulator.gui_close(player) elseif element.name == mod_prefix .. "-interburbulator-submit" then Interburbulator.submit(player) end end Event.addListener(defines.events.on_gui_click, Interburbulator.on_gui_click) function Interburbulator.on_gui_opened(event) local player = game.players[event.player_index] if event.entity and event.entity.valid and event.entity.name == mod_prefix.."interburbulator-control" then player.opened = nil if player.character and player.character.surface == event.entity.surface and Util.vectors_delta_length(player.character.position, event.entity.position) < 5 then Interburbulator.gui_open(player) Interburbulator.update() --Interburbulator.update(player) else event.entity.surface.create_entity{ name = "flying-text", position = event.entity.position, text = {"space-exploration.out_of_reach"}, render_player_index = player.index, } end end end Event.addListener(defines.events.on_gui_opened, Interburbulator.on_gui_opened) function Interburbulator.on_gui_text_changed(event) if not (event.element and event.element.valid) then return end local element = event.element local player = game.players[event.player_index] root = gui_element_or_parent(element, Interburbulator.name_interburbulator_gui_root) if not (root and global.interburbulator) then return end if element.parent and element.parent.parent and element.parent.parent.name == "attempt" then -- always allowed else if not global.interburbulator.freeplay_unlocked then Interburbulator.message(player, {"space-exploration.interburbulator_deny_freeplay_"..(game.tick%6+1)}) Interburbulator.gui_update(player) end end end Event.addListener(defines.events.on_gui_text_changed, Interburbulator.on_gui_text_changed) function Interburbulator.on_gui_confirmed(event) if not (event.element and event.element.valid) then return end local element = event.element local player = game.players[event.player_index] root = gui_element_or_parent(element, Interburbulator.name_interburbulator_gui_root) if not (root and global.interburbulator) then return end Interburbulator.submit(player, true) end Event.addListener(defines.events.on_gui_confirmed, Interburbulator.on_gui_confirmed) return Interburbulator