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

Advanced Tree Revive System v1.0.0.0

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
Contains
  • Constant variable customization
  • Methods for queuing dying trees to be paused
  • Can manually add new destructibles to be revived
  • Tree does not revive until no alive unit is in range of that tree
  • Dead tree revive check is never done on the same tree twice in a row or until every other tree has been checked first
    These trees check rate is randomized with how often and with what order
JASS:
/*
    How to import
    
Copy and paste trigger in the test map into your map
Or create your own trigger and copy and paste code into it

Requires JNGP/Jass helper to compile the code
*/

JASS:
library AdvancedTreeReviveSystem /* v1.0.0.0, created by DeathChef
    
	struct ReviveTrees extends array

		Description
            
            Dead tree indexes are mixed up and randomized
            Indexes are only checked a repeated time when all other current existing indexes are checked
            
            Prevents the same tree from being checked "5 times in a row" when there are other trees in
            the queue unlike other systems
            
		Fields
            
            trigger ReviveTrees
                 - Disable to stop dying trees from being queued to revive
                 - Re enable to let dying trees queue to be revived
            
            
            readonly static boolean Paused
                 - Is Timer Paused
            
		Methods
            
            static method RegisterTreeDeath takes destructable d returns nothing
                 - Newly created trees don't get revived, so
                   I made a method to manually add them
            
            static method TimerPauseAuto takes nothing returns nothing
                 - If paused it unpauses/if unpaused it pauses
                 - Stops dead trees from being revived
            
            static method TimerPauseBoolean takes boolean flag returns nothing
            
            static method TimerPause takes nothing returns nothing
            
            static method TimerResume takes nothing returns nothing
            
            
            
        Settings
*/    
            //! textmacro ATR_SETTINGS
                
                private static constant boolean REVIVE_IS_INITIALY_ON = true
                    //On map initialization Reviving is initialy on
                    
                private static constant boolean STORING_IS_INITIALY_ON = true
                    //On map initialization storing fallen trees are on
                    
                    
                private static constant integer TREE_TYPE = 'LTlt'
                    //Add more types here and to the CONDITIONS module
                    
                private static constant rect TREE_REGISTER_AREA = bj_mapInitialPlayableArea
                    //In this rect area only trees on init will get revived
                    
                    
                private static constant real CHECK_RATE = .34
                    //How often Check priodically runs
                    
                    
                private static real UnitCheckDistance = 151
                    //Distance a tree will be disallowed by a unit
                    
                private static real CheckRatio = .34
                    //Chance to check per tree loop check
                    //Must be >= 0 and <= 1
                
            //! endtextmacro
/*
        Conditions
*/
            //! textmacro ATR_CONDITIONS
                
                local integer DestTypeId = GetDestructableTypeId(GetFilterDestructable())
                
                return DestTypeId == TREE_TYPE// or DestTypeId == CONSTANT
                    //Can add more destructable types here
                
            //! endtextmacro
