• 🏆 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!

Panel System v2.1

Description:
This is a custom user interface system in disguise. It allows you to easily adds custom user interfaces into the screen. It supports UI parenting and layering out of the box, giving you easy control over multiple custom UI properties. It's written in highly optimized vJass code with particular rendering technique to allow hundreds of custom interfaces added into the screen with minimal performance cost! Supports clean & highly intuitive API too!

Map example: EmberCraft ARPG
Includes:
- Inventory & equipment system
- Equipment set system
- Item enhancement & socketing system
- Custom status bar
- Shortcut bar system
- Item tooltips system
- Arcane statistic window
- Skill list window
- Shop System

Note: if you need a new font style (face), don't hesitate to request me to make it. Just give me the ttf file (or just mention the name) and I will send you all the textures complete with its configurations very soon.

Available fonts:

Requirements:
  • LinkedListModule
  • (Optional) PanelCameraRegulator: custom camera refreshing and provides event, necessary for the panel system to update positions precisely.
  • (Plugin - Optional) PanelModel: plugin for adding model files into panels.
  • (Plugin - Optional) PanelPlatform: plugin for adding platform objects into panels.
  • (Plugin - Optional) PanelTextTag: plugin for adding text tags into panels.
  • (Plugin - Optional) PanelText: plugin for adding texts with custom style into panels.
Codes (v2.0):

System Core

Camera Regulator

Plugin - Model

Plugin - Platform

Plugin - TextTag

Plugin - Text

JASS:
library PanelCore requires LinkedListModule, optional PanelCamera

    /*
        ~ Panel Core ~

        Provides parenting, events, coordinate conversions & calculations,
        and all necessary functions for panel contents and plugins.
 
        I. API
 
            struct Panel
         
                Members:
                    readonly unit dummy
                        - Panel's dummy unit object
                    readonly boolean visible
                        - Get panel's visibility state
                    readonly real zDepth
                        - Panel's depth
                    readonly Panel base
                        - List containing all panels
                 
                    readonly static real ScreenCenterX
                    readonly static real ScreenCenterY
                    readonly static real ScreenCenterZ
                        - Get current camera center position
                 
                    readonly static real ReturnValX
                    readonly static real ReturnValY
                    readonly static real ReturnValZ
                        - Returned value from getRelativePos & Win2World method
                 
                Event related members:
                    readonly static integer EventType
                        - Type of triggered event
                    readonly static thistype TriggeringPanel
                        - Get which panel is triggering the event
             
                    static constant integer EVENT_PANEL_REFRESHED
                        - Fired when a panel is done refreshing
                    static constant integer EVENT_PANEL_CLEARED
                        - Fired when a panel is done clearing its contents
                    static constant integer EVENT_PANEL_VISIBILITY_MODIFIED
                        - Fired when a panel's visibility is changed (shown/hidden)
                    static constant integer EVENT_PANEL_OPACITY_MODIFIED
                        - Fired when a panel's opacity/transparency is changed
                    static constant integer EVENT_PANEL_DESTROYED
                        - Fired right before a panel is destroyed
     
                Methods:
                    static method create takes integer id, integer background, real xOffset, real yOffset, real zDepth returns Panel
                        - Instantiate new panel
                        - x/yOffset indicates the distance from center of the screen
                        - zDepth indicates how far from screen position the panel will be
 
                    static method Win2World takes real xOffset, real yOffset, real zDepth returns nothing
                        - Converts screen coordinates into world coordinates
                        - Returned values are stored in: ReturnValX/Y/Z
                 
                    static method RegisterAnyPanelEvent takes code func returns triggercondition
                    static method UnregisterAnyPanelEvent takes triggercondition tc returns nothing
                        - (Un)register a function to be executed on panel events
                        - Passed function must returns boolean
                 
                    method operator background= takes integer texture returns nothing
                        - Modify panel's background texture
                 
                    method operator scale= takes real r returns nothing
                    method operator scale takes nothing returns real
                        - Set/get panel's scale
                 
                    method operator xOffset takes nothing returns real
                    method operator yOffset takes nothing returns real
                        - Get panel position coordinate
                 
                    method operator opacity= takes integer i returns nothing
                    method operator opacity takes nothing returns integer
                        - Set/get panel's opacity/transparency
             
                    method refresh takes nothing returns nothing
                        - Refresh panel and its contents properties
                    method destroy takes nothing returns nothing
                        - Destroy the panel
                    method clear takes nothing returns nothing
                        - Remove all contents from the panel
                    method move takes real xOffset, real yOffset, real zDepth returns nothing
                        - Move the panel
                    method show takes boolean b returns nothing
                        - Show/hide the panel from screen
                    method getRelativePos takes real xOffset, real yOffset, real zDepth returns nothing
                        - Get screen position relative to panels position
                        - Returned values are stored in: ReturnValX/Y/Z
             
        III. Credits
            Dirac  | LinkedListModule  | https://www.hiveworkshop.com/threads/snippet-linkedlistmodule.206552/
         
    */

                               ////////////////////
                               // Configurations //
                               ////////////////////
        globals
            // Rawcode of texture replacer ability
            public constant integer TEXTURE_REPLACER_ID = 'APTR'
            public constant integer REPLACER_ORDER_ID = 852511
            // Maximum number of rendering level at zero Z Offset
            public constant integer MAX_LEVEL = 50
            // Only used if not using the camera regulator system
            public constant real REFRESH_RATE = 0.03
        endglobals

                                //////////////////
                                // System codes //
                                //////////////////

    globals
        private location L = Location(0, 0)
        public real DeltaZ = 0
        public real WorldMaxX = 0
        public real WorldMaxY = 0
        public real WorldMinX = 0
        public real WorldMinY = 0
        public constant real HP   = bj_PI/2
        public constant real TAU  = bj_PI*2
        public constant real R270 = bj_PI+HP
        public constant real LEVEL_GAP  = 0.00275
        public constant real CAMERA_GAP = 99.975+LEVEL_GAP*MAX_LEVEL
        public constant real GENERAL_SIZE = 0.0905
        public constant real PIXEL_CORRECTION_X = GENERAL_SIZE*0.8899125
        public constant real PIXEL_CORRECTION_Y = PIXEL_CORRECTION_X*1.3186813
        public constant player PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
    endglobals

    public function AngularDifference takes real a, real b returns real
        return Atan2(Sin(a-b), Cos(a-b))
    endfunction

    public function GetTerrainZ takes real x, real y returns real
        call MoveLocation(L, x, y)
        return GetLocationZ(L)
    endfunction

    public function GetUnitZ takes unit u returns real
        return GetTerrainZ(GetUnitX(u), GetUnitY(u))+GetUnitFlyHeight(u)
    endfunction
 
    public function SetUnitZ takes unit u, real z returns nothing
        call SetUnitFlyHeight(u, z-GetTerrainZ(GetUnitX(u), GetUnitY(u)), 0)
    endfunction

    public function ChangeTexture takes unit whichUnit, integer whichTexture returns nothing

        local destructable d = null
        local real x
        local real y
 
        if whichTexture != 0 then
            set d = CreateDestructable(whichTexture, 0, 0, 0, 0, 1)
            if d != null then
                set x = GetUnitX(whichUnit)
                set y = GetUnitY(whichUnit)
                call SetUnitX(whichUnit, 0)
                call SetUnitY(whichUnit, 0)
                call IssueTargetOrderById(whichUnit, REPLACER_ORDER_ID, d)
                call RemoveDestructable(d)
                call SetUnitX(whichUnit, x)
                call SetUnitY(whichUnit, y)
                set d = null
            endif
        endif
 
    endfunction

    struct Panel extends array

        implement LinkedList
 
        readonly real size
        readonly real zDepth
        readonly real xOffset
        readonly real yOffset
 
        private  integer skin
        private  integer op
        readonly boolean visible
        readonly unit dummy
 
        readonly static real ReturnValX = 0
        readonly static real ReturnValY = 0
        readonly static real ReturnValZ = 0
        readonly static real ScreenCenterX = 0
        readonly static real ScreenCenterY = 0
        readonly static real ScreenCenterZ = 0
 
        private static real YawC    = 0
        private static real YawS    = 0
        private static real YawC2   = 0
        private static real YawS2   = 0
        private static real PitchC  = 0
        private static real PitchS  = 0
        private static real Pitch2C = 0
        private static real Pitch2S = 0
 
        readonly static integer  EventType = 0
        readonly static thistype TriggeringPanel = 0
        private  static trigger  EventTrigger = CreateTrigger()
 
        static if not LIBRARY_PanelCamera then
            private static timer Timer = CreateTimer()
        endif
 
        static constant integer EVENT_PANEL_REFRESHED           = 1
        static constant integer EVENT_PANEL_CLEARED             = 2
        static constant integer EVENT_PANEL_VISIBILITY_MODIFIED = 3
        static constant integer EVENT_PANEL_DESTROYED           = 4
        static constant integer EVENT_PANEL_OPACITY_MODIFIED    = 5
 
        private method fireEvent takes integer whichEvent returns nothing
            set TriggeringPanel = this
            set EventType = whichEvent
            call TriggerEvaluate(EventTrigger)
        endmethod
 
        static method Win2World takes real xOffset, real yOffset, real zDepth returns nothing
 
            local real yzOffset = yOffset*Pitch2S*PIXEL_CORRECTION_Y-zDepth*PitchC
     
            set ReturnValX = ScreenCenterX+xOffset*PIXEL_CORRECTION_X*YawC2+yzOffset*YawC
            set ReturnValY = ScreenCenterY+xOffset*PIXEL_CORRECTION_X*YawS2+yzOffset*YawS
            set ReturnValZ = ScreenCenterZ+yOffset*PIXEL_CORRECTION_Y*Pitch2C+zDepth*PitchS
     
        endmethod
 
        static method RegisterAnyPanelEvent takes code func returns triggercondition
            return TriggerAddCondition(EventTrigger, Condition(func))
        endmethod
 
        static method UnregisterAnyPanelEvent takes triggercondition tc returns nothing
            call TriggerRemoveCondition(EventTrigger, tc)
        endmethod
 
        method operator background= takes integer texture returns nothing
            if texture != .skin then
                call ChangeTexture(.dummy, texture)
                set .skin = texture
            endif
        endmethod
 
        method operator opacity= takes integer i returns nothing
            set .op = i
            call SetUnitVertexColor(.dummy, 255, 255, 255, i)
            call fireEvent(EVENT_PANEL_OPACITY_MODIFIED)
        endmethod
 
        method operator scale= takes real r returns nothing
            set .size = r*GENERAL_SIZE
            if .visible then
                call SetUnitScale(.dummy, .size, 1, 1)
            endif
        endmethod
 
        method operator background takes nothing returns integer
            return .skin
        endmethod
 
        method operator opacity takes nothing returns integer
            return .op
        endmethod
 
        method operator scale takes nothing returns real
            return .size/GENERAL_SIZE
        endmethod
 
        method getRelativePos takes real xOffset, real yOffset, real zDepth returns nothing
            call Win2World(.xOffset+xOffset, .yOffset+yOffset, .zDepth+zDepth)
        endmethod
 
        method refresh takes nothing returns nothing
 
            if .visible then
                call Win2World(.xOffset, .yOffset, .zDepth)
                if ReturnValX > WorldMinX and ReturnValX < WorldMaxX and ReturnValY > WorldMinY and ReturnValY < WorldMaxY then
                    call SetUnitX(.dummy, ReturnValX)
                    call SetUnitY(.dummy, ReturnValY)
                    call SetUnitZ(.dummy, ReturnValZ)
                    call SetUnitScale(.dummy, .size, 1, 1)
                else
                    call SetUnitScale(.dummy, 0, 0, 0)
                endif
                call fireEvent(EVENT_PANEL_REFRESHED)
            endif
     
        endmethod
 
        method clear takes nothing returns nothing
            call fireEvent(EVENT_PANEL_CLEARED)
        endmethod
 
        method destroy takes nothing returns nothing
            call fireEvent(EVENT_PANEL_DESTROYED)
            call RemoveUnit(.dummy)
            call removeNode()
            call deallocate()
            set .dummy = null
        endmethod
 
        method show takes boolean b returns nothing
            if b != .visible then
                set .visible = b
                if b then
                    call SetUnitScale(.dummy, .size, 1, 1)
                else
                    call SetUnitScale(.dummy, 0, 0, 0)
                    call SetUnitX(.dummy, WorldMaxX)
                    call SetUnitY(.dummy, WorldMaxY)
                endif
                call fireEvent(EVENT_PANEL_VISIBILITY_MODIFIED)
            endif
        endmethod
 
        method move takes real xOffset, real yOffset, real zDepth returns nothing
            set .xOffset = xOffset
            set .yOffset = yOffset
            set .zDepth  = -zDepth
        endmethod
 
        static method create takes integer id, integer background, real xOffset, real yOffset, real zDepth returns Panel
     
            local thistype this = allocate()
     
            set .scale   = 1
            set .opacity = 255
            set .visible = true
            set .dummy   = CreateUnit(PASSIVE, id, 0, 0, 0)
            set .skin    = background
     
            static if not LIBRARY_AutoFly then
                if UnitAddAbility(.dummy, 'Amrf') and UnitRemoveAbility(.dummy, 'Amrf') then
                endif
            endif
            call UnitAddAbility(.dummy, TEXTURE_REPLACER_ID)
            call UnitRemoveAbility(.dummy, 'Amov')
            call SetUnitPathing(.dummy, false)
            call ChangeTexture(.dummy, background)
            call move(xOffset, yOffset, zDepth)
            call base.insertNode(this)
            call refresh()
     
            return this
        endmethod
 
        private static method GetScreenCenterPos takes nothing returns nothing
     
            local real d
            local real x
            local real y
            local real z
            local real x2
            local real y2
            local real cd
            local real cz
            local real yaw
            local real pitch
         
            static if LIBRARY_PanelCamera then
                set x   = PanelCamera_LocX
                set y   = PanelCamera_LocY
                set cz  = PanelCamera_ZOffset+DeltaZ
                set cd  = PanelCamera_TargetDistance-CAMERA_GAP
                set yaw = PanelCamera_Rotation
                set pitch = PanelCamera_AngleOfAttack
            else
                set x   = GetCameraTargetPositionX()
                set y   = GetCameraTargetPositionY()
                set cz  = GetCameraTargetPositionZ()
                set cd  = GetCameraField(CAMERA_FIELD_TARGET_DISTANCE)-CAMERA_GAP
                set yaw = GetCameraField(CAMERA_FIELD_ROTATION)
                set pitch = GetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK)
            endif
     
            if pitch < R270 and pitch > HP then
                set yaw   = bj_PI+yaw
                set pitch = bj_PI-pitch
            endif
            set pitch   = (pitch-AngularDifference(pitch, R270)*2)-bj_PI
            set YawC    = Cos(yaw)
            set YawS    = Sin(yaw)
            set YawC2   = Cos(yaw-HP)
            set YawS2   = Sin(yaw-HP)
            set PitchC  = Cos(pitch)
            set PitchS  = Sin(pitch)
            set pitch   = AngularDifference(pitch-HP, R270)
            set Pitch2C = Cos(pitch)
            set Pitch2S = Sin(pitch)
            set d        = cd*PitchC
            set ScreenCenterX = x-d*YawC
            set ScreenCenterY = y-d*YawS
            set ScreenCenterZ = cz+cd*PitchS
     
        endmethod
 
        private static method refreshPanels takes nothing returns boolean
 
            local thistype node = base.next
     
            call GetScreenCenterPos()
            loop
                exitwhen node.head or node == 0
                if node.visible then
                    call node.refresh()
                endif
                set node = node.next
            endloop
     
            return false
        endmethod
 
        private static method onInit takes nothing returns nothing
 
            set WorldMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
            set WorldMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
            set WorldMinX = GetRectMinX(bj_mapInitialPlayableArea)
            set WorldMinY = GetRectMinX(bj_mapInitialPlayableArea)
     
            call SetCameraPosition(0, 0)
            set DeltaZ = GetCameraTargetPositionZ()
            static if LIBRARY_PanelCamera then
                call RegisterOnCameraRefreshEvent(function thistype.refreshPanels)
            else
                call TimerStart(Timer, REFRESH_RATE, true, function thistype.refreshPanels)
            endif
     
        endmethod
 
    endstruct

