1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  5. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  6. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  7. The results are out! Check them out.
    Dismiss Notice
  8. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  9. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  10. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[vJass, JESP] Time Stop 1.3.2

Submitted by Cheezeman
This bundle is marked as approved. It works and satisfies the submission rules.

Time Stop



Completely stops the time for all enemy units within
an area around the caster
100% Multi-User instancable and stacks properly
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯


This is my very first spell.
It follows the JESP standard and is written in vJass. In this spell I've focused more on a userfriendly and easy Setup section rather than optimization. For example, I added the function Pick() so that Targets() would take 'target' instead of GetFilterUnit() as an argument.
I didn't know that such a spell already existed in DotA when I started my work, so don't judge my creativity (which sucks, but I'm not a stealer).
And please, when reviewing my script don't tell me "use structs man, you suck". I don't know them yet, or at least when I'm writing this.

Ignore hvo-busterkomo's review. It was for 1.0 and alot has been changed in scripting since then.

Constructive feedback and critisism is most welcome :thumbs_up:
No credits is required when used in your map, though a shiny sphere would be nice.

This resource is frequently updated, whenever bugs are discovered or code improvement is found.
When you see that a new version is released, please tell me what you think about it. If you feel uncomfortable with reviving a spell (you can't really 'revive' a spell which has been updated...), you can PM me with opinions (actually, I want you to PM me with them).



Pros and Cons
¯¯¯¯¯¯¯¯¯¯¯¯
[+]
Follows the JESP standard (document included in this map)
--[+] Fully customizable in a clear Setup section
--[+] 100% Multi User Instancable
--[+] Easy to import with no configuration problems
[+] Neat special effect with lots of customization
[+] Should be leakless, though one can never be sure
[-] Requires an additional unit
[-] Special effect settings outside the Setup section
[-] If you use other spells with the PauseUnit() native,
----you have to replace it with PauseUnitEx() or Time Stop
----will cause bugs

Requirements
¯¯¯¯¯¯¯¯¯¯¯
- A vJass compiler (I recommend JassHelper by Vexorian, get it with Jass NewGen Pack)
- CSSafety
--- TimerUtils by Vexorian
--- GroupUtils by Rising_Dusk
- PauseUtils (Included in map. If possible replace with UnitToggling)

Credits
¯¯¯¯¯¯
* Flame_Phoenix; Teaching me vJass and helping me optimizing this spell
* Vexorian; Creating the TimerUtils system
* Rising_Dusk; Creating the GroupUtils system
* tomtefar1988 (not a Hive member); Showing me the neat special effect

Awards
- 103 Downloads the first 48 hours
- More than 1000 total downloads
- Was Newest Spell on hive for a long period (19 days counted so far)
- Record-fast import time of 2:56 (everything ready to use) on a moderatly sized map

__________________
Version 1.3.2
Made by Cheezeman
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

Documentation
Script (excluding TimerUtils and GroupUtils)
Code (vJASS):
//===========================================================================
//    
//                            Time Stop
//    
//              Stops the time for all enemy units within
//              an area around the caster
//              Does not target magic immune or mechanical units
//             ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//    
//      Import
//      ¯¯¯¯¯¯
//      Copy and paste these triggers* to your map:
//         - Time Stop
//         - TimerUtils
//         - GroupUtils
//         - PauseUtils
//      Copy and paste these objects to your map:
//         - Abilities\\SPELL_ID
//         - Units\\EFFECT_DUMMY_ID
//         - Units\\DUMMY_ID
//      Make sure the Setup section contains all the correct rawcodes:
//         - SPELL_ID
//         - DUMMY_ID
//         - EFFECT_DUMMY_ID
//    
//      * Trigger window objects
//    
//    
//      Pros and Cons
//      ¯¯¯¯¯¯¯¯¯¯¯¯¯
//      [+] Follows the JESP standard (document included in this map)
//        [+] Fully customizable in a clear Setup section
//        [+] 100% Multi User Instancable
//        [+] Easy to import with no configuration problems
//      [+] Neat special effect with lots of customization
//      [+] Should be leakless, though one can never be sure
//      [-] Requires an additional unit
//      [-] Special effect settings outside the Setup section
//      [-] If you use other spells with the PauseUnit() native,
//          you have to replace it with PauseUnitEx() or Time Stop
//          will cause bugs
//    
//    
//      For more information please check out this map's documentation folder,
//      or - if you found it in a public map - the official upload page:
//      hiveworkshop.com/forums/spells-569/vjass-jesp-time-stop-1-2-a-133719/
//      ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//    
//    
//       ____________________
//      I Version 1.3       I
//      I Made by Cheezeman I
//       ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//    
//===========================================================================

scope TimeStop initializer Initialize
//===========================================================================
//=============================== SETUP =====================================
//===========================================================================

    globals
        private constant integer SPELL_ID           = 'A000'    //The rawcode of the spell the Hero uses
        private constant integer DUMMY_ID           = 'h000'    //The rawcode of the normal dummy unit (used for preload)
        private constant integer EFFECT_DUMMY_ID    = 'h003'    //The rawcode of the special effect dummy unit
        //NOTE: To change the special effect, open the EFFECT_DUMMY_ID inside the Object Editor and change "Art - Model File"
    endglobals
   
    private constant function Duration takes integer level returns real
        return 3. + ( 2. * level ) //The duration of the spell
    endfunction
   
    private constant function AreaOfEffect takes integer level returns real
        return 150. + ( 150. * level ) //The area the spell affects
    endfunction

    private function AllowedTargets takes unit caster, unit target returns boolean
        //These are the conditions the target must meet.
        //If you want to add more, simply copy a line, paste it inside the block
        //and modify it to a statement.
        return /*
        //==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====            //The target...
        */
IsUnitEnemy( target, GetOwningPlayer( caster ) )         and /*  //- must be an enemy
        */
GetWidgetLife( target ) > 0.405                          and /*  //- must be alive
        */
IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) == false      and /*  //- mustn't be magic immune
        */
IsUnitType( target, UNIT_TYPE_STRUCTURE ) == false       and /*  //- mustn't be a structure
        */
IsUnitType( target, UNIT_TYPE_MECHANICAL ) == false      and /*  //- mustn't be mechanical
        //==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
        */
true
    endfunction

    //========================== Advanced Setup =========================
    //======= These functions are for 'advanced' Jass/vJass users =======

    private function AdditionalSpecialEffects takes unit Effect, real casters_current_height returns nothing
        call SetUnitScale( Effect, 2., 2., 2. )
        call SetUnitFlyHeight( Effect, casters_current_height + 100., 0. )
        //Here you can tweak the special effect even more.
        //You can colorize it, make it move, spin and lots of other things
        //(the 'effect' is a unit, so it has all the options a normal unit has)
    endfunction

    private function RevertTimeScale takes unit target returns nothing
        call SetUnitTimeScale( target, 1. )
        //If your map already utilize the TimeScale for other purposes,
        //you can add an If/Then/Else statement to revert its TimeScale
        //to the one it had before ('original' TimeScale)
    endfunction

    private function PreloadTimeStop takes nothing returns nothing
        set bj_lastCreatedUnit = CreateUnit( Player( 15 ), DUMMY_ID, 0, 0, 0 )
        call UnitAddAbility( bj_lastCreatedUnit, SPELL_ID )
        call KillUnit( bj_lastCreatedUnit )
        //This is the preload the ability is using.
        //If you're using xe in your map, just replace this with XE_PreloadAbility(SPELL_ID)
        //(or whatever the function is named)
       
        //Before I get any stupid comments on these lines, note that bj_ variables are not
        //evil. Only BJ >>Functions<< are evil.
    endfunction

//===========================================================================
//============================= END SETUP ===================================
//================ Don't mess with the code below this line =================
//===========================================================================
    globals
        private hashtable Hash
        private unit TemporareCaster
        private boolexpr Target_Checker
        private boolexpr DummyFilter
        private trigger BugfixTrigger
        private integer ReferanceCounter = 0
    endglobals
//===========================================================================
    private function Pick takes nothing returns boolean
        return AllowedTargets( TemporareCaster, GetFilterUnit() )
    endfunction
   
    private constant function AntiLeakFilter takes nothing returns boolean
        return true
    endfunction

    private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == SPELL_ID
    endfunction
   
    private function Bugfix_Conditions takes nothing returns boolean
        return LoadInteger( Hash, 1, GetHandleId( GetTriggerUnit() ) ) > 0
    endfunction
//============================ Main script ==================================

    private function PauseTargets takes nothing returns nothing
        local unit enum = GetEnumUnit()

        call SaveInteger( Hash, 1, GetHandleId( enum ), LoadInteger( Hash, 1, GetHandleId( enum ) ) + 1 )
        call PauseUnitEx( enum, true )
        call SetUnitTimeScale( enum, 0. )
       
        set enum = null
    endfunction

    private function UnpauseTargets takes nothing returns nothing
        local unit enum = GetEnumUnit()
        local integer enum_id = GetHandleId( enum )
       
        //Although it uses PauseUtils, it still requires to check if it should reset time scale
        call PauseUnitEx( enum, false )
        call SaveInteger( Hash, 1, enum_id, LoadInteger( Hash, 1, enum_id ) - 1 )
        if LoadInteger( Hash, 1, enum_id ) <= 0 then
            call RemoveSavedInteger( Hash, 1, enum_id )
            call RevertTimeScale( enum )
        endif
       
        set enum = null
    endfunction

    private function ActionsContinued takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer t_dat = GetHandleId( t )
       
        call ForGroup( LoadGroupHandle( Hash, 2, t_dat ), function UnpauseTargets )
        call SetUnitTimeScale( LoadUnitHandle( Hash, 3, t_dat ), 5. )

        set ReferanceCounter = ReferanceCounter - 1
        if ReferanceCounter <= 0. then
            set ReferanceCounter = 0
            call DisableTrigger( BugfixTrigger )
        endif

        call ReleaseGroup( LoadGroupHandle( Hash, 2, t_dat ) )
        call ReleaseTimer( t )
        call RemoveSavedHandle( Hash, 2, t_dat )
        call RemoveSavedHandle( Hash, 3, t_dat )
        set t = null
    endfunction

    private function Actions takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local integer caster_id = GetHandleId( caster )
        local real casterX = GetUnitX( caster )
        local real casterY = GetUnitY( caster )
        local integer level = GetUnitAbilityLevel( caster, SPELL_ID )
        local real duration = Duration( level )
        local real caster_fly = GetUnitFlyHeight( caster )
        local timer t = NewTimer()
        local unit dummy = CreateUnit( GetOwningPlayer( caster ), EFFECT_DUMMY_ID, casterX, casterY, 0.00 )
        local group g = NewGroup()
        set TemporareCaster = caster
       
        set ReferanceCounter = ReferanceCounter + 1
        call EnableTrigger( BugfixTrigger )
       
        call SaveUnitHandle( Hash, 3, caster_id, dummy )
        call AdditionalSpecialEffects( dummy, caster_fly )
        call UnitApplyTimedLife( dummy, 'BTLF', duration )
        call SetUnitTimeScale( dummy, 1. / duration )
       
        call GroupEnumUnitsInRange( g, casterX, casterY, AreaOfEffect( level ), Target_Checker )
        call SaveGroupHandle( Hash, 2, GetHandleId( t ), g )
        call ForGroup( g, function PauseTargets )
        call TimerStart( t, duration, false, function ActionsContinued )

        set caster = null
        set dummy = null
        set t = null
        set g = null
    endfunction
   
    private function Bugfix_Actions takes nothing returns nothing
        call RevertTimeScale( GetTriggerUnit() )
    endfunction
//============================= Initialze ===================================
    private function Initialize takes nothing returns nothing
        local integer ForLoop = 0
        local trigger spell = CreateTrigger()
       
        set BugfixTrigger = CreateTrigger()
        set Target_Checker = Condition( function Pick )
        set DummyFilter = Condition( function AntiLeakFilter )
        set Hash = InitHashtable()
        call DisableTrigger( BugfixTrigger )
        call PreloadTimeStop()
       
        loop
            exitwhen ForLoop > 15
            call TriggerRegisterPlayerUnitEvent( spell, Player(ForLoop), EVENT_PLAYER_UNIT_SPELL_EFFECT, DummyFilter )
            call TriggerRegisterPlayerUnitEvent( BugfixTrigger, Player( ForLoop ), EVENT_PLAYER_UNIT_DEATH, DummyFilter )
            set ForLoop = ForLoop + 1
        endloop
        call TriggerAddCondition( spell, Condition( function Conditions ) )
        call TriggerAddAction( spell, function Actions )
        call TriggerAddCondition( BugfixTrigger, Condition( function Bugfix_Conditions ) )
        call TriggerAddAction( BugfixTrigger, function Bugfix_Actions )
    endfunction
endscope
Changelog
1.3.2
- Added Jass version

1.3.1
- Removed an old debug call

1.3 - The new age
- Changed the AllowedTargets() so it would be easier to manipulate
- Remade the system so it now uses a public stack module instead of a private one
- Moved AllowedTargets() out of Advanced Functions section
- Renamed StackingCounter to ReferanceCounter
- Renamed setup function Range() to AreaOfEffect()

1.2 - The next generation
- Replaced the H2I and resized arrays with Hashtables
- Added a Advanced Setup section, which includes
--- AdditionalSpecialEffects() [removed the EFFECT_SCALE and EFFECT_FLY_HEIGHT global constants for this]
--- RevertTimeScale() [For special cases of maps]
--- AllowedTargets() [Units that can be affected]
--- PreloadAbility() [Anti first-time-lag]
- Added a trigger which resets a 'stopped' units animation speed if it's killed (trigger is automatically disabled when not used)
- Enhanced the spell with GroupUtils
- Added comments to the code
- Renamed SPECIAL_DUMMY_ID to EFFECT_DUMMY_ID
- Tweaked the header
- Changed import guide, aswell as added comment windows with additional information

1.1 - The timer era
- Replaced TriggerSleepAction() with timers (using TimerUtils)
- Replaced the FirstOfGroup() looping with ForGroup()
- Properly destroyed and cleaned the all[] group
- Changed the special effect's fly height speed to 0. instead or 90000.
- Made the Range() and Duration() functions constant
- Removed the two unnecessary GUI globals from the map
- Moved the first 5 test creeps slightly closer to the bridge

1.0 - Initial release
Import Guide
Copy and paste these triggers* to your map:
----- Time Stop
----- TimerUtils
----- GroupUtils
----- PauseUtils
Copy and paste these objects to your map:
----- Abilities\\SPELL_ID
----- Units\\EFFECT_DUMMY_ID
----- Units\\DUMMY_ID
Make sure the Setup section contains all the correct rawcodes:
----- SPELL_ID
----- DUMMY_ID
----- EFFECT_DUMMY_ID

Now you're set. Enjoy.

* The 'triggers' refered to here are the trigger window objects in the map, but they are indeed not triggers.
The JESP Standard Manifest
This is the JESP standard document, if a map contains this document it means that there are
spells that follow this standard.

Spells of this map that follow the standard:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- Time Stop

Advantages of the Standard
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- Implementing spells that follow the standard is relatively easier than implementing JASS
spells that don't follow the standard.

- Configuring/Balancing spells that follow the standard is relatively easier than
implementing JASS spells that don't follow the standard.

- Users may do the following procedure to make a new ability that uses the spell's script :

* Create a new Trigger with a name (case sensitive)
* Convert that trigger to custom text.
* Copy the spell's script to a text editor like Notepad or your OS equivalent.
* Replace the spell's Code name with the name you used on the trigger.
* Copy the new text to the new trigger
* Duplicate the Spell's original objects to have new ones for the new spell script.

You are now able to use that new version of the spell.

- In case two guys give the same name to 2 different spells, there are no conflict problems
because you can easily change the name of one of them

What is the JESP Standard?
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
The JESP standard was designed to make spell sharing much better. And to make sure JASS
enhanced spells follow a rule, to prevent chaos.

What does JESP Standard stands for?
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
JASS
Enhanced
Spell
Pseudotemplate

Requirements for a spell to follow the JESP Standard
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- The spell is written in JASS
- The spell is 100% multi instanceable.
- The spell script is ready to support spells of any number of levels.
(default config header is not required to support all of them)

- The Spell has a specific code name.

- The Spell's trigger must have the spell's codename as name

- The Spell's InitTrig function must be named: InitTrig_<CodeName>

- The spell has a configuration header.

- It is mandatory that rawcodes of objects are configurable in the header.

- All the spell's specific code is inside the spell's "Trigger" (Trigger== that custom text
slot that world editor calls Trigger, the spell may use as many 'trigger' OBJECTS as needed)

- Every spell-specific single identifier or key works in such a way that reproducing the
spell's trigger but after performing a text-replace of codename with another name (and thus
renaming the cloned trigger to the new code name) it won't cause compile errors / conflicts
when playing the map.

