z_mirror/Krastorio2
git clone https://git.raiguard.me/z_mirror/Krastorio2
2aad641c
discrete-steel-pipes
1local flib_gui =require ( "__flib__.gui" ) 2local flib_math =require ( "__flib__.math" ) 3local flib_table =require ( "__flib__.table" ) 4 5local util =require ( "scripts.util" ) 6 7--- @class PlanetaryTeleporterGui 8--- @field elems table<string, LuaGuiElement> 9--- @field entity LuaEntity 10--- @field data PlanetaryTeleporterData 11--- @field player LuaPlayer 12--- @field search_open boolean 13--- @field search_query string 14 15--- @param player LuaPlayer 16--- @param from LuaEntity 17--- @param to LuaEntity 18local function teleport_player ( player , from , to ) 19from . energy =0 20to . energy =0 21local position =to . position 22position . y =position . y + 1.1 23player . teleport ( position , to . surface ) 24from . surface . play_sound ( { 25path ="kr-planetary-teleporter-effect-sound" , 26volume_modifier =0.8 , 27position =from . position , 28} ) 29to . surface . play_sound ( { 30path ="kr-planetary-teleporter-effect-sound" , 31position =to . position , 32volume_modifier =1 , 33} ) 34end 35 36--- @param self PlanetaryTeleporterGui 37local function filter_destinations ( self ) 38local search_query =self . search_query 39for _ , frame in pairs ( self . elems . destinations_table . children ) do 40if search_query == "" then 41frame . visible =true 42goto continue 43end 44local unit_number =tonumber ( frame . name ) --[[@as uint]] 45local data =storage . planetary_teleporter [ unit_number ] 46if not data then 47frame . destroy () 48goto continue 49end 50if data . name and string . find ( string . lower ( data . name ), search_query , nil , true ) then 51frame . visible =true 52else 53frame . visible =false 54end 55:: continue :: 56end 57end 58 59--- @param self PlanetaryTeleporterGui 60--- @param by_click boolean 61local function toggle_search ( self , by_click ) 62local search_button =self . elems . search_button 63if not by_click then 64search_button . toggled =not search_button . toggled 65end 66self . search_open =search_button . toggled 67 68local search_textfield =self . elems . search_textfield 69search_textfield . visible =self . search_open 70if self . search_open then 71search_textfield . focus () 72search_textfield . select_all () 73else 74self . search_query ="" 75end 76 77filter_destinations ( self ) 78end 79 80--- @param self PlanetaryTeleporterGui 81local function destroy_gui ( self ) 82local window =self . elems . kr_planetary_teleporter_window 83if window . valid then 84window . destroy () 85if self . player . opened == window then 86self . player . opened =nil 87end 88end 89storage . planetary_teleporter_gui [ self . player . index ] =nil 90end 91 92--- @param e EventData.on_gui_closed|EventData.on_gui_click 93local function on_window_closed ( e ) 94local self =storage . planetary_teleporter_gui [ e . player_index ] 95if not self then 96return 97end 98if self . search_open then 99toggle_search ( self , false ) 100self . player . opened =self . elems . kr_planetary_teleporter_window 101return 102end 103destroy_gui ( self ) 104end 105 106--- @param e EventData.on_gui_text_changed 107local function on_search_textfield_text_changed ( e ) 108local self =storage . planetary_teleporter_gui [ e . player_index ] 109if not self then 110return 111end 112self . search_query =e . element . text 113filter_destinations ( self ) 114end 115 116--- @param e EventData.on_gui_click|EventData.CustomInputEvent 117local function on_search_button_clicked ( e ) 118local self =storage . planetary_teleporter_gui [ e . player_index ] 119if not self then 120return 121end 122toggle_search ( self , true ) 123end 124 125--- @param e EventData.on_gui_click 126local function on_rename_button_clicked ( e ) 127local self =storage . planetary_teleporter_gui [ e . player_index ] 128if not self or not self . elems . kr_planetary_teleporter_window . valid then 129return 130end 131local textfield =self . elems . name_textfield 132local label =self . elems . name_label 133if textfield . visible then 134label . visible =true 135textfield . visible =false 136else 137label . visible =false 138textfield . text =self . data . name or "" 139textfield . visible =true 140textfield . select_all () 141textfield . focus () 142end 143end 144 145--- @param e EventData.on_gui_confirmed 146local function on_name_textfield_confirmed ( e ) 147local self =storage . planetary_teleporter_gui [ e . player_index ] 148if not self or not self . elems . kr_planetary_teleporter_window . valid then 149return 150end 151local text =e . element . text 152if # text > 0 then 153self . data . name =e . element . text 154else 155self . data . name =nil 156end 157on_rename_button_clicked ( e --[[@as EventData.on_gui_click]] ) 158end 159 160--- @param e EventData.on_gui_click 161local function on_teleport_button_clicked ( e ) 162local self =storage . planetary_teleporter_gui [ e . player_index ] 163if not self or not self . elems . kr_planetary_teleporter_window . valid then 164return 165end 166local target_unit_number =e . element . tags . unit_number --[[@as UnitNumber]] 167assert ( target_unit_number , "target_unit_number is nil" ) 168local target_data =storage . planetary_teleporter [ target_unit_number ] 169assert ( target_data , "target_data is nil" ) 170local players =storage . planetary_teleporter_players [ 171target_data . entities . turret . unit_number --[[@as uint]] 172] 173if players then 174util . flying_text_with_sound ( self . player , { "gui.kr-planetary-teleporter-destination-blocked" } ) 175return 176end 177local source_unit_number =self . entity . unit_number 178assert ( source_unit_number , "source_unit_number is nil" ) 179local source_data =storage . planetary_teleporter [ source_unit_number ] 180teleport_player ( self . player , source_data . entities . base , target_data . entities . base ) 181destroy_gui ( self ) 182end 183 184--- @type table<defines.entity_status, { sprite: SpritePath, label: LocalisedString }> 185local status_sprites ={ 186[ defines . entity_status . charging ] ={ label ={ "entity-status.charging" } , sprite ="utility/status_yellow" } , 187[ defines . entity_status . fully_charged ] ={ 188label ={ "entity-status.fully-charged" } , 189sprite ="utility/status_working" , 190} , 191[ defines . entity_status . no_power ] ={ label ={ "entity-status.no-power" } , sprite ="utility/status_not_working" } , 192[ defines . entity_status . normal ] ={ label ={ "entity-status.normal" } , sprite ="utility/status_working" } , 193} 194 195--- @param self PlanetaryTeleporterGui 196local function update_gui ( self ) 197local buffer_capacity =self . entity . prototype . electric_energy_source_prototype . buffer_capacity 198local status =self . entity . status 199local status_properties =status_sprites [ status ] or {} 200self . elems . status_icon . sprite =status_properties . sprite 201self . elems . status_label . caption =status_properties . label 202 203local charge =self . entity . energy / buffer_capacity 204self . elems . charge_progressbar . value =charge 205self . elems . charge_progressbar . caption ={ "format-percent" , flib_math . round ( charge * 100 ) } 206 207local players =storage . planetary_teleporter_players [ self . data . entities . turret . unit_number ] 208local standing_on_teleporter =players and flib_table . find ( players , self . player . index ) or false 209local too_many_players =players and # players > 1 or false 210local source_fully_charged =flib_math . round ( charge , 0.1 ) >= 1 211local fully_operational =standing_on_teleporter and source_fully_charged and not too_many_players 212 213if fully_operational then 214self . elems . destinations_status_icon . sprite ="flib_indicator_green" 215self . elems . destinations_status_label . caption ={ "gui.kr-planetary-teleporter-ready" } 216else 217self . elems . destinations_status_icon . sprite ="flib_indicator_red" 218if not standing_on_teleporter then 219self . elems . destinations_status_label . caption ={ "gui.kr-planetary-teleporter-not-on-teleporter" } 220elseif too_many_players then 221self . elems . destinations_status_label . caption ={ "gui.kr-planetary-teleporter-too-many-players" } 222else 223self . elems . destinations_status_label . caption ={ "gui.kr-planetary-teleporter-not-fully-charged" } 224end 225end 226 227self . elems . name_label . caption =self . data . name or { "gui.kr-planetary-teleporter-unnamed" } 228 229for _ , frame in pairs ( self . elems . destinations_table . children ) do 230local unit_number =tonumber ( frame . name ) --[[@as uint]] 231local dest_data =storage . planetary_teleporter [ unit_number ] 232if not dest_data then 233goto continue 234end 235local dest_entity =dest_data . entities . base 236local dest_charge =dest_entity . energy / buffer_capacity 237local dest_fully_charged =flib_math . round ( dest_charge , 0.1 ) == 1 238local minimap =frame . minimap_frame . minimap --[[@as LuaGuiElement]] 239minimap . progressbar . value =dest_charge 240minimap . progressbar . visible =not dest_fully_charged 241minimap . minimap_button . enabled =fully_operational and dest_fully_charged 242if not dest_fully_charged then 243minimap . minimap_button . tooltip ={ "format-percent" , flib_math . round ( dest_charge * 100 ) } 244elseif fully_operational then 245minimap . minimap_button . tooltip ={ "gui.kr-planetary-teleporter-teleport" } 246else 247minimap . minimap_button . tooltip =nil 248end 249:: continue :: 250end 251end 252 253local function on_tick () 254for _ , gui in pairs ( storage . planetary_teleporter_gui ) do 255update_gui ( gui ) 256end 257end 258 259--- @param e EventData.on_gui_opened 260local function on_gui_opened ( e ) 261local entity =e . entity 262if not entity or not entity . valid or entity . name ~= "kr-planetary-teleporter" then 263return 264end 265 266local player =game . get_player ( e . player_index ) 267if not player then 268return 269end 270 271local destination_buttons ={} 272for unit_number , data in pairs ( storage . planetary_teleporter ) do 273if unit_number == entity . unit_number or data . force ~= entity . force or data . surface ~= entity . surface then 274goto continue 275end 276destination_buttons [ # destination_buttons + 1 ] ={ 277type ="frame" , 278name =unit_number , 279style ="train_with_minimap_frame" , 280direction ="vertical" , 281{ 282type ="frame" , 283name ="minimap_frame" , 284style ="deep_frame_in_shallow_frame" , 285{ 286type ="minimap" , 287name ="minimap" , 288style ="kr_planetary_teleporter_destination_minimap" , 289position =data . entities . base . position , 290{ 291type ="button" , 292name ="minimap_button" , 293style ="kr_planetary_teleporter_destination_minimap_button" , 294tags ={ unit_number =unit_number } , 295handler ={ [ defines . events . on_gui_click ] =on_teleport_button_clicked } , 296} , 297{ 298type ="progressbar" , 299name ="progressbar" , 300style ="kr_planetary_teleporter_destination_charge_bar" , 301ignored_by_interaction =true , 302} , 303{ 304type ="label" , 305style ="kr_planetary_teleporter_destination_label" , 306style_mods ={ top_margin =8 , right_margin =8 } , 307caption =data . name or { "gui.kr-planetary-teleporter-unnamed" } , 308ignored_by_interaction =true , 309} , 310} , 311} , 312} 313:: continue :: 314end 315 316local elems =flib_gui . add ( player . gui . screen , { 317type ="frame" , 318name ="kr_planetary_teleporter_window" , 319direction ="vertical" , 320elem_mods ={ auto_center =true } , 321handler ={ [ defines . events . on_gui_closed ] =on_window_closed } , 322{ 323type ="flow" , 324style ="flib_titlebar_flow" , 325drag_target ="kr_planetary_teleporter_window" , 326{ 327type ="label" , 328style ="flib_frame_title" , 329caption ={ "entity-name.kr-planetary-teleporter" } , 330ignored_by_interaction =true , 331} , 332{ type ="empty-widget" , style ="flib_titlebar_drag_handle" , ignored_by_interaction =true } , 333{ 334type ="textfield" , 335name ="search_textfield" , 336style ="flib_titlebar_search_textfield" , 337visible =false , 338handler ={ [ defines . events . on_gui_text_changed ] =on_search_textfield_text_changed } , 339} , 340{ 341type ="sprite-button" , 342name ="search_button" , 343style ="frame_action_button" , 344sprite ="utility/search" , 345tooltip ={ "gui.flib-search-instruction" } , 346auto_toggle =true , 347handler ={ [ defines . events . on_gui_click ] =on_search_button_clicked } , 348} , 349{ 350type ="sprite-button" , 351style ="frame_action_button" , 352sprite ="utility/close" , 353tooltip ={ "gui.close-instruction" } , 354handler ={ [ defines . events . on_gui_click ] =on_window_closed } , 355} , 356} , 357{ 358type ="flow" , 359style_mods ={ horizontal_spacing =12 } , 360{ 361type ="frame" , 362style ="inside_shallow_frame" , 363direction ="vertical" , 364{ 365type ="frame" , 366style ="subheader_frame" , 367style_mods ={ width =424 } , 368{ 369type ="label" , 370name ="name_label" , 371style ="subheader_caption_label" , 372style_mods ={ horizontally_squashable =true } , 373} , 374{ 375type ="textfield" , 376name ="name_textfield" , 377visible =false , 378handler ={ [ defines . events . on_gui_confirmed ] =on_name_textfield_confirmed } , 379} , 380{ 381type ="sprite-button" , 382style ="mini_button_aligned_to_text_vertically_when_centered" , 383sprite ="utility/rename_icon" , 384handler ={ [ defines . events . on_gui_click ] =on_rename_button_clicked } , 385} , 386} , 387{ 388type ="flow" , 389style_mods ={ padding =12 , top_padding =8 , vertical_spacing =8 } , 390direction ="vertical" , 391{ 392type ="flow" , 393style_mods ={ vertical_align ="center" } , 394{ type ="sprite" , name ="status_icon" , style ="flib_indicator" } , 395{ type ="label" , name ="status_label" } , 396} , 397{ 398type ="frame" , 399style ="deep_frame_in_shallow_frame" , 400{ type ="entity-preview" , style ="wide_entity_button" , elem_mods ={ entity =entity } } , 401} , 402{ 403type ="progressbar" , 404name ="charge_progressbar" , 405style ="production_progressbar" , 406style_mods ={ horizontally_stretchable =true } , 407caption ="foo" , 408value =0.2 , 409} , 410{ type ="empty-widget" , style ="entity_frame_filler" } , 411} , 412} , 413{ 414type ="frame" , 415style ="inside_deep_frame" , 416direction ="vertical" , 417{ 418type ="frame" , 419style ="subheader_frame" , 420{ 421type ="label" , 422style ="subheader_caption_label" , 423caption ={ "gui.kr-planetary-teleporter-destinations" } , 424} , 425{ type ="empty-widget" , style ="flib_horizontal_pusher" } , 426{ 427type ="flow" , 428name ="destinations_status_flow" , 429style_mods ={ vertical_align ="center" , right_margin =8 } , 430{ 431type ="sprite" , 432name ="destinations_status_icon" , 433style ="flib_indicator" , 434sprite ="flib_indicator_red" , 435} , 436{ 437type ="label" , 438name ="destinations_status_label" , 439caption ={ "gui.kr-planetary-teleporter-not-on-teleporter" } , 440} , 441} , 442} , 443{ 444type ="scroll-pane" , 445style ="kr_planetary_teleporter_destinations_scroll_pane" , 446vertical_scroll_policy ="auto-and-reserve-space" , 447{ 448type ="table" , 449name ="destinations_table" , 450style ="slot_table" , 451column_count =3 , 452children =destination_buttons , 453} , 454} , 455} , 456} , 457} ) 458 459player . opened =elems . kr_planetary_teleporter_window 460 461--- @type PlanetaryTeleporterGui 462storage . planetary_teleporter_gui [ e . player_index ] ={ 463elems =elems , 464data =storage . planetary_teleporter [ entity . unit_number ], 465entity =entity , 466player =player , 467search_open =false , 468search_query ="" , 469} 470end 471 472--- @param e EventData.CustomInputEvent 473local function on_focus_search ( e ) 474local self =storage . planetary_teleporter_gui [ e . player_index ] 475if self then 476toggle_search ( self , false ) 477end 478end 479 480local planetary_teleporter_gui ={} 481 482function planetary_teleporter_gui . on_init () 483--- @type table<uint, PlanetaryTeleporterGui> 484storage . planetary_teleporter_gui ={} 485end 486 487function planetary_teleporter_gui . on_configuration_changed () 488for _ , gui in pairs ( storage . planetary_teleporter_gui or {} ) do 489if gui . elems . window . valid then 490gui . elems . window . destroy () 491end 492end 493storage . planetary_teleporter_gui ={} 494end 495 496planetary_teleporter_gui . events ={ 497[ defines . events . on_gui_opened ] =on_gui_opened , 498[ defines . events . on_tick ] =on_tick , 499[ "kr-linked-focus-search" ] =on_focus_search , 500} 501 502flib_gui . add_handlers ( { 503planetary_teleporter_on_name_textfield_confirmed =on_name_textfield_confirmed , 504planetary_teleporter_on_rename_button_clicked =on_rename_button_clicked , 505planetary_teleporter_on_search_button_clicked =on_search_button_clicked , 506planetary_teleporter_on_search_textfield_text_changed =on_search_textfield_text_changed , 507planetary_teleporter_on_teleport_button_clicked =on_teleport_button_clicked , 508planetary_teleporter_on_window_closed =on_window_closed , 509} ) 510 511return planetary_teleporter_gui