endlibrary
JASS:
library PanelCamera
 
    /*
        ~ Panel Camera Regulator ~
   
        A complementary system for the panel system. Required in
        order to let it reposition itself accurately. It works just
        like the native camera, with some hotfixes of course.
   
        By using this, default camera scrolling (mouse & keyboard) will be
        disabled. Camera field roll and field of view isn't allowed to be
        modified as well. And you are only allowed to use some specific
        camera related functions which will be specified below. Deal with it.
   
        I. API
            function RefreshCamera takes nothing returns nothing
                - Call this everytime you update the camera
           
            function SetCameraFieldEx takes camerafield whichField, real value, real duration returns nothing
                - This is a replacement of native SetCameraField
                - You can still use the native ones but you can use this instead if you need some extra speed
           
            function RegisterOnCameraRefreshEvent takes code func return triggercondition
            function UnregisterOnCameraRefreshEvent takes triggercondition cond return nothing
                - (Un)register a function to be executed everytime camera is done refreshing
       
        II. Extra notes
   
            So far you may only use these native and BJ functions:
                - SetCameraField
                - SetCameraFieldForPlayer [GUI]
                - SetCameraPosition
                - PanCameraTo
                - PanCameraToTimed
                - PanCameraToTimedLocForPlayer [GUI]
                - CameraSetSmoothingFactor
                - CameraSetupApply
                - CameraSetupApplyForceDuration
                - CameraSetupApplyForPlayer [GUI]
                - SetCameraTargetController
                - SetCameraTargetControllerNoZForPlayer[GUI]
           
            Just let me know if you need more functions to be supported.
         
            Function call replacements:
                (Variable name) = (Replaced function)
                LocX            = GetCameraTargetPositionX()
                LocY            = GetCameraTargetPositionY()
                ZOffset            = CAMERA_FIELD_ZOFFSET / GetCameraTargetPositionZ()
                AngleOfAttack    = CAMERA_FIELD_ANGLE_OF_ATTACK
                CameraFarZ        = CAMERA_FIELD_FARZ
                Rotation        = CAMERA_FIELD_ROTATION
                TargetDistance    = CAMERA_FIELD_TARGET_DISTANCE
    */
 
                               ////////////////////
                               // Configurations //
                               ////////////////////
                         
    globals
        // Minimum value difference that will be processed by the system
        // Must be a positive value
        private constant real TOLERANCE = 0.1
        // Lower value makes the camera looks smoother but will cause the system
        // to work significantly harder
        private constant real INTERVAL = 0.03125
    endglobals
 
                                //////////////////
                                // System codes //
                                //////////////////

    globals
        public real LocX            = 0
        public real LocY            = 0
        public real ZOffset         = 0
        public real TargetDistance  = bj_CAMERA_DEFAULT_DISTANCE
        public real Rotation        = bj_CAMERA_DEFAULT_ROTATION*bj_DEGTORAD
        public real AngleOfAttack   = bj_CAMERA_DEFAULT_AOA*bj_DEGTORAD
   
        private real LocXTarget     = LocX
        private real LocYTarget     = LocY
        private real TargetDistanceTarget = TargetDistance
        private real RotationTarget = Rotation
        private real AngleOfAttackTarget = AngleOfAttack
        private real ZOffsetTarget  = ZOffset
        private real LocXRate       = 0.0
        private real LocYRate       = 0.0
        private real ZOffsetRate    = 0.0
        private real TargetDistanceRate = 0.0
        private real RotationRate   = 0.0
        private real AngleOfAttackRate = 0.0
   
        private unit    CameraMan
        private player  Locale
        private boolean Boole       = false
        private boolean Notify      = true
        private timer   CamTimer    = CreateTimer()
        private timer   StopTimer   = CreateTimer()
        private trigger Trigg       = CreateTrigger()
        private constant real HP    = bj_PI/2
        private constant real TAU   = bj_PI*2
    endglobals
 
    private function AngularDifference takes real a, real b returns real
        return RAbsBJ(Atan2(Sin(a-b), Cos(a-b)))
    endfunction
 
    function RefreshCamera takes nothing returns nothing
        set Boole = true
        call SetCameraField(CAMERA_FIELD_ROLL, 0, 0)
        call SetCameraField(CAMERA_FIELD_FIELD_OF_VIEW, bj_CAMERA_DEFAULT_FOV, 0)
        call SetCameraField(CAMERA_FIELD_ROTATION, Rotation*bj_RADTODEG, 0)
        call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, AngleOfAttack*bj_RADTODEG, 0)
        call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, TargetDistance, 0)
        call SetCameraField(CAMERA_FIELD_ZOFFSET, ZOffset, 0)
        call SetCameraTargetController(CameraMan, LocX, LocY, false)
        set Boole = false
    endfunction
 
    private function FireEvent takes nothing returns nothing
        if Notify then
            call RefreshCamera()
            call TriggerEvaluate(Trigg)
        endif
    endfunction
 
    private function onTick takes nothing returns nothing
        set Notify = false
        if Rotation != RotationTarget then
            if Cos(Rotation-RotationTarget) <= Cos(RotationRate) then
                if Sin(RotationTarget-Rotation) >= 0 then
                    set Rotation = Rotation + RotationRate
                else
                    set Rotation = Rotation - RotationRate
                endif
            else
                set Rotation = RotationTarget
            endif
            set Notify = true
        endif
        if AngleOfAttack != AngleOfAttackTarget then
            if Cos(AngleOfAttack-AngleOfAttackTarget) <= Cos(AngleOfAttackRate) then
                if Sin(AngleOfAttackTarget-AngleOfAttack) >= 0 then
                    set AngleOfAttack = AngleOfAttack + AngleOfAttackRate
                else
                    set AngleOfAttack = AngleOfAttack - AngleOfAttackRate
                endif
            else
                set AngleOfAttack = AngleOfAttackTarget
            endif
            set Notify = true
        endif
        if TargetDistance != TargetDistanceTarget then
            if RAbsBJ(TargetDistance-TargetDistanceTarget) <= RAbsBJ(TargetDistanceRate) then
                set TargetDistance = TargetDistanceTarget
            else
                set TargetDistance = TargetDistance + TargetDistanceRate
            endif
            set Notify = true
        endif
        if ZOffset != ZOffsetTarget then
            if RAbsBJ(ZOffset-ZOffsetTarget) <= RAbsBJ(ZOffsetRate) then
                set ZOffset = ZOffsetTarget
            else
                set ZOffset = ZOffset + ZOffsetRate
            endif
            set Notify = true
        endif
        if LocX != LocXTarget then
            if RAbsBJ(LocX-LocXTarget) <= RAbsBJ(LocXRate) then
                set LocX = LocXTarget
            else
                set LocX = LocX + LocXRate
            endif
            set Notify = true
        endif
        if LocY != LocYTarget then
            if RAbsBJ(LocY-LocYTarget) <= RAbsBJ(LocYRate) then
                set LocY = LocYTarget
            else
                set LocY = LocY + LocYRate
            endif
            set Notify = true
        endif
        call FireEvent()
        set Notify = true
    endfunction
 
    function SetCameraFieldEx takes camerafield whichField, real value, real duration returns nothing
        if whichField == CAMERA_FIELD_ROTATION then
            if AngularDifference(Rotation, value*bj_DEGTORAD) > TOLERANCE*bj_DEGTORAD then
                set RotationTarget = value*bj_DEGTORAD
                if duration <= 0 then
                    set Rotation = RotationTarget
                    call FireEvent()
                else
                    set RotationRate = AngularDifference(Rotation, RotationTarget)/duration*INTERVAL
                endif
            endif
        elseif whichField == CAMERA_FIELD_ANGLE_OF_ATTACK then
            if AngularDifference(AngleOfAttack, value*bj_DEGTORAD) > TOLERANCE*bj_DEGTORAD then
                set AngleOfAttackTarget = value*bj_DEGTORAD
                if duration <= 0 then
                    set AngleOfAttack = AngleOfAttackTarget
                    call FireEvent()
                else
                    set AngleOfAttackRate = AngularDifference(AngleOfAttack, AngleOfAttackTarget)/duration*INTERVAL
                endif
            endif
        elseif whichField == CAMERA_FIELD_TARGET_DISTANCE then
            if RAbsBJ(TargetDistance-value) > TOLERANCE then
                set TargetDistanceTarget = value
                if duration <= 0 then
                    set TargetDistance = value
                    call FireEvent()
                else
                    set TargetDistanceRate = (value-TargetDistance)/duration*INTERVAL
                endif
            endif
        elseif whichField == CAMERA_FIELD_ZOFFSET then
            if RAbsBJ(ZOffset-value) > TOLERANCE then
                set ZOffsetTarget = value
                if duration <= 0 then
                    set ZOffset = value
                    call FireEvent()
                else
                    set ZOffsetRate = (value-ZOffset)/duration*INTERVAL
                endif
            endif
        endif
    endfunction
 
    private function SetCameraFieldCatcher takes camerafield whichField, real value, real duration returns nothing
        if not Boole then
            call SetCameraFieldEx(whichField, value, duration)
        endif
    endfunction
 
    private function SetCameraFieldForPlayerEx takes player whichPlayer, camerafield whichField, real value, real duration returns nothing
        if Locale == whichPlayer then
            call SetCameraFieldEx(whichField, value, duration)
        endif
    endfunction
 
    private function SetCameraPositionEx takes real x, real y returns nothing
        set LocX = x
        set LocY = y
        set LocXTarget = x
        set LocYTarget = y
        call FireEvent()
    endfunction
 
    private function PanCameraToTimedEx takes real x, real y, real duration returns nothing
   
        local boolean updateX = RAbsBJ(LocX-x) > TOLERANCE
        local boolean updateY = RAbsBJ(LocY-y) > TOLERANCE
   
        if updateX or updateY then
            if duration <= 0 then
                call SetCameraPositionEx(x, y)
            else
                if updateX then
                    set LocXTarget = x
                    set LocXRate = (x-LocX)/duration*INTERVAL
                endif
                if updateY then
                    set LocYTarget = y
                    set LocYRate = (y-LocY)/duration*INTERVAL
                endif
            endif
        endif
   
    endfunction
 
    private function PanCameraToTimedLocForPlayerEx takes player whichPlayer, location loc, real duration returns nothing
        if Locale == whichPlayer then
            call PanCameraToTimedEx(GetLocationX(loc), GetLocationY(loc), duration)
        endif
    endfunction
 
    private function CameraSetupApplyForceDurationEx takes camerasetup whichSetup, boolean doPan, real forceDuration returns nothing
        call SetCameraFieldEx(CAMERA_FIELD_ANGLE_OF_ATTACK, CameraSetupGetField(whichSetup, CAMERA_FIELD_ANGLE_OF_ATTACK), forceDuration)
        call SetCameraFieldEx(CAMERA_FIELD_FARZ, CameraSetupGetField(whichSetup, CAMERA_FIELD_FARZ), forceDuration)
        call SetCameraFieldEx(CAMERA_FIELD_FIELD_OF_VIEW, CameraSetupGetField(whichSetup, CAMERA_FIELD_FIELD_OF_VIEW), forceDuration)
        call SetCameraFieldEx(CAMERA_FIELD_ROLL, CameraSetupGetField(whichSetup, CAMERA_FIELD_ROLL), forceDuration)
        call SetCameraFieldEx(CAMERA_FIELD_ROTATION, CameraSetupGetField(whichSetup, CAMERA_FIELD_ROTATION), forceDuration)
        call SetCameraFieldEx(CAMERA_FIELD_TARGET_DISTANCE, CameraSetupGetField(whichSetup, CAMERA_FIELD_TARGET_DISTANCE), forceDuration)
        call SetCameraFieldEx(CAMERA_FIELD_ZOFFSET, CameraSetupGetField(whichSetup, CAMERA_FIELD_ZOFFSET), forceDuration)
        if doPan then
            call SetCameraPositionEx(CameraSetupGetDestPositionX(whichSetup), CameraSetupGetDestPositionY(whichSetup))
        endif
    endfunction
 
    private function CameraSetupApplyEx takes camerasetup whichSetup, boolean doPan, boolean panTimed returns nothing
        call CameraSetupApplyForceDurationEx(whichSetup, doPan, 0)
    endfunction
 
    private function CameraSetupApplyForPlayerEx takes boolean doPan, camerasetup whichSetup, player whichPlayer, real duration returns nothing
        if Locale == whichPlayer then
            call CameraSetupApplyForceDurationEx(whichSetup, doPan, duration)
        endif
    endfunction
 
    private function CameraSetSmoothingFactorEx takes real factor returns nothing
        if not Boole then
            set Boole = true
            call CameraSetSmoothingFactor(0)
            set Boole = false
        endif
    endfunction
 
    private function SetCameraTargetControllerEx takes unit whichUnit, real xoffset, real yoffset, boolean inheritOrientation returns nothing
        if not Boole then
            set Boole = true
            call SetCameraTargetController(CameraMan, LocX, LocY, false)
            set Boole = false
        endif
    endfunction
 
    private function SetCameraTargetControllerNoZForPlayerEx takes player whichPlayer, unit whichUnit, real xoffset, real yoffset, boolean inheritOrientation returns nothing
        if Locale == whichPlayer then
            call SetCameraTargetControllerEx(CameraMan, LocX, LocY, false)
        endif
    endfunction

    hook SetCameraField SetCameraFieldCatcher
    hook SetCameraFieldForPlayer SetCameraFieldForPlayerEx
    hook SetCameraPosition SetCameraPositionEx
    hook PanCameraTo SetCameraPositionEx
    hook PanCameraToTimed PanCameraToTimedEx
    hook PanCameraToTimedLocForPlayer PanCameraToTimedLocForPlayerEx
    hook CameraSetSmoothingFactor CameraSetSmoothingFactorEx
    hook CameraSetupApply CameraSetupApplyEx
    hook CameraSetupApplyForceDuration CameraSetupApplyForceDurationEx
    hook CameraSetupApplyForPlayer CameraSetupApplyForPlayerEx
    hook SetCameraTargetController SetCameraTargetControllerEx
    hook SetCameraTargetControllerNoZForPlayer SetCameraTargetControllerNoZForPlayerEx
 
    function RegisterOnCameraRefreshEvent takes code func returns triggercondition
        return TriggerAddCondition(Trigg, Condition(func))
    endfunction
 
    function UnregisterOnCameraRefreshEvent takes triggercondition cond returns nothing
        call TriggerRemoveCondition(Trigg, cond)
    endfunction
 
    private module InitModule
        private static method onInit takes nothing returns nothing
            call init()
        endmethod
    endmodule
 
    private struct Initializer
 
        private static method init takes nothing returns nothing
            set Locale = GetLocalPlayer()
            set CameraMan = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'hpea', 0, 0, 0)
            call SetUnitPathing(CameraMan, false)
            call PauseUnit(CameraMan, true)
            call ShowUnit(CameraMan, false)
            call SetUnitX(CameraMan, 0)
            call SetUnitY(CameraMan, 0)
            call SetCameraTargetController(CameraMan, LocX, LocY, false)
            call TimerStart(CamTimer, INTERVAL, true, function onTick)
            call FireEvent()
        endmethod
   
        implement InitModule
   
    endstruct
 
