z_mirror/Krastorio2
git clone https://git.raiguard.me/z_mirror/Krastorio2
ad91ece5
discrete-steel-pipes
1local flib_position =require ( "__flib__.position" ) 2 3--- @class BiterVirusData 4--- @field active BiterVirusActiveData[] 5--- @field active_len integer 6--- @field to_iterate ChunkPositionAndAreaAndDistance[] 7--- @field to_iterate_len integer 8--- @field surface LuaSurface 9 10--- @class BiterVirusActiveData 11--- @field entities LuaEntity[] 12--- @field entities_len integer 13--- @field to_kill integer 14 15--- @class ChunkPositionAndAreaAndDistance : ChunkPositionAndArea 16--- @field distance_squared number 17 18--- @param e EventData.on_player_used_capsule 19local function on_player_used_capsule ( e ) 20local item =e . item 21if not item or not item . valid or item . name ~= "kr-biter-virus" then 22return 23end 24 25local player =game . get_player ( e . player_index ) 26if not player then 27return 28end 29 30local surface =player . surface 31if storage . biter_viruses [ surface . index ] then 32return 33end 34 35local origin =flib_position . to_chunk ( e . position ) 36--- @type ChunkPositionAndAreaAndDistance[] 37local chunks ={} 38for chunk in surface . get_chunks () do 39if surface . is_chunk_generated ( chunk ) then 40--- @cast chunk ChunkPositionAndAreaAndDistance 41chunk . distance_squared =flib_position . distance_squared ( chunk --[[@as ChunkPosition]] , origin ) 42chunks [ # chunks + 1 ] =chunk 43end 44end 45table . sort ( chunks , function ( pos_a , pos_b ) 46-- Sort backwards so that we can remove items from the end. 47return pos_a . distance_squared > pos_b . distance_squared 48end ) 49 50storage . biter_viruses [ surface . index ] ={ 51active ={} , 52active_len =0 , 53to_iterate =chunks , 54to_iterate_len =# chunks , 55surface =surface , 56} 57end 58 59local function on_tick () 60if not storage . biter_viruses then 61return 62end 63--- @type uint[] 64local to_remove ={} 65for surface_index , virus in pairs ( storage . biter_viruses ) do 66if not virus . surface . valid or ( virus . active_len == 0 and virus . to_iterate_len == 0 ) then 67to_remove [ # to_remove + 1 ] =surface_index 68goto continue 69end 70 71for _ =1 , 5 - virus . active_len do 72if virus . to_iterate_len > 0 then 73local chunk =table . remove ( virus . to_iterate , virus . to_iterate_len ) 74virus . to_iterate_len =virus . to_iterate_len - 1 75 76local entities =virus . surface . find_entities_filtered ( { 77area =chunk . area , 78force ="enemy" , 79type ={ "unit" , "unit-spawner" } , 80} ) 81local entities_len =# entities 82if entities_len > 0 then 83virus . active_len =virus . active_len + 1 84virus . active [ virus . active_len ] ={ 85entities =entities , 86entities_len =entities_len , 87to_kill =math . ceil ( entities_len / 3 ), 88} 89end 90end 91end 92 93local active_to_remove ={} 94for i =1 , virus . active_len do 95local active =virus . active [ i ] 96if active then 97local entity =table . remove ( active . entities , active . entities_len ) 98active . entities_len =active . entities_len - 1 99if entity and entity . valid then 100entity . die () 101active . to_kill =active . to_kill - 1 102end 103if active . to_kill == 0 then 104active_to_remove [ # active_to_remove + 1 ] =i 105end 106end 107end 108for i =# active_to_remove , 1 , - 1 do 109table . remove ( virus . active , active_to_remove [ i ]) 110virus . active_len =virus . active_len - 1 111end 112 113:: continue :: 114end 115 116for i =1 , # to_remove do 117storage . biter_viruses [ to_remove [ i ]] =nil 118end 119end 120 121local virus ={} 122 123function virus . on_init () 124--- @type table<uint, BiterVirusData> 125storage . biter_viruses ={} 126end 127 128virus . events ={ 129[ defines . events . on_player_used_capsule ] =on_player_used_capsule , 130[ defines . events . on_tick ] =on_tick , 131} 132 133return virus