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

[Solved] Remove Unit issue with MoveSpeedX v1.1.0.0

Status
Not open for further replies.
Level 19
Joined
Feb 27, 2019
Messages
590
Hello! I am using MoveSpeedX by PurgeandFire
MoveSpeedX for GUI v1.1.0.0

If I use Remove Unit there is sometimes an issue in which a new unit will not get any extra move speed above 522 applied. The first 7-10 times the unit is created it will get the correct extra move speed, then it stops working for about 2-3 times then works again, stops working and so on. It works flawlessly if I use Kill unit instead of Remove unit. My humble guess is that it cant detect a removed unit, only dead units somewhere in the code. If I change UDexWasted to a lower value than the default 15 the problem presents itself earlier.

This is how I apply the move speed:
  • Unit - Create 1 ENSNAREDUMMY for (Owner of (Triggering unit)) at (Position of (Triggering unit)) facing (Position of tempunit)
  • Set VariableSet U_ENSNAREDUMMY = (Last created unit)
  • Unit - Set U_ENSNAREDUMMY movement speed to 700.00
I might have to add another condition to the code thats checks if the unit has been removed but I dont know how to do that.

* How to add an OR condition that checks if a unit has been removed/doesnt exist in vJazz?
* Do you have any other idea why the extra movement speed is not applied?


My guess is I should add the condition here:
if IsUnitType(u, UNIT_TYPE_DEAD) then
call this.destroy()

  • Unit Indexer
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: call ExecuteFunc("InitializeUnitIndexer")
      • Custom script: endfunction
      • -------- --------
      • -------- This is the most important function - it provides an index for units as they enter the map --------
      • -------- --------
      • Custom script: function IndexUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • -------- --------
      • -------- You can use the boolean UnitIndexerEnabled to protect some of your undesirable units from being indexed --------
      • -------- - Example: --------
      • -------- -- Set UnitIndexerEnabled = False --------
      • -------- -- Unit - Create 1 Dummy for (Triggering player) at TempLoc facing 0.00 degrees --------
      • -------- -- Set UnitIndexerEnabled = True --------
      • -------- --------
      • -------- You can also customize the following block - if conditions are false the (Matching unit) won't be indexed. --------
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • UnitIndexerEnabled Equal to True
        • Then - Actions
          • -------- --------
          • -------- Generate a unique integer index for this unit --------
          • -------- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UDexRecycle Equal to 0
            • Then - Actions
              • Set VariableSet UDex = (UDexGen + 1)
              • Set VariableSet UDexGen = UDex
            • Else - Actions
              • Set VariableSet UDex = UDexRecycle
              • Set VariableSet UDexRecycle = UDexNext[UDex]
          • -------- --------
          • -------- Link index to unit, unit to index --------
          • -------- --------
          • Set VariableSet UDexUnits[UDex] = (Matching unit)
          • Unit - Set the custom value of UDexUnits[UDex] to UDex
          • -------- --------
          • -------- Use a doubly-linked list to store all active indexes --------
          • -------- --------
          • Set VariableSet UDexPrev[UDexNext[0]] = UDex
          • Set VariableSet UDexNext[UDex] = UDexNext[0]
          • Set VariableSet UDexNext[0] = UDex
          • -------- --------
          • -------- Fire index event for UDex --------
          • -------- --------
          • Set VariableSet UnitIndexEvent = 0.00
          • Set VariableSet UnitIndexEvent = 1.00
          • Set VariableSet UnitIndexEvent = 0.00
          • Custom script: set udg_UDex = pdex
        • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • -------- --------
      • -------- The next function is called each time a unit enters the map --------
      • -------- --------
      • Custom script: function IndexNewUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • Custom script: local integer ndex
      • -------- --------
      • -------- Recycle indices of units no longer in-play every (15) units created --------
      • -------- --------
      • Set VariableSet UDexWasted = (UDexWasted + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • UDexWasted Equal to 15
        • Then - Actions
          • Set VariableSet UDexWasted = 0
          • Set VariableSet UDex = UDexNext[0]
          • Custom script: loop
          • Custom script: exitwhen udg_UDex == 0
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Custom value of UDexUnits[UDex]) Equal to 0
            • Then - Actions
              • -------- --------
              • -------- Remove index from linked list --------
              • -------- --------
              • Custom script: set ndex = udg_UDexNext[udg_UDex]
              • Custom script: set udg_UDexNext[udg_UDexPrev[udg_UDex]] = ndex
              • Custom script: set udg_UDexPrev[ndex] = udg_UDexPrev[udg_UDex]
              • Set VariableSet UDexPrev[UDex] = 0
              • -------- --------
              • -------- Fire deindex event for UDex --------
              • -------- --------
              • Set VariableSet UnitIndexEvent = 2.00
              • Set VariableSet UnitIndexEvent = 0.00
              • -------- --------
              • -------- Recycle the index for later use --------
              • -------- --------
              • Set VariableSet UDexUnits[UDex] = No unit
              • Set VariableSet UDexNext[UDex] = UDexRecycle
              • Set VariableSet UDexRecycle = UDex
              • Custom script: set udg_UDex = ndex
            • Else - Actions
              • Set VariableSet UDex = UDexNext[UDex]
          • Custom script: endloop
          • Custom script: set udg_UDex = pdex
        • Else - Actions
      • -------- --------
      • -------- Handle the entering unit (Matching unit) --------
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Custom value of (Matching unit)) Equal to 0
        • Then - Actions
          • Custom script: call IndexUnit()
        • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • -------- --------
      • -------- The next function initializes the core of the system --------
      • -------- --------
      • Custom script: function InitializeUnitIndexer takes nothing returns nothing
      • Custom script: local integer i = 0
      • Custom script: local region re = CreateRegion()
      • Custom script: local rect r = GetWorldBounds()
      • Set VariableSet UnitIndexerEnabled = True
      • Custom script: call RegionAddRect(re, r)
      • Custom script: call TriggerRegisterEnterRegion(CreateTrigger(), re, Filter(function IndexNewUnit))
      • Custom script: call RemoveRect(r)
      • Custom script: set re = null
      • Custom script: set r = null
      • Custom script: loop
      • Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), Filter(function IndexUnit))
      • Custom script: set i = i + 1
      • Custom script: exitwhen i == 16
      • Custom script: endloop
      • -------- --------
      • -------- This is the "Unit Indexer Initialized" event, use it instead of "Map Initialization" for best results --------
      • -------- --------
      • Set VariableSet UnitIndexEvent = 3.00
      • Set VariableSet UnitIndexEvent = 0.00