endlibrary
JASS:
library PanelModel requires PanelCore

    /*
        ~ Panel Model Plugin ~
   
        Allows to add model files into panels.
   
        I. How to import:
            1. Copy "PanelModel" trigger to your map.
            2. Export "PanelModelDummy.mdx" in import manager to your map.
            3. Save your map, then close and reopen it.
            4. Delete/comment out this line:                                                                                                        */
            //! external ObjectMerger w3u hfoo hPSD unsf "PanelModelDummy" unam "" umdl "war3mapImported\PanelModelDummy.mdl" ubdg 1 uabi "Aloc" uble 0 uico "" umxp 0 umxr 0 ussc 0 ushu "" uaen "" udea "" umvt "float" ucol 0 usnd "" ufle 0 ufoo 0 uspe 1 uhom 1 urac "unknown" usid 0 usin 0 upgr "" uhot "" utip "" utub ""
    /*      5. Done.
   
        II. API
   
            struct PanelModel
           
                Members:
                    boolean transformAxis
                        - If true, the model's coordinate will be rescaled based on it's parent size
                    readonly unit dummy
                        - Model's dummy unit object
                   
                    readonly real xOffset
                    readonly real yOffset
                        - x/y offset of the model
                   
                    readonly boolean visible
                        - Model's current visibility state
                    readonly Panel parent
                        - Panel that's containing the model
               
                    readonly static thistype array List
                        - A list containing models in a specific Panel
                        - Takes the desired Panel (parent) instance as index
               
                Methods:
                    static method create takes Panel parent, string path, real xOffset, real yOffset, integer level returns thistype
                        - Add a model into a Panel
                   
                    method operator modelPath= takes string path returns nothing
                        - Change the model file
                    method operator level takes nothing returns integer
                        - Get model's rendering level
                   
                    method operator scale= takes real r returns nothing
                    method operator scale takes nothing returns real
                        - Set/get model size
                   
                    method refresh takes nothing returns nothing
                        - Refresh model screen position
                    method destroy takes nothing returns nothing
                        - Delete and remove the model from its parents collection
                    method move takes real xOffset, real yOffset, integer level returns nothing
                        - Move the model to new screen coordinate
                    method show takes boolean b returns nothing
                        - Modify text tag's visibility
               
    */
                               ////////////////////
                               // Configurations //
                               ////////////////////
    globals
        // Billboarded dummy unit dummy ID
        private constant integer DUMMY_ID = 'hPSD'
        // No need to modify
        private constant string ATTACH_POINT = "origin"
    endglobals
 
                                //////////////////
                                // System codes //
                                //////////////////
 
    struct PanelModel extends array
   
        implement LinkedList
 
        boolean transformAxis
        private effect model
        readonly  unit dummy
   
        readonly real xOffset
        readonly real yOffset
        private  real zOffset
        private  real size
   
        private  boolean pvisible
        readonly boolean visible
        readonly Panel parent
   
        readonly static thistype array List
   
        method operator modelPath= takes string path returns nothing
            call DestroyEffect(.model)
            set .model = AddSpecialEffectTarget(path, .dummy, ATTACH_POINT)
        endmethod
   
        method operator scale= takes real r returns nothing
            set .size = r*PanelCore_GENERAL_SIZE
            if .visible then
                call SetUnitScale(.dummy, .size*.parent.scale, 1, 1)
            endif
        endmethod
   
        method operator level takes nothing returns integer
            return R2I(.zOffset/PanelCore_LEVEL_GAP)
        endmethod
   
        method operator scale takes nothing returns real
            return .size/PanelCore_GENERAL_SIZE
        endmethod
   
        method destroy takes nothing returns nothing
            call DestroyEffect(.model)
            call RemoveUnit(.dummy)
            call removeNode()
            call deallocate()
            set .dummy = null
            set .model = null
        endmethod
   
        method refresh takes nothing returns nothing
            if .visible and .parent.visible then
                if .transformAxis then
                    call .parent.getRelativePos(.xOffset*.parent.scale, .yOffset*.parent.scale, .zOffset)
                else
                    call .parent.getRelativePos(.xOffset, .yOffset, .zOffset)
                endif
                if Panel.ReturnValX > PanelCore_WorldMinX and Panel.ReturnValX < PanelCore_WorldMaxX and Panel.ReturnValY > PanelCore_WorldMinY and Panel.ReturnValY < PanelCore_WorldMaxY then
                    call SetUnitX(.dummy, Panel.ReturnValX)
                    call SetUnitY(.dummy, Panel.ReturnValY)
                    call PanelCore_SetUnitZ(.dummy, Panel.ReturnValZ)
                    call SetUnitScale(.dummy, .size*.parent.scale, 1, 1)
                else
                    call SetUnitScale(.dummy, 0, 0, 0)
                endif
            endif
        endmethod
   
        method move takes real xOffset, real yOffset, integer level returns nothing
            set .xOffset = xOffset
            set .yOffset = yOffset
            set .zOffset = PanelCore_LEVEL_GAP*level
        endmethod
   
        method show takes boolean b returns nothing
            if b != .visible then
                set .visible = b
                if b then
                    call SetUnitScale(.dummy, .size*.parent.scale, 1, 1)
                else
                    call SetUnitScale(.dummy, 0, 0, 0)
                    call SetUnitX(.dummy, PanelCore_WorldMaxX)
                    call SetUnitY(.dummy, PanelCore_WorldMaxY)
                endif
            endif
        endmethod
   
        static method create takes Panel parent, string path, real xOffset, real yOffset, integer level returns thistype
   
            local thistype this = allocate()
       
            set .parent  = parent
            set .scale   = 1
            set .visible = true
            set .dummy   = CreateUnit(PanelCore_PASSIVE, DUMMY_ID, 0, 0, 0)
            set .model   = AddSpecialEffectTarget(path, .dummy, ATTACH_POINT)
            set .transformAxis = true
       
            static if not LIBRARY_AutoFly then
                if UnitAddAbility(.dummy, 'Amrf') and UnitRemoveAbility(.dummy, 'Amrf') then
                endif
            endif
            call UnitRemoveAbility(.dummy, 'Amov')
            call SetUnitScale(.dummy, .size, 1, 1)
            call move(xOffset, yOffset, level)
            call refresh()
            if List[parent] == 0 then
                set List[parent] = createNode()
            endif
            call List[parent].insertNode(this)
       
            return this
        endmethod
   
        private static method onPanelEvent takes nothing returns boolean
       
            local thistype node
       
            if List[Panel.TriggeringPanel] != 0 then
                set node = List[Panel.TriggeringPanel].next
                loop
                    exitwhen node.head or node == 0
                    if Panel.EventType == Panel.EVENT_PANEL_REFRESHED then
                        call node.refresh()
                    elseif Panel.EventType == Panel.EVENT_PANEL_CLEARED or Panel.EventType == Panel.EVENT_PANEL_DESTROYED then
                        call node.destroy()
                    elseif Panel.EventType == Panel.EVENT_PANEL_VISIBILITY_MODIFIED then
                        if not node.parent.visible then
                            call SetUnitX(node.dummy, PanelCore_WorldMaxX)
                            call SetUnitY(node.dummy, PanelCore_WorldMaxY)
                        endif
                    endif
                    set node = node.next
                endloop
                if Panel.EventType == Panel.EVENT_PANEL_DESTROYED then
                    call List[Panel.TriggeringPanel].flushNode()
                    set List[Panel.TriggeringPanel] = 0
                endif
            endif
       
            return false
        endmethod
   
        private static method onInit takes nothing returns nothing
            call Panel.RegisterAnyPanelEvent(function thistype.onPanelEvent)
        endmethod
   
    endstruct
 