- There is no code inside the spell's "Trigger" that is not specific to the spell.

- There are no requirements for GUI variables that are specific to the spell. If a system
used by the spell requires GUI variables the code for the system must be outside the "Trigger"

- Eyecandy and spell's balance have to be easy to configure

- The name of the author should be included in the spell's script.

- The reason to exist of this standard is spell sharing. This document should be included
within the map. And it should specify which spell follows the standard, in the top list.
Bonus: Jass version
Code (vJASS):
//===========================================================================
//    
//                            Time Stop
//                          [Jass version]
//    
//              Stops the time for all enemy units within
//              an area around the caster
//              Does not target magic immune or mechanical units
//             ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//    
//      Import
//      ¯¯¯¯¯¯
//      - Copy this trigger* (only this trigger) to your map
//      - Copy and paste these objects to your map:
//          Abilities\\udg_TimeStop__SPELL_ID
//          Units\\udg_TimeStop__EFFECT_DUMMY_ID
//          Units\\udg_TimeStop__DUMMY_ID
//      - Create these variables in your map:
//          [Name]                      [Type]
//          TimeStop__Bugfix            trigger
//          TimeStop__DUMMY_ID          integer
//          TimeStop__EFFECT_DUMMY_ID   integer
//          TimeStop__Hash              hashtable
//          TimeStop__RefCount          integer
//          TimeStop__SPELL_ID          integer
//          TimeStop__TempCast          unit
//          //You may rename these later, as long as the first time you
//          //create them they have these names.
//      - Make sure the Setup section contains all the correct rawcodes:
//          udg_TimeStop__SPELL_ID
//          udg_TimeStop__DUMMY_ID
//          udg_TimeStop__EFFECT_DUMMY_ID
//      - If you get a compile error, make sure the name of this trigger is "TimeStop Jass"
//        You can rename it after you've saved.
//    
//      * Trigger window object
//    
//    
//      Pros and Cons
//      ¯¯¯¯¯¯¯¯¯¯¯¯¯
//      [+] Follows the JESP standard (document included in this map)
//        [+] Fully customizable in a clear Setup section
//        [+] 100% Multi User Instancable
//        [+] Easy to import with no configuration problems
//      [+] Neat special effect with lots of customization
//      [+] Should be leakless, though one can never be sure
//      [-] Requires an additional unit
//      [-] Special effect settings outside the Setup section
//      [-] If you use other spells with the PauseUnit() native,
//          this spell will cause bugs.
//    
//    
//      For more information please check out this map's documentation folder,
//      or - if you found it in a public map - the official upload page:
//      hiveworkshop.com/forums/spells-569/vjass-jesp-time-stop-1-2-a-133719/
//      ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//    
//    
//       ____________________
//      I Version 1.3.2     I
//      I Made by Cheezeman I
//       ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//    
//===========================================================================

