z_mirror/Krastorio2

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

Caleb HeuerChange to four-space indentation07409ca6

four-space-indentation
7.9 KiB252 linesraw
1local flib_table = require("__flib__.table")
2
3--- @class PlanetaryTeleporterData
4--- @field entities PlanetaryTeleporterEntities
5--- @field force LuaForce
6--- @field name string?
7--- @field position MapPosition
8--- @field surface LuaSurface
9--- @field turret_unit_number UnitNumber
10
11--- @class PlanetaryTeleporterEntities
12--- @field base LuaEntity
13--- @field turret LuaEntity
14--- @field collision_1 LuaEntity
15--- @field collision_2 LuaEntity
16--- @field collision_3 LuaEntity
17--- @field front_layer LuaEntity
18
19local collision_entity_offsets = {
20    { x = 0, y = 0 },
21    { x = -2, y = 2 },
22    { x = 2, y = 2 },
23}
24
25--- @param base_entity LuaEntity
26--- @return PlanetaryTeleporterEntities?
27local function create_entities(base_entity)
28    local entities = {
29        base = base_entity,
30    }
31    local surface = base_entity.surface
32    local position = base_entity.position
33
34    -- Building the turret can fail due to AAI vehicles
35    entities.turret = surface.create_entity({
36        name = "kr-planetary-teleporter-turret",
37        position = { x = position.x, y = position.y + 1.15 },
38        force = "kr-internal-turrets",
39        create_build_effect_smoke = false,
40        raise_built = true,
41    })
42
43    if not entities.turret or not entities.turret.valid then
44        game.print(
45            "Building planetary teleporter failed due to AAI Programmable Vehicles. This teleporter will not function."
46        )
47        base_entity.active = false
48        return
49    end
50
51    for i, offset in ipairs(collision_entity_offsets) do
52        entities["collision_" .. i] = surface.create_entity({
53            name = "kr-planetary-teleporter-collision-" .. i,
54            position = { x = position.x + offset.x, y = position.y + offset.y },
55            create_build_effect_smoke = false,
56            raise_built = true,
57        })
58    end
59    entities.front_layer = surface.create_entity({
60        name = "kr-planetary-teleporter-front-layer",
61        position = position,
62        create_build_effect_smoke = false,
63        raise_built = true,
64    })
65    for name, entity in pairs(entities) do
66        if name ~= "base" then
67            entity.destructible = false
68        end
69    end
70    return entities
71end
72
73--- @param e EntityBuiltEvent
74local function on_entity_built(e)
75    local entity = e.entity or e.destination
76    if not entity or not entity.valid then
77        return
78    end
79    local entity_name = entity.name
80
81    -- Don't keep cloned internal entities.
82    if
83        e.name == defines.events.on_entity_cloned
84        and (
85            entity_name == "kr-planetary-teleporter-front-layer"
86            or entity_name == "kr-planetary-teleporter-turret"
87            or string.find(entity_name, "kr-planetary-teleporter-collision", nil, true)
88        )
89    then
90        entity.destroy()
91        return
92    end
93
94    if entity_name ~= "kr-planetary-teleporter" then
95        return
96    end
97
98    -- If revived from a blueprint and it has a name, get it from the tags
99    local name = e.tags and e.tags.kr_planetary_teleporter_name or nil --[[@as string?]]
100    local entities = create_entities(entity)
101    if not entities then
102        return
103    end
104
105    storage.planetary_teleporter[entity.unit_number] = {
106        entities = entities,
107        force = entity.force --[[@as LuaForce]],
108        name = name,
109        position = entity.position,
110        surface = entity.surface,
111        turret_unit_number = entities.turret.unit_number,
112    }
113end
114
115--- @param e EntityDestroyedEvent
116local function on_entity_destroyed(e)
117    local entity = e.entity
118    if not entity or not entity.valid or entity.name ~= "kr-planetary-teleporter" then
119        return
120    end
121    local unit_number = entity.unit_number --[[@as uint]]
122    local data = storage.planetary_teleporter[unit_number]
123    -- AAI vehicles will destroy the entity before we have an opportuity to create data.
124    if not data then
125        return
126    end
127    for _, entity_to_destroy in pairs(data.entities) do
128        if entity_to_destroy.valid then
129            entity_to_destroy.destroy()
130        end
131    end
132    storage.planetary_teleporter[unit_number] = nil
133end
134
135--- @param e EventData.on_player_setup_blueprint
136local function on_player_setup_blueprint(e)
137    local player = game.get_player(e.player_index)
138    if not player then
139        return
140    end
141
142    -- Get blueprint
143    local bp = player.blueprint_to_setup
144    if not bp or not bp.valid_for_read then
145        bp = player.cursor_stack
146        if not bp then
147            return
148        end
149        if bp.type == "blueprint-book" then
150            local item_inventory = bp.get_inventory(defines.inventory.item_main)
151            if item_inventory then
152                bp = item_inventory[bp.active_index]
153            else
154                return
155            end
156        end
157    end
158
159    local entities = bp.get_blueprint_entities()
160    if not entities then
161        return
162    end
163
164    -- Iterate each entity
165    for i = 1, #entities do
166        local entity = entities[i]
167        local entity_name = entity.name
168        if entity_name == "kr-planetary-teleporter" then
169            local real_entity = player.surface.find_entity("kr-planetary-teleporter", entity.position)
170            if real_entity then
171                local unit_number = real_entity.unit_number --[[@as uint]]
172                local data = storage.planetary_teleporter[unit_number]
173                if data and data.name then
174                    bp.set_blueprint_entity_tag(i, "kr_planetary_teleporter_name", data.name)
175                end
176            end
177        end
178    end
179end
180
181--- @param e EventData.on_script_trigger_effect
182local function on_script_trigger_effect(e)
183    if e.effect_id ~= "kr-planetary-teleporter-character-trigger" then
184        return
185    end
186
187    if not e.source_entity.valid or not e.target_entity.valid or e.target_entity.type ~= "character" then
188        return
189    end
190
191    local player = e.target_entity.player
192    if not player or not player.valid then
193        return
194    end
195
196    table.insert(
197        flib_table.get_or_insert(storage.planetary_teleporter_players, e.source_entity.unit_number, {}),
198        player.index
199    )
200end
201
202-- on_tick is executed before on_script_trigger_effect
203local function on_tick()
204    storage.planetary_teleporter_players = {}
205end
206
207-- Get all planetary teleporters on each surface
208-- Get the name from old storage
209-- Nuke old storage
210-- Re-init
211-- Call build functions for each existing teleporter
212
213--- @class PlanetaryTeleporterHandler : event_handler
214local planetary_teleporter = {}
215
216function planetary_teleporter.on_init()
217    --- @type table<uint, PlanetaryTeleporterData>
218    storage.planetary_teleporter = {}
219    --- @type table<UnitNumber, PlayerIndex[]>
220    storage.planetary_teleporter_players = {}
221end
222
223planetary_teleporter.events = {
224    [defines.events.on_built_entity] = on_entity_built,
225    [defines.events.on_entity_cloned] = on_entity_built,
226    [defines.events.on_entity_died] = on_entity_destroyed,
227    [defines.events.on_player_mined_entity] = on_entity_destroyed,
228    [defines.events.on_player_setup_blueprint] = on_player_setup_blueprint,
229    [defines.events.on_robot_built_entity] = on_entity_built,
230    [defines.events.on_robot_mined_entity] = on_entity_destroyed,
231    [defines.events.on_script_trigger_effect] = on_script_trigger_effect,
232    [defines.events.on_tick] = on_tick,
233    [defines.events.script_raised_built] = on_entity_built,
234    [defines.events.script_raised_destroy] = on_entity_destroyed,
235    [defines.events.script_raised_revive] = on_entity_built,
236    [defines.events.on_space_platform_built_entity] = on_entity_built,
237    [defines.events.on_space_platform_mined_entity] = on_entity_destroyed,
238}
239
240--- Only to be used for pre-2.0 migrations.
241--- @param entity LuaEntity
242--- @param name string?
243function planetary_teleporter.migrate_teleporter(entity, name)
244    on_entity_built({
245        name = defines.events.on_built_entity,
246        tick = game.tick,
247        entity = entity,
248        tags = { kr_planetary_teleporter_name = name }, --- @diagnostic disable-line: assign-type-mismatch
249    })
250end
251
252return planetary_teleporter