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