z_mirror/Krastorio2

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

plafix: Remove unused prototype properties (#751)0ee5744d

trunk
7.4 KiB277 linesraw
1local flib_gui = require("__flib__.gui")
2
3local util = require("scripts.util")
4
5--- @type table<string, {color: Color?, suffix: string, text: string}>
6local mode_data = {
7  normal = { suffix = "", text = "normal" },
8  construction = { color = { r = 0.5, g = 1, b = 0.4 }, suffix = "-construction-mode", text = "construction" },
9  logistic = { color = { r = 1, g = 0.5, b = 0.25 }, suffix = "-logistic-mode", text = "logistic" },
10}
11
12local next_roboport_mode = {
13  [""] = "construction",
14  ["-construction-mode"] = "logistic",
15  ["-logistic-mode"] = "normal",
16}
17
18local roboport_has_variants_gui = {}
19do
20  -- Find all compatible roboports
21  local lookup = {}
22  for _, entity in pairs(prototypes.get_entity_filtered({ { filter = "type", type = "roboport" } })) do
23    local matched, _, base_name = string.find(entity.name, "^(.-)%-%w*%-mode")
24    if matched then
25      lookup[base_name] = true
26      lookup[entity.name] = true
27    end
28  end
29
30  -- Convert to a format usable by GuiAnchor
31  local i = 0
32  for entity_name in pairs(lookup) do
33    i = i + 1
34    roboport_has_variants_gui[i] = entity_name
35  end
36end
37
38--- @param player LuaPlayer
39--- @param entity LuaEntity
40local function update_gui(player, entity)
41  local player_gui = storage.roboport_guis[player.index]
42  if not player_gui or not player_gui.valid then
43    return
44  end
45  local mode = string.match(entity.name, "^.*%-(%w*)%-mode") or "normal"
46
47  for _, button in pairs(player_gui.inner_frame.children) do
48    if button.name == mode then
49      button.state = true
50    else
51      button.state = false
52    end
53  end
54end
55
56--- @param entity LuaEntity
57--- @param player LuaPlayer
58--- @param to_mode string?
59local function change_mode(entity, player, to_mode)
60  local matched, _, base_name, suffix = string.find(entity.name, "^(.-)(%-%w-%-mode)$")
61  if not matched then
62    base_name = entity.name
63    suffix = ""
64  end
65
66  local new_mode_data
67  if to_mode then
68    new_mode_data = mode_data[to_mode]
69  else
70    new_mode_data = mode_data[next_roboport_mode[suffix]]
71  end
72
73  local new_name = base_name .. new_mode_data.suffix
74
75  if new_name == entity.name then
76    return
77  end
78
79  if not prototypes.entity[new_name] then
80    util.flying_text_with_sound(player, { "message.kr-roboport-modes-not-supported" }, { position = entity.position })
81    return
82  end
83
84  local energy = entity.energy
85  local health = entity.health
86
87  -- Find all players that have this roboport open
88  -- This must be done before the roboport is swapped
89  local guis_to_update = {}
90  for player_index in pairs(storage.roboport_guis) do
91    local gui_player = game.get_player(player_index)
92    if gui_player and gui_player.opened_gui_type == defines.gui_type.entity then
93      local opened = gui_player.opened
94      if opened and opened == entity then
95        table.insert(guis_to_update, gui_player)
96      end
97    end
98  end
99
100  local new_entity = entity.surface.create_entity({
101    name = new_name,
102    position = entity.position,
103    force = entity.force,
104    direction = entity.direction,
105    quality = entity.quality,
106    fast_replace = true,
107    raise_built = true,
108    spill = false,
109    create_build_effect_smoke = false,
110  })
111
112  if not new_entity then
113    return
114  end
115  new_entity.energy = energy
116  new_entity.health = health
117  new_entity.last_user = player
118
119  util.entity_flying_text(new_entity, { "message.kr-" .. new_mode_data.text .. "-mode" }, new_mode_data.color)
120  game.play_sound({
121    path = "kr-welding",
122    position = new_entity.position,
123    volume_modifier = 1.0,
124  })
125  new_entity.surface.create_particle({
126    name = "kr-welding-particle",
127    position = { new_entity.position.x, new_entity.position.y + 1 },
128    movement = { 0.0, -0.05 },
129    height = 1.0,
130    vertical_speed = 0.015,
131    frame_speed = 1,
132  })
133
134  -- Swapping the entity will close any open GUIs, so we must re-open them.
135  for _, gui_player in pairs(guis_to_update) do
136    gui_player.opened = new_entity
137    update_gui(gui_player, new_entity)
138  end
139end
140
141--- @param e EventData.on_gui_checked_state_changed
142local function on_mode_radio_button_checked(e)
143  local player = game.get_player(e.player_index)
144  if not player or player.opened_gui_type ~= defines.gui_type.entity then
145    return
146  end
147  local entity = player.opened --[[@as LuaEntity]]
148  if not entity.valid or entity.type ~= "roboport" then
149    return
150  end
151  change_mode(entity, player, e.element.name)
152end
153
154--- @param mode string
155local function radio_button(mode)
156  return {
157    type = "radiobutton",
158    name = mode,
159    caption = { "message.kr-" .. mode .. "-mode" },
160    state = false,
161    handler = { [defines.events.on_gui_checked_state_changed] = on_mode_radio_button_checked },
162  }
163end
164
165--- @param player_index uint
166local function destroy_gui(player_index)
167  local player_gui = storage.roboport_guis[player_index]
168  if not player_gui then
169    return
170  end
171  if player_gui.valid then
172    player_gui.destroy()
173  end
174  storage.roboport_guis[player_index] = nil
175end
176
177--- @param player LuaPlayer
178local function refresh_gui(player)
179  destroy_gui(player.index)
180
181  _, storage.roboport_guis[player.index] = flib_gui.add(player.gui.relative, {
182    type = "frame",
183    name = "kr_roboport_mode_window",
184    caption = { "gui.kr-change-mode" },
185    anchor = {
186      gui = defines.relative_gui_type.roboport_gui,
187      position = defines.relative_gui_position.right,
188      names = roboport_has_variants_gui,
189    },
190    {
191      type = "frame",
192      name = "inner_frame",
193      style = "inside_shallow_frame_with_padding",
194      direction = "vertical",
195      radio_button("normal"),
196      radio_button("construction"),
197      radio_button("logistic"),
198    },
199  })
200end
201
202--- @param e EventData.on_gui_opened
203local function on_gui_opened(e)
204  local entity = e.entity
205  if not entity or not entity.valid then
206    return
207  end
208  local player = game.get_player(e.player_index)
209  if not player then
210    return
211  end
212  if entity.type == "roboport" then
213    update_gui(player, entity)
214  end
215end
216
217--- @param e EventData.on_player_created
218local function on_player_created(e)
219  local player = game.get_player(e.player_index)
220  if player then
221    refresh_gui(player)
222  end
223end
224
225--- @param e EventData.on_player_removed
226local function on_player_removed(e)
227  destroy_gui(e.player_index)
228end
229
230--- @param e EventData.CustomInputEvent
231local function on_change_roboport_mode_hotkey(e)
232  local player = game.get_player(e.player_index)
233  if not player then
234    return
235  end
236  local selected = player.selected
237  if selected and selected.valid and selected.type == "roboport" then
238    change_mode(selected, player)
239  end
240end
241
242local function refresh()
243  for _, player in pairs(game.players) do
244    refresh_gui(player)
245  end
246end
247
248local function on_init()
249  -- XXX: When migrating from standalone K2SO to K2 + K2SO, there will be a leftover GUI which will cause a crash. It must be removed here.
250  for _, player in pairs(game.players) do
251    local window = player.gui.relative["kr_roboport_mode_window"]
252    if window and window.valid then
253      window.destroy()
254    end
255  end
256
257  --- @type table<uint, LuaGuiElement>
258  storage.roboport_guis = {}
259  refresh()
260end
261
262--- @class RoboportHandler : event_handler
263local roboport = {}
264
265roboport.on_init = on_init
266roboport.on_configuration_changed = on_configuration_changed
267
268roboport.events = {
269  [defines.events.on_gui_opened] = on_gui_opened,
270  [defines.events.on_player_created] = on_player_created,
271  [defines.events.on_player_removed] = on_player_removed,
272  ["kr-change-roboport-state"] = on_change_roboport_mode_hotkey,
273}
274
275flib_gui.add_handlers({ roboport_on_mode_radio_button_checked = on_mode_radio_button_checked })
276
277return roboport