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