z_mirror/Krastorio2

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

Caleb HeuerRun stylua02265e00

trunk
7.5 KiB286 linesraw
1local flib_position = require("__flib__.position")
2
3--- @class RadioactivityPlayerData
4--- @field entity boolean
5--- @field damaged boolean
6--- @field inventory boolean
7--- @field last_position MapPosition
8
9local default_entities = { "uranium-ore" }
10local default_items = {
11  "nuclear-fuel",
12  "uranium-235",
13  "uranium-238",
14  "uranium-fuel-cell",
15  "uranium-ore",
16  "depleted-uranium-fuel-cell",
17}
18local range = 7
19
20--- @param player LuaPlayer
21local function check_inventory(player)
22  if not storage.radioactivity.enabled or not next(storage.radioactivity.entities) then
23    return
24  end
25
26  local player_data = storage.radioactivity.players[player.index]
27  if not player_data then
28    return
29  end
30
31  local character = player.character
32  if not character or not character.valid then
33    player_data.inventory = false
34    return
35  end
36
37  local inventory = character.get_main_inventory()
38  if not inventory then
39    return
40  end
41
42  for _, item_name in pairs(storage.radioactivity.items) do
43    -- FIXME: This does not check trash inventory
44    if inventory.get_item_count_filtered({ name = item_name }) > 0 then
45      player_data.inventory = true
46      return
47    end
48  end
49
50  player_data.inventory = false
51end
52
53--- @param player LuaPlayer
54local function check_around_player(player)
55  if not storage.radioactivity.enabled or not next(storage.radioactivity.items) then
56    return
57  end
58
59  local player_data = storage.radioactivity.players[player.index]
60  if not player_data then
61    return
62  end
63
64  if not player.character or not player.character.valid then
65    player_data.entity = false
66    return
67  end
68
69  local position = flib_position.floor(player.physical_position)
70  local last_position = player_data.last_position
71  if flib_position.eq(position, last_position) then
72    return
73  end
74  player_data.last_position = position
75
76  player_data.entity = player.surface.count_entities_filtered({
77    name = storage.radioactivity.entities,
78    radius = range,
79    position = position,
80  }) > 0
81end
82
83--- @param player LuaPlayer
84local function add_player(player)
85  storage.radioactivity.players[player.index] = {
86    entity = false,
87    damaged = false,
88    inventory = false,
89    last_position = { x = 0, y = 0 },
90  }
91end
92
93--- @param player_index uint
94local function remove_player(player_index)
95  storage.radioactivity.players[player_index] = nil
96end
97
98local function update_and_damage()
99  if not storage.radioactivity.enabled then
100    return
101  end
102
103  for player_index, player_data in pairs(storage.radioactivity.players) do
104    if not player_data.entity and not player_data.inventory then
105      goto continue
106    end
107
108    local player = game.get_player(player_index)
109    if not player or not player.connected or not player.character then
110      goto continue
111    end
112
113    player.add_custom_alert(
114      player.character,
115      { type = "virtual", name = "kr-nuclear-2" },
116      { "gui-alert-tooltip.kr-taking-radioactive-damage" },
117      false
118    )
119
120    -- Damage the player
121    -- TODO: Account for armor and energy shields
122    local base_damage = 7.25
123    player_data.damaged = player.character.damage(base_damage, "enemy", "kr-radioactive") > 0
124
125    ::continue::
126  end
127end
128
129local function update_sounds()
130  if not storage.radioactivity.enabled then
131    return
132  end
133
134  for player_index, player_data in pairs(storage.radioactivity.players) do
135    if not player_data.entity and not player_data.inventory then
136      goto continue
137    end
138
139    if not player_data.damaged then
140      goto continue
141    end
142
143    local player = game.get_player(player_index)
144    if not player or not player.connected then
145      goto continue
146    end
147
148    player.play_sound({
149      path = "kr-radioactive",
150      position = player.physical_position,
151      volume_modifier = 0.5,
152    })
153
154    ::continue::
155  end
156end
157
158--- @param e EventData.on_player_changed_position|EventData.on_player_changed_surface
159local function on_player_moved(e)
160  local player = game.get_player(e.player_index)
161  if player then
162    check_around_player(player)
163  end
164end
165
166--- @param e EventData.on_player_main_inventory_changed|EventData.on_player_trash_inventory_changed
167local function on_player_inventory_changed(e)
168  local player = game.get_player(e.player_index)
169  if player then
170    check_inventory(player)
171  end
172end
173
174--- @param e EventData.on_player_died|EventData.on_player_respawned
175local function on_player_alive_state_changed(e)
176  local player = game.get_player(e.player_index)
177  if player then
178    check_around_player(player)
179    check_inventory(player)
180  end
181end
182
183--- @param e EventData.on_player_created
184local function on_player_created(e)
185  local player = game.get_player(e.player_index)
186  if not player then
187    return
188  end
189
190  add_player(player)
191end
192
193--- @param e EventData.on_player_removed
194local function on_player_removed(e)
195  remove_player(e.player_index)
196end
197
198--- @param e EventData.on_runtime_mod_setting_changed
199local function on_runtime_mod_setting_changed(e)
200  if e.setting ~= "kr-enable-radioactivity" or not storage.radioactivity then
201    return
202  end
203
204  storage.radioactivity.enabled = settings.global["kr-enable-radioactivity"].value --[[@as boolean]]
205end
206
207--- @class RadioactivityHandler : event_handler
208local radioactivity = {}
209
210function radioactivity.on_init()
211  storage.radioactivity = {
212    enabled = settings.global["kr-enable-radioactivity"].value --[[@as boolean]],
213    --- @type table<uint, RadioactivityPlayerData>
214    players = {},
215  }
216  radioactivity.on_configuration_changed()
217end
218
219function radioactivity.on_configuration_changed()
220  storage.radioactivity.entities = {}
221  for _, entity_name in pairs(default_entities) do
222    if prototypes.entity[entity_name] then
223      table.insert(storage.radioactivity.entities, entity_name)
224    end
225  end
226  storage.radioactivity.items = {}
227  for _, item_name in pairs(default_items) do
228    if prototypes.item[item_name] then
229      table.insert(storage.radioactivity.items, item_name)
230    end
231  end
232end
233
234remote.add_interface("kr-radioactivity", {
235  --- @param name string
236  add_entity = function(name)
237    if not storage.radioactivity then
238      return
239    end
240    if not name or type(name) ~= "string" then
241      error("`name` must be a string.")
242    end
243
244    if not prototypes.entity[name] then
245      error("Entity `" .. name .. "` does not exist.")
246    end
247
248    table.insert(storage.radioactivity.entities, name)
249  end,
250  --- @param name string
251  add_item = function(name)
252    if not storage.radioactivity then
253      return
254    end
255    if not name or type(name) ~= "string" then
256      error("`name` must be a string.")
257    end
258
259    if not prototypes.item[name] then
260      error("Item `" .. name .. "` does not exist.")
261    end
262
263    table.insert(storage.radioactivity.items, name)
264  end,
265})
266
267radioactivity.events = {
268  [defines.events.on_player_changed_position] = on_player_moved,
269  [defines.events.on_player_changed_surface] = on_player_moved,
270  [defines.events.on_player_created] = on_player_created,
271  [defines.events.on_player_cursor_stack_changed] = on_player_inventory_changed,
272  [defines.events.on_player_died] = on_player_alive_state_changed,
273  [defines.events.on_player_main_inventory_changed] = on_player_inventory_changed,
274  [defines.events.on_player_removed] = on_player_removed,
275  [defines.events.on_player_respawned] = on_player_alive_state_changed,
276  [defines.events.on_player_toggled_map_editor] = on_player_moved,
277  [defines.events.on_player_trash_inventory_changed] = on_player_inventory_changed,
278  [defines.events.on_runtime_mod_setting_changed] = on_runtime_mod_setting_changed,
279  [defines.events.on_tick] = update_sounds,
280}
281
282radioactivity.on_nth_tick = {
283  [20] = update_and_damage,
284}
285
286return radioactivity