z_mirror/RateCalculator

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

Caleb HeuerFix LuaLS warning8cbeb98

trunk
6.3 KiB239 linesraw
1local calc_util = require("scripts.calc-util")
2
3local gui = require("scripts.gui")
4
5--- @class Set<T>: { [T]: boolean }
6
7--- @alias CalculationError
8--- | "max-crafting-speed"
9--- | "incompatible-science-packs"
10--- | "no-active-research"
11--- | "no-input-fluid"
12--- | "no-fuel"
13--- | "no-mineable-resources"
14--- | "no-power"
15--- | "no-recipe"
16
17--- @class CalculationSet
18--- @field completed Set<string>
19--- @field errors Set<CalculationError>
20--- @field player LuaPlayer
21--- @field rates table<string, Rates>
22--- @field research_data ResearchData?
23--- @field pollutant string
24
25--- @alias MachineCounts table<string, uint>
26
27--- @class Rate
28--- @field machine_counts MachineCounts
29--- @field machines integer
30--- @field rate double
31
32--- @class Rates
33--- @field type string
34--- @field name string
35--- @field quality string?
36--- @field temperature double?
37--- @field output Rate
38--- @field input Rate
39
40--- @class ResearchData
41--- @field ingredients Ingredient[]
42--- @field multiplier double
43--- @field speed_modifier double
44
45--- @param player LuaPlayer
46--- @return CalculationSet
47local function new_calculation_set(player)
48  local force = player.force
49  local current_research = force.current_research
50  --- @type ResearchData?
51  local research_data
52  if current_research then
53    research_data = {
54      ingredients = current_research.research_unit_ingredients,
55      multiplier = 1 / (current_research.research_unit_energy / 60),
56      speed_modifier = force.laboratory_speed_modifier,
57    }
58  end
59  local pollutant = ""
60  local pollutant_prototype = player.surface.pollutant_type
61  if pollutant_prototype then
62    pollutant = pollutant_prototype.name
63  end
64  return {
65    completed = {},
66    errors = {},
67    player = player,
68    rates = {},
69    research_data = research_data,
70    pollutant = pollutant,
71  }
72end
73
74local entity_blacklist = {
75  -- Transport Drones
76  ["buffer-depot"] = true,
77  ["fluid-depot"] = true,
78  ["fuel-depot"] = true,
79  ["request-depot"] = true,
80}
81
82--- @param set CalculationSet
83--- @param entity LuaEntity
84--- @param invert boolean
85local function process_entity(set, entity, invert)
86  if entity_blacklist[entity.name] then
87    return
88  end
89
90  local emissions_per_second = entity.prototype.emissions_per_second[set.pollutant] or 0
91  local type = entity.type
92
93  if type == "burner-generator" or type == "generator" then
94    calc_util.add_rate(
95      set,
96      "output",
97      "item",
98      "rcalc-power-dummy",
99      "normal",
100      entity.prototype.get_max_power_output(entity.quality) * 60,
101      invert,
102      entity.name
103    )
104  elseif type ~= "burner-generator" and entity.prototype.electric_energy_source_prototype then
105    emissions_per_second = calc_util.process_electric_energy_source(set, entity, invert, emissions_per_second)
106  elseif entity.prototype.fluid_energy_source_prototype then
107    emissions_per_second = calc_util.process_fluid_energy_source(set, entity, invert, emissions_per_second)
108  elseif entity.prototype.heat_energy_source_prototype then
109    calc_util.process_heat_energy_source(set, entity, invert)
110  end
111
112  if entity.burner then
113    emissions_per_second = calc_util.process_burner(set, entity, invert, emissions_per_second)
114  end
115
116  if type == "assembling-machine" or type == "furnace" or type == "rocket-silo" then
117    emissions_per_second = calc_util.process_crafter(set, entity, invert, emissions_per_second)
118  elseif type == "beacon" then
119    calc_util.process_beacon(set, entity)
120  elseif type == "boiler" then
121    calc_util.process_boiler(set, entity, invert)
122  elseif type == "lab" then
123    calc_util.process_lab(set, entity, invert)
124  elseif type == "generator" then
125    calc_util.process_generator(set, entity, invert)
126  elseif type == "mining-drill" then
127    calc_util.process_mining_drill(set, entity, invert)
128  elseif type == "offshore-pump" then
129    calc_util.process_offshore_pump(set, entity, invert)
130  elseif type == "reactor" then
131    calc_util.process_reactor(set, entity, invert)
132  end
133
134  if emissions_per_second > 0 then
135    calc_util.add_rate(
136      set,
137      "output",
138      "item",
139      "rcalc-pollution-dummy",
140      "normal",
141      emissions_per_second,
142      invert,
143      entity.name
144    )
145  elseif emissions_per_second < 0 then
146    calc_util.add_rate(
147      set,
148      "input",
149      "item",
150      "rcalc-pollution-dummy",
151      "normal",
152      -emissions_per_second,
153      invert,
154      entity.name
155    )
156  end
157end
158
159--- @param set CalculationSet
160--- @param entities LuaEntity[]
161--- @param invert boolean
162local function process_entities(set, entities, invert)
163  for _, entity in pairs(entities) do
164    process_entity(set, entity, invert)
165  end
166end
167
168--- @param e EventData.on_player_selected_area
169local function on_player_selected_area(e)
170  if e.item ~= "rcalc-selection-tool" then
171    return
172  end
173  if not next(e.entities) then
174    return
175  end
176  local player = game.get_player(e.player_index)
177  if not player then
178    return
179  end
180  local set = new_calculation_set(player)
181  process_entities(set, e.entities, false)
182  gui.build_and_show(player, set, true)
183  if player.mod_settings["rcalc-dismiss-tool-on-selection"].value then
184    player.clear_cursor()
185  end
186end
187
188--- @param e EventData.on_player_alt_selected_area
189local function on_player_alt_selected_area(e)
190  if e.item ~= "rcalc-selection-tool" then
191    return
192  end
193  if not next(e.entities) then
194    return
195  end
196  local player = game.get_player(e.player_index)
197  if not player then
198    return
199  end
200  local set = gui.get_current_set(player)
201  if not set then
202    set = new_calculation_set(player)
203  end
204  set.errors = {}
205  process_entities(set, e.entities, false)
206  gui.build_and_show(player, set)
207end
208
209--- @param e EventData.on_player_reverse_selected_area
210local function on_player_alt_reverse_selected_area(e)
211  if e.item ~= "rcalc-selection-tool" then
212    return
213  end
214  if not next(e.entities) then
215    return
216  end
217  local player = game.get_player(e.player_index)
218  if not player then
219    return
220  end
221  local set = gui.get_current_set(player)
222  if not set then
223    set = new_calculation_set(player)
224  end
225  set.errors = {}
226  process_entities(set, e.entities, true)
227  gui.build_and_show(player, set)
228end
229
230--- @class Calc: event_handler
231local calc = {}
232
233calc.events = {
234  [defines.events.on_player_alt_reverse_selected_area] = on_player_alt_reverse_selected_area,
235  [defines.events.on_player_alt_selected_area] = on_player_alt_selected_area,
236  [defines.events.on_player_selected_area] = on_player_selected_area,
237}
238
239return calc