//===========================================================================
//=============================== SETUP =====================================
//===========================================================================

    function TimeStop__Setup takes nothing returns nothing
        set udg_TimeStop__SPELL_ID          = 'A000'    //The rawcode of the spell the Hero uses
        set udg_TimeStop__DUMMY_ID          = 'h000'    //The rawcode of the normal dummy unit (used for preload)
        set udg_TimeStop__EFFECT_DUMMY_ID   = 'h003'    //The rawcode of the special effect dummy unit
    endfunction

    constant function TimeStop__Duration takes integer level returns real
        return 3. + ( 2. * level ) //The duration of the spell
    endfunction
   
    constant function TimeStop__AreaOfEffect takes integer level returns real
        return 150. + ( 150. * level ) //The area the spell affects
    endfunction

    function TimeStop__AllowedTargets takes unit caster,unit target returns boolean
        local boolean b = true
       
        //These are the conditions the target must meet.
        //If you want to add more, simply copy a line, paste it inside the block
        //and modify it to a statement.
        set b = b and IsUnitEnemy(target , GetOwningPlayer(caster))
        set b = b and GetWidgetLife(target) > 0.405
        set b = b and IsUnitType(target , UNIT_TYPE_MAGIC_IMMUNE) == false
        set b = b and IsUnitType(target , UNIT_TYPE_STRUCTURE) == false
        set b = b and IsUnitType(target , UNIT_TYPE_MECHANICAL) == false

        return b
    endfunction

    //========================== Advanced Setup =========================
    //======= These functions are for 'advanced' Jass/vJass users =======

    function TimeStop__AdditionalSpecialEffects takes unit Effect,real casters_current_height returns nothing
        call SetUnitScale(Effect , 2. , 2. , 2.)
        call SetUnitFlyHeight(Effect , casters_current_height + 100. , 0.)
        //Here you can tweak the special effect even more.
        //You can colorize it, make it move, spin and lots of other things
        //(the 'effect' is a unit, so it has all the options a normal unit has)
    endfunction

    function TimeStop__RevertTimeScale takes unit target returns nothing
        call SetUnitTimeScale(target , 1.)
        //If your map already utilize the TimeScale for other purposes,
        //you can add an If/Then/Else statement to revert its TimeScale
        //to the one it had before ('original' TimeScale)
    endfunction

    function TimeStop__PreloadTimeStop takes nothing returns nothing
        set bj_lastCreatedUnit = CreateUnit(Player(15) , udg_TimeStop__DUMMY_ID , 0 , 0 , 0)
        call UnitAddAbility(bj_lastCreatedUnit , udg_TimeStop__SPELL_ID)
        call KillUnit(bj_lastCreatedUnit)
        //This is the preload the ability is using.
        //If you're using xe in your map, just replace this with XE_PreloadAbility(SPELL_ID)
        //(or whatever the function is named)
       
        //Before I get any stupid comments on these lines, note that bj_ variables are not
        //evil. Only BJ >>Functions<< are evil.
    endfunction