endlibrary
JASS:
library PanelPlatform requires PanelCore

    /*
        ~ Panel Platform Plugin ~
   
        Allows to add platform objects into panels.
   
        I. How to import:
            1. Copy "PanelPlatform" trigger to your map.
            2. Done.
   
        II. API
   
            struct PanelPlatform
           
                Members:
                    boolean transformAxis
                        - If true, the platform's coordinate will be rescaled based on it's parent size
                    readonly unit dummy
                        - Platform's dummy unit object
               
                    readonly real xOffset
                    readonly real yOffset
                        - x/y offset of the platform
               
                    readonly integer red
                    readonly integer green
                    readonly integer blue
                    readonly integer alpha
                        - Platform's color channels
               
                    readonly boolean visible
                        - Platform's visibility state
                    readonly Panel parent
                        - Panel that's containing the platform
               
                    readonly static thistype array List
                        - A list containing platforms in a specific Panel
                        - Takes the desired Panel (parent) instance as index
               
                Methods:
                    static method create takes Panel parent, integer id, integer texture, real xOffset, real yOffset, integer level returns thistype
                        - Add a platform into a Panel
                   
                    method operator texture= takes integer i returns nothing
                        - Change the platform texture
                    method operator level takes nothing returns integer
                        - Get platform's rendering level
                   
                    method operator scale= takes real r returns nothing
                    method operator scale takes nothing returns real
                        - Get/set platform's size
                   
                    method refresh takes nothing returns nothing
                        - Refresh platform screen position
                    method destroy takes nothing returns nothing
                        - Delete and remove the model from its parents collection
                    method move takes real xOffset, real yOffset returns nothing
                        - Move the platform to a new screen coordinate
                    method show takes boolean b returns nothing
                        - Modify platform's visibility state
                    method setColor takes integer r, integer g, integer b, integer a returns nothing
                        - Modify platform's vertex colors
               
    */
                                //////////////////
                                // System codes //
                                //////////////////

    struct PanelPlatform extends array
   
        implement LinkedList
 
        boolean transformAxis
        readonly unit dummy
   
        readonly real xOffset
        readonly real yOffset
        private  real zOffset
        private  real size
   
        readonly integer red
        readonly integer green
        readonly integer blue
        readonly integer alpha
        private  integer skin
   
        readonly boolean visible
        private  boolean pvisible
        readonly Panel   parent
   
        readonly static thistype array List
   
        method operator texture= takes integer i returns nothing
            if i != .skin then
                set .skin = i
                call PanelCore_ChangeTexture(.dummy, i)
            endif
        endmethod
   
        method operator scale= takes real r returns nothing
            set .size = r*PanelCore_GENERAL_SIZE
            if .visible then
                call SetUnitScale(.dummy, .size*.parent.scale, 1, 1)
            endif
        endmethod
   
        method operator texture takes nothing returns integer
            return .skin
        endmethod
   
        method operator level takes nothing returns integer
            return R2I(.zOffset/PanelCore_LEVEL_GAP)
        endmethod
   
        method operator scale takes nothing returns real
            return .size/PanelCore_GENERAL_SIZE
        endmethod
   
        method destroy takes nothing returns nothing
            call RemoveUnit(.dummy)
            call removeNode()
            call deallocate()
            set .dummy = null
        endmethod
   
        method refresh takes nothing returns nothing
            if .visible and .parent.visible then
                if .transformAxis then
                    call .parent.getRelativePos(.xOffset*.parent.scale, .yOffset*.parent.scale, .zOffset)
                else
                    call .parent.getRelativePos(.xOffset, .yOffset, .zOffset)
                endif
                if Panel.ReturnValX > PanelCore_WorldMinX and Panel.ReturnValX < PanelCore_WorldMaxX and Panel.ReturnValY > PanelCore_WorldMinY and Panel.ReturnValY < PanelCore_WorldMaxY then
                    call SetUnitX(.dummy, Panel.ReturnValX)
                    call SetUnitY(.dummy, Panel.ReturnValY)
                    call PanelCore_SetUnitZ(.dummy, Panel.ReturnValZ)
                    call SetUnitScale(.dummy, .size*.parent.scale, 1, 1)
                else
                    call SetUnitScale(.dummy, 0, 0, 0)
                endif
            endif
        endmethod
   
        method move takes real xOffset, real yOffset, integer level returns nothing
            set .xOffset = xOffset
            set .yOffset = yOffset
            set .zOffset = PanelCore_LEVEL_GAP*level
        endmethod
   
        method setColor takes integer r, integer g, integer b, integer a returns nothing
            set .red   = r
            set .green = g
            set .blue  = b
            set .alpha = a
            call SetUnitVertexColor(.dummy, .red, .green, .blue, R2I(.alpha*.parent.opacity/255.))
        endmethod
   
        method show takes boolean b returns nothing
            if b != .visible then
                set .visible = b
                if b then
                    call SetUnitScale(.dummy, .size*.parent.scale, 1, 1)
                else
                    call SetUnitScale(.dummy, 0, 0, 0)
                    call SetUnitX(.dummy, PanelCore_WorldMaxX)
                    call SetUnitY(.dummy, PanelCore_WorldMaxY)
                endif
            endif
        endmethod
   
        static method create takes Panel parent, integer id, integer texture, real xOffset, real yOffset, integer level returns thistype
       
            local thistype this = allocate()
       
            set .parent  = parent
            set .scale   = 1
            set .visible = true
            set .dummy   = CreateUnit(PanelCore_PASSIVE, id, 0, 0, 0)
            set .skin    = texture
            set .transformAxis = true
       
            static if not LIBRARY_AutoFly then
                if UnitAddAbility(.dummy, 'Amrf') and UnitRemoveAbility(.dummy, 'Amrf') then
                endif
            endif
            call UnitRemoveAbility(.dummy, 'Amov')
            call UnitAddAbility(.dummy, PanelCore_TEXTURE_REPLACER_ID)
            call SetUnitPathing(.dummy, false)
            call SetUnitScale(.dummy, .size, 1, 1)
            call setColor(255, 255, 255, 255)
            call PanelCore_ChangeTexture(.dummy, texture)
            call move(xOffset, yOffset, level)
            if parent.visible then
                call refresh()
            else
                call SetUnitX(.dummy, PanelCore_WorldMaxX)
                call SetUnitY(.dummy, PanelCore_WorldMaxY)
            endif
            if List[parent] == 0 then
                set List[parent] = createNode()
            endif
            call List[parent].insertNode(this)
       
            return this
        endmethod
   
        private static method onPanelEvent takes nothing returns boolean
       
            local thistype node
       
            if List[Panel.TriggeringPanel] != 0 then
                set node = List[Panel.TriggeringPanel].next
                loop
                    exitwhen node.head or node == 0
                    if Panel.EventType == Panel.EVENT_PANEL_REFRESHED then
                        call node.refresh()
                    elseif Panel.EventType == Panel.EVENT_PANEL_CLEARED or Panel.EventType == Panel.EVENT_PANEL_DESTROYED then
                        call node.destroy()
                    elseif Panel.EventType == Panel.EVENT_PANEL_VISIBILITY_MODIFIED then
                        if not node.parent.visible then
                            call SetUnitX(node.dummy, PanelCore_WorldMaxX)
                            call SetUnitY(node.dummy, PanelCore_WorldMaxY)
                        endif
                    elseif Panel.EventType == Panel.EVENT_PANEL_OPACITY_MODIFIED then
                        call SetUnitVertexColor(node.dummy, node.red, node.green, node.blue, R2I(node.alpha*node.parent.opacity/255.))
                    endif
                    set node = node.next
                endloop
                if Panel.EventType == Panel.EVENT_PANEL_DESTROYED then
                    call List[Panel.TriggeringPanel].flushNode()
                    set List[Panel.TriggeringPanel] = 0
                endif
            endif
       
            return false
        endmethod
   
        private static method onInit takes nothing returns nothing
            call Panel.RegisterAnyPanelEvent(function thistype.onPanelEvent)
        endmethod
   
    endstruct

