• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Local Frame

Level 6
Joined
Aug 26, 2016
Messages
100
I'm trying to create a frame by pressing the "P" key, the trigger itself works, but does not create the "SimpleFrame" I need for the local player.
JASS:
library TotorOn
globals
 private framehandle KeyboxD
 private real Key 
 private real Key2 
endglobals
private function Trig_TutorialkeyOn_Actions takes nothing returns nothing
    local player p = GetOwningPlayer(GetTriggerUnit())
     local framehandle gameUIВ = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
   
    
    call DisplayTextToForce( GetPlayersAll(), "112211" )
   
    
    
     
     
     
    set Key = 0.30
    set Key2 = 0.40
    if GetLocalPlayer() == p then
    
    call BlzLoadTOCFile("war3mapImported\\tocs2.toc")
    set KeyboxD = BlzCreateSimpleFrame("KeyboxS", gameUIB, 0)
    
    call BlzFrameSetAbsPoint(KeyboxD, FRAMEPOINT_CENTER, Key2, Key)
    endif


    set p = null
    set gameUIВ = null



endfunction

//===========================================================================
function InitTrig_TutorialkeyOn takes nothing returns nothing
    set gg_trg_TutorialkeyOn = CreateTrigger(  )
    
    call BlzTriggerRegisterPlayerKeyEvent(gg_trg_TutorialkeyOn,Player(0),OSKEY_P,0,true)
    
   
    call TriggerAddAction( gg_trg_TutorialkeyOn, function Trig_TutorialkeyOn_Actions )
endfunction

endlibrary
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,562
Edit: A glaring mistake I overlooked:
vJASS:
local player p = GetOwningPlayer(GetTriggerUnit())
That is trying to get the Owner of the Triggering Unit when the Event has absolutely nothing to do with a Unit. Change it to GetTriggerPlayer().

I can't guarantee that you've setup your fdf file properly so for all I know the "KeyboxS" doesn't even work, but here's what I would try:
vJASS:
library TotorOn initializer Tutorial_Init

    private function Tutorial_Create_Frame takes nothing returns nothing
        local player p = GetTriggerPlayer()
        local framehandle gameUI = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
        local framehandle fh

        set fh = BlzCreateSimpleFrame("KeyboxS", gameUI, 0)
        call BlzFrameSetAbsPoint(fh, FRAMEPOINT_CENTER, 0.30, 0.40)

        // Hide the frame for everyone
        call BlzFrameSetVisible(fh, false)

        // Show the frame to the local player
        if GetLocalPlayer() == p then
            call BlzFrameSetVisible(fh, true)
        endif
 
        set p = null
        set gameUI = null
        set fh = null
    endfunction
 
    function Tutorial_Init takes nothing returns nothing
        local trigger t = CreateTrigger()

        // You only need to load the TOC file once at the start of the game.
        // Once loaded you can reference it's frames anytime you want:
        call BlzLoadTOCFile("war3mapImported\\tocs2.toc")

        call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), OSKEY_P, 0, true)
        call TriggerAddAction(t, function Tutorial_Create_Frame)

        set t = null
    endfunction
 
endlibrary
1) I made it so the code no longer needs a trigger from the Trigger Editor. Everything is contained inside of the script.
2) I created the frame for everyone but only show it to the desired player. I BELIEVE this is the go to method to prevent desyncs.
3) I only load the TOC file once. It shouldn't be loaded mutltiple times.
4) I cleaned some things up just for the sake of clarity. Feel free to add the global variables back.
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,562
I get it), but how do I turn off the frame or hide it when I press or release the button again?
Before we go there, what exactly are you trying to do? To me, it sounds like you want to Create this frame once at the start of the game, then hide it for everyone, and then only show it when the player presses the "P" hotkey. If they press "P" again it should be hidden again.

So like this:
Game starts -> Create frame and hide it.
Player 1 presses "P" once -> Show frame.
Player 1 presses "P" again -> Hide frame.

So Player 1 can toggle the frame visibility on and off by pressing "P".

Or do you only want to show it while you're HOLDING down "P"?
 
Level 6
Joined
Aug 26, 2016
Messages
100
Yes, I’m very interested in how to do this, I made a picture in Photoshop with the buttons that are used in the map, I understood how to display it on the screen, but I don’t know how to remove it).
 

Attachments

  • изображение_2023-09-10_174055510.png
    изображение_2023-09-10_174055510.png
    497.4 KB · Views: 9

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,562
This function toggles visibility on/off:
vJASS:
call BlzFrameSetVisible(frame, false)
call BlzFrameSetVisible(frame, true)
true = Show, false = Hide. It should be shown locally if you only want one player to see it.

