z_mirror/Krastorio2
git clone https://git.raiguard.me/z_mirror/Krastorio2
041f29c4
santichu95/patch-1
1local flib_gui =require ( "__flib__.gui" ) 2local flib_math =require ( "__flib__.math" ) 3local flib_position =require ( "__flib__.position" ) 4 5local util =require ( "scripts.util" ) 6 7--- @alias IntergalacticTransceiverStatus 8--- | "charging" 9--- | "discharging" 10--- | "not_enough_input" 11--- | "ready" 12 13local defines_to_status ={ 14[ defines . entity_status . charging ] ="charging" , 15[ defines . entity_status . discharging ] ="discharging" , 16} 17 18--- @type table<IntergalacticTransceiverStatus, { label: LocalisedString, sprite: SpritePath }> 19local status_properties ={ 20charging ={ 21label ={ "entity-status.charging" } , 22icon ="utility/status_working" , 23} , 24discharging ={ 25alert_label ={ "gui.kr-intergalactic-transceiver-alert-discharging" } , 26label ={ "entity-status.discharging" } , 27icon ="utility/status_not_working" , 28} , 29not_enough_input ={ 30alert_label ={ "gui.kr-intergalactic-transceiver-alert-not-enough-input" } , 31label ={ "entity-status.kr-not-enough-input" } , 32icon ="utility/status_not_working" , 33tooltip ={ "entity-status-tooltip.kr-not-enough-input" } , 34} , 35no_power ={ 36alert_label ={ "gui.kr-intergalactic-transceiver-alert-no-power" } , 37label ={ "entity-status.no-power" } , 38icon ="utility/status_not_working" , 39} , 40ready ={ 41alert_label ={ "gui.kr-intergalactic-transceiver-alert-ready" } , 42label ={ "entity-status.kr-ready" } , 43icon ="utility/status_working" , 44} , 45} 46 47local min_charge_delta =2.5e8 -- Requires charge rate of 15 GW 48local max_charge_delta =2e9 49local max_energy =prototypes . entity [ "kr-intergalactic-transceiver" ]. electric_energy_source_prototype . buffer_capacity 50- max_charge_delta 51local energy_drain =50e9 52 53--- @param transceiver_data IntergalacticTransceiverForceData 54local function activate_transceiver ( transceiver_data ) 55local entity =transceiver_data . entity 56local entity_surface =entity . surface 57local entity_position =entity . position 58for _ , player in pairs ( entity . force . connected_players ) do 59if player . surface == entity_surface and flib_position . distance ( entity_position , player . position ) <= 100 then 60player . set_controller ( { 61type =defines . controllers . cutscene , 62waypoints ={ 63{ 64position =entity . position , 65zoom =1.2 , 66transition_time =70 , 67time_to_wait =30 , 68} , 69{ 70position =entity . position , 71zoom =1.2 , 72transition_time =0 , 73time_to_wait =15 , 74} , 75{ 76position =entity . position , 77zoom =0.8 , 78transition_time =130 , 79time_to_wait =10 , 80} , 81{ 82position =entity . position , 83zoom =1.2 , 84transition_time =200 , 85time_to_wait =60 , 86} , 87} , 88final_transition_time =60 , 89} ) 90end 91end 92storage . intergalactic_transceiver . in_cutscene [ entity . force_index ] =true 93end 94 95--- @param e EventData.on_cutscene_finished 96local function on_cutscene_finished ( e ) 97local player =game . get_player ( e . player_index ) 98if not player then 99return 100end 101-- FIXME: What if the character dies while in the cutscene? 102if not storage . intergalactic_transceiver or not storage . intergalactic_transceiver . in_cutscene [ player . force_index ] then 103return 104end 105storage . intergalactic_transceiver . in_cutscene [ player . force_index ] =nil 106player . force . technologies [ "kr-logo" ]. enabled =true 107if not storage . intergalactic_transceiver . is_victory then 108return 109end 110game . set_game_state ( { 111can_continue =true , 112game_finished =true , 113victorious_force =player . force , 114player_won =true , 115} ) 116player . force . play_sound ( { path ="kr-win-joke-voice" } ) 117end 118 119--- @param e EventData.on_cutscene_waypoint_reached 120local function on_cutscene_waypoint_reached ( e ) 121if not storage . intergalactic_transceiver then 122return 123end 124local player =game . get_player ( e . player_index ) 125if not player or not storage . intergalactic_transceiver . in_cutscene [ player . force_index ] then 126return 127end 128 129local transceiver_data =storage . intergalactic_transceiver . forces [ player . force_index ] 130if not transceiver_data then 131return 132end 133local entity =transceiver_data . entity 134if not entity . valid then 135return 136end 137 138if e . waypoint_index == 1 then 139entity . surface . create_entity ( { 140type ="projectile" , 141name ="intergalactic-transceiver-wave" , 142force =entity . force , 143position =entity . position , 144speed =0 , 145max_range =100 , 146target =entity , 147create_build_effect_smoke =false , 148raise_built =true , 149} ) 150elseif e . waypoint_index == 2 then 151local force =entity . force 152local player =entity . last_user 153local position =entity . position 154local surface =entity . surface 155entity . destroy () 156transceiver_data . activating =true 157local new_entity =surface . create_entity ( { 158name ="kr-activated-intergalactic-transceiver" , 159position =position , 160force =force , 161player =player , 162create_build_effect_smoke =false , 163raise_built =true , 164} ) 165transceiver_data . activating =false 166if not new_entity or not new_entity . valid then 167return 168end 169storage . intergalactic_transceiver . forces [ force . index ] ={ entity =new_entity } 170end 171end 172 173--- @param e EventData.on_gui_click 174local function on_gui_window_closed ( e ) 175local self =storage . intergalactic_transceiver . guis [ e . player_index ] 176if not self then 177return 178end 179self . elems . kr_intergalactic_transceiver_window . destroy () 180self . player . opened =nil 181self . player . play_sound ( { path ="entity-close/kr-intergalactic-transceiver" } ) 182storage . intergalactic_transceiver . guis [ e . player_index ] =nil 183end 184 185--- @param entity LuaEntity 186local function close_open_guis ( entity ) 187for player_index , self in pairs ( storage . intergalactic_transceiver . guis ) do 188if self . entity == entity or not self . entity . valid then 189on_gui_window_closed ( { player_index =player_index } ) 190end 191end 192end 193 194--- @param e EventData.on_gui_click 195local function on_gui_activate_button_clicked ( e ) 196local player =game . get_player ( e . player_index ) 197if not player then 198return 199end 200local transceiver_data =storage . intergalactic_transceiver . forces [ player . force_index ] 201close_open_guis ( transceiver_data . entity ) 202activate_transceiver ( transceiver_data ) 203end 204 205--- @param self IntergalacticTransceiverGuiData 206local function update_gui ( self ) 207local charged =flib_math . round ( self . entity . energy / max_energy , 0.01 ) 208local transceiver_data =storage . intergalactic_transceiver . forces [ self . player . force_index ] 209local status_properties =status_properties [ transceiver_data . status ] 210self . elems . status_icon . sprite =status_properties . icon 211self . elems . status_label . caption =status_properties . label 212self . elems . charge_progressbar . value =charged 213self . elems . charge_progressbar . caption =math . floor ( charged * 100 ) .. " %" 214self . elems . activate_button . enabled =charged == 1 215end 216 217--- @param player LuaPlayer 218--- @param entity LuaEntity 219local function create_gui ( player , entity ) 220local elems =flib_gui . add ( player . gui . screen , { 221type ="frame" , 222name ="kr_intergalactic_transceiver_window" , 223direction ="vertical" , 224elem_mods ={ auto_center =true } , 225handler ={ [ defines . events . on_gui_closed ] =on_gui_window_closed } , 226{ 227type ="flow" , 228style ="flib_titlebar_flow" , 229{ 230type ="label" , 231style ="frame_title" , 232caption ={ "entity-name.kr-intergalactic-transceiver" } , 233ignored_by_interaction =true , 234} , 235{ type ="empty-widget" , style ="flib_titlebar_drag_handle" , ignored_by_interaction =true } , 236{ 237type ="sprite-button" , 238style ="frame_action_button" , 239sprite ="utility/close" , 240mouse_button_filter ={ "left" } , 241handler ={ [ defines . events . on_gui_click ] =on_gui_window_closed } , 242} , 243} , 244{ 245type ="frame" , 246style ="entity_frame" , 247direction ="vertical" , 248{ 249type ="flow" , 250style_mods ={ vertical_align ="center" } , 251{ type ="sprite" , name ="status_icon" , style ="flib_indicator" } , 252{ type ="label" , name ="status_label" } , 253} , 254{ 255type ="frame" , 256style ="deep_frame_in_shallow_frame" , 257{ type ="entity-preview" , style ="wide_entity_button" , elem_mods ={ entity =entity } } , 258} , 259{ 260type ="progressbar" , 261name ="charge_progressbar" , 262style ="production_progressbar" , 263style_mods ={ horizontally_stretchable =true } , 264value =0 , 265} , 266{ 267type ="button" , 268name ="activate_button" , 269style_mods ={ horizontally_stretchable =true } , 270caption ={ "gui.kr-intergalactic-transceiver-activate" } , 271enabled =false , 272handler ={ [ defines . events . on_gui_click ] =on_gui_activate_button_clicked } , 273} , 274} , 275} ) 276 277--- @class IntergalacticTransceiverGuiData 278storage . intergalactic_transceiver . guis [ player . index ] ={ 279elems =elems , 280entity =entity , 281player =player , 282} 283 284player . opened =elems . kr_intergalactic_transceiver_window 285if not game . is_multiplayer () then 286player . play_sound ( { path ="entity-open/kr-intergalactic-transceiver" } ) 287end 288end 289 290--- @param entity LuaEntity 291local function on_transceiver_destroyed ( entity ) 292local force_index =entity . force . index 293storage . intergalactic_transceiver . forces [ force_index ] =nil 294close_open_guis ( entity ) 295end 296 297--- @param entity LuaEntity 298local function on_inactive_transceiver_destroyed ( entity ) 299storage . intergalactic_transceiver . inactive [ entity . unit_number ] =nil 300end 301 302--- @param e EntityDestroyedEvent 303local function on_entity_destroyed ( e ) 304local entity =e . entity 305if not entity or not entity . valid then 306return 307end 308 309if entity . name == "kr-intergalactic-transceiver" then 310on_transceiver_destroyed ( entity ) 311elseif entity . name == "kr-inactive-intergalactic-transceiver" then 312on_inactive_transceiver_destroyed ( entity ) 313end 314end 315 316--- @param entity LuaEntity 317local function on_transceiver_built ( entity ) 318local existing =storage . intergalactic_transceiver . forces [ entity . force . index ] 319if existing then 320local position =entity . position 321local force =entity . force 322local player =entity . last_user 323local surface =entity . surface 324entity . destroy () 325 326local new_entity =surface . create_entity ( { 327name ="kr-inactive-intergalactic-transceiver" , 328position =position , 329force =force , 330player =player , 331create_build_effect_smoke =false , 332raise_built =true , 333} ) 334if new_entity and new_entity . valid then 335storage . intergalactic_transceiver . inactive [ new_entity . unit_number ] =new_entity 336end 337 338return 339end 340 341--- @class IntergalacticTransceiverForceData 342storage . intergalactic_transceiver . forces [ entity . force . index ] ={ 343activating =false , 344entity =entity , 345last_alert_tick =game . tick , 346last_energy =entity . energy , 347status ="empty" , 348} 349end 350 351--- @param entity LuaEntity 352local function on_active_transceiver_built ( entity ) 353local existing =storage . intergalactic_transceiver . forces [ entity . force . index ] 354if not existing or not existing . activating then 355local position =entity . position 356local force =entity . force 357local player =entity . last_user 358local surface =entity . surface 359entity . destroy () 360 361local new_entity =surface . create_entity ( { 362name ="kr-intergalactic-transceiver" , 363position =position , 364force =force , 365player =player , 366create_build_effect_smoke =false , 367raise_built =true , 368} ) 369 370if new_entity and new_entity . valid then 371on_transceiver_built ( new_entity ) 372end 373end 374end 375 376--- @param e EntityBuiltEvent 377local function on_entity_built ( e ) 378local entity =e . entity or e . destination 379if not entity or not entity . valid then 380return 381end 382 383if entity . name == "kr-intergalactic-transceiver" then 384on_transceiver_built ( entity ) 385elseif entity . name == "kr-activated-intergalactic-transceiver" then 386on_active_transceiver_built ( entity ) 387end 388end 389 390--- @param data IntergalacticTransceiverForceData 391--- @param entity LuaEntity 392local function update_transceiver ( data , entity ) 393if not data . last_energy then 394return 395end 396local current_energy =entity . energy 397local new_energy =current_energy 398local difference =current_energy - data . last_energy 399--- @type IntergalacticTransceiverStatus 400local status ="charging" 401-- If we're not receiving enough power 402if difference < min_charge_delta and current_energy > 0 then 403-- Drain the transceiver at 3 TJ / sec 404new_energy =math . max ( 0 , current_energy - energy_drain ) 405-- Update status 406if new_energy > 0 then 407status ="discharging" 408else 409status ="not_enough_input" 410end 411else 412if current_energy > max_energy then 413-- XXX: If the energy remains constant, the entity status will change to "normal", so give it a random offset. 414new_energy =max_energy + math . random ( 0 , 20 ) * 1000000 415status ="ready" 416else 417local current_status =defines_to_status [ entity . status ] 418if status_properties [ current_status ] then 419status =current_status 420end 421end 422end 423 424if new_energy ~= current_energy then 425entity . energy =new_energy 426end 427local last_status =data . status 428data . last_energy =new_energy 429data . status =status 430 431local status_properties =status_properties [ status ] 432if status_properties and status_properties . alert_label and game . tick - data . last_alert_tick >= 60 then 433data . last_alert_tick =game . tick 434for _ , player in pairs ( entity . force . players ) do 435player . add_custom_alert ( 436entity , 437{ type ="item" , name ="kr-intergalactic-transceiver" } , 438status_properties . alert_label , 439true 440) 441if status == "discharging" and last_status ~= status then 442player . play_sound ( { 443path ="kr-intergalactic-transceiver-discharging-warning" , 444} ) 445end 446end 447end 448end 449 450--- @param e EventData.on_gui_opened 451local function on_gui_opened ( e ) 452if storage . intergalactic_transceiver . guis [ e . player_index ] then 453return 454end 455if e . gui_type ~= defines . gui_type . entity then 456return 457end 458local entity =e . entity 459if not entity or entity . name ~= "kr-intergalactic-transceiver" then 460return 461end 462local player =game . get_player ( e . player_index ) 463if not player then 464return 465end 466create_gui ( player , entity ) 467end 468 469local function on_tick () 470if not storage . intergalactic_transceiver then 471return 472end 473 474local transceivers =storage . intergalactic_transceiver . forces 475for force_index , data in pairs ( transceivers ) do 476local entity =data . entity 477if entity and entity . valid then 478update_transceiver ( data , entity ) 479else 480transceivers [ force_index ] =nil 481end 482end 483 484for _ , self in pairs ( storage . intergalactic_transceiver . guis ) do 485update_gui ( self ) 486end 487end 488 489local function on_180th_tick () 490if not storage . intergalactic_transceiver then 491return 492end 493for unit_number , entity in pairs ( storage . intergalactic_transceiver . inactive ) do 494if entity . valid then 495util . entity_flying_text ( entity , { "message.kr-transceiver-is-inactive" } , { r =1 } ) 496else 497storage . intergalactic_transceiver . inactive [ unit_number ] =nil 498end 499end 500end 501 502--- @class intergalactic_transceiver 503local intergalactic_transceiver ={} 504 505function intergalactic_transceiver . on_init () 506-- Can be already initialised through remote interface 507if storage . intergalactic_transceiver then 508return 509end 510storage . intergalactic_transceiver ={ 511--- @type table<uint, IntergalacticTransceiverForceData> 512forces ={} , 513--- @type table<uint, IntergalacticTransceiverGuiData> 514guis ={} , 515--- @type table<uint, boolean> 516in_cutscene ={} , 517--- @type table<uint, LuaEntity> 518inactive ={} , 519is_victory =true , 520} 521end 522 523intergalactic_transceiver . events ={ 524[ defines . events . on_built_entity ] =on_entity_built , 525[ defines . events . on_cutscene_cancelled ] =on_cutscene_finished , 526[ defines . events . on_cutscene_finished ] =on_cutscene_finished , 527[ defines . events . on_cutscene_waypoint_reached ] =on_cutscene_waypoint_reached , 528[ defines . events . on_entity_cloned ] =on_entity_built , 529[ defines . events . on_entity_died ] =on_entity_destroyed , 530[ defines . events . on_gui_opened ] =on_gui_opened , 531[ defines . events . on_player_mined_entity ] =on_entity_destroyed , 532[ defines . events . on_robot_built_entity ] =on_entity_built , 533[ defines . events . on_robot_mined_entity ] =on_entity_destroyed , 534[ defines . events . on_tick ] =on_tick , 535[ defines . events . script_raised_built ] =on_entity_built , 536[ defines . events . script_raised_destroy ] =on_entity_destroyed , 537[ defines . events . script_raised_revive ] =on_entity_built , 538[ defines . events . on_space_platform_built_entity ] =on_entity_built , 539[ defines . events . on_space_platform_mined_entity ] =on_entity_destroyed , 540} 541 542intergalactic_transceiver . on_nth_tick ={ 543[ 180 ] =on_180th_tick , 544} 545 546-- REMOTE 547 548remote . add_interface ( "kr-intergalactic-transceiver" , { 549get_is_victory =function () 550if storage . intergalactic_transceiver then 551intergalactic_transceiver . on_init () 552end 553return storage . intergalactic_transceiver . is_victory 554end , 555set_is_victory =function ( to_state ) 556if to_state == nil or type ( to_state ) ~= "boolean" then 557error ( "`to_state` must be a boolean" ) 558end 559if not storage . intergalactic_transceiver then 560intergalactic_transceiver . on_init () 561end 562storage . intergalactic_transceiver . is_victory =to_state 563end , 564} ) 565 566flib_gui . add_handlers ( { 567transceiver_on_window_closed =on_gui_window_closed , 568transceiver_on_activate_button_clicked =on_gui_activate_button_clicked , 569} ) 570 571return intergalactic_transceiver