/*

*/

    struct ReviveTrees extends array
        
        //! runtextmacro ATR_SETTINGS()
        
        readonly static boolean Paused
        
        private static timer CheckTimer
        
        private static integer DeadTreesCount = 0
        private static destructable array DeadTrees
        
        //Recycle indexes
        //(Currently checking true or false side)
        private static boolean IsTrue = true
        //(Indicates what boolean side it it on)
        private static boolean array IsCheckedAsTrue
        
        //(Count for each boolean side)
        private static integer CheckedTrueCount = 0
        private static integer CheckedFalseCount = 0
        
        //(Boolean index -> actual index)
        private static integer array CheckedTrue
        private static integer array CheckedFalse
        
        //(Actual index -> boolean index)
        private static integer array CheckedTrueIndex
        private static integer array CheckedFalseIndex
        //
        
        private static method IsUnitDead takes nothing returns boolean
            return not IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD)
        endmethod
        
        private static method Count takes nothing returns nothing
            set bj_groupCountUnits = bj_groupCountUnits + 1
        endmethod
        
        private static method CheckPath takes nothing returns nothing
            local group UnitsInRange
            local integer Index
            local integer TreeBeingChecked
            
            local integer Temp_MaxIndex = DeadTreesCount
            
            loop
                exitwhen Temp_MaxIndex == 0
                
                if GetRandomReal(0., 1.) < CheckRatio then
                    if IsTrue then
                        set Index = GetRandomInt(1, CheckedTrueCount)
                        
                        set TreeBeingChecked = CheckedTrue[Index]
                        
                        if Index < CheckedTrueCount then
                            set CheckedTrue[Index] = CheckedTrue[CheckedTrueCount]
                            set CheckedTrueIndex[CheckedTrue[CheckedTrueCount]] = Index
                        elseif CheckedTrueCount == 1 then
                            set IsTrue = false
                        endif
                            
                        set CheckedTrueCount = CheckedTrueCount - 1
                        set CheckedFalseCount = CheckedFalseCount + 1
                        
                        set CheckedFalse[CheckedFalseCount] = TreeBeingChecked
                        
                        set IsCheckedAsTrue[TreeBeingChecked] = false
                        set CheckedFalseIndex[TreeBeingChecked] = CheckedFalseCount
                    else
                        set Index = GetRandomInt(1, CheckedFalseCount)
                        
                        set TreeBeingChecked = CheckedFalse[Index]
                        
                        if Index < CheckedFalseCount then
                            set CheckedFalse[Index] = CheckedFalse[CheckedFalseCount]
                            set CheckedFalseIndex[CheckedFalse[CheckedFalseCount]] = Index
                        elseif CheckedFalseCount == 1 then
                            set IsTrue = true
                        endif
                        
                        set CheckedFalseCount = CheckedFalseCount - 1
                        set CheckedTrueCount = CheckedTrueCount + 1
                        
                        set CheckedTrue[CheckedTrueCount] = TreeBeingChecked
                        
                        set IsCheckedAsTrue[TreeBeingChecked] = true
                        set CheckedTrueIndex[TreeBeingChecked] = CheckedTrueCount
                    endif
                    
                    set UnitsInRange = CreateGroup()
                    call GroupEnumUnitsInRange(UnitsInRange, GetDestructableX(DeadTrees[TreeBeingChecked]), GetDestructableY(DeadTrees[TreeBeingChecked]), UnitCheckDistance, CheckIsUnitDead)
                    
                    set bj_groupCountUnits = 0
                    call ForGroup(UnitsInRange, function thistype.Count)
                    call DestroyGroup(UnitsInRange)
                    
                    if bj_groupCountUnits == 0 then
                        call DestructableRestoreLife(DeadTrees[TreeBeingChecked], GetDestructableMaxLife(DeadTrees[TreeBeingChecked]), true)
                        
                        if IsCheckedAsTrue[TreeBeingChecked] then
                            set Index = CheckedTrueIndex[TreeBeingChecked]
                            
                            if Index < CheckedTrueCount then
                                set CheckedTrue[Index] = CheckedTrue[CheckedTrueCount]
                                set CheckedTrueIndex[CheckedTrue[CheckedTrueCount]] = Index
                            elseif CheckedTrueCount == 1 then
                                set IsTrue = false
                            endif
                            
                            set CheckedTrueCount = CheckedTrueCount - 1
                        else
                            set Index = CheckedFalseIndex[TreeBeingChecked]
                            
                            if Index < CheckedFalseCount then
                                set CheckedFalse[Index] = CheckedFalse[CheckedFalseCount]
                                set CheckedFalseIndex[CheckedFalse[CheckedFalseCount]] = Index
                            elseif CheckedFalseCount == 1 then
                                set IsTrue = true
                            endif
                            
                            set CheckedFalseCount = CheckedFalseCount - 1
                        endif
                        
                        //--
                        if TreeBeingChecked == DeadTreesCount then
                            set DeadTrees[TreeBeingChecked] = null
                        else
                            set DeadTrees[TreeBeingChecked] = DeadTrees[DeadTreesCount]
                            set DeadTrees[DeadTreesCount] = null
                            
                        endif
                        
                        
                            if IsCheckedAsTrue[DeadTreesCount] then
                                set Index = CheckedTrueIndex[DeadTreesCount]
                                
                                set CheckedTrue[Index] = TreeBeingChecked
                                set CheckedTrueIndex[TreeBeingChecked] = Index
                                
                                set IsCheckedAsTrue[TreeBeingChecked] = true
                            else
                                set Index = CheckedFalseIndex[DeadTreesCount]
                                
                                set CheckedFalse[Index] = TreeBeingChecked
                                set CheckedFalseIndex[TreeBeingChecked] = Index
                                
                                set IsCheckedAsTrue[TreeBeingChecked] = false
                            endif
                        
                        set DeadTreesCount = DeadTreesCount - 1
                    endif
                endif
                
                set Temp_MaxIndex = Temp_MaxIndex - 1
            endloop
            
            if DeadTreesCount == 0 then
                call DestroyTimer(CheckTimer)
                set CheckTimer = null
            endif
        endmethod
        
        
        private static method TreeDies takes nothing returns nothing
            set DeadTreesCount = DeadTreesCount + 1
            set DeadTrees[DeadTreesCount] = GetTriggerDestructable()
            
            if GetRandomInt(0, 1) == 0 then
                set CheckedTrueCount = CheckedTrueCount + 1
                set CheckedTrue[CheckedTrueCount] = DeadTreesCount
                
                set IsCheckedAsTrue[DeadTreesCount] = true
                set CheckedTrueIndex[DeadTreesCount] = CheckedTrueCount
                
                if DeadTreesCount == 1 then
                    set IsTrue = true
                    set CheckTimer = CreateTimer()
                    call TimerStart(CheckTimer, CHECK_RATE, true, function thistype.CheckPath)
                endif
            else
                set CheckedFalseCount = CheckedFalseCount + 1
                set CheckedFalse[CheckedFalseCount] = DeadTreesCount
                
                set IsCheckedAsTrue[DeadTreesCount] = false
                set CheckedFalseIndex[DeadTreesCount] = CheckedFalseCount
                
                if DeadTreesCount == 1 then
                    set IsTrue = false
                    set CheckTimer = CreateTimer()
                    call TimerStart(CheckTimer, CHECK_RATE, true, function thistype.CheckPath)
                endif
            endif
            
        endmethod
        
        //different methods to pause/resume this system to revive trees
        static method TimerPauseAuto takes nothing returns nothing
            if Paused then
                if DeadTreesCount > 0 and CheckTimer != null then
                    set Paused = false
                    
                    set CheckTimer = CreateTimer()
                    call TimerStart(CheckTimer, CHECK_RATE, true, function thistype.CheckPath)
                endif
            else
                set Paused = true
                
                call DestroyTimer(CheckTimer)
                set CheckTimer = null
            endif
        endmethod
        
        static method TimerPauseBoolean takes boolean flag returns nothing
            if flag then
                if Paused and DeadTreesCount > 0 and CheckTimer != null then
                    set Paused = false
                    
                    set CheckTimer = CreateTimer()
                    call TimerStart(CheckTimer, CHECK_RATE, true, function thistype.CheckPath)
                endif
            else
                if not Paused then
                    set Paused = true
                    
                    call DestroyTimer(CheckTimer)
                    set CheckTimer = null
                endif
            endif
        endmethod
        
        static method TimerPause takes nothing returns nothing
            if not Paused then
                set Paused = true
                
                call DestroyTimer(CheckTimer)
                set CheckTimer = null
            endif
        endmethod
        
        static method TimerResume takes nothing returns nothing
            if Paused and DeadTreesCount > 0 and CheckTimer != null then
                set Paused = false
                
                set CheckTimer = CreateTimer()
                call TimerStart(CheckTimer, CHECK_RATE, true, function thistype.CheckPath)
            endif
        endmethod
        
        static trigger ReviveTrees
        private static boolexpr CheckIsUnitDead
        
        static method RegisterTreeDeath takes destructable d returns nothing
            call TriggerRegisterDeathEvent(ReviveTrees, d)
        endmethod
        
        private static method IsTree takes nothing returns boolean
            //! runtextmacro ATR_CONDITIONS()
        endmethod
        
        private static method RegisterTree takes nothing returns nothing
            call TriggerRegisterDeathEvent(ReviveTrees, GetEnumDestructable())
        endmethod
        
        private static method onInit takes nothing returns nothing
            set ReviveTrees = CreateTrigger()
            call TriggerAddAction(ReviveTrees, function thistype.TreeDies)
            call EnumDestructablesInRect(TREE_REGISTER_AREA, Condition(function thistype.IsTree), function thistype.RegisterTree)
            call RemoveRect(TREE_REGISTER_AREA)
            
            set CheckIsUnitDead = Condition(function thistype.IsUnitDead)
        endmethod
    
    endstruct