//===========================================================================
//============================= END SETUP ===================================
//================ Don't mess with the code below this line =================
//===========================================================================
    function TimeStop__Pick takes nothing returns boolean
        return TimeStop__AllowedTargets(udg_TimeStop__TempCast , GetFilterUnit())
    endfunction
   
    function TimeStop__Conditions takes nothing returns boolean
        return GetSpellAbilityId() == udg_TimeStop__SPELL_ID
    endfunction
   
    function TimeStop__Bugfix_Conditions takes nothing returns boolean
        return LoadInteger(udg_TimeStop__Hash , 1 , GetHandleId(GetTriggerUnit())) > 0
    endfunction
//============================ Main script ==================================

    function TimeStop__PauseTargets takes nothing returns nothing
        local unit enum= GetEnumUnit()

        call SaveInteger(udg_TimeStop__Hash , 1 , GetHandleId(enum) , LoadInteger(udg_TimeStop__Hash , 1 , GetHandleId(enum)) + 1)
        call PauseUnit(enum , true)
        call SetUnitTimeScale(enum , 0.)
       
        set enum = null
    endfunction

    function TimeStop__UnpauseTargets takes nothing returns nothing
        local unit enum= GetEnumUnit()
        local integer enum_id= GetHandleId(enum)
       
        call SaveInteger(udg_TimeStop__Hash , 1 , enum_id , LoadInteger(udg_TimeStop__Hash , 1 , enum_id) - 1)
        if LoadInteger(udg_TimeStop__Hash , 1 , enum_id) <= 0 then
            call RemoveSavedInteger(udg_TimeStop__Hash , 1 , enum_id)
            call TimeStop__RevertTimeScale(enum)
            call PauseUnit(enum , false)
        endif
       
        set enum = null
    endfunction

    function TimeStop__ActionsContinued takes nothing returns nothing
        local timer t= GetExpiredTimer()
        local integer t_dat= GetHandleId(t)
       
        call ForGroup(LoadGroupHandle(udg_TimeStop__Hash , 2 , t_dat) , function TimeStop__UnpauseTargets)
        call SetUnitTimeScale(LoadUnitHandle(udg_TimeStop__Hash , 3 , t_dat) , 5.)

        set udg_TimeStop__RefCount = udg_TimeStop__RefCount - 1
        if udg_TimeStop__RefCount <= 0. then
            set udg_TimeStop__RefCount = 0
            call DisableTrigger(udg_TimeStop__Bugfix)
        endif

        call DestroyGroup(LoadGroupHandle(udg_TimeStop__Hash , 2 , t_dat))
        call DestroyTimer(t)
        call RemoveSavedHandle(udg_TimeStop__Hash , 2 , t_dat)
        call RemoveSavedHandle(udg_TimeStop__Hash , 3 , t_dat)
        set t = null
    endfunction

    function TimeStop__Actions takes nothing returns nothing
        local unit caster= GetTriggerUnit()
        local integer caster_id= GetHandleId(caster)
        local real casterX= GetUnitX(caster)
        local real casterY= GetUnitY(caster)
        local integer level= GetUnitAbilityLevel(caster , udg_TimeStop__SPELL_ID)
        local real duration= TimeStop__Duration(level)
        local real caster_fly= GetUnitFlyHeight(caster)
        local timer t= CreateTimer()
        local unit dummy= CreateUnit(GetOwningPlayer(caster) , udg_TimeStop__EFFECT_DUMMY_ID , casterX , casterY , 0.00)
        local group g= CreateGroup()
        local boolexpr b= Condition(function TimeStop__Pick)
        set udg_TimeStop__TempCast = caster
       
        set udg_TimeStop__RefCount = udg_TimeStop__RefCount + 1
        call EnableTrigger(udg_TimeStop__Bugfix)
       
        call SaveUnitHandle(udg_TimeStop__Hash , 3 , caster_id , dummy)
        call TimeStop__AdditionalSpecialEffects(dummy , caster_fly)
        call UnitApplyTimedLife(dummy , 'BTLF' , duration)
        call SetUnitTimeScale(dummy , 1. / duration)
       
        call GroupEnumUnitsInRange(g , casterX , casterY , TimeStop__AreaOfEffect(level) , b)
        call SaveGroupHandle(udg_TimeStop__Hash , 2 , GetHandleId(t) , g)
        call ForGroup(g , function TimeStop__PauseTargets)
        call TimerStart(t , duration , false , function TimeStop__ActionsContinued)

        set caster = null
        set dummy = null
        set t = null
        set g = null
    endfunction
   
    function TimeStop__Bugfix_Actions takes nothing returns nothing
        call TimeStop__RevertTimeScale(GetTriggerUnit())
    endfunction