endlibrary
JASS:
library PanelTextTag requires PanelCore, optional ZLibrary

    /*
        ~ Panel Text Tag Plugin ~
   
        Allows to add text tags into panels.
   
        I. How to import:
            1. Copy "PanelTextTag" trigger to your map.
            2. Export "PanelTextTagDummy.mdx" in import manager to your map.
            3. Save your map, then close and reopen it.
            4. Delete/comment out this line:                                                                                                        */
            //! external ObjectMerger w3u hfoo hPTD unsf "PanelTextTagDummy" unam "" umdl "war3mapImported\PanelTextTagDummy.mdl" ubdg 1 uabi "Aloc" uble 0 uico "" umxp 0 umxr 0 ussc 0 ushu "" uaen "" udea "" umvt "float" ucol 0 usnd "" ufle 0 ufoo 0 uspe 1 uhom 1 urac "unknown" usid 0 usin 0 upgr "" uhot "" utip "" utub ""
    /*      5. Done.
   
        II. API
   
            struct PanelTextTag
           
                Members:
                    boolean transformAxis
                        - If true, the text tag's coordinate will be rescaled based on it's parent size
                   
                    readonly real xOffset
                    readonly real yOffset
                        - x/y offset of the text tag
               
                    readonly integer red
                    readonly integer green
                    readonly integer blue
                    readonly integer alpha
                        - Text tag's color channels
               
                    readonly string text
                    readonly real size
                        - Text tag's current text & size
                    readonly boolean visible
                        - Text tag's current visibility state
                    readonly Panel parent
                        - Panel that's containing the text tag
                   
                    readonly static thistype array List
                        - A list containing text tags in a specific Panel
                        - Takes the desired Panel (parent) instance as index
               
                Methods:
                    static method create takes Panel parent, string s, real size, real xOffset, real yOffset returns thistype
                        - Add a text tag into a panel
                   
                    method refresh takes nothing returns nothing
                        - Refresh text tag screen position
                    method destroy takes nothing returns nothing
                        - Delete and remove the text tag from its parents collection
                    method move takes real xOffset, real yOffset returns nothing
                        - Move the text tag to a new screen coordinate
                    method show takes boolean b returns nothing
                        - Modify text tag's visibility
                    method setText takes string s, real size returns nothing
                        - Change the text tag's text and size
                    method setColor takes integer red, integer green, integer blue, integer alpha returns nothing
                        - Change the text tag's color
               
    */
                               ////////////////////
                               // Configurations //
                               ////////////////////
 
    globals
        private constant integer DUMMY_ID = 'hPTD'
        private constant real    ZOFFSET  = -14.8
    endglobals
 
                                //////////////////
                                // System codes //
                                //////////////////

    struct PanelTextTag extends array
   
        implement LinkedList
 
        boolean transformAxis
        private texttag tag
   
        readonly real xOffset
        readonly real yOffset
   
        readonly integer red
        readonly integer green
        readonly integer blue
        readonly integer alpha
   
        readonly string text
        readonly real size
   
        private  boolean pvisible
        readonly boolean visible
        readonly Panel parent
   
        readonly static thistype array List
        private  static unit ZPlacer
        private  static player LocalPlayer
   
        method destroy takes nothing returns nothing
            call DestroyTextTag(.tag)
            call removeNode()
            call deallocate()
            set .tag = null
        endmethod
   
        method refresh takes nothing returns nothing
            if .visible and .parent.visible then
                if .transformAxis then
                    call .parent.getRelativePos(.xOffset*.parent.scale, .yOffset*.parent.scale, 0)
                else
                    call .parent.getRelativePos(.xOffset, .yOffset, 0)
                endif
                if Panel.ReturnValX > PanelCore_WorldMinX and Panel.ReturnValX < PanelCore_WorldMaxX and Panel.ReturnValY > PanelCore_WorldMinY and Panel.ReturnValY < PanelCore_WorldMaxY then
                    call SetUnitX(ZPlacer, Panel.ReturnValX)
                    call SetUnitY(ZPlacer, Panel.ReturnValY)
                    call PanelCore_SetUnitZ(ZPlacer, Panel.ReturnValZ)
                    call SetTextTagPosUnit(.tag, ZPlacer, ZOFFSET)
                    call SetTextTagText(.tag, .text, .size*.parent.scale)
                    call SetTextTagVisibility(.tag, true)
                else
                    call SetTextTagVisibility(.tag, false)
                endif
            endif
        endmethod
   
        method show takes boolean b returns nothing
            if b != .visible then
                set .visible = b
                if not b then
                    call SetTextTagVisibility(.tag, false)
                endif
            endif
        endmethod
   
        method move takes real xOffset, real yOffset returns nothing
            set .xOffset = xOffset
            set .yOffset = yOffset
        endmethod
   
        method setText takes string s, real size returns nothing
            set .text = s
            set .size = size
        endmethod
   
        method setColor takes integer red, integer green, integer blue, integer alpha returns nothing
            set .red   = red
            set .green = green
            set .blue  = blue
            set .alpha = alpha
            call SetTextTagColor(.tag, .red, .green, .blue, R2I(.alpha*.parent.opacity/255.))
        endmethod
   
        static method create takes Panel parent, player p, string s, real size, real xOffset, real yOffset returns thistype
       
            local thistype this = allocate()
       
            set .parent  = parent
            set .visible = true
            if GetLocalPlayer() == p then
                set .tag = CreateTextTag()
            else
                set .tag = null
            endif
            set .transformAxis = true
       
            call SetTextTagVisibility(.tag, true)
            call SetTextTagPermanent(.tag, true)
            call setText(s, size)
            call setColor(255, 255, 255, 255)
            call move(xOffset, yOffset)
            call refresh()
            if List[parent] == 0 then
                set List[parent] = createNode()
            endif
            call List[parent].insertNode(this)
       
            return this
        endmethod
   
        private static method onPanelEvent takes nothing returns boolean
       
            local thistype node
       
            if List[Panel.TriggeringPanel] != 0 then
                set node = List[Panel.TriggeringPanel].next
                loop
                    exitwhen node.head or node == 0
                    if Panel.EventType == Panel.EVENT_PANEL_REFRESHED then
                        call node.refresh()
                    elseif Panel.EventType == Panel.EVENT_PANEL_CLEARED or Panel.EventType == Panel.EVENT_PANEL_DESTROYED then
                        call node.destroy()
                    elseif Panel.EventType == Panel.EVENT_PANEL_VISIBILITY_MODIFIED then
                        if not node.parent.visible then
                            call SetTextTagVisibility(node.tag, false)
                        endif
                    elseif Panel.EventType == Panel.EVENT_PANEL_OPACITY_MODIFIED then
                        call SetTextTagColor(node.tag, node.red, node.green, node.blue, R2I(node.alpha*node.parent.opacity/255.))
                    endif
                    set node = node.next
                endloop
                if Panel.EventType == Panel.EVENT_PANEL_DESTROYED then
                    call List[Panel.TriggeringPanel].flushNode()
                    set List[Panel.TriggeringPanel] = 0
                endif
            endif
       
            return false
        endmethod
   
        private static method onInit takes nothing returns nothing
            set ZPlacer = CreateUnit(PanelCore_PASSIVE, DUMMY_ID, 0, 0, 0)
            static if not LIBRARY_AutoFly then
                if UnitAddAbility(ZPlacer, 'Amrf') and UnitRemoveAbility(ZPlacer, 'Amrf') then
                endif
            endif
            call PauseUnit(ZPlacer, true)
            call ShowUnit(ZPlacer, false)
            call Panel.RegisterAnyPanelEvent(function thistype.onPanelEvent)
        endmethod
   
    endstruct
 
