• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[System] Jump In Place

Well, a simple Jump in Place library

JASS:
/*

    Jump in Place version 1.02
    by Adiktuz
    
    Basically, this library handles jumping in place, but mainly for usage with the
    impale system
    
    It also allows the user to specify actions to be done after the jump is done
    
    You're also allowed to choose what to do when a unit that is currently jumping
    is re-jumped again by modifying the value of the jumptype parameter
        You can use either:
           JUMP_TYPE_STACK - stack each instance of jump for the unit
           JUMP_TYPE_HEIGHT_STACK - stack only the jump height
           JUMP_TYPE_RESET - stops the existing jump and resets unit height before doing the jump
           JUMP_TYPE_NO_OVERWRITE - don't allow stacking

    Disclaimer: Mixing these jump types might look weird...    
         
    Please take note that if you registered a StopEvent for the spell, and set the jumps to stack or reset,
    the event will only run once when the unit hits the ground
    
    How to Use:
    
        call JumpInPlace.fire(unit flyUnit, unit causeUnit, real duration, real maxheight, integer abil, integer jumptype)
        
        unit flyUnit -> unit that will jump
        unit causeUnit -> the unit that caused the jump
        real duration -> duration of jump
        real maxheight -> maxheight of jump
        integer abil -> rawcode of the ability that caused the jump
        integer jumptype -> jump type
        
    How to set action for when the unit returns to it's original height:
        call JumpInPlace.registerStopEvent(integer abil, code action)
        
        integer abil => the rawcode of the spell in which you want to add the action
                             use 0 if it won't be tied to any ability
        code action => the function which will be run
    
    You can also register global stop and start actions

        call JumpInPlace.registerGlobalEndEvent(code action)
        -> fires for any jump that finishes

        call JumpInPlace.registerGlobalStartEvent(code action)
        -> fires for any jump that starts
    
    But before using them, make sure to set their correspoding variables to true on the globals block below

    Variables you can use for the Event handlers
        JumpInPlace.tmpFlyUnit => unit that triggered the event (the jumping unit)
        JumpInPlace.tmpCauseUnit => the unit that caused the FlyUnit to jump
*/