To manage the hotkeys you change true/false in this key event function:
vJASS:
// P key is pressed down (true)
call BlzTriggerRegisterPlayerKeyEvent(trigger, player, OSKEY_P, 0, true)

// P key is released (false)
call BlzTriggerRegisterPlayerKeyEvent(trigger, player, OSKEY_P, 0, false)
true = key is pressed down, false = key is released.


Here's the code for toggling the frame's visibility on and off. When you press and release the "P" key the frame is either shown or hidden based on a boolean variable that we toggle from false to true and true to false:
vJASS:
library TotorOn initializer Init_Keyboard_Frame

    globals
        private framehandle array keyboard
        private boolean array frameIsVisible
    endglobals

    private function Toggle_Keyboard_Frame takes nothing returns nothing
        local player p = GetTriggerPlayer()
        local integer id = GetPlayerId(p)

        // Toggle visibility boolean
        if frameIsVisible[id] then
            // Hide the frame for everyone:
            call BlzFrameSetVisible(keyboard[id], false)
            set frameIsVisible[id] = false
        else
            // Show the frame to the local player:
            if GetLocalPlayer() == p then
                call BlzFrameSetVisible(keyboard[id], true)
            endif
            set frameIsVisible[id] = true
        endif

        set p = null
    endfunction

    private function Create_Keyboard_Frame takes integer id returns nothing
        local player p = Player(id)
        local framehandle origin = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)

        set keyboard[id] = BlzCreateSimpleFrame("KeyboxS", origin, 0)
        call BlzFrameSetAbsPoint(keyboard[id], FRAMEPOINT_CENTER, 0.30, 0.40)

        // Hide the frame for everyone:
        call BlzFrameSetVisible(keyboard[id], false)
 
        set p = null
        set origin = null
    endfunction
 
    function Init_Keyboard_Frame takes nothing returns nothing
        local trigger toggleTrigger = CreateTrigger()
        local integer id = 0

        // You only need to load the TOC file once at the start of the game.
        // Once loaded you can reference it's frames anytime you want:
        call BlzLoadTOCFile("war3mapImported\\tocs2.toc")
 
        // Loop over Players 1 - 24 (0 -> 23) and setup their frames/triggers:
        loop
            call Create_Keyboard_Frame(id)

            call BlzTriggerRegisterPlayerKeyEvent(toggleTrigger, Player(id), OSKEY_P, 0, false)
            call TriggerAddAction(toggleTrigger, function Toggle_Keyboard_Frame)

            set id = id + 1
            exitwhen id == 24
        endloop

        set toggleTrigger = null
    endfunction
 
endlibrary


Here's the same code but instead of toggling the hotkey we check to see if the "P" key is being held down:
vJASS:
library TotorOn initializer Init_Keyboard_Frame

    globals
        private framehandle array keyboard
    endglobals

    private function Show_Keyboard_Frame takes nothing returns nothing
        local player p = GetTriggerPlayer()
        local integer id = GetPlayerId(p)

        // Show the frame to the local player:
        if GetLocalPlayer() == p then
            call BlzFrameSetVisible(keyboard[id], true)
        endif

        set p = null
    endfunction

    private function Hide_Keyboard_Frame takes nothing returns nothing
        local player p = GetTriggerPlayer()
        local integer id = GetPlayerId(p)

        // Hide the frame for everyone:
        call BlzFrameSetVisible(keyboard[id], false)

        set p = null
    endfunction

    private function Create_Keyboard_Frame takes integer id returns nothing
        local player p = Player(id)
        local framehandle origin = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)

        set keyboard[id] = BlzCreateSimpleFrame("KeyboxS", origin, 0)
        call BlzFrameSetAbsPoint(keyboard[id], FRAMEPOINT_CENTER, 0.30, 0.40)

        // Hide the frame for everyone:
        call BlzFrameSetVisible(keyboard[id], false)
 
        set p = null
        set origin = null
    endfunction
 
    function Init_Keyboard_Frame takes nothing returns nothing
        local trigger showTrigger = CreateTrigger()
        local trigger hideTrigger = CreateTrigger()
        local integer id = 0

        // You only need to load the TOC file once at the start of the game.
        // Once loaded you can reference it's frames anytime you want:
        call BlzLoadTOCFile("war3mapImported\\tocs2.toc")
 
        // Loop over Players 1 - 24 (0 -> 23) and setup their frames/triggers:
        loop
            call Create_Keyboard_Frame(id)
            call BlzTriggerRegisterPlayerKeyEvent(showTrigger, Player(id), OSKEY_P, 0, true)
            call TriggerAddAction(showTrigger, function Show_Keyboard_Frame)
            call BlzTriggerRegisterPlayerKeyEvent(hideTrigger, Player(id), OSKEY_P, 0, false)
            call TriggerAddAction(hideTrigger, function Hide_Keyboard_Frame)
            set id = id + 1
            exitwhen id == 24
        endloop

        set showTrigger = null
        set hideTrigger = null
    endfunction
 