Code:
library MoveSpeedXGUI /* v1.1.0.0
*************************************************************************************
*
*   This library allows you to set unit movement speeds beyond 522 without bugs.
*   This is an extension of the library MoveSpeedX, but is formatted for GUI use.
*   Credits to Jesus4Lyf for the original system.
*
************************************************************************************
*
*   SETTINGS
*/
globals
    private constant real PERIOD = 0.03125
        //  This is the period on which all units will be run.
        // If you lower this value, movement bonuses will be smoother,
        // but will require more processing power (lag more).
        //  Also, the lower this is, the higher the move speed can be
        // before it starts bugging on waypoints. The lowest valid
        // period is 0.00125. A period of 0.00625 is very robust.
    private constant real MARGIN = 0.01
        // This is the margin of approximation when comparing reals.
        // You will most likely not need to change this.
endglobals
/*
************************************************************************************
*
*    Functions
*
*        function GetUnitMoveSpeedX takes unit whichUnit returns real
*           - Returns a unit movement speed. The GUI function will
*           - not return the correct value. This function will always
*           - return the correct value regardless of whether the unit
*           - has a movement speed beyond 522.
*
************************************************************************************
*
*   REQUIREMENTS
*
*       1.  JassNewGen Pack v5d
*       2.  JassHelper 0.A.2.B
*       3.  Any unit indexer
*
*   HOW TO IMPLEMENT
* 
*       1.  Copy the 'folder' MoveSpeedX.
*       2.  Paste it into your map.
*       3.  Open "Advanced -> Gameplay Constants".
*       4.  Checkmark "Use Custom Gameplay Constants".
*       5.  Find the field, "Movement - Unit Speed - Maximum", change
*           that to 522.
*       6.  Find the field, "Movement - Unit Speed - Minimum", hold
*           shift and click, and change it to 0.
*       7.  Read HOW TO USE.
*
************************************************************************************
*
*   HOW TO USE
*
*       This system will automatically work by itself. You can use the
*       normal GUI function for modifying unit movement speeds. Simply
*       use "Unit - Set Movement Speed", input whatever value you want,
*       and you are good to go! It will handle values beyond 522 by itself.
*
*       HOWEVER, the GUI function will not return correct values if a unit
*       has a movement speed greater than 522. To fix this, use the function
*       GetUnitMoveSpeedX to return the correct value. A sample is given in
*       the trigger "Speed Change" in the test map.
*
************************************************************************************
*
*   NOTES
*
*       Units that were issued orders as groups might not *always* end up in the proper
*       "order". (they might not end up in an organized formation) They do sometimes though.
*       This is only for units with speeds above 522.
*
*       This also will not factor in bonuses and probably not slows either.
*
*       Units may waddle around the point for a little bit. Reduce PERIOD to fix
*       it a little bit. I recommend about 0.02 if you have really high speeds.
*
************************************************************************************/

    private function ApproxEqual takes real A, real B returns boolean
        return (A >= (B - MARGIN)) and (A <= (B + MARGIN))
    endfunction
  
    private module M
        private static trigger issued = CreateTrigger()
      
        thistype next
        thistype prev
      
        boolean enabled
        unit curr
        real speed
        real x
        real y
        real ox
        real oy
      
        method destroy takes nothing returns nothing
            set this.next.prev = this.prev
            set this.prev.next = this.next
            set this.enabled = false
        endmethod
          
        private static method periodic takes nothing returns nothing
            local thistype this = thistype(0).next // first instance in list
            local real nx // the x-coordinate after tick
            local real ny // the y-coordinate after tick
            local real dx // distance between new-x and old-x
            local real dy // distance between new-y and old-y
            local real d  // distance between new point and old point
            local integer order // the unit's current order
            local unit u // unit being affected
            loop
                exitwhen this == 0
                set u  = .curr
                set nx = GetUnitX(u)
                set ny = GetUnitY(u)
                if IsUnitType(u, UNIT_TYPE_DEAD) then
                    call this.destroy()
                elseif not ApproxEqual(nx, .x) or not ApproxEqual(ny, .y) then
                    if (not IsUnitPaused(u)) and GetUnitAbilityLevel(u, 'BSTN') == 0 and GetUnitAbilityLevel(u, 'BPSE') == 0 then
                        set order = GetUnitCurrentOrder(u)
                        set dx = nx - .x
                        set dy = ny - .y
                        set d  = SquareRoot(dx * dx + dy * dy)
                        set dx = dx / d * .speed // move the unit offset-x by this
                        set dy = dy / d * .speed // move the unit offset-y by this
                      
                        if (order == 851986 or order == 851971) and /*
                        */ (this.ox - nx)*(this.ox - nx) < (dx*dx) and /*
                        */ (this.oy - ny)*(this.oy - ny) < (dy*dy) then
                            // if the unit is issued a move or smart order and they are near their destination
                            // then move them there instantly (removes a bit of glitchyness towards the end)
                            call SetUnitX(u, .ox)
                            call SetUnitY(u, .oy)
                            set .x = .ox
                            set .y = .oy
                            call IssueImmediateOrderById(u, 851972) // order them to stop
                        else
                            set .x = nx + dx
                            set .y = ny + dy
                            call SetUnitX(u, .x)
                            call SetUnitY(u, .y)
                        endif
                    endif
                endif
                set this = this.next
            endloop
            set u = null
        endmethod
      
        static method create takes unit whichUnit, real newSpeed returns thistype
            local thistype this = GetUnitUserData(whichUnit)
            set this.next = thistype(0).next
            set thistype(0).next.prev = this
            set thistype(0).next = this
            set this.prev  = 0
            set this.curr  = whichUnit
            set this.speed = (newSpeed - 522) * PERIOD
            set this.x     = GetUnitX(whichUnit)
            set this.y     = GetUnitY(whichUnit)
            set this.enabled = true
            return this
        endmethod
      
        static method update takes unit whichUnit, real newSpeed returns nothing
            local thistype this = GetUnitUserData(whichUnit)
            if this.enabled then
                if newSpeed > 522 then
                    set this.speed = (newSpeed - 522) * PERIOD
                else
                    call this.destroy()
                endif
            elseif newSpeed > 522 then
                call thistype.create(whichUnit, newSpeed)
            endif
        endmethod
      
        private static method storeOrderPoint takes nothing returns boolean
            local thistype this = GetUnitUserData(GetTriggerUnit())
            set this.ox = GetOrderPointX()
            set this.oy = GetOrderPointY()
            return false
        endmethod
  
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), PERIOD, true, function thistype.periodic)
            call TriggerRegisterAnyUnitEventBJ(issued, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
            call TriggerAddCondition(issued, Condition(function thistype.storeOrderPoint))
        endmethod
    endmodule
  
    private struct MoveSpeedStruct extends array
        implement M
    endstruct
  
    function GetUnitMoveSpeedX takes unit whichUnit returns real
        if MoveSpeedStruct(GetUnitUserData(whichUnit)).enabled then
            return udg_UnitSpeedX[GetUnitUserData(whichUnit)]
        endif
        return GetUnitMoveSpeed(whichUnit)
    endfunction
  
    function SetUnitMoveSpeedX takes unit whichUnit, real newSpeed returns nothing
        call MoveSpeedStruct.update(whichUnit, newSpeed)
        set udg_UnitSpeedX[GetUnitUserData(whichUnit)] = newSpeed
    endfunction

    hook SetUnitMoveSpeed SetUnitMoveSpeedX
endlibrary
 
Level 19
Joined
Feb 27, 2019
Messages
590
Why not Kill then Remove?
Thanks for replying. I have tried but it doesnt work. I tried doing kill unit then instantly remove unit right after.

The unit is used for a spell and lives for about 0.9 seconds. It has locust and gets assigned a variable. The unit is removed. The next spell will use the same variable but cant be cast for another 6 seconds. Its just a bit odd that it works if its killed but not removed.
 
Level 19
Joined
Feb 27, 2019
Messages
590
Have you tried changing this
JASS:
                if IsUnitType(u, UNIT_TYPE_DEAD) then
                    call this.destroy()
into
JASS:
                if IsUnitType(u, UNIT_TYPE_DEAD) or (GetUnitTypeId(u) == 0) then
                    call this.destroy()
This was exactly what I was looking for. I added the condition and it works without any issues now. Thanks for the help!
 
Status
Not open for further replies.
Top