//============================= Initialze ===================================
    function InitTrig_TimeStop_Jass takes nothing returns nothing
        local integer ForLoop= 0
        local trigger spell= CreateTrigger()
       
        call TimeStop__Setup()
        set udg_TimeStop__Bugfix = CreateTrigger()
        set udg_TimeStop__Hash = InitHashtable()
        call DisableTrigger(udg_TimeStop__Bugfix)
        call TimeStop__PreloadTimeStop()
       
        loop
            exitwhen ForLoop > 15
            call TriggerRegisterPlayerUnitEvent(spell , Player(ForLoop) , EVENT_PLAYER_UNIT_SPELL_EFFECT , null )
            call TriggerRegisterPlayerUnitEvent(udg_TimeStop__Bugfix , Player(ForLoop) , EVENT_PLAYER_UNIT_DEATH , null)
            set ForLoop = ForLoop + 1
        endloop
        call TriggerAddCondition(spell , Condition(function TimeStop__Conditions))
        call TriggerAddAction(spell , function TimeStop__Actions)
        call TriggerAddCondition(udg_TimeStop__Bugfix , Condition(function TimeStop__Bugfix_Conditions))
        call TriggerAddAction(udg_TimeStop__Bugfix , function TimeStop__Bugfix_Actions)
    endfunction
 

