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