endlibrary
JASS:
library PanelText requires PanelCore, PanelPlatform, Ascii

    /*
        ~ Panel Text Plugin ~
 
        Allows to add texts with custom font font into panels.
 
        Text is more powerful that TextTag, it allows you to have
        many  font fonts with "indefinite" length and amount limit.
        Also  it appears  much smoother than TextTag. However, it's
        a lot heavier both in terms of storage and computation.
   
        It's highly recommended not to use too much of it.
 
        I. Requirements:
            - PanelCore                    | -
            - (plugin)   PanelPlatform    | -
            - (required) Ascii            | https://www.hiveworkshop.com/threads/snippet-ascii.190746/
 
        II. How to import:
            1. Copy "PanelText" trigger to your map.
            2. Export "PanelTextDummy.mdx" in import manager to your map.
            3. Save your map, then close and reopen it.
            4. Delete/comment out this line:                                                                                                */
            //! external ObjectMerger w3u hfoo hTED unsf "PanelTextDummy" unam "" umdl "war3mapImported\PanelTextDummy.mdl" ubdg 1 uabi "Aloc" uble 0 uico "" umxp 0 umxr 0 ussc 0 ushu "" uaen "" udea "" umvt "float" ucol 0 usnd "" ufle 0 ufoo 0 uspe 1 uhom 1 urac "unknown" usid 0 usin 0 upgr "" uhot "" utip "" utub ""
    /*      5. Done.
 
        III. API
 
            struct PanelText
         
                Members:
                    readonly real width
                        - Total width of the whole text in pixel
                    readonly real xOffset
                    readonly real yOffset
                        - Position of the text
             
                    readonly string font
                        - Text's font font
                    readonly integer length
                        - Number of characters in the text
                    readonly integer level
                        - Rendering level of the text
             
                    readonly Panel parent
                        - Panel that's containing the text
                 
                    readonly static thistype array List
                        - A list containing Text's in a specific Panel
                        - Takes the desired Panel (parent) instance as index
             
                Methods:
                    static method create takes Panel parent, string text, string font, real xOffset, real yOffset, integer level returns thistype
                        - Add new Text to a panel
                 
                    method operator visible takes nothing returns boolean
                        - Get text's current visibility state
                 
                    method operator red takes nothing returns integer
                    method operator green takes nothing returns integer
                    method operator blue takes nothing returns integer
                    method operator alpha takes nothing returns integer
                        - Get text's color channels
                 
                    method operator scale takes nothing returns real
                    method operator scale= takes real r returns nothing
                        - Get/set text size
                   
                    method operator transformAxis= takes boolean b returns nothing
                        - If true, the text's coordinate will be rescaled based on it's parent size
             
                    method setText takes string text, string font returns nothing
                        - Change the text and its font font
                    method refresh takes nothing returns nothing
                        - Refresh text screen position
                    method destroy takes nothing returns nothing
                        - Remove the text from its container
                    method move takes real xOffset, real yOffset, integer level returns nothing
                        - Move the text to different coordinate and level
                    method setColor takes integer r, integer g, integer b, integer a returns nothing
                        - Modify text's color and transparency
                    method show takes boolean b returns nothing
                        - Show/hide the text
             
    */
                               ////////////////////
                               // Configurations //
                               ////////////////////
 
    globals
        // Platform object for display characters
        private constant integer DUMMY_ID = 'hTED'
        // Space character width in pixel
        private constant real SPACE_WIDTH = 8.0 // px
        // Default spacing between characters
        private constant real CHAR_GAP    = 1.0
    endglobals
 
                                //////////////////
                                // System codes //
                                //////////////////
 
    private module InitModule
        private static method onInit takes nothing returns nothing
            call init()
        endmethod
    endmodule

    struct PanelTextChar extends array
 
        implement LinkedList
 
        string char
        real   width
        real   height
        real   depth
        PanelPlatform plat
 
        method operator xOffset takes nothing returns real
            return .plat.xOffset
        endmethod
 
        method operator yOffset takes nothing returns real
            return .plat.yOffset
        endmethod
 
        method operator visible takes nothing returns boolean
            return .plat.visible
        endmethod
 
        method show takes boolean b returns nothing
            call .plat.show(b)
        endmethod
 
    endstruct
 
    struct PanelText extends array
 
        implement LinkedList
 
        private  real size
        readonly real width
        readonly real height
        readonly real depth
        readonly real xOffset
        readonly real yOffset
 
        readonly string  text
        readonly integer font
        readonly integer length
        readonly integer level
 
        readonly Panel parent
        readonly PanelTextChar chars
 
        readonly static thistype array List
        readonly static hashtable FontData = InitHashtable()
 
        private method getCharTexture takes string s returns integer
            return LoadInteger(FontData, font + 0, Char2Ascii(s))
        endmethod
 
        private method getCharWidth takes string s returns real
            return LoadReal(FontData, font + 1, Char2Ascii(s))
        endmethod
 
        private method getCharHeight takes string s returns real
            return LoadReal(FontData, font + 2, Char2Ascii(s))
        endmethod
 
        private method getCharDepth takes string s returns real
            return LoadReal(FontData, font + 3, Char2Ascii(s))
        endmethod
 
        method operator visible takes nothing returns boolean
            return .chars.next.plat.visible
        endmethod
 
        method operator red takes nothing returns integer
            return .chars.next.plat.red
        endmethod
 
        method operator green takes nothing returns integer
            return .chars.next.plat.green
        endmethod
 
        method operator blue takes nothing returns integer
            return .chars.next.plat.blue
        endmethod
 
        method operator alpha takes nothing returns integer
            return .chars.next.plat.alpha
        endmethod
 
        method operator scale takes nothing returns real
            return .size
        endmethod
 
        method operator scale= takes real r returns nothing
            set .size = r
            call refresh()
        endmethod
   
        method operator transformAxis= takes boolean b returns nothing
   
            local PanelTextChar c = .chars.next
       
            loop
                exitwhen c.head
                if c.plat != 0 then
                    set c.plat.transformAxis = b
                endif
                set c = c.next
            endloop
        endmethod
 
        method refresh takes nothing returns nothing
     
            local PanelTextChar c = .chars.next
            local real xOffset = .xOffset
            local real offset
     
            set .width  = 0
            set .height = 0
            set .depth  = 0
            loop
                exitwhen c.head
                set offset  = c.width*.size
                if c.plat != 0 then
                    set c.plat.scale = .size
                    call c.plat.move(xOffset+offset/2, .yOffset, .level)
                    call c.plat.refresh()
                endif
                set xOffset = xOffset+offset+CHAR_GAP
                set .width  = .width+offset+CHAR_GAP
                if c.height > .height then
                    set .height = c.height*.size
                endif
                if c.depth > .depth then
                    set .depth = c.depth*.size
                endif
                set c = c.next
            endloop
            set .width = .width-CHAR_GAP
     
        endmethod
 
        private method clear takes nothing returns nothing
     
            local PanelTextChar c = .chars.next
     
            loop
                exitwhen c.head
                if c.plat != 0 then
                    call c.plat.destroy()
                endif
                set c = c.next
            endloop
            call chars.clearNode()
     
        endmethod
 
        method destroy takes nothing returns nothing
            call clear()
            call chars.flushNode()
            call removeNode()
            call deallocate()
        endmethod
 
        method move takes real xOffset, real yOffset, integer level returns nothing
            set .xOffset = xOffset
            set .yOffset = yOffset
            set .level   = level
            call refresh()
        endmethod
 
        method setColor takes integer r, integer g, integer b, integer a returns nothing
     
            local PanelTextChar c = .chars.next
     
            loop
                exitwhen c.head
                if c.plat != 0 then
                    call c.plat.setColor(r, g, b, a)
                endif
                set c = c.next
            endloop
     
        endmethod
 
        method show takes boolean b returns nothing
     
            local PanelTextChar c = .chars.next
     
            loop
                exitwhen c.head
                if c.plat != 0 then
                    call c.plat.show(b)
                endif
                set c = c.next
            endloop
     
        endmethod
 
        private method initText takes nothing returns nothing
 
            local integer i = 0
            local string s
            local real xOffset = .xOffset
            local real yOffset
            local real offset
            local PanelTextChar c
     
            set .width  = 0
            set .height = 0
            set .depth  = 0
            loop
                exitwhen i == .length
                set s = SubString(.text, i, i+1)
                set c = PanelTextChar.allocate()
                if s == " " then
                    set c.char   = " "
                    set c.width  = SPACE_WIDTH
                    set c.height = 0.0
                    set c.depth  = 0.0
                    set offset   = c.width*.size
                    set c.plat   = 0
                else
                    set c.char   = s
                    set c.width  = getCharWidth(s)
                    set c.height = getCharHeight(s)
                    set c.depth  = getCharDepth(s)
                    set offset   = c.width*.size
                    set c.plat   = PanelPlatform.create(.parent, DUMMY_ID, getCharTexture(s), xOffset+offset/2, .yOffset, level)
                endif
                set xOffset = xOffset+offset+CHAR_GAP
                set .width  = .width+offset+CHAR_GAP
                if c.height > .height then
                    set .height = c.height*.size
                endif
                if c.depth > .depth then
                    set .depth = c.depth*.size
                endif
                call .chars.insertNode(c)
                set i = i + 1
            endloop
            set .width = .width-CHAR_GAP
     
        endmethod
 
        method setText takes string text, integer font returns nothing
            if .text != text then
                call clear()
                set .text   = text
                set .font   = font
                set .length = StringLength(text)
                call initText()
            endif
        endmethod
 
        static method create takes Panel parent, string text, integer font, real xOffset, real yOffset, integer level returns thistype
     
            local thistype this = allocate()
     
            set .parent  = parent
            set .size    = 1
            set .xOffset = xOffset
            set .yOffset = yOffset
            set .level   = level
            set .text    = text
            set .font    = font
            set .length  = StringLength(text)
            set .chars   = PanelTextChar.createNode()
            call initText()
     
            if List[parent] == 0 then
                set List[parent] = createNode()
            endif
            call List[parent].insertNode(this)
     
            return this
        endmethod
 
        private static method onPanelEvent takes nothing returns boolean
     
            local thistype node
     
            if List[Panel.TriggeringPanel] != 0 then
                set node = List[Panel.TriggeringPanel].next
                loop
                    exitwhen node.head
                    if Panel.EventType == Panel.EVENT_PANEL_CLEARED or Panel.EventType == Panel.EVENT_PANEL_DESTROYED then
                        call node.destroy()
                    endif
                    set node = node.next
                endloop
                if Panel.EventType == Panel.EVENT_PANEL_DESTROYED then
                    call List[Panel.TriggeringPanel].flushNode()
                    set List[Panel.TriggeringPanel] = 0
                endif
            endif
     
            return false
        endmethod
 
        private static method init takes nothing returns nothing
     
            local string s
            local integer asc
     
            call Panel.RegisterAnyPanelEvent(function PanelText.onPanelEvent)
            implement PanelTextFontData
       
        endmethod
   
        implement InitModule
 
    endstruct
 
    // Font data stuffs
 
    globals
        public integer FontIndex = 0
    endglobals
 
    //! textmacro DefineFontStyle takes FONT
    globals
        integer FONTSTYLE_$FONT$ = -1
    endglobals
    //! endtextmacro
 
    //! textmacro InitFontObject takes FONT, CHAR, INDEX, CODE, WIDTH, HEIGHT, DEPTH
        if FONTSTYLE_$FONT$ == -1 then
            set FONTSTYLE_$FONT$ = PanelText_FontIndex
            set PanelText_FontIndex = PanelText_FontIndex + 4
        endif
        if "$CHAR$" == "''" then // symbol " breaks textmacro
            set asc = Char2Ascii("\"")
        else
            set asc = Char2Ascii("$CHAR$")
        endif
        call SaveInteger(FontData, FONTSTYLE_$FONT$ + 0, asc, '$CODE$$INDEX$')
        call SaveReal   (FontData, FONTSTYLE_$FONT$ + 1, asc, $WIDTH$)
        call SaveReal   (FontData, FONTSTYLE_$FONT$ + 2, asc, $HEIGHT$)
        call SaveReal   (FontData, FONTSTYLE_$FONT$ + 3, asc, $DEPTH$)
    //! endtextmacro
 
    //! textmacro CreateFontObject takes FONT, INDEX, CODE, FILEPATH, EXTENSION
        //! external ObjectMerger w3b YTlb $CODE$$INDEX$ bnam "($FONT$) Char $INDEX$" bfxr -1 bfil ".mdl" boch 0 btxf "$FILEPATH$$INDEX$$EXTENSION$" btxi 33 bsel 0 bgsc 0 bshd "" barm "Ethereal" btar "tree" bcpr 0 bcpd 0 buch 0 bptx "" bsuf "" bcat "D"
    //! endtextmacro
 
