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

[vJASS] UnitAppearance

JASS:
library UnitAppearance/* 1.0 by Almia
*************************************************************************************
*
*   For tracking Unit Apperances
*
*   Units must have ARGB values of 255 in the Object Editor, as well as 1.0 for
*   the scaling value.
*
*   If you want to modify the unit's appearance when indexed given the unit type,
*   please refer to the setup below this documentation
*
*************************************************************************************
*
*   */ requires /*
*
*   */Table /*
*       hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*   */UnitIndexerGUI /* 
*       hiveworkshop.com/forums/jass-resources-412/snippet-gui-unit-indexer-vjass-plugin-268592/
*
*************************************************************************************
*
*   API
*
*   function SetUnitVertexColorEx takes unit u, integer r, integer g, integer b, integer a returns nothing
*   function SetUnitScaleEx takes unit u, real scale returns nothing
*   - Sets the current appearance values
*
*   function GetUnitRed takes unit u returns integer
*   function GetUnitGreen takes unit u returns integer
*   function GetUnitBlue takes unit u returns integer
*   function GetUnitAlpha takes unit u returns integer
*   function GetUnitScale takes unit u returns real
*   - Gets the current appearance values
*
*   function GetUnitDefaultRed takes unit u returns integer
*   function GetUnitDefaultGreen takes unit u returns integer
*   function GetUnitDefaultBlue takes unit u returns integer
*   function GetUnitDefaultAlpha takes unit u returns integer
*   function GetUnitDefaultScale takes unit u returns real
*   - Gets the current appearance values
*
*   function RestoreUnitAppearance takes unit u returns nothing
*   - Restores the unit apperance values to it's default value
*
*************************************************************************************
*
*   SETUP
*
*
*/  
    //! textmacro UNIT_APPEARANCE_DEFAULT
        private static method setup takes nothing returns nothing
            /*
            *   Setup your unit type's intended appearance
            *   units who the same unit type will get modified
            *   once they are indexed.
            *
            *   Format:
            *   call setDefault(<yourUnitType>, <red>, <green>, <blue>, <alpha>, <scale>)
            */
            
            call setDefault('hfoo', 255, 0, 0, 100, 2.0)
        endmethod
    //! endtextmacro
/*
*
*************************************************************************************
*
*   Credits
*
*   Bribe - Table and Unit Indexer
*   
*************************************************************************************/
    private module Init
        private static method onInit takes nothing returns nothing
            call init()
        endmethod
    endmodule
    
    struct UnitAppearance
        // for check units that are indexed in this system
        private boolean indexed
        
        private unit Unit
        
        // unit type id of the unit 
        readonly integer unitType
        
        // current appearance values
        readonly integer red
        readonly integer green 
        readonly integer blue
        readonly integer alpha 
        readonly real scale
        
        // for checking unit types that are modified
        private static Table modifiedType
        
        // default value tables
        private static Table defaultRed
        private static Table defaultGreen
        private static Table defaultBlue
        private static Table defaultAlpha
        private static Table defaultScale
        
        /*
        *   For retrieving default values
        */
        //! textmacro UA_DEF_GET takes FIELD
        method def$FIELD$ takes nothing returns integer
            // Check if the unit's unit type id is 
            // a modified type
            //if modifiedType.has(unitType) then
            if modifiedType.boolean[unitType] then
                // if true, return it's default value
                return default$FIELD$[unitType]
            endif
            // instead, return 255
            return 255
        endmethod
        //! endtextmacro
        
        //! runtextmacro UA_DEF_GET("Red")
        //! runtextmacro UA_DEF_GET("Green")
        //! runtextmacro UA_DEF_GET("Blue")
        //! runtextmacro UA_DEF_GET("Alpha")
        
        method defScale takes nothing returns real
            //if modifiedType.has(unitType) then
            if modifiedType.boolean[unitType] then
                return defaultScale.real[unitType]
            endif
            return 1.0
        endmethod
        /*
        *   Restore unit appearance
        */
        method restore takes nothing returns nothing
            // Check if the instance is valid
            if this != 0 then
                // Get all the default values for the unit 
                set red = defRed()
                set green = defGreen()
                set blue = defBlue()
                set alpha = defAlpha()
                set scale = defScale()
                // Apply appearance values
                call SetUnitVertexColor(Unit, red, green, blue, alpha)
                call SetUnitScale(Unit, scale, 0, 0)
            endif
        endmethod
        /*
        *   for type casting a unit into a UnitAppearance Instance
        *   unit -> unit id -> UnitAppearance instance
        */
        static method operator [] takes unit u returns thistype
            local thistype this = GetUnitUserData(u)
            // Check if the unit is valid
            if this != 0 then
                // Check if the system has not yet indexed the unit
                if not indexed then
                    // Get the unit and it's unit type
                    set Unit = u
                    set unitType = GetUnitTypeId(u)
                    // apply default values by restoring it
                    call restore()
                    // unit has been indexed
                    set indexed = true 
                endif
                // return instance
                return this
            endif
            return 0
        endmethod
        
        method setColor takes integer r, integer g, integer b, integer a returns nothing
            // Check if unit is valid
            if this != 0 then
                // Apply changes. Update values
                set red = r
                set green = g
                set blue = b
                set alpha = a
            
                call SetUnitVertexColor(Unit, r, g, b, a)
            endif
        endmethod
        
        method setScale takes real value returns nothing
            if this != 0 then
                // update value. apply changes
                set scale = value
                call SetUnitScale(Unit, scale, 0, 0)
            endif
        endmethod
        
        static method setDefault takes integer uType, integer r, integer g, integer b, integer a, real s returns nothing
            // unit type is now a modified type
            set modifiedType.boolean[uType] = true
            
            // save the default values to the table
            set defaultRed[uType] = r
            set defaultGreen[uType] = g
            set defaultBlue[uType] = b
            set defaultAlpha[uType] = a
            
            set defaultScale.real[uType] = s
        endmethod
        
        // When units are indexed by the unit indexer, the system automatically indexes them
        // When indexed it also applies the default values to the unit.
        private static method onIndex takes nothing returns boolean
            return UnitAppearance[GetIndexedUnit()] != 0
        endmethod
        
        // When deindexed, clear the unit values
        private static method onDeindex takes nothing returns boolean
            local thistype this = udg_UDex
            set indexed = false 
            set unitType = 0
            set red = 255
            set green = 255
            set blue = 255
            set alpha = 255
            set scale = 1.0
            return false
        endmethod
        
        // Implement the default values
        //! runtextmacro UNIT_APPEARANCE_DEFAULT()
        
        private static method init takes nothing returns nothing
            set modifiedType = Table.create()
            set defaultRed = Table.create()
            set defaultGreen = Table.create()
            set defaultBlue = Table.create()
            set defaultAlpha = Table.create()
            set defaultScale = Table.create()
            
            call OnUnitIndex(function thistype.onIndex)
            call OnUnitDeindex(function thistype.onDeindex)
            call setup()
        endmethod
        
        implement Init 
    endstruct
    /*
    *   Wrappers
    */
    function SetUnitVertexColorEx takes unit u, integer r, integer g, integer b, integer a returns nothing
        call UnitAppearance[u].setColor(r, g, b, a)
    endfunction
    
    function SetUnitScaleEx takes unit u, real scale returns nothing
        call UnitAppearance[u].setScale(scale)
    endfunction
    
    //! textmacro UNIT_APPEARANCE_GET takes FIELD, field, TYPE
    function GetUnit$FIELD$ takes unit u returns $TYPE$
        return UnitAppearance[u].$field$
    endfunction
    
    function GetUnitDefault$FIELD$ takes unit u returns $TYPE$
        return UnitAppearance[u].def$FIELD$()
    endfunction
    //! endtextmacro
    
    //! runtextmacro UNIT_APPEARANCE_GET("Red",   "red",   "integer")
    //! runtextmacro UNIT_APPEARANCE_GET("Green", "green", "integer")
    //! runtextmacro UNIT_APPEARANCE_GET("Blue",  "blue",  "integer")
    //! runtextmacro UNIT_APPEARANCE_GET("Alpha", "alpha", "integer")
    //! runtextmacro UNIT_APPEARANCE_GET("Scale", "scale", "real")
    function RestoreUnitAppearance takes unit u returns nothing
        call UnitAppearance[u].restore()
    endfunction
