z_mirror/MouseOverConstruction
git clone https://git.raiguard.me/z_mirror/MouseOverConstruction
7a81c3d
insertion
1local common =require ( "scripts.common" ) 2 3--- @generic T 4--- @param array T[] 5--- @param pred fun(elem: T): boolean 6local function remove_if ( array , pred ) 7local to_remove ={} 8for i =1 , # array do 9if pred ( array [ i ]) then 10to_remove [ # to_remove + 1 ] =i 11end 12end 13-- Remove from back to front to keep the indices valid 14for i =# to_remove , 1 , - 1 do 15table . remove ( array , to_remove [ i ]) 16end 17end 18 19--- @param base LocalisedString 20--- @param child LocalisedString 21local function append_localised_string ( base , child ) 22--- @cast base -? 23 24local len =# base 25 26if len < 18 then 27base [ len + 1 ] =child 28return 29end 30 31if len == 18 then 32base [ 19 ] ={ "" } 33end 34 35append_localised_string ( base [ 19 ], child ) 36end 37 38--- @alias Deltas table<string, {name: string, quality: string, count: integer}> 39 40--- @param deltas Deltas 41--- @param name string 42--- @param quality string 43--- @param count integer 44local function add_delta ( deltas , name , quality , count ) 45local key =name .. "/" .. quality 46local delta =deltas [ key ] 47if not delta then 48delta ={ name =name , quality =quality , count =0 } 49deltas [ key ] =delta 50end 51delta . count =delta . count + count 52end 53 54--- @param player LuaPlayer 55--- @param entity LuaEntity 56return function ( player , entity ) 57if not player . mod_settings [ "moc-enable-insertion" ]. value then 58return 59end 60 61if entity . type == "entity-ghost" then 62return 63end 64 65local proxy =entity . item_request_proxy 66if not proxy then 67return 68end 69 70--- @type Deltas 71local deltas ={} 72 73local entity_insert_plan =proxy . insert_plan 74remove_if ( entity_insert_plan , function ( insert_plan ) 75-- TODO: Equipment grids 76local inventories =insert_plan . items . in_inventory 77if not inventories then 78return false 79end 80 81-- Despite the docs, these reads are not LuaObjects because insert_plan is a PropertyTree... 82local name =insert_plan . id . name --[[@as string]] 83local quality_name =insert_plan . id . quality or "normal" --[[@as string]] 84local quality =prototypes . quality [ quality_name ] 85 86remove_if ( inventories , function ( inventory_position ) 87local inventory =entity . get_inventory ( inventory_position . inventory ) 88if not inventory then 89return false 90end 91 92if not inventory_position . count then 93inventory_position . count =1 94end 95 96while inventory_position . count > 0 do 97local item =common . get_item ( player , name , quality )() 98if not item then 99return false 100end 101 102-- For some ungodly reason, stack is zero indexed! 103local destination_stack =inventory [ inventory_position . stack + 1 ] 104local to_transfer =math . min ( inventory_position . count , item . count ) 105assert ( destination_stack . transfer_stack ( item , to_transfer ), "Inventory transfer failed" ) 106inventory_position . count =inventory_position . count - to_transfer 107-- Negate because the deltas are relative to the player inventory. 108add_delta ( deltas , name , quality_name , - to_transfer ) 109end 110 111return inventory_position . count == 0 112end ) 113 114return not next ( inventories ) 115end ) 116proxy . insert_plan =entity_insert_plan 117 118local entity_removal_plan =proxy . removal_plan 119remove_if ( entity_removal_plan , function ( removal_plan ) 120-- TODO: Equipment grids 121local inventories =removal_plan . items . in_inventory 122if not inventories then 123return false 124end 125 126-- Despite the docs, these reads are not LuaObjects because removal_plan is a PropertyTree... 127local name =removal_plan . id . name --[[@as string]] 128local item_prototype =prototypes . item [ name ] 129local quality_name =removal_plan . id . quality or "normal" --[[@as string]] 130local quality =prototypes . quality [ quality_name ] 131 132remove_if ( inventories , function ( inventory_position ) 133local inventory =entity . get_inventory ( inventory_position . inventory ) 134if not inventory then 135return false 136end 137 138local count_to_remove =inventory_position . count or 1 139 140-- For some ungodly reason, stack is zero indexed! 141local source_stack =inventory [ inventory_position . stack + 1 ] 142-- This probably can't ever happen. 143if source_stack . count < count_to_remove then 144return false 145end 146 147local destination_stack_iterator =common . get_item ( player , name , quality ) 148repeat 149local destination_stack =destination_stack_iterator () 150if not destination_stack then 151return false 152end 153 154local to_transfer =math . min ( inventory_position . count , destination_stack . count ) 155assert ( destination_stack . transfer_stack ( destination_stack , to_transfer ), "Inventory transfer failed" ) 156inventory_position . count =inventory_position . count - to_transfer 157-- Negate because the deltas are relative to the player inventory. 158add_delta ( deltas , name , quality_name , - to_transfer ) 159until count_to_remove <= 0 or not destination_stack 160 161return inventory_position . count == 0 162end ) 163 164return not next ( inventories ) 165end ) 166proxy . removal_plan =entity_removal_plan 167 168table . sort ( deltas , function ( a , b ) 169return a . count > b . count 170end ) 171 172--- @type LocalisedString 173local output ={ "" } 174 175for _ , delta in pairs ( deltas ) do 176if delta . count == 0 then 177goto continue 178end 179 180player . play_sound ( { path ="item-drop/" .. delta . name } ) 181local delta_string =tostring ( delta . count ) 182if delta . count > 0 then 183delta_string ="+" .. delta_string 184end 185append_localised_string ( output , { 186"" , 187delta_string , 188" " , 189"[item=" .. delta . name .. "] " , 190prototypes . item [ delta . name ]. localised_name , 191"\n" , 192} ) 193 194:: continue :: 195end 196 197player . create_local_flying_text ( { 198position =entity . position , 199text =output , 200} ) 201 202return true 203end