z_mirror/Tapeline

git clone https://git.raiguard.me/z_mirror/Tapeline

Caleb HeuerUse slash requires37bb3aa

color-setting
11.3 KiB335 linesraw
1local area = require("__flib__/area")
2local event = require("__flib__/event")
3local migration = require("__flib__/migration")
4
5local constants = require("__Tapeline__/constants")
6local migrations = require("__Tapeline__/migrations")
7local player_data = require("__Tapeline__/player-data")
8local tape = require("__Tapeline__/tape")
9
10--- @param player_table PlayerTable
11local function destroy_last_entity(player_table)
12  local last_entity = player_table.last_entity
13  if last_entity then
14    last_entity.destroy()
15    player_table.last_entity = nil
16  end
17end
18
19--- @param tapes table<number, TapeData>
20--- @param cursor_position MapPosition
21--- @param surface LuaSurface
22local function select_tape(tapes, cursor_position, surface)
23  local topmost_tape
24  local most_recent_update_time = 0
25  for i, tape_data in ipairs(tapes) do
26    local TapeArea = area.load(tape_data.Area)
27    if tape_data.surface == surface and TapeArea:contains_position(cursor_position) then
28      if tape_data.last_update_tick > most_recent_update_time then
29        most_recent_update_time = tape_data.last_update_tick
30        topmost_tape = i
31      end
32    end
33  end
34
35  return topmost_tape
36end
37
38--- @param player LuaPlayer
39local function holding_tl_tool(player)
40  local cursor_stack = player.cursor_stack
41  return cursor_stack and cursor_stack.valid_for_read and cursor_stack.name == "tl-tool"
42end
43
44--- @param player LuaPlayer
45--- @param player_table PlayerTable
46local function set_cursor_label(player, player_table)
47  local settings, TapeArea
48  if player_table.flags.drawing then
49    settings = player_table.tape_settings
50    TapeArea = area.load(player_table.tapes.drawing.Area)
51  elseif player_table.flags.editing then
52    local tape_data = player_table.tapes.editing
53    settings = tape_data.settings
54    TapeArea = area.load(tape_data.Area)
55  else
56    settings = player_table.tape_settings
57  end
58
59  local cursor_stack = player.cursor_stack
60  if cursor_stack and cursor_stack.valid_for_read then
61    cursor_stack.label = (
62      (TapeArea and (TapeArea:width() .. "x" .. TapeArea:height() .. " | ") or "")
63      .. constants.mode_labels[settings.mode]
64      .. " mode | "
65      .. constants.divisor_labels[settings.mode]
66      .. " "
67      .. settings[settings.mode .. "_divisor"]
68    )
69  end
70end
71
72event.on_init(function()
73  --- @type table<uint, PlayerTable>
74  global.players = {}
75
76  for _, player in pairs(game.players) do
77    player_data.init(player.index)
78    player_data.refresh(player, global.players[player.index])
79  end
80end)
81
82event.on_configuration_changed(function(e)
83  if migration.on_config_changed(e, migrations) then
84    for i, player_table in pairs(global.players) do
85      local player = game.get_player(i) --[[@as LuaPlayer]]
86      player_data.refresh(player, player_table)
87    end
88  end
89end)
90
91event.register("tl-get-tool", function(e)
92  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
93  if player.clear_cursor() then
94    player.cursor_stack.set_stack({ name = "tl-tool", count = 100 })
95  end
96end)
97
98event.register("tl-edit-tape", function(e)
99  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
100  local player_table = global.players[e.player_index]
101
102  if holding_tl_tool(player) then
103    local tapes = player_table.tapes
104    local tape_to_edit = select_tape(tapes, e.cursor_position, player.surface)
105    if tape_to_edit then
106      if player_table.flags.editing then
107        tape.exit_edit_mode(player_table)
108        set_cursor_label(player, player_table)
109      end
110      tape.enter_edit_mode(player, player_table, tape_to_edit)
111      set_cursor_label(player, player_table)
112    end
113  end
114end)
115
116event.register("tl-delete-tape", function(e)
117  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
118  local player_table = global.players[e.player_index]
119
120  if holding_tl_tool(player) then
121    local tapes = player_table.tapes
122    local tape_to_delete = select_tape(tapes, e.cursor_position, player.surface)
123    if tape_to_delete then
124      tape.delete(player_table, tape_to_delete)
125      set_cursor_label(player, player_table)
126    end
127  end
128end)
129
130event.register({
131  "tl-increase-divisor",
132  "tl-decrease-divisor",
133}, function(e)
134  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
135  if holding_tl_tool(player) then
136    local player_table = global.players[e.player_index]
137    local settings
138    if player_table.flags.editing then
139      settings = player_table.tapes.editing.settings
140    else
141      settings = player_table.tape_settings
142    end
143    local mode = settings.mode
144    local key = mode .. "_divisor"
145    local delta = string.find(e.input_name, "increase") and 1 or -1
146    local new_divisor = settings[key] + delta
147    if new_divisor >= constants.divisor_minimums[mode] then
148      settings[key] = new_divisor
149      set_cursor_label(player, player_table)
150      if player_table.flags.drawing then
151        tape.update_draw(player, player_table)
152      elseif player_table.flags.editing then
153        tape.edit_settings(e.player_index, player_table, mode, new_divisor)
154      end
155    else
156      player.create_local_flying_text({
157        text = { "message.tl-minimal-value-is", constants.divisor_minimums[mode] },
158        create_at_cursor = true,
159      })
160      player.play_sound({ path = "utility/cannot_build", volume_modifier = 0.75 })
161    end
162  end
163end)
164
165event.register({
166  "tl-next-mode",
167  "tl-previous-mode",
168}, function(e)
169  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
170  if holding_tl_tool(player) then
171    local player_table = global.players[e.player_index]
172    local settings
173    if player_table.flags.editing then
174      settings = player_table.tapes.editing.settings
175    else
176      settings = player_table.tape_settings
177    end
178    local new_mode = next(constants.modes, settings.mode)
179    if not new_mode then
180      new_mode = next(constants.modes)
181    end
182    settings.mode = new_mode
183    local divisor = settings[new_mode .. "_divisor"]
184    set_cursor_label(player, player_table)
185    if player_table.flags.drawing then
186      tape.update_draw(player, player_table)
187    elseif player_table.flags.editing then
188      tape.edit_settings(e.player_index, player_table, new_mode, divisor)
189    end
190  end
191end)
192
193event.register("tl-clear-cursor", function(e)
194  local player_table = global.players[e.player_index]
195  if player_table.flags.drawing or player_table.flags.editing then
196    local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
197    player.clear_cursor()
198  end
199end)
200
201event.on_built_entity(function(e)
202  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
203  local player_table = global.players[e.player_index]
204  local entity = e.created_entity
205  local is_ghost = entity.name == "entity-ghost"
206
207  destroy_last_entity(player_table)
208
209  if is_ghost then
210    -- instantly revive the entity if it is a ghost
211    local _, new_entity = entity.silent_revive()
212    if not new_entity then
213      return
214    end
215    entity = new_entity
216  end
217  -- make the entity invincible to prevent attacks
218  entity.destructible = false
219  player_table.last_entity = entity
220
221  -- update tape
222  if player_table.flags.drawing then
223    tape.update_draw(player, player_table, entity.position, is_ghost)
224  elseif player_table.flags.editing then
225    tape.move(player, player_table, entity.position, entity.surface)
226  else
227    tape.start_draw(player, player_table, entity.position, entity.surface)
228  end
229
230  -- update the cursor
231  player.cursor_stack.set_stack({ name = "tl-tool", count = 100 })
232  set_cursor_label(player, player_table)
233end, {
234  { filter = "name", name = "tl-dummy-entity" },
235  { filter = "ghost_name", name = "tl-dummy-entity" },
236})
237
238event.register({
239  defines.events.on_player_selected_area,
240  defines.events.on_player_alt_selected_area,
241}, function(e)
242  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
243  local player_table = global.players[e.player_index]
244  if player_table.flags.drawing then
245    player_table.flags.drawing = false
246    destroy_last_entity(player_table)
247    tape.complete_draw(player, player_table, e.name == defines.events.on_player_selected_area)
248    set_cursor_label(player, player_table)
249  elseif player_table.flags.editing then
250    destroy_last_entity(player_table)
251    tape.complete_move(player_table)
252  end
253end)
254
255event.on_player_created(function(e)
256  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
257  player_data.init(e.player_index)
258  player_data.refresh(player, global.players[e.player_index])
259end)
260
261event.on_player_removed(function(e)
262  global.players[e.player_index] = nil
263end)
264
265event.on_player_cursor_stack_changed(function(e)
266  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
267  local player_table = global.players[e.player_index]
268  if not player_table then
269    return
270  end
271  local cursor_stack = player.cursor_stack
272  local is_empty = not cursor_stack or not cursor_stack.valid_for_read
273  if player_table.flags.holding_tool then
274    if is_empty or cursor_stack.name ~= "tl-tool" then --- @diagnostic disable-line
275      player_table.flags.holding_tool = false
276      destroy_last_entity(player_table)
277      if player_table.flags.editing then
278        tape.exit_edit_mode(player_table)
279        player.cursor_stack.set_stack({ name = "tl-tool", count = 100 })
280        set_cursor_label(player, player_table)
281      else
282        if player_table.flags.drawing then
283          tape.cancel_draw(player_table)
284        end
285        if player.controller_type == defines.controllers.character and player_table.flags.increased_build_distance then
286          player_table.flags.increased_build_distance = false
287          local build_distance = player.character_build_distance_bonus
288          if build_distance >= 1000000 then
289            -- decrease build distance
290            player.character_build_distance_bonus = build_distance - 1000000 --[[@as uint]]
291          end
292        end
293      end
294    end
295  elseif holding_tl_tool(player) then
296    player_table.flags.holding_tool = true
297    player.cursor_stack.set_stack({ name = "tl-tool", count = 100 })
298    set_cursor_label(player, player_table)
299    if player.controller_type == defines.controllers.character and not player_table.flags.increased_build_distance then
300      -- increase build distance
301      player_table.flags.increased_build_distance = true
302      player.character_build_distance_bonus = player.character_build_distance_bonus + 1000000 --[[@as uint]]
303    end
304  end
305end)
306
307-- FIXME: Cancel draw when any controller change occurs (requires API addition)
308event.on_pre_player_toggled_map_editor(function(e)
309  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
310  local player_table = global.players[e.player_index]
311  if not player_table then
312    return
313  end
314  if player_table.flags.increased_build_distance then
315    player_table.flags.increased_build_distance = false
316    local build_distance = player.character_build_distance_bonus
317    if build_distance >= 1000000 then
318      -- decrease build distance
319      player.character_build_distance_bonus = build_distance - 1000000 --[[@as uint]]
320    end
321  end
322end)
323
324event.on_runtime_mod_setting_changed(function(e)
325  local internal = constants.setting_names[e.setting]
326  if internal then
327    local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
328    local player_table = global.players[e.player_index]
329    local visual_settings = player_table.visual_settings
330    player_data.update_visual_setting(player, visual_settings, e.setting, internal)
331    for _, tape_data in ipairs(player_table.tapes) do
332      tape.update_visual_settings(tape_data, visual_settings)
333    end
334  end
335end)