endlibrary

Test
JASS:
library Tester requires UnitAppearance UnitIndexerGUI
struct Test extends array
    private static unit footman
    private static method restore takes nothing returns nothing
        call DestroyTimer(GetExpiredTimer())
        call BJDebugMsg("Unit restored")
        call RestoreUnitAppearance(footman)
    endmethod
    
    private static method modify takes nothing returns nothing
        call DestroyTimer(GetExpiredTimer())
        call SetUnitVertexColorEx(footman, 255, 255, 0, 128)
        call SetUnitScaleEx(footman, 0.5)
        call BJDebugMsg("started test")
        call BJDebugMsg("Footman ARGB and Scale Values:")
        call BJDebugMsg("    Alpha : " + I2S(GetUnitAlpha(footman)) + " Default : " + I2S(GetUnitDefaultAlpha(footman)))
        call BJDebugMsg("    Red : "   + I2S(GetUnitRed(footman))   + " Default : " + I2S(GetUnitDefaultRed(footman)))
        call BJDebugMsg("    Green : " + I2S(GetUnitGreen(footman)) + " Default : " + I2S(GetUnitDefaultGreen(footman)))
        call BJDebugMsg("    Blue : "  + I2S(GetUnitBlue(footman))  + " Default : " + I2S(GetUnitDefaultBlue(footman)))
        call BJDebugMsg("    Scale : " + R2S(GetUnitScale(footman)) + " Default : " + R2S(GetUnitDefaultScale(footman)))
    endmethod
    
    private static method start takes nothing returns boolean
        set footman = CreateUnit(Player(0), 'hfoo', 0, 0, 270)
        call TimerStart(CreateTimer(), 2.0, false, function thistype.modify)
        call TimerStart(CreateTimer(), 12.0, false, function thistype.restore)
        return false
    endmethod
    
    private static method onInit takes nothing returns nothing
        call OnUnitIndexerInitialized(function thistype.start)
    endmethod
endstruct
endlibrary
 

Attachments

  • UnitAppearance.w3x
    39.5 KB · Views: 51
I don't see sense in overloading [] operator in this case. Why not directly register onIndex function?

Could you explain please why set/reset values when unit is being indexed?

Imo the tables for default values can be replaced by readonly members of the struct -- Like it's done with *current*values. Default members would be set once onIndex. What's your thought?

setDefault -> private.

Are the this!=0 checks even needed?

The user should be notified exclusivly to use this system to modify unit apperance values over natives, as they are not hooked.

--------

So differences to system by Anitarf is basicly:

- You don't hook
- You don't use ARGB (ARGB might be used by some, but it also can make itharder for beginners, especially to make default settings)
- You use struct members for storing data (atm not for default values though) instead of table lookup
- Anitarf addiotionaly tracks UnitTimeScale

----------

Just listing for easier lookup later.
 
Top