library JumpInPlace requires T32, Table
    
    globals
        //Do you have an auto-fly library (like Magtheridon96's or Nestharus')?
        private boolean AUTO_FLY = false
        private constant integer FLY_ID = 'Amrf'
        //Set to true if you're gonna use the global start event handler
        private constant boolean USE_GLOBAL_START = false 
        //Set to true if you're gonna use the global end event handler
        private constant boolean USE_GLOBAL_END = false 
        //Do not touch
        constant integer JUMP_TYPE_STACK = 1
        constant integer JUMP_TYPE_HEIGHT_STACK = 2
        constant integer JUMP_TYPE_RESET = 3
        constant integer JUMP_TYPE_NO_OVERWRITE = 4
    endglobals

    private module init
        static method onInit takes nothing returns nothing
            set FlyTable = Table.create()
            set EventTable = Table.create()
            static if USE_GLOBAL_START then
                set globalStart = CreateTrigger()
            endif
            static if USE_GLOBAL_END then
                set globalEnd = CreateTrigger()
            endif
        endmethod
    endmodule
    
    struct JumpInPlace extends array
        private static integer instanceCount = 0
        private static thistype recycle = 0
        private thistype recycleNext
        static Table FlyTable 
        static Table EventTable 
        static trigger globalEnd
        static trigger globalStart
        static unit tmpFlyUnit
        static unit tmpCauseUnit
        unit flyUnit
        unit causeUnit
        real maxheight
        real hps
        real height
        real dfh
        boolean up
        integer abil
        
        static method registerStopEvent takes integer abil, code toDo returns nothing
            if not EventTable.handle.has(abil) then
                set EventTable.trigger[abil] = CreateTrigger()
            endif
            call TriggerAddCondition(EventTable.trigger[abil], Filter(toDo))
        endmethod
        

        static method registerGlobalStartEvent takes code toDo returns nothing
            call TriggerAddCondition(globalStart,Filter(toDo))
        endmethod
        
        static method registerGlobalEndEvent takes code toDo returns nothing
            call TriggerAddCondition(globalEnd,Filter(toDo))
        endmethod

        method stop takes nothing returns nothing
            call SetUnitFlyHeight(this.flyUnit, this.dfh, 0.0)
            call this.stopPeriodic()
            set thistype.tmpFlyUnit = this.flyUnit
            set thistype.tmpCauseUnit = this.causeUnit
            if EventTable.handle.has(this.abil) then
                call TriggerEvaluate(EventTable.trigger[this.abil])
            endif
            static if USE_GLOBAL_END then
                call TriggerEvaluate(globalEnd)
            endif
            set FlyTable[GetHandleId(this.flyUnit)] = 0
            set recycleNext = recycle
            set recycle = this
        endmethod
        


        method periodic takes nothing returns nothing
                if this.up then
                    set this.height = this.height + hps
                    if this.height >= this.maxheight then
                        set this.up = false
                    endif
                    call SetUnitFlyHeight(this.flyUnit, this.height, 0.0)
                else
                    set this.height = this.height - hps
                    call SetUnitFlyHeight(this.flyUnit, this.height, 0.0)
                    if this.height <= this.dfh then
                        set this.up = true
                        call this.stop()
                    endif
                endif
        endmethod
        
        implement T32x
        
        static method fire takes unit flyUnit, unit causeUnit, real duration, real maxheight, integer abil, integer jumptype returns nothing
            local thistype this
            local integer id = GetHandleId(flyUnit)
            if FlyTable[id] == 0 or jumptype == 1 then
                if (recycle == 0) then
                    set instanceCount = instanceCount + 1
                    set this = instanceCount
                else
                    set this = recycle
                    set recycle = recycle.recycleNext
                endif
                set FlyTable[id] = this
                static if not AUTO_FLY then
                    if UnitAddAbility(flyUnit, FLY_ID) and UnitRemoveAbility(flyUnit, FLY_ID) then
                    endif
                endif
                set this.abil = abil
                set this.causeUnit = causeUnit
                set this.flyUnit = flyUnit
                set this.dfh = GetUnitDefaultFlyHeight(flyUnit)
                set this.maxheight = maxheight + dfh
                set this.hps = (maxheight*2/duration)*T32_PERIOD
                set this.height = dfh
                set this.up = true
                call this.startPeriodic()
            else
                set this = FlyTable[id]
                if jumptype == 2 then
                    static if not AUTO_FLY then
                        if UnitAddAbility(flyUnit, FLY_ID) and UnitRemoveAbility(flyUnit, FLY_ID) then
                        endif
                    endif
                    set this.abil = abil
                    set this.causeUnit = causeUnit
                    set this.maxheight = this.maxheight + maxheight
                    set this.hps = ((this.maxheight*2 - this.height)/duration)*T32_PERIOD
                    set this.up = true
                elseif jumptype == 3 then
                    static if not AUTO_FLY then
                        if UnitAddAbility(flyUnit, FLY_ID) and UnitRemoveAbility(flyUnit, FLY_ID) then
                        endif
                    endif
                    set this.causeUnit = causeUnit
                    set this.abil = abil
                    call SetUnitFlyHeight(this.flyUnit, dfh, 0.0)
                    set this.maxheight = maxheight + dfh
                    set this.hps = (maxheight*2/duration)*T32_PERIOD
                    set this.height = dfh
                    set this.up = true
                elseif jumptype == 4 then
                    return
                endif
            endif
            set thistype.tmpFlyUnit = this.flyUnit
            set thistype.tmpCauseUnit = this.causeUnit
            static if USE_GLOBAL_START then
                call TriggerEvaluate(globalStart)
            endif
        endmethod
        
        implement init
    endstruct

endlibrary
 
Last edited:
The name is a bit weird. I can't think of anything really better, but it just seems a bit weird to me. :p If not, I prefer JumpInPlace.xxx rather than JumpIP.xxx, might just be me. Something to consider though.

As for the system, did you try compiling it? This part:
JASS:
        static Table FlyTable = Table.create
        static Table EventTable = Table.create
I don't think it would work. You should set them on init instead. (also, you are missing the parentheses afterward: Table.create())
 
I've actually been using it and it seems to work... anyway, Maggy also suggested to change that part, I just forgot to do it... (btw it won't compile if I put a parenthesis in it)...