endlibrary

Credits:
  • Dirac: LinkedListModule
  • TheDamien and Nestharus: Ascii
Previews
Contents

Panel System (Map)

Reviews
KILLCIDE
Not sure what the craze is right now with Interface systems, but man this one is awesome. As I told TriggerHappy, a system like this can only be improved if more users use it, and I trust that they will report any of the bugs / issues they find. As of...

Deleted member 219079

D

Deleted member 219079

Camera behavior in the demo is a bit weird.

If only we could have a patch which extends viewport to whole screen.

And yes flicker is annoying.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
I've found the problem and turned out it was my fault. The camera system was conflicting with the demo code (risk of using hooks), which is now solved. If it's still flicking for you please let me know.

EDIT:
Minor update: added dragon form to demo unit.

EDIT:
Update (v1.01):
- Now requires nothing more than the camera system
- Now you can apply z offset to panels
- Camera roll and field of view modification is now properly disabled
- Some other improvements in camera system
- Improved demo code

EDIT:
Minor update (v1.01a):
- Fixed a mistake in angular difference calculation
 

Attachments

  • asdad.jpg
    asdad.jpg
    429.7 KB · Views: 473
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update v1.2:
- Added world bounds into account
- Fixed a mistake in clear method
- Now content is removed properly from panel's collection
- Now utilizes LinkedList
- Added panel content level getter
- Started working on new components (texttag, custom text, progress bar, etc.)

Next:
- We will have a more convenient coordinate system!
- I will try to finish at least the text tag and progress bar plug in, I'm still not sure to do the custom text plug in since it will be quite heavy
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update v1.3:
- Now using pixel (px) as measure of coordinating
- Added new method to panel: applyAxesTransform
- Added text tag plugin
- Added new function to the camera system for extra efficiency for end user
- Some other nerdy improvements

Update v1.31:
- Improved the coordinating system
- Rescaled all platform models accurately using the new coordinating system

