mirror of
https://github.com/ApfelTeeSaft/Perfectium.git
synced 2026-08-26 19:33:36 +00:00
577 lines
17 KiB
NASM
577 lines
17 KiB
NASM
INCLUDE include\master.inc
|
||
|
||
EXTERNDEF GameModeLateGame_InitializeGameplay :PROC
|
||
|
||
; SDK offsets - AFortGameStateAthena
|
||
AGSA_WarmupCountdownEndTime EQU 14F4h
|
||
AGSA_AircraftStartTime EQU 14F8h
|
||
AGSA_GamePhase EQU 1B98h ; BYTE, EAthenaGamePhase
|
||
AGSA_bWillSkipAircraft EQU 1BA8h ; BYTE
|
||
AGSA_PlayerArray_Data EQU 0330h ; TArray<APlayerState*>.Data
|
||
AGSA_PlayerArray_Num EQU 0338h ; TArray<APlayerState*>.Num
|
||
|
||
; UWorld offsets
|
||
UWORLD_GameState EQU 0148h
|
||
UWORLD_AuthorityGameMode EQU 0140h
|
||
|
||
; AGameModeBase offsets
|
||
AGMB_GameSession EQU 0370h ; AGameSession*
|
||
|
||
; AActor offsets
|
||
AACTOR_Owner EQU 0108h ; AActor* (PlayerController for PlayerState)
|
||
|
||
; EAthenaGamePhase::Aircraft = 3
|
||
EGAMEPHASE_Aircraft EQU 3
|
||
|
||
; FText size
|
||
FTEXT_SIZE EQU 18h ; 24 bytes
|
||
|
||
; Window parameters
|
||
GUI_WINDOW_W_BITS EQU 43FA0000h ; 500.0f
|
||
GUI_WINDOW_H_BITS EQU 444F0000h ; 828.0f
|
||
GUI_WINDOW_H_BITS2 EQU 44AF0000h ; 700.0f (for header)
|
||
|
||
; Position of GUI window
|
||
; Menu pos: FVector2D starting at 200, 250
|
||
F_200_0 EQU 43480000h ; 200.0f
|
||
F_250_0 EQU 437A0000h ; 250.0f
|
||
|
||
.const
|
||
|
||
; Wide string constants for GUI text
|
||
szTitle_Raider DW 'R','a','i','d','e','r', 0
|
||
szBtn_StartBus DW 'S','t','a','r','t',' ','B','u','s', 0
|
||
szBtn_Back DW '<', 0
|
||
szBtn_Kick DW 'K','i','c','k', 0
|
||
szBtnTab_Game DW 'G','a','m','e', 0
|
||
szBtnTab_Players DW 'P','l','a','y','e','r','s', 0
|
||
szText_CurPlayer DW 'C','u','r','r','e','n','t',' ','P','l','a','y','e','r',':', 0
|
||
szText_ConnPlayers DW 'C','o','n','n','e','c','t','e','d',' ','P','l','a','y','e','r','s', 0
|
||
|
||
; Console command: "startaircraft"
|
||
szConsoleCmd_W DW 's','t','a','r','t','a','i','r','c','r','a','f','t', 0
|
||
|
||
; UFunction / UClass paths for static calls
|
||
szFn_ExecConsoleCmd DB "Function Engine.KismetSystemLibrary.ExecuteConsoleCommand", 0
|
||
szClass_KismetSys DB "Class Engine.KismetSystemLibrary", 0
|
||
szFn_GetPlayerName DB "Function Engine.PlayerState.GetPlayerName", 0
|
||
szFn_ConvStrToText DB "Function Engine.KismetTextLibrary.Conv_StringToText", 0
|
||
szClass_KismetText DB "Class Engine.KismetTextLibrary", 0
|
||
|
||
; Kick reason wide string
|
||
szKickReason DW 'Y','o','u',' ','h','a','v','e',' ','b','e','e','n',' ','k','i','c','k','e','d','.', 0
|
||
|
||
; Sizebit constants as REAL4
|
||
f_25_0 REAL4 25.0
|
||
f_100_0 REAL4 100.0
|
||
f_110_0 REAL4 110.0
|
||
f_60_0 REAL4 60.0
|
||
f_90_0 REAL4 90.0
|
||
f_130_0 REAL4 130.0
|
||
f_500_0 REAL4 500.0
|
||
f_700_0 REAL4 700.0
|
||
f_0_5_gui REAL4 0.5
|
||
|
||
.data?
|
||
|
||
; Persistent menu state
|
||
GUI_menu_opened BYTE ? ; bool: menu visible (toggled by F2)
|
||
GUI_initialized BYTE ? ; one-time init done
|
||
GUI_tab DWORD ? ; active tab (0=Game, 1=Players)
|
||
GUI_currentPlayer QWORD ? ; APlayerState* selected for kick view (or 0)
|
||
GUI_pos_X REAL4 ? ; window position X (drag-persistent)
|
||
GUI_pos_Y REAL4 ? ; window position Y
|
||
|
||
; Cached UFunction* and UClass* pointers
|
||
GUI_pFn_ExecConsole QWORD ?
|
||
GUI_pClass_KismetSys QWORD ?
|
||
GUI_pFn_GetPlyName QWORD ?
|
||
GUI_pFn_ConvStr QWORD ?
|
||
GUI_pClass_TextLib QWORD ?
|
||
|
||
; Scratch buffer for player name FString (single-frame, reused per player)
|
||
GUI_nameFStr_Data QWORD ? ; FString.Data (wchar_t*)
|
||
GUI_nameFStr_Num DWORD ? ; FString.Num
|
||
GUI_nameFStr_Max DWORD ? ; FString.Max
|
||
|
||
; Scratch buffer for kick reason FString
|
||
GUI_kickFStr_Data QWORD ?
|
||
GUI_kickFStr_Num DWORD ?
|
||
GUI_kickFStr_Max DWORD ?
|
||
|
||
.code
|
||
|
||
; GUI__GetPlayerName (internal helper)
|
||
; Calls GetPlayerName UFunction on a PlayerState via ProcessEvent.
|
||
; Fills GUI_nameFStr_Data/Num/Max.
|
||
; In: RCX = APlayerState* (PlayerState object)
|
||
; Out: RAX = wchar_t* (Data pointer, or 0 on failure)
|
||
;
|
||
; Frame: 2 pushes (RBX=PlayerState*) + sub 28h -> RSP = 0
|
||
; GetPlayerName params at [rsp+20h..+2Fh]:
|
||
; +0x00: FString ReturnValue (16 bytes)
|
||
GUI__GetPlayerName PROC
|
||
push rbx
|
||
push rsi
|
||
sub rsp, 28h
|
||
|
||
mov rbx, rcx ; PlayerState*
|
||
|
||
; Lazy-load GetPlayerName UFunction*
|
||
mov rsi, QWORD PTR [GUI_pFn_GetPlyName]
|
||
test rsi, rsi
|
||
jnz @@fn_ready
|
||
lea rcx, [szFn_GetPlayerName]
|
||
call SDK_FindObject
|
||
mov QWORD PTR [GUI_pFn_GetPlyName], rax
|
||
mov rsi, rax
|
||
test rsi, rsi
|
||
jz @@fail
|
||
@@fn_ready:
|
||
|
||
; Zero the ReturnValue FString at [rsp+20h]
|
||
xor eax, eax
|
||
mov QWORD PTR [rsp+20h], rax ; Data = nullptr
|
||
mov QWORD PTR [rsp+28h], rax ; Num=0, Max=0 - wait this overwrites our saved RSI
|
||
|
||
mov QWORD PTR [rsp+20h], 0 ; Data = 0
|
||
mov DWORD PTR [rsp+28h], 0 ; Num = 0 (this is fine - shadow can be written)
|
||
mov DWORD PTR [rsp+2Ch], 0 ; Max = 0
|
||
|
||
; ProcessEvent(PlayerState, GetPlayerName, ¶ms)
|
||
mov rcx, rbx
|
||
mov rdx, rsi
|
||
lea r8, [rsp+20h]
|
||
call QWORD PTR [ProcessEvent]
|
||
|
||
; Return FString.Data (the wchar_t* pointer)
|
||
mov rax, QWORD PTR [rsp+20h]
|
||
jmp @@done
|
||
@@fail:
|
||
xor rax, rax
|
||
@@done:
|
||
add rsp, 28h
|
||
pop rsi
|
||
pop rbx
|
||
ret
|
||
GUI__GetPlayerName ENDP
|
||
|
||
|
||
; GUI__KickController (internal helper)
|
||
; Calls Native_OnlineSession_KickPlayer(Session, PC, &empty_FText).
|
||
; In: RCX = APlayerController* (PC to kick)
|
||
; Out: none
|
||
;
|
||
; Frame: 2 pushes (RBX=PC) + sub 38h -> RSP = 8-16-56 = -64 = 0
|
||
; [rsp+20h..+37h] = zeroed FText (0x18 = 24 bytes)
|
||
GUI__KickController PROC
|
||
push rbx
|
||
push rsi
|
||
sub rsp, 38h
|
||
|
||
mov rbx, rcx ; PC to kick
|
||
test rbx, rbx
|
||
jz @@done
|
||
|
||
; Get GameSession: World->AuthorityGameMode->GameSession
|
||
call SDK_GetWorld
|
||
test rax, rax
|
||
jz @@done
|
||
mov rsi, QWORD PTR [rax + UWORLD_AuthorityGameMode]
|
||
test rsi, rsi
|
||
jz @@done
|
||
mov rsi, QWORD PTR [rsi + AGMB_GameSession]
|
||
test rsi, rsi
|
||
jz @@done
|
||
|
||
; Zero FText at [rsp+20h] (24 bytes)
|
||
xor eax, eax
|
||
mov QWORD PTR [rsp+20h], rax
|
||
mov QWORD PTR [rsp+28h], rax
|
||
mov QWORD PTR [rsp+30h], rax
|
||
|
||
; Native_OnlineSession_KickPlayer(Session, PC, &FText)
|
||
mov rcx, rsi ; Session
|
||
mov rdx, rbx ; PC
|
||
lea r8, [rsp+20h] ; &FText (empty)
|
||
call QWORD PTR [Native_OnlineSession_KickPlayer]
|
||
|
||
@@done:
|
||
add rsp, 38h
|
||
pop rsi
|
||
pop rbx
|
||
ret
|
||
GUI__KickController ENDP
|
||
|
||
|
||
; GUI__StartBus (internal helper)
|
||
; Sets GameState fields and fires "startaircraft" console command
|
||
; then calls GameModeLateGame_InitializeGameplay.
|
||
; In: none
|
||
; Frame: 4 pushes (RBX=GameState*,RBP=World*,RSI=KismetClass,RDI=fn)
|
||
; + sub 48h -> RSP = 8-32-72 = -96 = 0
|
||
; Params for ExecuteConsoleCommand at [rsp+20h]:
|
||
; +0x00: WorldContextObject QWORD
|
||
; +0x08: FString.Data QWORD
|
||
; +0x10: FString.Num DWORD
|
||
; +0x14: FString.Max DWORD
|
||
; +0x18: SpecificPlayer QWORD = 0
|
||
; Total = 0x20 = 32 bytes (fits in shadow + [rsp+20h..+3Fh])
|
||
GUI__StartBus PROC
|
||
push rbx
|
||
push rbp
|
||
push rsi
|
||
push rdi
|
||
sub rsp, 48h
|
||
|
||
; Get World
|
||
call SDK_GetWorld
|
||
test rax, rax
|
||
jz @@done
|
||
mov rbp, rax ; World*
|
||
|
||
; Get GameState
|
||
mov rbx, QWORD PTR [rbp + UWORLD_GameState]
|
||
test rbx, rbx
|
||
jz @@done
|
||
|
||
; GameState->bGameModeWillSkipAircraft = false
|
||
mov BYTE PTR [rbx + AGSA_bWillSkipAircraft], 0
|
||
|
||
; GameState->AircraftStartTime = 0
|
||
xor eax, eax
|
||
mov DWORD PTR [rbx + AGSA_AircraftStartTime], eax
|
||
|
||
; GameState->WarmupCountdownEndTime = 0
|
||
mov DWORD PTR [rbx + AGSA_WarmupCountdownEndTime], eax
|
||
|
||
; ExecuteConsoleCommand via KismetSystemLibrary
|
||
; Lazy-load KismetSystemLibrary class
|
||
mov rsi, QWORD PTR [GUI_pClass_KismetSys]
|
||
test rsi, rsi
|
||
jnz @@kls_ready
|
||
lea rcx, [szClass_KismetSys]
|
||
call SDK_FindObject
|
||
mov QWORD PTR [GUI_pClass_KismetSys], rax
|
||
mov rsi, rax
|
||
test rsi, rsi
|
||
jz @@done
|
||
@@kls_ready:
|
||
|
||
; Lazy-load ExecuteConsoleCommand UFunction*
|
||
mov rdi, QWORD PTR [GUI_pFn_ExecConsole]
|
||
test rdi, rdi
|
||
jnz @@fn_ready
|
||
lea rcx, [szFn_ExecConsoleCmd]
|
||
call SDK_FindObject
|
||
mov QWORD PTR [GUI_pFn_ExecConsole], rax
|
||
mov rdi, rax
|
||
test rdi, rdi
|
||
jz @@done
|
||
@@fn_ready:
|
||
|
||
; Build FString for "startaircraft" command using FString_FromWideChar
|
||
; Temporarily store the FString at [rsp+30h] (3 slots: Data*, Num, Max = 16 bytes)
|
||
lea rcx, [rsp+30h]
|
||
lea rdx, [szConsoleCmd_W]
|
||
call FString_FromWideChar
|
||
|
||
; Build params block at [rsp+20h]:
|
||
; [rsp+20h] = World* (WorldContextObject)
|
||
; [rsp+28h] = FString.Data (wchar_t*)
|
||
; [rsp+30h] = FString.Num (DWORD)
|
||
; [rsp+34h] = FString.Max (DWORD)
|
||
; [rsp+38h] = SpecificPlayer = 0
|
||
mov QWORD PTR [rsp+20h], rbp ; World*
|
||
mov rax, QWORD PTR [rsp+30h] ; FString.Data (was stored by FString_FromWideChar)
|
||
mov QWORD PTR [rsp+28h], rax
|
||
|
||
mov QWORD PTR [rsp+20h], rbp ; WorldContextObject = World*
|
||
lea rcx, [rsp+28h] ; out = &Command FString
|
||
lea rdx, [szConsoleCmd_W]
|
||
call FString_FromWideChar
|
||
xor rax, rax
|
||
mov QWORD PTR [rsp+38h], rax ; SpecificPlayer = nullptr
|
||
|
||
; ProcessEvent(KismetSysClass, fn, ¶ms)
|
||
mov rcx, rsi ; KismetSystemLibrary class object
|
||
mov rdx, rdi ; ExecuteConsoleCommand fn
|
||
lea r8, [rsp+20h]
|
||
call QWORD PTR [ProcessEvent]
|
||
|
||
; Free the command FString
|
||
lea rcx, [rsp+28h]
|
||
call FString_Free
|
||
|
||
; Call GameModeLateGame_InitializeGameplay
|
||
call GameModeLateGame_InitializeGameplay
|
||
|
||
; Set bStartedBus = true
|
||
mov BYTE PTR [bStartedBus], 1
|
||
|
||
@@done:
|
||
add rsp, 48h
|
||
pop rdi
|
||
pop rsi
|
||
pop rbp
|
||
pop rbx
|
||
ret
|
||
GUI__StartBus ENDP
|
||
|
||
|
||
; GUI_Tick
|
||
; Called each frame from Hooks_PostRender.
|
||
; Frame: 4 pushes (RBX=World, RBP=GameState, RSI=playerState loop, RDI=spare)
|
||
; + sub 68h (104) -> RSP = 8-32-104 = -128 = 0
|
||
GUI_Tick PROC
|
||
push rbx
|
||
push rbp
|
||
push rsi
|
||
push rdi
|
||
sub rsp, 68h
|
||
|
||
; One-time initialization
|
||
movzx eax, BYTE PTR [GUI_initialized]
|
||
test al, al
|
||
jnz @@skip_init
|
||
; Set initial window position
|
||
mov DWORD PTR [GUI_pos_X], F_200_0
|
||
mov DWORD PTR [GUI_pos_Y], F_250_0
|
||
; menu_opened = true by default
|
||
mov BYTE PTR [GUI_menu_opened], 1
|
||
; tab = 0
|
||
mov DWORD PTR [GUI_tab], 0
|
||
; currentPlayer = nullptr
|
||
xor rax, rax
|
||
mov QWORD PTR [GUI_currentPlayer], rax
|
||
mov BYTE PTR [GUI_initialized], 1
|
||
@@skip_init:
|
||
|
||
; ZeroInput_Update (poll mouse state)
|
||
call ZeroInput_Update
|
||
|
||
; F2 toggle
|
||
mov ecx, 071h ; VK_F2 = 0x71
|
||
call GetAsyncKeyState
|
||
test ax, 1 ; check lowest bit (just-pressed flag)
|
||
jz @@no_toggle
|
||
movzx eax, BYTE PTR [GUI_menu_opened]
|
||
xor al, 1
|
||
mov BYTE PTR [GUI_menu_opened], al
|
||
@@no_toggle:
|
||
|
||
; ZeroGUI_Begin (Window)
|
||
lea rcx, [szTitle_Raider]
|
||
lea rdx, [GUI_pos_X] ; pos (FVector2D*) - persistent in .data?
|
||
movss xmm0, DWORD PTR [f_500_0]
|
||
movd r8d, xmm0 ; sizeX bits
|
||
movss xmm0, DWORD PTR [f_700_0]
|
||
movd r9d, xmm0 ; sizeY bits
|
||
movzx eax, BYTE PTR [GUI_menu_opened]
|
||
mov DWORD PTR [rsp+20h], eax ; isOpen (5th arg)
|
||
call ZeroGUI_Begin
|
||
test al, al
|
||
jz @@end_gui ; window closed
|
||
|
||
; Inside window: only if bListening && HostBeacon
|
||
movzx eax, BYTE PTR [bListening]
|
||
test al, al
|
||
jz @@end_gui
|
||
mov rax, QWORD PTR [HostBeacon]
|
||
test rax, rax
|
||
jz @@end_gui
|
||
|
||
; Get World and GameState (used by both tabs)
|
||
call SDK_GetWorld
|
||
test rax, rax
|
||
jz @@end_gui
|
||
mov rbx, rax ; rbx = World*
|
||
mov rbp, QWORD PTR [rbx + UWORLD_GameState]
|
||
test rbp, rbp
|
||
jz @@end_gui
|
||
; rbp = GameState*
|
||
|
||
; currentPlayer != nullptr branch
|
||
mov rax, QWORD PTR [GUI_currentPlayer]
|
||
test rax, rax
|
||
jz @@show_tabs
|
||
|
||
; Back button
|
||
lea rcx, [szBtn_Back]
|
||
movss xmm0, DWORD PTR [f_25_0]
|
||
movd edx, xmm0 ; sizeX = 25.0f
|
||
movd r8d, xmm0 ; sizeY = 25.0f
|
||
call ZeroGUI_Button
|
||
test al, al
|
||
jz @@no_back
|
||
; Back pressed: clear currentPlayer
|
||
xor rax, rax
|
||
mov QWORD PTR [GUI_currentPlayer], rax
|
||
jmp @@end_gui ; redraw next frame
|
||
|
||
@@no_back:
|
||
; NextColumn(90.0f)
|
||
movss xmm0, DWORD PTR [f_90_0]
|
||
call ZeroGUI_NextColumn
|
||
|
||
; Text("Current Player:")
|
||
lea rcx, [szText_CurPlayer]
|
||
xor dl, dl ; center=false
|
||
xor r8b, r8b ; outline=false
|
||
call ZeroGUI_Text
|
||
|
||
; Kick button
|
||
lea rcx, [szBtn_Kick]
|
||
movss xmm0, DWORD PTR [f_60_0]
|
||
movd edx, xmm0
|
||
movss xmm0, DWORD PTR [f_25_0]
|
||
movd r8d, xmm0
|
||
call ZeroGUI_Button
|
||
test al, al
|
||
jz @@no_kick
|
||
|
||
; Kick pressed: KickController(currentPlayer->Owner, ...)
|
||
mov rax, QWORD PTR [GUI_currentPlayer]
|
||
mov rcx, QWORD PTR [rax + AACTOR_Owner] ; Owner = PlayerController
|
||
call GUI__KickController
|
||
; Clear currentPlayer
|
||
xor rax, rax
|
||
mov QWORD PTR [GUI_currentPlayer], rax
|
||
jmp @@end_gui
|
||
|
||
@@no_kick:
|
||
jmp @@end_gui
|
||
|
||
; Tab bar
|
||
@@show_tabs:
|
||
; ButtonTab "Game" (110×25, active when tab==0)
|
||
lea rcx, [szBtnTab_Game]
|
||
movss xmm0, DWORD PTR [f_110_0]
|
||
movd edx, xmm0
|
||
movss xmm0, DWORD PTR [f_25_0]
|
||
movd r8d, xmm0
|
||
xor r9d, r9d
|
||
cmp DWORD PTR [GUI_tab], 0
|
||
sete r9b ; active = (tab == 0)
|
||
call ZeroGUI_ButtonTab
|
||
test al, al
|
||
jz @@no_tab0
|
||
mov DWORD PTR [GUI_tab], 0
|
||
@@no_tab0:
|
||
|
||
; ButtonTab "Players" (110×25, active when tab==1)
|
||
lea rcx, [szBtnTab_Players]
|
||
movss xmm0, DWORD PTR [f_110_0]
|
||
movd edx, xmm0
|
||
movss xmm0, DWORD PTR [f_25_0]
|
||
movd r8d, xmm0
|
||
xor r9d, r9d
|
||
cmp DWORD PTR [GUI_tab], 1
|
||
sete r9b
|
||
call ZeroGUI_ButtonTab
|
||
test al, al
|
||
jz @@no_tab1
|
||
mov DWORD PTR [GUI_tab], 1
|
||
@@no_tab1:
|
||
|
||
; NextColumn(130.0f)
|
||
movss xmm0, DWORD PTR [f_130_0]
|
||
call ZeroGUI_NextColumn
|
||
|
||
; Tab content
|
||
mov eax, DWORD PTR [GUI_tab]
|
||
cmp eax, 0
|
||
je @@tab_game
|
||
cmp eax, 1
|
||
je @@tab_players
|
||
jmp @@end_gui
|
||
|
||
; Tab 0: Game
|
||
@@tab_game:
|
||
; Only show "Start Bus" if !bStartedBus
|
||
movzx eax, BYTE PTR [bStartedBus]
|
||
test al, al
|
||
jnz @@end_gui
|
||
|
||
lea rcx, [szBtn_StartBus]
|
||
movss xmm0, DWORD PTR [f_100_0]
|
||
movd edx, xmm0
|
||
movss xmm0, DWORD PTR [f_25_0]
|
||
movd r8d, xmm0
|
||
call ZeroGUI_Button
|
||
test al, al
|
||
jz @@end_gui
|
||
|
||
; Start Bus clicked
|
||
call GUI__StartBus
|
||
jmp @@end_gui
|
||
|
||
; Tab 1: Players
|
||
@@tab_players:
|
||
; Text("Connected Players")
|
||
lea rcx, [szText_ConnPlayers]
|
||
xor dl, dl
|
||
xor r8b, r8b
|
||
call ZeroGUI_Text
|
||
|
||
; Iterate GameState->PlayerArray
|
||
mov esi, DWORD PTR [rbp + AGSA_PlayerArray_Num]
|
||
test esi, esi
|
||
jz @@end_gui
|
||
mov rdi, QWORD PTR [rbp + AGSA_PlayerArray_Data]
|
||
test rdi, rdi
|
||
jz @@end_gui
|
||
|
||
xor DWORD PTR [rsp+2Ch], 0 ; loop index = 0
|
||
mov DWORD PTR [rsp+2Ch], 0
|
||
|
||
@@player_loop:
|
||
mov eax, DWORD PTR [rsp+2Ch]
|
||
cmp eax, esi
|
||
jae @@end_gui ; done iterating
|
||
|
||
; Get PlayerState pointer = PlayerArray.Data[i] (array of pointers)
|
||
mov rax, QWORD PTR [rdi + rax*8]
|
||
test rax, rax
|
||
jz @@player_next
|
||
|
||
mov QWORD PTR [rsp+30h], rax ; save PlayerState*
|
||
|
||
; Get player name via ProcessEvent
|
||
mov rcx, rax
|
||
call GUI__GetPlayerName ; RAX = wchar_t* (or 0)
|
||
test rax, rax
|
||
jz @@player_next
|
||
|
||
; Button with player name (100×25)
|
||
mov rcx, rax ; name = wchar_t*
|
||
movss xmm0, DWORD PTR [f_100_0]
|
||
movd edx, xmm0
|
||
movss xmm0, DWORD PTR [f_25_0]
|
||
movd r8d, xmm0
|
||
call ZeroGUI_Button
|
||
test al, al
|
||
jz @@player_next
|
||
|
||
; Button clicked: set currentPlayer = PlayerState
|
||
mov rax, QWORD PTR [rsp+30h]
|
||
mov QWORD PTR [GUI_currentPlayer], rax
|
||
jmp @@end_gui
|
||
|
||
@@player_next:
|
||
inc DWORD PTR [rsp+2Ch]
|
||
jmp @@player_loop
|
||
|
||
@@end_gui:
|
||
; ZeroGUI_End (flush drawlist)
|
||
call ZeroGUI_End
|
||
|
||
add rsp, 68h
|
||
pop rdi
|
||
pop rsi
|
||
pop rbp
|
||
pop rbx
|
||
ret
|
||
GUI_Tick ENDP
|
||
|
||
END |