The only think I know of is that they might return the same table using the current set-up because when I tried doing them on the globals block they returned the same table... I'll change it now... :)

as for the name, hmmm... I'll try to think of a better name...
 
Bump.

Here's a suggestion:
You can add constants to this library so that users would have an easier time defining a Jump-type:

JASS:
globals
    constant integer JUMP_TYPE_STACK = 1
    constant integer JUMP_TYPE_HEIGHT_STACK = 2
    constant integer JUMP_TYPE_RESET = 3
    constant integer JUMP_TYPE_NO_OVERWRITE = 4
endglobals

Also, changing the struct name to JumpInPlace would be more appropriate because it makes more sense and is more intuitive, right? :/
 
Well, it doesn't really matter much unless a user is going to change the constants' values, but it still would be a bit better :p

--------
I wasn't really a fan of the "causeUnit" unit member of the struct, but then I realized it's like "UserData" thing. It's usefulness is debatable, but we have your Impale System, which justifies it :p

I'm also not a big fan of the fact that it's hardcoded to work for specific abilities :/

edit
Actually, nevermind, that's not a bad thing, people would just pass in the value 0 when they don't want this to be based on an ability :p
(Could you mention that in the documentation though?)
 
Oh yeah I forgot to mention that they can use 0 to make it untied to any ability... :)

hmm... Imma add a global stop jump event too like the others... and hmmm... maybe I should add a global onJumpStart event too? and maybe also for the other resources? what do you think? so that they can fire a global event when any jump starts...
 
@Zwieb: No one posted benchmarks proving T32 is worse than timer-per-struct.

It just isn't super popular anymore for a few reasons. Some don't like that the timer/counter isn't paused when there are no instances. Some prefer to use systems like CTL. Some don't like modules. Some don't like going on thehelper to find the thread. Some just don't like Jesus4Lyf. It is still fine to use though; and it is very fast*. :)

*In all realistic situations.
 
It just isn't super popular anymore for a few reasons. Some don't like that the timer/counter isn't paused when there are no instances. Some prefer to use systems like CTL. Some don't like modules. Some don't like going on thehelper to find the thread. Some just don't like Jesus4Lyf. It is still fine to use though; and it is very fast*. :)[/SIZE]
I think the main problem with all those timer systems and indexers is that there are way too many of them and that people can not decide for a standard.
If you want to collect different systems from hive, helper, etc in your map, you will once reach a point where you got 3 timer systems in your map. While this works fine in case of timer systems, it doesn't work with indexers (I am one of the few people that still use the old AIDS, because I like the ease-of-use PUI property syntax - in fact thats almost the only reason I use AIDS. I usually don't even use GetUnitIndex and instead do everything with a global hashtable because hashtables are awesome shit).

And even if people decide for a standard, you still need backwards compatibility, which means you must either replace old libraries or keep the old requirements intact. But sometimes there are discontinued libraries which makes it difficult, etc.

That's why all or most of my systems like my threat system or my destructable hider don't use modules or other libraries at all (except for stuff where it really makes sense). I simply don't like to import 3 new libraries with tons of code just for one little system/snippet to work, especially when I already got 3 other libraries that do the same.
 
I think the main problem with all those timer systems and indexers is that there are way too many of them and that people can not decide for a standard.
If you want to collect different systems from hive, helper, etc in your map, you will once reach a point where you got 3 timer systems in your map. While this works fine in case of timer systems, it doesn't work with indexers (I am one of the few people that still use the old AIDS, because I like the ease-of-use PUI property syntax - in fact thats almost the only reason I use AIDS. I usually don't even use GetUnitIndex and instead do everything with a global hashtable because hashtables are awesome shit).

And even if people decide for a standard, you still need backwards compatibility, which means you must either replace old libraries or keep the old requirements intact. But sometimes there are discontinued libraries which makes it difficult, etc.

That's why all or most of my systems like my threat system or my destructable hider don't use modules or other libraries at all (except for stuff where it really makes sense). I simply don't like to import 3 new libraries with tons of code just for one little system/snippet to work, especially when I already got 3 other libraries that do the same.

If you hadn't noticed, I did write virtually every system that you'd ever need. There are only a few left that are very useful that I haven't written.

