z_mirror/Krastorio2
git clone https://git.raiguard.me/z_mirror/Krastorio2
715d5ba0
real-fusion-reactor
1--- @class BeamData 2--- @field beam LuaEntity 3--- @field beam_number uint64 4--- @field target_data TargetData 5--- @field tower_data TowerData 6 7--- @class GridData 8--- @field absorber LuaEquipment? 9--- @field grid LuaEquipmentGrid 10 11--- @class TargetData 12--- @field connections TargetConnections 13--- @field entity LuaEntity 14--- @field full_tick uint64? 15--- @field grid_data GridData 16--- @field unit_number uint64 17 18--- @class TargetConnections 19--- @field by_beam table<number, ConnectionData> 20--- @field by_tower table<number, ConnectionData> 21 22--- @class TowerData 23--- @field entities TowerEntities 24--- @field tower_unit_number uint64 25--- @field turret_unit_number uint64 26 27--- @class TowerEntities 28--- @field collision LuaEntity 29--- @field tower LuaEntity 30--- @field turret LuaEntity 31 32local charging_rate =3000000 -- 3 MW 33local cooldown =10 34local loss_multiplier =1.8 35local range =20 36local required_energy =10000000 -- 10 MW 37 38local absorber_buffer_capacity =prototypes . equipment [ "kr-energy-absorber-equipment" ]. energy_source . buffer_capacity 39 40-- TOWER 41-- The entity that is interacted with 42 43--- @param e EntityBuiltEvent 44local function on_entity_built ( e ) 45local entity =e . entity or e . destination 46if not entity or not entity . valid then 47return 48end 49local entity_name =entity . name 50 51-- Internal entities should not be cloned 52if 53e . name == defines . events . on_entity_cloned 54and ( entity_name == "kr-tesla-coil-turret" or entity_name == "kr-tesla-coil-collision" ) 55then 56entity . destroy () 57return 58end 59 60if entity_name ~= "kr-tesla-coil" then 61return 62end 63 64local surface =entity . surface 65local unit_number =entity . unit_number --[[@as uint]] 66 67local turret =surface . create_entity ( { 68name ="kr-tesla-coil-turret" , 69position =entity . position , 70force =game . forces [ "kr-internal-turrets" ], 71create_build_effect_smoke =false , 72raise_built =true , 73} ) 74if not turret or not turret . valid then 75game . ( 76"Building tesla failed due to AAI Programmable Vehicles; This tesla coil will not function. To fix this, change the 'Deadzone construction denial range' map setting to zero." 77) 78entity . active =false 79return 80end 81turret . destructible =false 82 83local collision_entity =surface . create_entity ( { 84name ="kr-tesla-coil-collision" , 85position =entity . position , 86force =entity . force , 87create_build_effect_smoke =false , 88raise_built =true , 89} ) 90assert ( collision_entity , "Tesla coil collision entity was destroyed" ) 91collision_entity . destructible =false 92 93--- @type TowerData 94local data ={ 95entities ={ 96collision =collision_entity , 97tower =entity , 98turret =turret , 99} , 100tower_unit_number =unit_number , 101turret_unit_number =turret . unit_number , 102} 103 104storage . tesla_coil . turrets [ data . turret_unit_number ] =data 105storage . tesla_coil . towers [ unit_number ] =data 106end 107 108--- @param entity LuaEntity 109local function destroy_if_valid ( entity ) 110if entity . valid then 111entity . destroy () 112end 113end 114 115--- @param e EntityDestroyedEvent 116local function on_entity_destroyed ( e ) 117local entity =e . entity 118if not entity or not entity . valid or entity . name ~= "kr-tesla-coil" then 119return 120end 121 122local unit_number =entity . unit_number 123assert ( unit_number ) 124local tower_data =storage . tesla_coil . towers [ unit_number ] 125if not tower_data then 126return 127end 128 129destroy_if_valid ( tower_data . entities . collision ) 130destroy_if_valid ( tower_data . entities . turret ) 131 132storage . tesla_coil . turrets [ tower_data . turret_unit_number ] =nil 133storage . tesla_coil . towers [ unit_number ] =nil 134end 135 136-- TARGET 137-- An entity that will receive energy from a tesla coil 138 139--- @param target LuaEntity 140--- @return GridData? 141local function get_grid_data ( target ) 142--- @type LuaEquipmentGrid 143local grid 144if target . type == "character" then 145local armor_inventory =target . get_inventory ( defines . inventory . character_armor ) 146if armor_inventory and armor_inventory . valid then 147local armor =armor_inventory [ 1 ] 148if armor and armor . valid_for_read then 149grid =armor . grid 150end 151end 152else 153grid =target . grid 154end 155 156if grid then 157return { 158absorber =grid . find ( "kr-energy-absorber-equipment" ), 159grid =grid , 160} 161end 162end 163 164--- Updates the absorber object in a target's equipment grid 165--- @param grid LuaEquipmentGrid 166local function update_target_grid ( grid ) 167for _ , target_data in pairs ( storage . tesla_coil . targets ) do 168local grid_data =target_data . grid_data 169if grid_data . grid . valid and grid_data . grid == grid then 170grid_data . absorber =grid . find ( "kr-energy-absorber-equipment" ) 171end 172end 173end 174 175--- @param target LuaEntity 176--- @param tower_data TowerData 177local function add_target ( target , tower_data ) 178local target_unit_number =target . unit_number 179--- @cast target_unit_number -? 180local tower =tower_data . entities . tower 181if not tower . valid or tower . energy < required_energy then 182return 183end 184-- Check the target's equipment grid for an energy absorber 185local grid_data =get_grid_data ( target ) 186if grid_data and grid_data . absorber and grid_data . absorber . valid then 187--- @type TargetData 188local target_data ={ 189connections ={ 190--- @type table<number, ConnectionData> 191by_beam ={} , 192--- @type table<number, ConnectionData> 193by_tower ={} , 194} , 195entity =target , 196--- @type number? 197full_tick =nil , 198grid_data =grid_data , 199unit_number =target_unit_number , 200} 201storage . tesla_coil . targets [ target_unit_number ] =target_data 202return target_data 203end 204end 205 206--- @param target_unit_number number 207local function remove_target ( target_unit_number ) 208storage . tesla_coil . targets [ target_unit_number ] =nil 209end 210 211-- CONNECTION 212-- A connection between a tower and a target, comprising of a beam 213-- There can be unlimited connections per target 214 215--- @param target_data TargetData 216--- @param tower_data TowerData 217--- @return boolean 218local function add_connection ( target_data , tower_data ) 219-- Check if the absorber has space 220local absorber =target_data . grid_data . absorber 221if not absorber or not absorber . valid then 222remove_target ( target_data . unit_number ) 223return false 224end 225 226local tower =tower_data . entities . tower 227if not tower . valid then 228remove_target ( target_data . unit_number ) 229return false 230end 231 232if absorber . energy >= absorber_buffer_capacity then 233return false 234end 235 236-- Create beam entity 237local beam =tower_data . entities . tower . surface . create_entity ( { 238name ="kr-tesla-coil-electric-beam" , 239source =tower_data . entities . tower , 240source_offset ={ 0 , - 2.2 } , 241position =tower_data . entities . tower . position , 242target =target_data . entity , 243duration =0 , 244max_length =range , 245force =tower_data . entities . tower . force , 246raise_built =true , 247} ) 248if not beam then 249return false 250end 251local beam_number =script . register_on_object_destroyed ( beam ) 252 253storage . tesla_coil . beams [ beam_number ] ={ 254beam =beam , 255beam_number =beam_number , 256target_data =target_data , 257tower_data =tower_data , 258} 259 260--- @class ConnectionData 261local connection_data ={ 262beam =beam , 263beam_number =beam_number , 264tower_data =tower_data , 265} 266target_data . connections . by_beam [ beam_number ] =connection_data 267target_data . connections . by_tower [ tower_data . tower_unit_number ] =connection_data 268 269return true 270end 271 272--- @param target_data TargetData 273--- @param tower_data TowerData 274local function remove_connection ( target_data , tower_data ) 275local connection_data =target_data . connections . by_tower [ tower_data . tower_unit_number ] 276 277-- Destroy beam if it still exists 278if connection_data . beam . valid then 279connection_data . beam . destroy () 280end 281 282local beam_number =connection_data . beam_number 283storage . tesla_coil . beams [ beam_number ] =nil 284 285target_data . connections . by_beam [ beam_number ] =nil 286target_data . connections . by_tower [ tower_data . tower_unit_number ] =nil 287 288if table_size ( target_data . connections . by_beam ) == 0 then 289remove_target ( target_data . unit_number ) 290end 291end 292 293--- @param target_data TargetData 294--- @param tower_data TowerData 295local function update_connection ( target_data , tower_data ) 296local absorber =target_data . grid_data . absorber 297 298-- Check if the tower is powered 299if not absorber or not absorber . valid or tower_data . entities . tower . energy < required_energy then 300remove_connection ( target_data , tower_data ) 301return 302end 303 304local energy =absorber . energy 305if energy < absorber_buffer_capacity then 306-- Calculate how much to add 307local to_add =charging_rate / 60 * cooldown 308local result =energy + to_add 309local tower =tower_data . entities . tower 310 311if result >= absorber_buffer_capacity then 312absorber . energy =absorber_buffer_capacity 313target_data . full_tick =game . tick 314else 315absorber . energy =result 316target_data . full_tick =nil 317end 318 319tower . energy =tower . energy - ( to_add * loss_multiplier ) 320elseif target_data . full_tick and target_data . full_tick + cooldown <= game . tick then 321remove_connection ( target_data , tower_data ) 322end 323end 324 325--- @param target LuaEntity 326--- @param turret LuaEntity 327local function process_turret_fire ( target , turret ) 328local tower_data =storage . tesla_coil . turrets [ turret . unit_number ] 329if not tower_data then 330return 331end 332 333local target_data =storage . tesla_coil . targets [ target . unit_number ] 334if not target_data then 335target_data =add_target ( target , tower_data ) 336end 337 338if target_data then 339-- Just in case (#182) 340if not target_data . entity . valid then 341target_data . entity =target 342end 343local connection =target_data . connections . by_tower [ tower_data . tower_unit_number ] 344if connection or add_connection ( target_data , tower_data ) then 345update_connection ( target_data , tower_data ) 346end 347end 348end 349 350-- EVENTS 351 352--- @param e EventData.on_object_destroyed 353local function on_object_destroyed ( e ) 354local beam_data =storage . tesla_coil . beams [ e . registration_number ] 355if beam_data then 356remove_connection ( beam_data . target_data , beam_data . tower_data ) 357end 358end 359 360--- @param e EventData.on_equipment_inserted 361local function on_equipment_inserted ( e ) 362if not e . equipment . valid or e . equipment . name ~= "kr-energy-absorber-equipment" then 363return 364end 365update_target_grid ( e . grid ) 366end 367 368--- @param e EventData.on_equipment_removed 369local function on_equipment_removed ( e ) 370if e . equipment == "kr-energy-absorber-equipment" then 371update_target_grid ( e . grid ) 372end 373end 374 375--- @param e EventData.on_script_trigger_effect 376local function on_script_trigger_effect ( e ) 377if e . effect_id == "kr-tesla-coil-trigger" then 378process_turret_fire ( e . target_entity , e . source_entity ) 379end 380end 381 382local tesla_coil ={} 383 384function tesla_coil . on_init () 385storage . tesla_coil ={ 386--- @type table<number, BeamData> 387beams ={} , 388--- @type table<number, TowerData> 389turrets ={} , 390--- @type table<number, TowerData> 391towers ={} , 392--- @type table<number, TargetData> 393targets ={} , 394} 395end 396 397tesla_coil . events ={ 398[ defines . events . on_built_entity ] =on_entity_built , 399[ defines . events . on_entity_cloned ] =on_entity_built , 400[ defines . events . on_entity_died ] =on_entity_destroyed , 401[ defines . events . on_equipment_inserted ] =on_equipment_inserted , 402[ defines . events . on_equipment_removed ] =on_equipment_removed , 403[ defines . events . on_object_destroyed ] =on_object_destroyed , 404[ defines . events . on_player_mined_entity ] =on_entity_destroyed , 405[ defines . events . on_robot_built_entity ] =on_entity_built , 406[ defines . events . on_robot_mined_entity ] =on_entity_destroyed , 407[ defines . events . on_script_trigger_effect ] =on_script_trigger_effect , 408[ defines . events . script_raised_built ] =on_entity_built , 409[ defines . events . script_raised_destroy ] =on_entity_destroyed , 410[ defines . events . script_raised_revive ] =on_entity_built , 411[ defines . events . on_space_platform_built_entity ] =on_entity_built , 412[ defines . events . on_space_platform_mined_entity ] =on_entity_destroyed , 413} 414 415return tesla_coil 416 417--[[ 418-- Quick testing code 419event.register(remote.call("EditorExtensions", "debug_world_ready_event"), function() 420local surface = game.surfaces.nauvis 421 422local coils = { 423{ x = -9.5, y = -9.5 }, 424{ x = 10.5, y = -9.5 }, 425{ x = -9.5, y = 10.5 }, 426{ x = 10.5, y = 10.5 }, 427} 428for _, position in pairs(coils) do 429surface.create_entity({ 430name = "kr-tesla-coil", 431direction = defines.direction.north, 432position = position, 433force = game.forces.player, 434raise_built = true, 435create_build_effect_smoke = false, 436}) 437end 438surface.create_entity({ 439name = "ee-infinity-accumulator-primary-output", 440position = { x = -1, y = -9 }, 441force = game.forces.player, 442raise_built = true, 443create_build_effect_smoke = false, 444}) 445surface.create_entity({ 446name = "ee-super-substation", 447position = { x = 1, y = -9 }, 448force = game.forces.player, 449raise_built = true, 450create_build_effect_smoke = false, 451}) 452 453local character = game.get_player(1).character 454local armor_inventory = character.get_inventory(defines.inventory.character_armor) 455if armor_inventory and armor_inventory.valid then 456local armor = armor_inventory[1] 457if armor and armor.valid_for_read then 458armor.grid.put({ name = "kr-energy-absorber-equipment", position = { 5, 5 } }) 459end 460end 461end) 462]]