Hidden text: #332c29 Hidden quote: #222222

Keywords:
Cheezeman, JESP, Time, Stop, Time Stop, Chronosphere, DotA
Contents

Time Stop 1.3 (Map)

Reviews
Moderator
19:00, 28th Jun 2009 hvo-busterkomo: Coding: 2/5 Decent coding, although I still have my complaints. 1. You don't need to use a ridiculously large integer to create a instant height change. 0 will set to the specified height instantly. 2. Your...
  1. 19:00, 28th Jun 2009
    hvo-busterkomo:
    Review

    Coding: 2/5
    Decent coding, although I still have my complaints.
    1. You don't need to use a ridiculously large integer to create a instant height change. 0 will set to the specified height instantly.
    2. Your duration and range functions should be constant, and don't need the parentheses.
    3. Instead of copying the group, and then looping through it twice you should just use a ForGroup(). Your CopyGroup() also leaks.
    4. The H2I unit indexing along with the TriggerSleepAction is just awful (not to mention innacurate). You should instead use structs + timers + TimerUtils.
    5. You could use the dummy.mdx and attach the special effect to it. It would be a lot better than requiring the use of the object editor.

    Originality: 2/5
    I've seen the effect before, although it's not extremely unoriginal.

    Documentation: 5/5
    Documentation was acceptable.

    Overall = (Coding * 0.50) + (Originality * 0.30) + (Documentation * 0.20)
    Overall: 2.85
    Approved with a 3/5 (Useful) rating.
     
  2. Deuterium

    Deuterium

    Joined:
    Mar 17, 2009
    Messages:
    1,301
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    I must say it's unoriginal... I'm checking the script now
     
  3. Cheezeman

    Cheezeman

    Joined:
    Aug 19, 2008
    Messages:
    445
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    (maybe you're updating this post now but I'll answer anyway)
    Both yes and no.
    Yes, in that sence it's very simple.
    No, because I havn't seen it anywhere else.
    And come on, wierd spells with a lot of twists are just confusing and often looks wierd. I like to make simple spells because they're a hell-of-alot more user friendly. Not that I mind coding strange and wierd spells, but spells should be simple and understandable (just like blizzard has designed theirs).
     
  4. Deuterium

    Deuterium

    Joined:
    Mar 17, 2009
    Messages:
    1,301
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    I'm not saying spells have to be complex to be nice or original, but the well known DotA already has this spell and lready many people have done it...

    And ummm, script seems fine... I'm no Jass pro but I read it and it's well done
     
  5. Cheezeman

    Cheezeman

    Joined:
    Aug 19, 2008
    Messages:
    445
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    Well I don't play dota, so I'm not sure that counts.

    Why thank you :grin: I hope I didn't miss any leaks and so.
    Oh and I should update the description saying that I focus more on having a good and userfriendly SETUP section rather than optimization.
    (If you don't get what I mean, I for example added an extra function so the "Targets()" would take "target" instead of GetFilterUnit())
     
  6. Deaod

    Deaod

    Joined:
    Nov 18, 2007
    Messages:
    805
    Resources:
    12
    Maps:
    1
    Spells:
    11
    Resources:
    12
    • Destroying groups leaks. You leak the initial value of copy, btw.
    • TSA doesnt pause when a player starts lagging.
    • Instead of 90000., you could use 0. for the fly-height-change-rate.
    • Use xefx for the effect.
    • Use Unit Indexing.
    • Maybe, instead of pausing stun the unit for the duration of the spell, and additionally black out the command card if you want/are able to (i think it only works for non-hero units).
    • There can be dead units with more than 0.405 HP
    • This spell doesnt follow the JESP standard (not that that makes any difference nowadays)
    • Wasnt there a module for xe for preloading abilities? Use that one.
     
  7. mecatronic

    mecatronic

    Joined:
    Jun 20, 2005
    Messages:
    112
    Resources:
    1
    Maps:
    1
    Resources:
    1
    100% true.

    What?
     
  8. FullScale

    FullScale

    Joined:
    Jun 11, 2008
    Messages:
    19
    Resources:
    0
    Resources:
    0
    its hard to believe you would use the same special effect for the same spell that dota has without knowing it.
     
  9. Cheezeman

    Cheezeman

    Joined:
    Aug 19, 2008
    Messages:
    445
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    Reply to Deaod
    Good idea to change it... I didn't realize until now that my spell isn't instant (in which case it would be better to use 1 global variable)
    What is TSA?
    Hm... thank you, that would work as instant, right?
    No, the effect can't be slowed down when using a special effect
    What is that?
    So you suggest I spam the map with 20 instant create-dummy-and-cast-stun instead of letting the user add "IsUnitType(target, UNIT_TYPE_HERO) == false" himself?
    No, I don't think so...
    Well, Flame_Phoenix told me that there are no dead units with more than .405 hp, and he's been using that statment for a long time without bugs (he's got a huge-ass rpg and it works fine)
    Then tell me how it does not instead of stating that it does not.
    Yes there is, but I wanted it to be as self-sufficient as possible (without libraries). The preload is fine and doesn't lag (or leak), so if the user have this library he can preload it himself.

    Reply to FullScale
    Look, I'm serious. I don't play Dota. At all.
    If I would've known this spell existed I would've either said it in the description when I uploaded it, or wouldn't have made this at all.
    I hearby swear on my very soul to God that I did not know there was a similar spell in DotA, or any other map, when I started making this.

    Reply to hvo-busterkomo's review
    Right, I don't. It's on my change list now.
    No. Constant functions will never change, and I want the area and duration to be dependant on the level of the skill. Oh and the parantheses are just for making it easier to manipulate though they're totally useless.
    To pause all the units in my spell I'm using the "GroupRemoveUnit", and at the end my first group will be empty. If it's empty I cannot unpause them.
    Hence the CopyGroup. Oh and I'd be glad if someone told me how to fix the leaks in it.
    I don't know structs, but I might be able to pull it off with timers...
    I tried that, and it failed. Attaching a special effect to a unit, .mdx or normal dummy unit, still can't be slowed. The effect is still in the same time scale.
    I made a topic on this here

    I'll start working on it later today, right now I'm off to bed.
     
  10. 1)ark_NiTe

    1)ark_NiTe

    Joined:
    Nov 1, 2006
    Messages:
    1,680
    Resources:
    5
    Maps:
    1
    Spells:
    3
    Tutorials:
    1
    Resources:
    5
    Alright just to be practical here, a stop time spell is easily made with a modified War Stomp ability and some extra effects. I haven't looked at your coding but is it really necessary to do this if you can take care of it much more easily?
     
  11. busterkomo

    busterkomo

    Joined:
    Jun 17, 2007
    Messages:
    1,423
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    The functions are still constant. While the return value is technically different with each level, it will always be "level * 5 + 10", for example.

    Oh, and about the group. With a ForGroup you can avoid removing the units in the first place.
     
  12. Deaod

    Deaod

    Joined:
    Nov 18, 2007
    Messages:
    805
    Resources:
    12
    Maps:
    1
    Spells:
    11
    Resources:
    12
    TriggerSleepAction()

    I suggest you read up on xefx over at wc3c.net. You can slow down effects with xefx.

    You assign each unit a unique index in the range of 0-8190 without using H2I

    First of all, one dummy would be enough i imagine. Secondly, i think its a good choice gameplay-wise and blends well with other spells by blizzard.

    And where exactly is the part that should convince me that its not a possible bug? Kill a unit and then heal it via triggers. The unit wont revive but instead GetWidgetLife() will now return some value above 0.405, potentially breaking your spell.

    IIRC, it was something with InitTrig_*spellname* (possibly, there was even more). Like I said, it doesnt matter anyway.
     
  13. Cheezeman

    Cheezeman

    Joined:
    Aug 19, 2008
    Messages:
    445
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    Well... yeah.
    Just that you'd have to access the Object Editor when you wanna change duration, and then go back to the trigger and make some kind of mathmatical function that fits with it. Not that it would be hard but it would be doing the same thing twice.
    And I'd still have to loop through the units cause I really want to freeze them, not just pause them (in which case they still move which isn't very cool if you ask me). If I just loop them once then the special effect wouldn't stack.

    Just like when I realized (some posts above) that my spell isn't instant, I now realized that I don't have to count the units in the spell. This teqnique was used in Flame_Phoneix tutorial, because he counted the units in his spell, but I don't.
    Now I can remove the CopyGroup() function (which I'm courius about why you said it leaked).
    Oh and I'm not so sure about that constant function thingy. I'll have a look on it and update/post about it here later.

    Oh nuts, then I have to change it into timers.
    Alright I will. Would be epic if I finally found a solution to that annoying extra object for the spell.
    Healing a dead unit would not be a good idea. The creator shouldn't do that.
    And anyway why does that matter? You pause and unpause a dead unit... not even the decay animation stays, it will just die as normally and the user won't notice any difference. Speaking theoratically, 10 extra dead units in the memmory for 10 more seconds isn't a problem.
    If you mean that I should use a InitTrig_*spellname* instead of my initializer, you're wrong. In that Hero contest which was previously ended in wc3c.com a dude got minus points for using it instead of an initializer, and I think that means something...
    By the way, what is IIRC?



    . . . . . . Edit . . . . . .
    No! It clearly says "Warning: Uses UnitUserData", and I rank MUI (and easy config aswell) above optimization.

    . . . . . . Edit . . . . . .
    I can't find xefx :sad:
     
    Last edited: Jun 29, 2009
  14. Deaod

    Deaod

    Joined:
    Nov 18, 2007
    Messages:
    805
    Resources:
    12
    Maps:
    1
    Spells:
    11
    Resources:
    12
    Unit Indexing stores the index of that unit in its UserData, so you can always retrieve it. Unit Indexing is MUI, and if used properly really powerful.

    xefx is part of xe.

    If I Remember Correctly

    I didnt say you should. Thats what JESP says. And thats the reason why your spell doesnt comply with the JESP standard.

    Such things CAN and WILL happen once your map grows sufficiently large.
     
  15. Cheezeman

    Cheezeman

    Joined:
    Aug 19, 2008
    Messages:
    445
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    That's from JESP.
    And I don't have an InitTrig function, so I don't have to follow that rule. That's only for Jass spells, not for vJass.

    Oh and on another topic, please check back soon because I'm gonna update this post with my 1.1 BETA to see if you like it better or if it's worse.


    EDIT: Updated to 1.1. Check it out....

    Edit 2: I checked out xe0.6, and it seems nice.
    Just that it can't slow down effects.
    It can twist them, colorize them and move them, but not change the speed. Effects have the same speed no matter what when created with the trigger editor.

    Yes but if you already use UnitUserData, the spell will not work, and will thus not be MUI.

    Yes but it does not matter as I said earlier. In this case the units will still die normally and no harm is done.
     
    Last edited: Jun 30, 2009
  16. DeadZero

    DeadZero

    Joined:
    Feb 22, 2008
    Messages:
    451
    Resources:
    2
    Maps:
    1
    Tutorials:
    1
    Resources:
    2
    This has been done plenty of times in plenty of places...
     
  17. Cheezeman

    Cheezeman

    Joined:
    Aug 19, 2008
    Messages:
    445
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    Give me a concrete example with a link, and I will begin working on why people should choose mine instead of theirs :wink:

    Oh I found 1 here on hive. I've got some good examples why you should use mine
    1: Mine only uses 2 trigger windows, his uses 4 trigger windows
    2: Mine follows JESP
    3: Mine does not target magic immune creeps
    4: Mine does not need that "Every .05 seconds of the game" event, just "Unit starts the effect of an ability"
     
    Last edited: Jun 30, 2009
  18. f0rsAk3n

    f0rsAk3n

    Joined:
    Nov 2, 2008
    Messages:
    536
    Resources:
    10
    Spells:
    9
    Template:
    1
    Resources:
    10
    Hey this is like Chronosphere. Been looking for something similar for quite some time. Thanks.
     
  19. Cheezeman

    Cheezeman

    Joined:
    Aug 19, 2008
    Messages:
    445
    Resources:
    2
    Spells:
    1
    Tutorials:
    1
    Resources:
    2
    Thank you very much f0rsAk3n :grin:
    Oh and I should update header with the fact that no credits is needed when used in a map, I'd just like a cookie for my work (which you've of course already given me).