1 - effects (support via Lua)
2 - projectiles (2D/3D)
3 - good command system
4 - good string parser
5 - MD5 (being written by Magtheridon96)

And there are a few that I have written but need updates
1 - timer tools
2 - file i/o
3 - data synchronization

now, obviously I can't rewrite every resource in existence to use the latest stuff : \. I've also pretty much been doing these mass writes solo >.<. I got help from 1 person 1 time, mag writing MD5, and that was only if I'd fix 2 systems and write 2 systems... so it's not like anyone's helping me out here, lol...

but anyways, it's really up the user in the end >.>. However, if they want to make high quality resources more quickly, they should use systems. Most of the time, the stuff they code themselves isn't going to be nearly as good as the systems that were already written.

edit
Actually I got help from Purge once too, he wrote the tutorial on Lua : ).

edit
anyways, back on topic, nobody really uses T32 on THW anymore. The resources I've seen use CTL. Nobody uses TimerTools right now since it's bugged, even though I really wanted to replace CTL with it D:. Even if I unbug TimerTools, CTL is just too damn popular : (.

there are really 3 sets of standards right now- wc3c, th, thw

considering thw is the only community that's still alive, you should probably adopt THW standards, unless that is you want to use legacy resources from wc3c/th : ).

Each site pretty much has its own unit indexer, its own unit event (th doesn't have unit event), its own set of timer tools, and so on ;o. Now I may sound biased here, but the standards at THW are the newest and also best performing, plus they typically have extremely good APIs. Compare UnitIndexer at THW to the AIDS UnitIndexer API-wise... AIDS uses textmacro with weird function names whereas UnitIndexer uses a module.

Each site pretty much has its own standard for documentation as well.

It really is up to you. If you really want to use legacy stuff, more power to you. After all, THW doesn't have its own effects lib atm ;o (stun, etc). TH also has a Buff lib, although I wouldn't recommend using it.

Effects were under way, starting with stun, but it was found that the code for each effect is virtually identical, so some good Lua code is needed in order to easily create new effects. Someone was writing this at one point, but they stopped. I was going to do this, but that person told me to leave it to them. If anyone's up for doing these effects, that'd be awesome, I can forward the design or w/e.

edit
Actually, I think that the very best policy is to adopt the standards for site that you're on : ), like using THW resources when submitting your own THW resources : P.
 
I appreciate your work, but sometimes you will want some resource that is older - and as the content of your map grows, you will get more and more requirements with overlapping functionality. This is what is bothering me. Establishing a new standard is worth nothing as long as the content you have still requires the old standard.

It's the same about the MIDI standard in music. Its goddamn outdated and antique. Still every new piece of music equipment uses MIDI. Because USB is not backwards compatible, but MIDI is upwards compatible.

You can always adapt new resources to be able to be used with old systems. But you can not (without additional effort or rewriting the system on your own) adapt old resources to use new systems.



To be honest, this doesn't effect me that much. I tend to write everything on my own and almost never found a real use for advanced data structure or management libraries.
My map is an RPG. Most of the more fancy stuff is not needed to create an engaging RPG in my oppinion.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Plus Nestharus is not a map maker, you can't be sure that all of these codes are working correctly, excepted maybe few ones which are currently used by some map makers.

Ofc you can say the same or even worse for my main resource UnitLL. I'm not a map maker neither.
In fact i only know one person which is using it, and it's not me ... It could have more but i have doubts about it.
In the last version i've added some simple tests though.

Anyway you don't need the most-up-to-date resources to realease a good and playable map, it's quite the opposite in fact. (assuming you've working on since a while)
 
Plus Nestharus is not a map maker, you can't be sure that all of these codes are working correctly, excepted maybe few ones which are currently used by some map makers.

Ofc you can say the same or even worse for my main resource UnitLL. I'm not a map maker neither.
In fact i only know one person which is using it, and it's not me ... It could have more but i have doubts about it.
In the last version i've added some simple tests though.

Anyway you don't need the most-up-to-date resources to realease a good and playable map, it's quite the opposite in fact. (assuming you've working on since a while)

I don't know about you, but I thoroughly test my resources now -.-. For example, if you look at my later stuff, rarely does it ever goes past .0.0.0. This means that whenever I have done a full rewrite (design changes) or new resource of late that it has had 0 bugs.
 
Top