Update v1.32:
- Now panel allows negative level
- Now text tag doesn't have level parameter
- Now text tag is hidden and rescaled accordingly to its parent
- Improved documentations
- Fixed potential desync in the demo code
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update 1.4:
- Now the camera system is optional
- Increased coordinating precision (the demo code coordinating and platform dimensions are outdated)
- Added panel events, now it's much easier to create plugins
- Now panel refreshing is automatically done by the panel system itself
- Improved documentations

Update 1.41:
- Added Panel x/yOffset setter & getter method operator which is unaffected by pixel correction
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Big update with massive reconstructions:

General:
- Added new plugin, PanelModel: allows to display any model files on screen
- PanelContent is renamed to PanelPlatform and treated as a plugin
- refresh methods are now privatized
- Improved encapsulations
- Better collection listing
- Improved documentations & better trigger management

TextTag plugin:
- Added move method
- Fixed a critical mistake on event initialization

Update 1.51:
- Fixed compile error on PanelPlatform & PanelModel without UnitZ library
- Now PanelModel uses optimized billboarded dummy model
- Fixed some mistakes on CameraSystem
 
Last edited:
Is it a different model for each custom texture that is then attached to the dummy's "origin"? Is that better than using images (non-sarcastic honest question)?

Last time I checked this system has a new model and texture for each element.

The UI system I have in the spells section based off of DGUI, uses dummy units with a single model file and the war club ability to dynamically switch textures.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Ah ok.
Just wondering, why not using the native images instead? I enumerated the advantages vs disadvantages (based on my knowledge) and in my opinion the advantages outweighs the disadvantages (unless there's more to it that I'm not aware of).

The advantages are:
- (Quilnez's) You don't have to import a corresponding model for each element.
- (TriggerHappy's) You won't populate Destructable Manager with destructables for the warclub change.
- Create Unit (+ CreateDestructable for TriggerHappy's) vs CreateImage, I think image handle types are less heavy than unit handles.
- Can be visible in fog but can also be invisible in fog using IsVisibleToPlayer with GetLocalPlayer.

The disadvantages are:
- You can't use in-game texture, you have to re-import it with a 1 px transparent border but applying 1 px alpha border is easy to do using BLPLab.
- Will always appear parallel to the ground and can't have pitch and yaw (because of dummy) angle.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
I don't think you can change the angle of the image to fit the screen correctly.
By making the camera points directly to the ground, then you can make image fit the screen. But if the coder/modder does not want to change the camera angle during panel display, then images won't do the trick because they always appear parallel to the ground.

and of course you can't detect clicks.
Can be solved by using trackables but the downside is trackables cannot be destroyed (which I hope the new patch fix). I guess leaving a few undestroyed but disabled trackables won't hurt for one time panels like Hero Selection system but for dynamic panels like this, yeah it's not ideal to use trackables that get's created everytime the player needs the panel.

But yeah images would be better for non clickable items if it were possible to get that to work, but I don't think it is currently.
Images work fine as far as I know but it crashes on invalid blp/tga paths.

Also, images need a 1px transparent border.
Luckily there's a tool for that.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Last time I checked this system has a new model and texture for each element.

The UI system I have in the spells section based off of DGUI, uses dummy units with a single model file and the war club ability to dynamically switch textures.
Mine works exactly alike, it uses the war club trick too. I use multiple dummy units because each element has different width and height. You know we can't modify unit's x/y/z scale factor freely using trigger.

@Flux:
Your idea is good for FSI systems. But the whole point our system is to make the custom interfaces stick to the screen regardless of the camera setting. Thus images can't fit here because of mentioned issue above.

EDIT:
I forgot to revert the MAX_LEVEL constant back to "50". I will update it ASAP.
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
So I decided to update this earlier since there are a number of important fixes.

v1.7:
- Now works with any default cliff level
- Now TextTagEx is properly scaled and repositioned according to its parent
- Custom font height and depth are now defined
- TextTagExChar is now public
- TextTagEx text member is now readable
- Deleted applyAxesTransfrom method and replaced with a boolean member
- Improved TextTagEx dummy model so it won't get overlaid by other model with certain texture filtering mode

More bugs and errors might be exposed soon since I'm implementing this in a more advance system.

v1.71:
- Now contents can't be displayed if its parent isn't visible
- A number of bug fixes and improvements for TextEx plugin
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
This update is focusing on code optimizations. The system underwent hours of highly intensive optimizations. There were too much changes so maybe I can't list all of them.

v1.8:
- Now panels only get refreshed if the camera is updating
- Now camera and panels are effectively updated (only once per tick)
- Tons of micro optimizations on camera system
- The camera system is now properly initialized
- Now the camera system's global variables are public
- Fixed op limit error possibility on empty list enumerations
- Fonts initializations are now separated on different trigger
- Added new panel event for optimal content updating
- A lot of optimizations on the core system and all plugins, along with updated APIs
- Improved all structs members encapsulation
- Up to date documentations
- And many more...

I have benchmarked the improvements using cheat engine's speed hack on my UI pack system. Before the update, the FPS dropped to ~30s at 3x game speed. Now it stays healthy at 60 FPS at 6x game speed, FPS dropped to ~30 only when updating the camera.
I also ran second benchmark, previously it's capable of displaying 300 platforms at once (FPS dropped to ~30). Now it stays healthy at 60 FPS with 600+ platforms (FPS dropped to ~40 when updating the camera).

I'm very confident the system is at it's prime condition now and ready for public use. Even tho the documentations on those examples are still lacking, I will work on it later. Enjoy...

EDIT:
v1.81:
- Changed camera refreshing behavior
- Fixed inaccurate camera yaw & pitch rotation error
- Fixed double termination bug possibility on panel destroy event
- Some optimizations on core system

In the next update, I will probably re-structure the parenting system, making the coordinate calculation a bit more efficient and allows nested parenting (panels inside panel) so creating UI can't be any more comfortable than this.

EDIT:
v1.8b (new version formatting [1.82 > 1.8b]):
- The core system is now much better organized
- Coordinate conversions are now separated in its own method
- Now calculating panel coordinates equally fast as calculating components'
- Fixed some mistakes in previous update
 
Last edited:

Deleted member 247165

D

Deleted member 247165

This is a great and useful system. Good job for this! 5/5, vote for approval.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Thank you. I'm glad someone liked it :)

v1.8c:
- Fixed fatal mistake on TextEx platform deallocation which caused the list sequence to break
- Some minor improvements in the core system

v1.8d:
- Little fix on char correction
- Added new font style: Frizz QT (default font used by wc3)

Further on new fonts will not be included in the demo map.

v1.8e:
- Now compatible with water level

v1.8f:
- Now text tag plugin is compatible with water level without the need of ZLibrary. Credit goes to TriggerHappy for the idea.
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
v1.9:
- Fixed desync issue caused by some dummy unit settings
- Fixed texture destructable object issue with fog mask, now it will cause no fps drop when used often

The system should be desync free now. TextEx plugin still can't be used in maps with gamecache, because it's still using gamecache for storing font data. Already made with ascii version but still have some problems between double quotation and capitalized chars. Updated to use hashtable and ascii instead.
 
Last edited:
Level 37
Joined
Jul 22, 2015
Messages
3,485
Not sure what the craze is right now with Interface systems, but man this one is awesome. As I told TriggerHappy, a system like this can only be improved if more users use it, and I trust that they will report any of the bugs / issues they find. As of right now, the demo is superb and everything is well documented, so I have no reason to not approve it.

Needs Fixed

  • Nothing

Suggestions

  • Nothing

Status


Approved
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
I've uploaded a map demonstrating this system a lot: LINK
Includes:
- Inventory & equipment system
- Equipment set system
- Item enhancement & socketing system
- Custom status bar
- Shortcut bar system
- Item tooltips system
- Arcane statistic window
- Skill list window

I'm too lazy to pick some pics but here's one:
items-jpg.271952
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Thanks for the approval. Even tho somehow I forgot to update some plugins to the latest version. I will do so soon.
Soon enough..

Update v2.0:
- Updated all plugins to the latest version
- Fixed faulty texture changing behavior which led to desync in some occasions
- Fixed a mistake in camera regulator function
- Now TextTag plugin creator method will take a player as argument
- "TextEx" plugin renamed to "Text"
- A lot of other improvements which I've forgot
 
Last edited:
Level 4
Joined
Jan 28, 2013
Messages
74
I have tried to open and run this map with WEX editor and it says "Cannot load map data." after Warcraft3 opens.

When I try to save the map it says "Line 5747: InventoryPanel is not of a type that allows . syntax"

All I did was download the link provided, open it in WEX, and try to run it. Please let me know if there is something I am doing wrong.
 
Level 6
Joined
Aug 28, 2015
Messages
213
Great resource can be really handy for alot of situations.
Do you think with the new natives it could be possible to make this system with spezial effects and the mouse position calculation in relation to the locked unit(the camera position) to avoide the flickering problem by selecting a unit?
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
What flickering problem to be exact?

Did you mean mouse screen position calculation? This system relies on the screen2world calculation, which is self-made and it wasn't initially designed to support world2screen calculation. I will probably spare some times doing research about it later in the future, but I want to see first whether the classic team will add GetMouseUIPos natives or not.
 
Level 6
Joined
Aug 28, 2015
Messages
213
The little flicker when you select a UI unit.
Yes I ment the mouse screen position calculation with the new natives mouse button pressed and released should be possible to find the selected button without units and even support drag 'n drop.
Fair enough I hope the classic team will add a mouse screen position getter and maybe setter(so you could do easy fp cameras)
I'm already impressed by this system great work.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
The little flicker when you select a UI unit.
Yes I ment the mouse screen position calculation with the new natives mouse button pressed and released should be possible to find the selected button without units and even support drag 'n drop.
Fair enough I hope the classic team will add a mouse screen position getter and maybe setter(so you could do easy fp cameras)
I'm already impressed by this system great work.
Thank you. Yes those would be awesome additions indeed!
 
Top