endlibrary

Keywords:
tree, revive, advanced, system, DeathChef, Dashie, grow, regrow, revive, destructible
Contents

Just another Warcraft III map (Map)

Reviews
03:15, 4th Dec 2015 IcemanBo: Use a BPower's or an other Tree library. Create a demo. Don't remove bj handles. (onInit)

Moderator

M

Moderator

03:15, 4th Dec 2015
IcemanBo:
Use a BPower's or an other Tree library.
Create a demo.
Don't remove bj handles. (onInit)
 
Enjoy and stuff hopefully.
Created originally to be a part of a map I'm developing.

I would have used a snippet to let this system register with all the tree id's, although I found the following issue with these ones I found.

http://www.wc3c.net/showthread.php?p=1056151&fromattachment=1056151#1056151

- Doesn't work on initialization

http://www.hiveworkshop.com/forums/...ui-1-1-a-228385/?prev=search=tree&d=list&r=20

- Is inefficient, incomplete with tree id entries and GUI

http://www.hiveworkshop.com/forums/...abletree-222145/?prev=search=tree&d=list&r=20

- Isn't approved

Although the last one would probably work and would be the best one anyway, it hasn't been approved.
 
Last edited:
Uh yeh, I don't expect anyone to dive into much of the actual code, especially the CheckPath and TreeDies.
I guess I got kinda stubborn with the way I wanted this to turn out.

I'd say that these things would be the most useful.

//

Will halt reviving trees on init if set to false (still queues any trees that die though).
private static constant boolean REVIVE_IS_INITIALY_ON = true

Can be switched on and off with (there are 3 other methods that can turn on/off for personal preference)
static method TimerPauseBoolean takes boolean flag returns nothing

//
Changing the tree type that can be revived
private static constant integer TREE_TYPE = 'LTlt' //Add more types here and to the CONDITIONS module

and inside the conditions textmacro you can add the
return DestTypeId == TREE_TYPE// or DestTypeId == CONSTANT //Can add more destructable types here
//

Simply though if you put in the right tree id(s) and leave it at that those tree's will always revive as long as there is no units on top of their stumps.
(As long as you don't create any new ones which I configured a way to register them)


I might break down each part of the system more later and edit this post.
Kinda tired right now.

Suggestions on how to improve description would be nice...
 
Top