endlibrary
This way the keyboard is only visible while you're holding "P".
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,562
Thank you very much), excellent material for studying, I love this site, they are always ready to help), it’s a pity that there are not so many people in the Rus community who are ready to help.
Glad to help, hopefully the code isn't buggy, I couldn't really test it since I don't have your toc/fdf files and it's been a while since I've played around with frames. There may be a better method out there then what I have done but I think it should work fine. Tasyen would know best -> The Big UI-Frame Tutorial

Also, I edited the code recently, so make sure you're up to date.
 
Level 17
Joined
Apr 13, 2008
Messages
1,597
One very important thing:

If you save the game then load it back your frames will crash the game. This is because Blizzard forgot to include frames properly in save files, but your code will probably reference frames, so they will reference to places in the memory that do not exist -> boom, crash.

So you need an additional trigger that fires on game load. Example from my map:

JASS:
    call TriggerRegisterGameEvent(trg_LoadBugProtection, EVENT_GAME_LOADED)
    call TriggerAddAction(trg_LoadBugProtection, function LoadBugProtectionActions)

Two things are very important to have in this event.
1.) Destroy and recreate all the triggers which have frames registered as an event.
2.) Recreate all the frames and if you use frame variables, set these newly create frames to variables.

Example from my map (Work in progress):

JASS:
function LoadBugProtectionActions takes nothing returns nothing
    // As of 2023 September, there is a bug in Warcraft III's current patch, where logic containing frames always crashes the game upon loading a save game
    // Because of that, we set certain variables during EVENT_GAME_LOADED rather than map initialization
    local integer i = 0

    call BJDebugMsg("LoadBugProtectionActions function started")
    
    call DestroyTrigger(trg_InventoryToggleButtonClicked)
    call DestroyTrigger(trg_PageLeftClicked)
    call DestroyTrigger(trg_PageRightClicked)
    set trg_InventoryToggleButtonClicked = CreateTrigger()
    if InventoryPages > 1 then
    set trg_PageLeftClicked = CreateTrigger()
    set trg_PageRightClicked = CreateTrigger()
    endif
    
    set InventoryBotRightX = InventorySlotGap + InventoryTopLeftX + InventoryColumns * (InventorySlotGap + InventorySlotSize)
    set InventoryBotRightY = -InventorySlotGap + InventoryTopLeftY - InventoryRows * (InventorySlotGap + InventorySlotSize)
    
// CONFIGURE if you want:
// By default the close inventory X button will be on the top right of the inventory.
// You can put it whenever you want, or if you set its bot right coordinates equal to the topleft coords, then it will not be visible - you basically disabled it.
    set InventoryCloseTopLeftX = InventoryBotRightX + InventorySlotGap
    set InventoryCloseTopLeftY = InventoryTopLeftY + InventorySlotGap
    set InventoryCloseBotRightX = InventoryCloseTopLeftX + 0.03
    set InventoryCloseBotRightY = InventoryCloseTopLeftY - 0.03
    
    set i = 0
    loop
        if GetPlayerSlotState(Player(i))==PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i))==MAP_CONTROL_USER then
        call CreateInvToggleButton(i)
        call CreateInventoryUI(i)
        if InventoryPages > 1 then
            call BlzTriggerRegisterFrameEvent(trg_PageLeftClicked, InventoryPageLeftButtonFrame[i], FRAMEEVENT_CONTROL_CLICK)
            call BlzTriggerRegisterFrameEvent(trg_PageRightClicked, InventoryPageRightButtonFrame[i], FRAMEEVENT_CONTROL_CLICK)
        endif
            
        call BlzTriggerRegisterFrameEvent(trg_InventoryToggleButtonClicked,InventoryToggleButtonFrame[i], FRAMEEVENT_CONTROL_CLICK)
        call BlzTriggerRegisterFrameEvent(trg_InventoryToggleButtonClicked,InventoryXButtonFrame[i], FRAMEEVENT_CONTROL_CLICK)
        call TriggerRegisterPlayerUnitEvent(trg_ItemObtainedDI, Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
        endif
    set i = i + 1
    exitwhen i > 23
    endloop

    call TriggerAddAction(trg_InventoryToggleButtonClicked, function InventoryButtonClicked)
    call TriggerAddAction(trg_ItemObtainedDI, function ItemPickedUpActions)
    
    call BJDebugMsg("LoadBugProtectionActions function finished")
    endfunction
 
Top