z_mirror/Krastorio2
git clone https://git.raiguard.me/z_mirror/Krastorio2
07409ca6
four-space-indentation
1local flib_position =require ( "__flib__.position" ) 2local flib_table =require ( "__flib__.table" ) 3 4local data_util ={} 5 6-- To enable verbose mode, either hook the debug adapter or add a DEBUG.lua file to the mod root. 7local verbose =__DebugAdapter ~= nil or pcall ( require , "DEBUG" ) 8 9--- Prints the given error message to the log when in debug mode. 10--- @param message string 11function data_util . error ( message ) 12if not verbose then 13return 14end 15local output ="\n KRASTORIO 2 ERROR: " .. message 16local i =2 17while true do 18local info =debug . getinfo ( i , "nSl" ) 19if not info then 20break 21end 22 23output =output .. "\n " .. info . source .. ":" .. info . currentline 24if info . name then 25output =output .. " in function '" .. info . name .. "'" 26else 27output =output .. " in main chunk" 28end 29 30i =i + 1 31end 32log ( output ) 33end 34 35--- Calls `data_util.error` with the given `message` if `obj` is falsey. 36--- @param obj any? 37--- @param message string 38--- @return boolean passed "Whether the assert passed." 39function data_util . assert ( obj , message ) 40if not obj then 41data_util . error ( message ) 42return false 43end 44return true 45end 46 47--- Overwrites or adds ammo effects for the given technology. 48--- @param tech data.TechnologyPrototype 49--- @param effects data.Modifier[] 50function data_util . update_ammo_effects ( tech , effects ) 51if not tech . effects then 52tech . effects ={} 53end 54 55for _ , updated_effect in pairs ( effects ) do 56local exists =false 57for _ , effect in pairs ( tech . effects ) do 58if 59effect . type == updated_effect . type 60and ( 61( effect . ammo_category ~= nil and effect . ammo_category == updated_effect . ammo_category ) 62or ( effect . turret_id ~= nil and effect . turret_id == updated_effect . turret_id ) 63) 64then 65effect . modifier =updated_effect . modifier --- @diagnostic disable-line:assign-type-mismatch 66exists =true 67break 68end 69end 70if not exists then 71table . insert ( 72tech . effects , 73{ 74type =updated_effect . type , 75ammo_category =updated_effect . ammo_category , 76modifier =updated_effect . modifier , 77} --- @diagnostic disable-line:assign-type-mismatch 78) 79end 80end 81end 82 83--- @param technology_name data.TechnologyID 84--- @param new_effect data.Modifier 85function data_util . add_effect ( technology_name , new_effect ) 86local technology =data . raw . technology [ technology_name ] 87if not technology then 88data_util . error ( "Technology " .. technology_name .. " does not exist." ) 89return 90end 91local effects =technology . effects 92if not effects or not next ( effects ) then 93technology . effects ={ new_effect } 94return 95end 96 97local found =false 98for _ , effect in pairs ( effects ) do 99if effect . type == new_effect . type then 100-- TODO: Update for new effect types. 101if effect . type == "gun-speed" then 102if effect . ammo_category == new_effect . ammo_category and effect . modifier == new_effect . modifier then 103found =true 104break 105end 106elseif effect . type == "ammo-damage" then 107if effect . ammo_category == new_effect . ammo_category and effect . modifier == new_effect . modifier then 108found =true 109break 110end 111elseif effect . type == "give-item" then 112if effect . item == new_effect . item and effect . count == new_effect . count then 113found =true 114break 115end 116elseif effect . type == "turret-attack" then 117if effect . turret_id == new_effect . turret_id and effect . modifier == new_effect . modifier then 118found =true 119break 120end 121elseif effect . type == "unlock-recipe" then 122if effect . recipe == new_effect . recipe then 123found =true 124break 125end 126elseif effect . type == "nothing" then 127if effect . effect_description == new_effect . effect_description then 128found =true 129break 130end 131else 132if effect . modifier == new_effect . modifier then 133found =true 134break 135end 136end 137end 138end 139 140if not found then 141table . insert ( effects , new_effect ) 142end 143end 144 145--- Adds the given recipe as an unlock of the given technology. 146--- @param technology_name data.TechnologyID 147--- @param recipe_name data.RecipeID 148function data_util . add_recipe_unlock ( technology_name , recipe_name ) 149local technology =data . raw . technology [ technology_name ] 150if not technology then 151data_util . error ( "Technology " .. technology_name .. " does not exist." ) 152return 153end 154for _ , effect in pairs ( technology . effects ) do 155if effect . type == "unlock-recipe" and effect . recipe == recipe_name then 156data_util . error ( "Technology " .. technology_name .. " already unlocks recipe " .. recipe_name .. "." ) 157return 158end 159end 160table . insert ( technology . effects , { type ="unlock-recipe" , recipe =recipe_name } ) 161end 162 163--- Removes the given recipe from the unlocks of the given technology. 164--- @param technology_name data.TechnologyID 165--- @param recipe_name data.RecipeID 166function data_util . remove_recipe_unlock ( technology_name , recipe_name ) 167local technology =data . raw . technology [ technology_name ] 168if not technology then 169data_util . error ( "Technology " .. technology_name .. " does not exist." ) 170return 171end 172for i , effect in pairs ( technology . effects ) do 173if effect . type == "unlock-recipe" and effect . recipe == recipe_name then 174table . remove ( technology . effects , i ) 175return 176end 177end 178data_util . error ( "Technology " .. technology_name .. " does not unlock recipe " .. recipe_name .. "." ) 179end 180 181--- Adds the given prerequisite to the technology. 182--- @param technology_id data.TechnologyID 183--- @param prerequisite_id data.TechnologyID 184function data_util . add_prerequisite ( technology_id , prerequisite_id ) 185local technology =data . raw . technology [ technology_id ] 186if not technology then 187data_util . error ( "Technology " .. technology_id .. " does not exist." ) 188return 189end 190local prerequisite =data . raw . technology [ prerequisite_id ] 191if not prerequisite then 192data_util . error ( "Technology prerequisite " .. prerequisite_id .. " does not exist." ) 193return 194end 195if not technology . prerequisites then 196technology . prerequisites ={ prerequisite_id } 197return 198end 199if flib_table . find ( technology . prerequisites , prerequisite_id ) then 200data_util . error ( "Technology " .. technology_id .. " already has prerequisite " .. prerequisite_id ) 201return 202end 203table . insert ( technology . prerequisites , prerequisite_id ) 204end 205 206--- Removes the given prerequisite from the technology. 207--- @param technology_id data.TechnologyID 208--- @param prerequisite_id data.TechnologyID 209function data_util . remove_prerequisite ( technology_id , prerequisite_id ) 210local technology =data . raw . technology [ technology_id ] 211if not technology then 212data_util . error ( "Technology " .. technology_id .. " does not exist." ) 213return 214end 215local prerequisite =data . raw . technology [ prerequisite_id ] 216if not prerequisite then 217data_util . error ( "Technology prerequisite " .. prerequisite_id .. " does not exist." ) 218return 219end 220local i =flib_table . find ( technology . prerequisites or {} , prerequisite_id ) 221if not i then 222data_util . error ( "Technology " .. technology_id .. " does not have prerequisite " .. prerequisite_id ) 223return 224end 225table . remove ( technology . prerequisites , i ) 226end 227 228--- Converts one research unit ingredient to another, updating science pack prerequisites if needed. 229--- @param technology_id data.TechnologyID 230--- @param from_id data.ItemID 231--- @param to_id data.ItemID 232function data_util . convert_research_unit_ingredient ( technology_id , from_id , to_id ) 233local technology =data . raw . technology [ technology_id ] 234if not technology then 235data_util . error ( "Technology " .. technology_id .. " does not exist." ) 236return 237end 238if not technology . unit or not technology . unit . ingredients then 239data_util . error ( "Technology " .. technology_id .. " has no research unit ingredients." ) 240return 241end 242local converted =false 243for _ , ingredient in pairs ( technology . unit . ingredients ) do 244if ingredient [ 1 ] == from_id then 245converted =true 246ingredient [ 1 ] =to_id 247elseif ingredient [ 1 ] == to_id then 248data_util . error ( "Technology " .. technology_id .. " already has research unit ingredient " .. to_id ) 249return 250end 251end 252if not converted then 253data_util . error ( "Technology " .. technology_id .. " does not have research unit ingredient " .. from_id ) 254return 255end 256-- XXX: Hardcoding the science pack name like this feels bad, but it's what the old code did... 257local from_index =flib_table . find ( technology . prerequisites , from_id ) 258if from_index then 259table . remove ( technology . prerequisites , from_index ) 260end 261local new_tech =data . raw . technology [ to_id ] 262if not new_tech then 263return 264end 265if not technology . prerequisites then 266technology . prerequisites ={ to_id } 267return 268end 269if not flib_table . find ( technology . prerequisites , to_id ) then 270table . insert ( technology . prerequisites , to_id ) 271end 272end 273 274--- Adds the given research ingredient to the technology. 275--- @param technology_id data.TechnologyID 276--- @param ingredient_id data.ItemID 277--- @param ingredient_count uint? Defaults to 1. 278function data_util . add_research_unit_ingredient ( technology_id , ingredient_id , ingredient_count ) 279ingredient_count =ingredient_count or 1 280local technology =data . raw . technology [ technology_id ] 281if not technology then 282data_util . error ( "Technology " .. technology_id .. " does not exist." ) 283return 284end 285if technology . research_trigger then 286data_util . error ( "Technology " .. technology_id .. " has a research trigger, so cannot have ingredients." ) 287return 288end 289local unit =technology . unit 290if not unit then 291data_util . error ( "Technology " .. technology_id .. " has no research unit." ) 292return 293end 294for _ , ingredient in pairs ( technology . unit . ingredients ) do 295if ingredient [ 1 ] == ingredient_id then 296data_util . error ( "Technology " .. technology_id .. " already has research unit ingredient" .. ingredient_id ) 297return 298end 299end 300table . insert ( technology . unit . ingredients , { ingredient_id , ingredient_count } ) 301end 302 303--- Removes the given research ingredient from the technology. 304--- @param technology_id data.TechnologyID 305--- @param ingredient_id data.ItemID 306function data_util . remove_research_unit_ingredient ( technology_id , ingredient_id ) 307local technology =data . raw . technology [ technology_id ] 308if not technology then 309data_util . error ( "Technology " .. technology_id .. " does not exist." ) 310return 311end 312if not technology . unit then 313data_util . error ( "Technology " .. technology_id .. " has no research units." ) 314return 315end 316for i , ingredient in pairs ( technology . unit . ingredients ) do 317if ingredient [ 1 ] == ingredient_id then 318table . remove ( technology . unit . ingredients , i ) 319return 320end 321end 322data_util . error ( 323"Technology " .. technology_id .. " does not have research unit ingredient " .. ingredient_id .. "." 324) 325end 326 327--- Returns a technology that unlocks the given recipe. The technology returned will be the one that was added earliest. 328--- @param recipe_id data.RecipeID 329--- @return data.TechnologyPrototype? 330function data_util . get_technology_for_recipe ( recipe_id ) 331for _ , technology in pairs ( data . raw . technology ) do 332for _ , effect in pairs ( technology . effects or {} ) do 333if effect . type == "unlock-recipe" and effect . recipe == recipe_id then 334return technology 335end 336end 337end 338end 339 340--- Converts a furnace prototype into an assembling machine prototype. 341--- @param furnace_name data.EntityID 342--- @return data.AssemblingMachinePrototype? 343function data_util . furnace_to_assembler ( furnace_name ) 344local furnace =data . raw . furnace [ furnace_name ] 345if not furnace then 346data_util . error ( "Furnace " .. furnace_name .. " does not exist." ) 347return 348end 349 350local assembler =table . deepcopy ( furnace ) --[[@as data.AssemblingMachinePrototype]] 351assembler . type ="assembling-machine" 352assembler . source_inventory_size =nil --- @diagnostic disable-line 353assembler . energy_source . emissions_per_minute ={ pollution =2 } 354assembler . energy_usage ="0.2MW" 355data . raw . furnace [ furnace_name ] =nil 356data : extend ( { assembler } ) 357return assembler 358end 359 360--- Returns a copy of the given prototype's icons in the standard format. 361--- @param prototype k2.PrototypeWithIcons 362--- @return data.IconData[] 363function data_util . get_icons ( prototype ) 364local icons =prototype . icons -- LuaLS isn't inferring the dropped optional unless we assign it to a local first. 365if icons then 366return table . deepcopy ( icons ) 367end 368if prototype . icon then 369return { { icon =prototype . icon , icon_size =prototype . icon_size } } 370end 371return {} 372end 373 374--- Converts the given prototype's icons to the standard format and returns a reference to them. 375--- The game will throw an error if you provide an empty icons array, so if using the function, care must be taken to 376--- ensure that at least one icon layer exists at tne end of loading. 377--- @param prototype k2.PrototypeWithIcons 378--- @return data.IconData[] 379function data_util . standardize_icons ( prototype ) 380if not prototype . icons then 381prototype . icons ={} 382if prototype . icon then 383table . insert ( prototype . icons , { icon =prototype . icon , icon_size =prototype . icon_size } ) 384prototype . icon =nil 385prototype . icon_size =nil 386end 387end 388return prototype . icons 389end 390 391--- Overrides the prototype's icon. 392--- @param prototype k2.PrototypeWithIcons 393--- @param icon data.FileName 394--- @param icon_size double? 395function data_util . set_icon ( prototype , icon , icon_size ) 396data_util . assert ( prototype , "Provided prototype was nil." ) 397if prototype . icons then 398prototype . icons =nil 399end 400prototype . icon =icon 401prototype . icon_size =icon_size 402end 403 404--- Overrides the prototype's icons array. 405--- @param prototype k2.PrototypeWithIcons 406--- @param icons data.IconData[] 407function data_util . set_icons ( prototype , icons ) 408data_util . assert ( prototype , "Provided prototype was nil." ) 409prototype . icons =icons 410prototype . icon =nil 411prototype . icon_size =nil 412end 413 414--- Fields are analagous to `data.IconData`. 415--- @class k2.IconTransformOptions 416--- @field shift Vector? 417--- @field scale double? 418 419--- Applies the given transformations to each layer in the icons array in-place and returns the array. 420--- @param icons data.IconData[] 421--- @param transforms k2.IconTransformOptions 422--- @return data.IconData[] 423function data_util . transform_icons ( icons , transforms ) 424for _ , icon in pairs ( icons ) do 425if transforms . shift then 426icon . shift =flib_position . add (( icon . shift or { 0 , 0 } ), transforms . shift ) 427end 428if transforms . scale then 429icon . scale =( icon . scale or 1 ) * transforms . scale / ( icon . icon_size or 64 ) * 64 430end 431end 432return icons 433end 434 435--- Merges or adds the given ingredient to the recipe matching the given name. 436--- @param recipe_name data.RecipeID 437--- @param new_ingredient data.IngredientPrototype 438function data_util . merge_or_add_ingredient ( recipe_name , new_ingredient ) 439local recipe =data . raw . recipe [ recipe_name ] 440if not recipe then 441data_util . error ( "Recipe " .. recipe_name .. " does not exist" ) 442return 443end 444recipe . ingredients =recipe . ingredients or {} 445for _ , ingredient in pairs ( recipe . ingredients ) do 446if ingredient . name == new_ingredient . name then 447ingredient . amount =ingredient . amount + new_ingredient . amount 448return 449end 450end 451table . insert ( recipe . ingredients , new_ingredient ) 452end 453 454--- Overwrites or adds the given ingredient to the recipe matching the given name. 455--- @param recipe_name data.RecipeID 456--- @param new_ingredient data.IngredientPrototype 457function data_util . overwrite_or_add_ingredient ( recipe_name , new_ingredient ) 458local recipe =data . raw . recipe [ recipe_name ] 459if not recipe then 460data_util . error ( "Recipe " .. recipe_name .. " does not exist" ) 461return 462end 463recipe . ingredients =recipe . ingredients or {} 464for i , ingredient in pairs ( recipe . ingredients ) do 465if ingredient . name == new_ingredient . name then 466recipe . ingredients [ i ] =new_ingredient 467return 468end 469end 470table . insert ( recipe . ingredients , new_ingredient ) 471end 472 473--- Removes old_ingredient_name from the recipe matching the given name, then overwrites any ingredient with the 474--- same name as the new ingredient with the given new_ingredient. 475--- @param recipe_name data.RecipeID 476--- @param old_ingredient_name data.FluidID|data.ItemID 477--- @param new_ingredient data.IngredientPrototype 478function data_util . replace_and_overwrite_or_add_ingredient ( recipe_name , old_ingredient_name , new_ingredient ) 479local recipe =data . raw . recipe [ recipe_name ] 480if not recipe then 481data_util . error ( "Recipe " .. recipe_name .. " does not exist." ) 482return 483end 484recipe . ingredients =recipe . ingredients or {} 485data_util . remove_ingredient ( recipe_name , old_ingredient_name ) 486data_util . overwrite_or_add_ingredient ( recipe_name , new_ingredient ) 487end 488 489--- Removes old_ingredient_name from the recipe matching the given name, then merges or adds the new ingredient. 490--- @param recipe_name data.RecipeID 491--- @param old_ingredient_name data.FluidID|data.ItemID 492--- @param new_ingredient data.IngredientPrototype 493function data_util . replace_and_merge_or_add_ingredient ( recipe_name , old_ingredient_name , new_ingredient ) 494local recipe =data . raw . recipe [ recipe_name ] 495if not recipe then 496data_util . error ( "Recipe " .. recipe_name .. " does not exist" ) 497return 498end 499recipe . ingredients =recipe . ingredients or {} 500data_util . remove_ingredient ( recipe_name , old_ingredient_name ) 501data_util . merge_or_add_ingredient ( recipe_name , new_ingredient ) 502end 503 504--- Converts the given ingredient to the new ingredient, carrying over other properties. 505--- @param recipe_name data.RecipeID 506--- @param old_ingredient_name data.FluidID|data.ItemID 507--- @param new_ingredient_name data.FluidID|data.ItemID 508function data_util . convert_ingredient ( recipe_name , old_ingredient_name , new_ingredient_name ) 509local recipe =data . raw . recipe [ recipe_name ] 510if not recipe then 511data_util . error ( "Recipe " .. recipe_name .. " does not exist." ) 512return 513end 514if not recipe . ingredients then 515data_util . error ( "Recipe " .. recipe_name .. " has no ingredients." ) 516return 517end 518for _ , ingredient in pairs ( recipe . ingredients ) do 519if ingredient . name == old_ingredient_name then 520ingredient . name =new_ingredient_name 521break 522end 523end 524end 525 526--- Remove the given ingredient from the recipe. 527--- @param recipe_name data.RecipeID 528--- @param ingredient_name data.FluidID|data.ItemID 529function data_util . remove_ingredient ( recipe_name , ingredient_name ) 530local recipe =data . raw . recipe [ recipe_name ] 531if not recipe then 532data_util . error ( "Recipe " .. recipe_name .. " does not exist." ) 533return 534end 535if not recipe . ingredients then 536data_util . error ( "Recipe " .. recipe_name .. " has no ingredients." ) 537return 538end 539for i , ingredient in pairs ( recipe . ingredients ) do 540if ingredient . name == ingredient_name then 541table . remove ( recipe . ingredients , i ) 542return 543end 544end 545data_util . error ( "Recipe " .. recipe_name .. " does not have ingredient " .. ingredient_name .. "." ) 546end 547 548--- Merges or adds the given prodct to the recipe matching the given name. 549--- @param recipe_name data.RecipeID 550--- @param new_product data.ProductPrototype 551function data_util . merge_or_add_product ( recipe_name , new_product ) 552local recipe =data . raw . recipe [ recipe_name ] 553if not recipe then 554data_util . error ( "Recipe " .. recipe_name .. " does not exist" ) 555return 556end 557recipe . results =recipe . results or {} 558for _ , product in pairs ( recipe . results ) do 559if product . name == new_product . name then 560product . amount =product . amount + new_product . amount 561return 562end 563end 564table . insert ( recipe . results , new_product ) 565end 566 567--- Overwrites or adds the given product to the recipe matching the given name. 568--- @param recipe_name data.RecipeID 569--- @param new_product data.ProductPrototype 570function data_util . overwrite_or_add_product ( recipe_name , new_product ) 571local recipe =data . raw . recipe [ recipe_name ] 572if not recipe then 573data_util . error ( "Recipe " .. recipe_name .. " does not exist" ) 574return 575end 576recipe . results =recipe . results or {} 577for i , product in pairs ( recipe . results ) do 578if product . name == new_product . name then 579recipe . results [ i ] =new_product 580return 581end 582end 583table . insert ( recipe . results , new_product ) 584end 585 586--- Removes old_product_name from the recipe matching the given name, then overwrites any product with the 587--- same name as the new product with the given new_product. 588--- @param recipe_name data.RecipeID 589--- @param old_product_name data.FluidID|data.ItemID 590--- @param new_product data.ProductPrototype 591function data_util . replace_and_overwrite_or_add_product ( recipe_name , old_product_name , new_product ) 592local recipe =data . raw . recipe [ recipe_name ] 593if not recipe then 594data_util . error ( "Recipe " .. recipe_name .. " does not exist." ) 595return 596end 597recipe . results =recipe . results or {} 598data_util . remove_product ( recipe_name , old_product_name ) 599data_util . overwrite_or_add_product ( recipe_name , new_product ) 600end 601 602--- Removes old_product_name from the recipe matching the given name, then merges or adds the new product. 603--- @param recipe_name data.RecipeID 604--- @param old_product_name data.FluidID|data.ItemID 605--- @param new_product data.ProductPrototype 606function data_util . replace_and_merge_or_add_product ( recipe_name , old_product_name , new_product ) 607local recipe =data . raw . recipe [ recipe_name ] 608if not recipe then 609data_util . error ( "Recipe " .. recipe_name .. " does not exist" ) 610return 611end 612recipe . results =recipe . results or {} 613data_util . remove_product ( recipe_name , old_product_name ) 614data_util . merge_or_add_product ( recipe_name , new_product ) 615end 616 617--- Remove the given product from the recipe. 618--- @param recipe_name data.RecipeID 619--- @param product_name data.FluidID|data.ItemID 620function data_util . remove_product ( recipe_name , product_name ) 621local recipe =data . raw . recipe [ recipe_name ] 622if not recipe then 623data_util . error ( "Recipe " .. recipe_name .. " does not exist." ) 624return 625end 626if not recipe . results then 627data_util . error ( "Recipe " .. recipe_name .. " has no products." ) 628return 629end 630for i , product in pairs ( recipe . results ) do 631if product . name == product_name then 632table . remove ( recipe . results , i ) 633return 634end 635end 636data_util . error ( "Recipe " .. recipe_name .. " does not have product " .. product_name .. "." ) 637end 638 639--- @param lab_name data.EntityID 640--- @param input_name data.ItemID 641function data_util . remove_lab_input ( lab_name , input_name ) 642local lab =data . raw . lab [ lab_name ] 643data_util . assert ( lab , "Lab " .. lab_name .. " does not exist." ) 644local inputs =lab . inputs 645data_util . assert ( inputs , "Lab inputs are nil." ) 646for i =1 , # inputs do 647if inputs [ i ] == input_name then 648table . remove ( inputs , i ) 649return 650end 651end 652data_util . error ( "Lab " .. lab_name .. " does not contain input " .. input_name .. "." ) 653end 654 655--- @param energy_source data.EnergySource 656--- @param category_name data.FuelCategoryID 657function data_util . add_fuel_category ( energy_source , category_name ) 658if energy_source . type ~= "burner" then 659data_util . error ( "Energy source must be a burner to add a fuel category." ) 660return 661end 662if not energy_source . fuel_categories then 663energy_source . fuel_categories ={} 664end 665table . insert ( energy_source . fuel_categories , category_name ) 666end 667 668return data_util