z_mirror/Krastorio2

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

Caleb HeuerChange to four-space indentation07409ca6

four-space-indentation
8.1 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