Spell TimeWarp (with Videos)

Bribe

vJass errors are legion
Reaction score
67
Retro

spells_3355_screenshot.jpg

The coolest system on the market, Retro logs a unit's status for any amount of time, then restores them to the unit instant by instant. Stats include: x, y, z coordinates, optional facing, optional HP and optional MP. If you want more, ask, this system is very flexible and can easily handle new features..

Video is old and will be updated soon.

[YOUTUBE]_cqmRNwqj50[/YOUTUBE]

For the Auto-Index version and to read the manual on how to use this, click here.

Retro Library:

JASS:

library Retro requires Event, AIDS, Transport
//*******************************************
//    ___  ___  ___  ___  ___
//   /__/ /__   /   /__/ /  / 
//  /  | /__   /   /  \ /__/  
//                           Created by Bribe
//*******************************************
//  Specialized Version for TheHelper.net
//
/*  Requirements
 *  ¯¯¯¯¯¯¯¯¯¯¯¯
 *  Event by Jesus4Lyf ~ http://www.thehelper.net/forums/showthread.php?t=126846
 *  AIDS  by Jesus4Lyf ~ http://www.thehelper.net/forums/showthread.php?t=130752
 *  Transport by Jesus4Lyf ~ http://www.thehelper.net/forums/showthread.php?t=140727
 *  
 *  Description
 *  ¯¯¯¯¯¯¯¯¯¯¯
 *  Retro provides data retrieval and callback operators for use in simulating a time-travel effect for units.
 *  While there is no promise that this is an easy system to implement, I will try to label everything as easy
 *  to read and as simple as I can.  If you have any questions, please just ask.
 *
 *  To Know
 *  ¯¯¯¯¯¯¯
 *  On its own, the retro struct indexes every unit that passes through AutoEvents. It records a unit's data
 *  during each lapse of RETRO_TIMEOUT and saves it all in a three-dimensional hashtable. Simple array values
 *  record the current-moment's data aspects: x, y, z and, if you desire, facing angle, HP and MP.
 *  
 *  To allocate your own struct and have access to Retro's excellent callback features, the struct(s) you use
 *  must extend array and implement the module named RETRO. This module uses allocate and deallocate as method
 *  names to regulate those events.  You are welcome to call allocate/deallocate freely as they have built-in
 *  foolproofs. <deallocate> is also automatically called when a unit is loaded into a transport or dies.
 *
 *  You can only instanciate for a given unit once per struct-type.  You can create numerous structs which all
 *  implement the RETRO module.
 *
 *  Events
 *  ¯¯¯¯¯¯
    method onLoop           -> called during each iteration of RETRO_TIMEOUT.
    method onLoopForward    -> called for only one struct per iteration, if it's in forward-mode.
    method onLoopReverse    -> called for only one struct per iteration, if it's in reverse-mode.
  
    method onStart  ->  if you specify a "capture" real value, this will be called after that time has expired.
    method onFinish ->  is called by the deallocate method. deallocate is called automatically if you specify a
                        real value for "capture" or "initiate". It's basically your "onDestroy" method.
 *
 *  Syntax Example
 *  ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    struct timeStruct extends array
    
        method onFinish takes nothing returns nothing
            call BJDebugMsg(GetUnitName(.subject)+"'s stats:\n")
            call BJDebugMsg("X-coordinate is "+R2S(.x))
            call BJDebugMsg("Y-coordinate is "+R2S(.y))
            call BJDebugMsg("Z-coordinate is "+R2S(.z))
            call BJDebugMsg("facing is "+R2S(.ang))
            call BJDebugMsg("hit points are "+R2S(.hp))
            call BJDebugMsg("mana points are "+R2S(.mp)+"\n")
        endmethod
    
        implement RETRO
        
        static method create takes unit newSubject returns thistype
            local thistype this = thistype.allocate(newSubject, true, false) 
            return this
        endmethod
        
        static method onInit takes nothing returns nothing
            local thistype this = thistype.create(newSubject)
            call this.initiate(0.03)
        endmethod
        
    endstruct
 *
 *
 */
    
    globals
        // Values are in seconds;
        constant    real        RETRO_TIMEOUT       = 0.03125   /* This value is a tribute to Jesus4Lyf's helpful Timer32 */
        constant    real        RETRO_MEMORY_MAX    = 20.0      /* The hashtable will deallocate data past this threshold */
        private constant real   DECAY_TIME          = 90.0      /* The amount of time it takes for a corpse to disappear */
        private constant real   HERO_REVIVE_TIME    = 500.0     /* The maximum amount of time it takes a hero to revive */
        
        // Static-if controllers;
        private     constant    boolean     BREAKS_CHANNEL      = true      /* <true> uses SetUnitPosition for smoother motion */
        private     constant    boolean     RECORD_FACING       = true      /* If you're an efficiency-freak and don't care, set to false */
        private     constant    boolean     RECORD_HP           = true      /* Can save the health-points of units */
        private     constant    boolean     RECORD_MP           = false     /* Can save the mana-points of units */
    endglobals
    
    private module Validate
        static method create takes unit whichSubject returns retro
        
            if GetUnitDefaultMoveSpeed(whichSubject) == 0.00 or GetUnitAbilityLevel(whichSubject, 'Aloc') > 0 or IsUnitType(whichSubject, UNIT_TYPE_STRUCTURE) then
                return 0
            else
                return GetUnitId(whichSubject)
            endif
            
        endmethod   // Anything that returns 0 will under no condition be added to the system.
    endmodule
    
    globals
        private     hashtable   retro_memory    = InitHashtable()  /* Serves as a three-dimensional array */
        private     trigger     retro_launch    = CreateTrigger()  /* So this system only needs one timer */
        private     trigger     retro_expire    = CreateTrigger()  /* RETRO uses 5 fewer handles this way */
        constant    integer     RETRO_ERASER    = R2I(RETRO_MEMORY_MAX/RETRO_TIMEOUT)
        private     keyword     RetroInitializer
    endglobals
    
    native UnitAlive takes unit id returns boolean
    
    struct retro extends array
        
        private retro prev
        private retro next
        
        readonly unit subject
        readonly integer save
        readonly boolean active
        
        real x
        real y
        real z
        
        static if RECORD_FACING then    // Static ifs for maximum efficiency.
            real ang
        endif
        static if RECORD_HP then
            real hp
        endif
        static if RECORD_MP then
            real mp
        endif
        
        implement Validate
        
        method destroy takes nothing returns nothing
            debug call BJDebugMsg("Error: You cannot manually destroy a retro struct.")
        endmethod
        
        private static integer tick = 0
        
        private static method handler takes nothing returns nothing
            local retro this = retro(0).next
            set retro.tick = retro.tick + 1
            if (retro.tick == 4) then
                set retro.tick = 0
                loop
                    exitwhen this == 0
                    set .save = .save + 1
                    
                    set .x = GetUnitX(.subject)
                    set .y = GetUnitY(.subject)
                    set .z = GetUnitFlyHeight(.subject)
                    call SaveReal(retro_memory, this * 6 + 0, .save, .x)
                    call SaveReal(retro_memory, this * 6 + 1, .save, .y)
                    call SaveReal(retro_memory, this * 6 + 2, .save, .z)
                    
                    static if RECORD_FACING then
                        set .ang = GetUnitFacing(.subject)
                        call SaveReal(retro_memory, this * 6 + 3, .save, .ang)
                    endif
                    static if RECORD_HP then
                        set .hp = GetWidgetLife(.subject)
                        call SaveReal(retro_memory, this * 6 + 4, .save, .hp)
                    endif
                    static if RECORD_MP then
                        set .mp = GetUnitState(.subject, UNIT_STATE_MANA)
                        call SaveReal(retro_memory, this * 6 + 5, .save, .mp)
                    endif
                    
                    if (.save >= RETRO_ERASER) then
                        call RemoveSavedReal(retro_memory, this * 6 + 0, .save - RETRO_ERASER)
                        call RemoveSavedReal(retro_memory, this * 6 + 1, .save - RETRO_ERASER)
                        call RemoveSavedReal(retro_memory, this * 6 + 2, .save - RETRO_ERASER)
                        static if RECORD_FACING then
                            call RemoveSavedReal(retro_memory, this * 6 + 3, .save - RETRO_ERASER)
                        endif
                        static if RECORD_HP then
                            call RemoveSavedReal(retro_memory, this * 6 + 4, .save - RETRO_ERASER)
                        endif
                        static if RECORD_MP then
                            call RemoveSavedReal(retro_memory, this * 6 + 5, .save - RETRO_ERASER)
                        endif
                    endif
                    set this = .next
                endloop
            endif
            
            // Fire things;
            call TriggerEvaluate(retro_launch)
        endmethod
        
        static retro removing
        
        private method remove takes nothing returns nothing
            if (.active) then
            
                set .active    = false
                set .prev.next = .next
                set .next.prev = .prev
                
                call FlushChildHashtable(retro_memory, this * 6 + 0)
                call FlushChildHashtable(retro_memory, this * 6 + 1)
                call FlushChildHashtable(retro_memory, this * 6 + 2)
                static if RECORD_FACING then
                    call FlushChildHashtable(retro_memory, this * 6 + 3)
                endif
                static if RECORD_HP then
                    call FlushChildHashtable(retro_memory, this * 6 + 4)
                endif
                static if RECORD_MP then
                    call FlushChildHashtable(retro_memory, this * 6 + 5)
                endif
                
                // Fire things;
                set retro.removing = this
                call TriggerEvaluate(retro_expire)
                
                set .subject = null
            endif
        endmethod
        
        private static method add takes unit newSubject returns retro
            local retro this = retro.create(newSubject)
            if this != 0 and not .active then
            
                set .active = true
                set .subject = newSubject
                set .save = 0
                
                set retro(0).next.prev = this
                set this.next = retro(0).next
                set retro(0).next = this
                set this.prev = retro(0)
                
                return this
            endif
            return 0
        endmethod
        
        private trigger deathEvent
        
        private static method addRessurrect takes nothing returns nothing   // Coming back to life -> allocate
            local unit u = GetTriggerUnit()
            local real decay = DECAY_TIME + 10.0
            if IsUnitType(u, UNIT_TYPE_HERO) then
                set decay = HERO_REVIVE_TIME + 100.0
            endif
            loop
                call TriggerSleepAction(0.25)
                if UnitAlive(u) then
                    call retro.add(u)
                    exitwhen true
                endif
                set decay = decay - 0.25
                exitwhen decay <= 0.00
                exitwhen u == null
            endloop
            set u = null
        endmethod
        private static method removeOnDeath takes nothing returns boolean   // Death -> deallocate
            local retro this = retro.create(GetTriggerUnit()) 
            if this > 0 then
                call .remove()
                call ExecuteFunc(addRessurrect.name)
            endif
            return false
        endmethod
        
        private static method addInitial takes nothing returns boolean      // Exists -> allocate
            local retro this = retro.add(AIDS_GetEnteringIndexUnit())
            if this > 0 and .deathEvent == null then
                set .deathEvent = CreateTrigger()
                call TriggerAddCondition(.deathEvent, Filter(function retro.removeOnDeath))
                call TriggerRegisterUnitStateEvent(.deathEvent, .subject, UNIT_STATE_LIFE, LESS_THAN, 0.405)
            endif
            return false
        endmethod
        private static method removeFinal takes nothing returns boolean     // Removal -> deallocate
            local retro this = retro(AIDS_GetDecayingIndex)
            if this > 0 then
                call DestroyTrigger(.deathEvent)
                set .deathEvent = null
                call .remove()
            endif
            return false
        endmethod
        
        private static method addOnUnload takes nothing returns boolean     // Exit transport -> allocate
            call retro.add(GetUnloadedUnit())
            return false
        endmethod
        private static method removeOnLoad takes nothing returns boolean    // Enter transport -> deallocate
            call retro.create(GetTriggerUnit()).remove()                    // Reason: movement was interrupted
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local trigger t
            
            call TimerStart(CreateTimer(), RETRO_TIMEOUT, true, function retro.handler)
            
            call AIDS_RegisterOnEnter(Filter(function retro.addInitial))        // AIDS Filter
            call AIDS_RegisterOnDeallocate(Filter(function retro.removeFinal))  // AIDS Filter
            
            set t = CreateTrigger()
            call TriggerAddCondition(t, Filter(function retro.addOnUnload))     // Transport Event
            call Transport_RegisterUnloadEvent(t)
            
            set t = CreateTrigger()
            call TriggerAddCondition(t, Filter(function retro.removeOnLoad))    // Transport Event
            call Transport_RegisterLoadEvent(t)
        endmethod
        
    endstruct
    
    module RETRO    /* May only be implemented in <extends array> structs */
        
        boolean noLoops     /* To toggle a method on/off that gets called <every single> loop */
        boolean noExtras    /* To toggle the extra methods on/off (called for one instance per loop) */
        
        private thistype prev
        private thistype next
      
        private boolean active
        private boolean reverse
        private boolean captured
        
        private real timeLeft
        private real timePend
        private integer iSave
        
        static if RECORD_FACING then
            method operator ang takes nothing returns real  // Delegate ang from retro
                return retro(this).ang
            endmethod
            method operator ang= takes real r returns nothing
                set retro(this).ang = r
            endmethod
        endif
        static if RECORD_HP then
        
            boolean restoreGoodHP
            boolean restoreBadHP
            boolean restoreAnyHP
            
            method operator hp takes nothing returns real   // Delegate hp from retro
                return retro(this).hp
            endmethod
            method operator hp= takes real r returns nothing
                set retro(this).hp = r
            endmethod
            
        endif
        static if RECORD_MP then
        
            boolean restoreGoodMP
            boolean restoreBadMP
            boolean restoreAnyMP
            
            method operator mp takes nothing returns real   // Delegate mp from retro
                return retro(this).mp
            endmethod
            method operator mp= takes real r returns nothing
                set retro(this).mp = r
            endmethod
            
        endif
        
        method operator x takes nothing returns real        // Delegate x
            return retro(this).x
        endmethod
        method operator x= takes real r returns nothing
            set retro(this).x = r
        endmethod
            
        method operator y takes nothing returns real        // Delegate y
            return retro(this).y
        endmethod
        method operator y= takes real r returns nothing
            set retro(this).y = r
        endmethod
            
        method operator z takes nothing returns real        // Delegate z
            return retro(this).z
        endmethod
        method operator z= takes real r returns nothing
            set retro(this).z = r
        endmethod
            
        method operator subject takes nothing returns unit  // Readonly subject
            return retro(this).subject
        endmethod
        
        method deallocate takes nothing returns nothing
            if .active then
                set .active = false
                set .reverse = false
                set .captured = false
                set .prev.next = .next
                set .next.prev = .prev
                static if BREAKS_CHANNEL then
                    call SetUnitPathing(.subject, true)
                endif
                static if thistype.onFinish.exists then
                    call .onFinish()
                endif
            endif
        endmethod
        
        method initiate takes real duration returns nothing
            set .iSave = retro(this).save
            set .timeLeft = .timeLeft + duration
            set .reverse = true
            static if BREAKS_CHANNEL then
                call SetUnitPathing(.subject, false)
            endif
        endmethod   /* <duration> is the time the unit will be in reverse */
        
        method capture takes real duration returns nothing
            set .timeLeft = .timeLeft + duration
            set .captured = true
            if .reverse then
                set .reverse = false
                static if BREAKS_CHANNEL then
                    call SetUnitPathing(.subject, true)
                endif
            endif
        endmethod   /* <duration> is the time the unit will be in forward. Reverse is 1/4 of that */
        
        method collapse takes nothing returns nothing
            if not .reverse and .captured then
                set .timeLeft = (.timePend / 4)
                set .iSave = retro(this).save
                set .timePend = 0.00
                set .captured = false
                set .reverse = true
                static if thistype.onStart.exists then
                    call .onStart()
                endif
                static if BREAKS_CHANNEL then
                    call SetUnitPathing(.subject, false)
                endif
            endif
        endmethod
        
        private static method handler takes nothing returns boolean
            local thistype array choices
            local thistype this = thistype(0).next
            local thistype rand = 0
            local real r
            loop
                exitwhen (this == 0)
                
                if .reverse then
                    
                    set .x = LoadReal(retro_memory, this * 6 + 0, .iSave)
                    set .y = LoadReal(retro_memory, this * 6 + 1, .iSave)
                    set .z = LoadReal(retro_memory, this * 6 + 2, .iSave)
                    
                    static if BREAKS_CHANNEL then
                        call SetUnitPosition(.subject, .x, .y)
                    else
                        call SetUnitX(.subject, .x)
                        call SetUnitY(.subject, .y)
                    endif
                    call SetUnitFlyHeight(.subject, .z, 0.00)
                    
                    static if RECORD_FACING then
                        set .ang = LoadReal(retro_memory, this * 6 + 3, .iSave)
                        call SetUnitFacing(.subject, .ang)
                    endif
                    static if RECORD_HP then   
                        set r = GetWidgetLife(.subject)
                        set .hp = LoadReal(retro_memory, this * 6 + 4, .iSave)
                        if .restoreAnyHP or (.restoreGoodHP and r < .hp - 1) or (.restoreBadHP and r > .hp + 1) then
                            call SetWidgetLife(.subject, .hp)
                        endif
                    endif
                    static if RECORD_MP then
                        set r = GetUnitState(.subject, UNIT_STATE_MANA)
                        set .mp = LoadReal(retro_memory, this * 6 + 5, .iSave)
                        if .restoreAnyMP or (.restoreGoodMP and r < .mp + 1) or (.restoreBadMP and r > .mp + 1) then
                            call SetUnitState(.subject, UNIT_STATE_MANA, .mp)
                        endif
                    endif
                    
                    set .iSave = .iSave - 1
                    set .timeLeft = .timeLeft - RETRO_TIMEOUT
                    if (.timeLeft <= 0.00 or .iSave <= 0) then
                        call .deallocate()
                    endif
                    
                elseif .captured then
                    set .timePend = .timePend + RETRO_TIMEOUT
                    if (.timePend >= .timeLeft) then
                        call .collapse()
                    endif
                endif
                
                static if thistype.onLoop.exists then
                    if not .noLoops then
                        call .onLoop()
                    endif
                endif
                if not .noExtras then
                    set rand:choices = this
                    set rand = rand + 1
                endif
                set this = .next
            endloop
            
            if (rand > 0) then
                set rand = choices[GetRandomInt(0, rand - 1)]
                if rand.reverse then
                    static if thistype.onLoopReverse.exists then
                        call rand.onLoopReverse()
                    endif
                else
                    static if thistype.onLoopForward.exists then
                        call rand.onLoopForward()
                    endif
                endif
            endif
            
            return false
        endmethod
        
        static method allocate takes unit theSubject, boolean wantLoop, boolean wantLoopEx returns thistype
            local thistype this = retro.create(theSubject)
            
            if this == 0 or retro(this).save == 0 then
                return 0
            elseif .active then
                call .deallocate()
            endif
            
            set .active   = true
            set .noLoops  = not wantLoop
            set .noExtras = not wantLoopEx
            set .timeLeft = 0.00
            set .timePend = 0.00
            
            static if RECORD_HP then
                set .restoreGoodHP = false
                set .restoreBadHP = false
                set .restoreAnyHP = false
            endif
            static if RECORD_MP then
                set .restoreGoodMP = false
                set .restoreBadMP = false
                set .restoreAnyMP = false
            endif
            
            set thistype(0).next.prev = this
            set this.next = thistype(0).next
            set thistype(0).next = this
            set this.prev = thistype(0)
            
            return this
        endmethod
        
        private static method onRemoval takes nothing returns boolean
            if thistype(retro.removing).active then
                call thistype(retro.removing).deallocate()
            endif
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            call TriggerAddCondition(retro_launch, Condition(function thistype.handler))    // Enables the handler event
            call TriggerAddCondition(retro_expire, Condition(function thistype.onRemoval))  // Enables the onRemoval event
        endmethod
        
    endmodule
    
    module RetroTimerModule
        private static method onInit takes nothing returns nothing
            call TriggerAddCondition(retro_launch, Condition(function thistype.handler))    // Basically for RetroFade
        endmethod
    endmodule
    
endlibrary


Example:

JASS:

library RetroExample requires Retro
    
    private struct example extends array
    // Retro structs must <extend array>
        
    
        effect attach   // This effect gets attached to the unit for the duration of the spell.
        
        method onFinish takes nothing returns nothing
            call DestroyEffect(.attach)
        endmethod   // <onFinish> is the <onDestroy> method. You don't need to call <deallocate> from it.
        
    /*
     *  <onLoopReverse> or <onLoopForward> methods are called only once per cycle of RETRO_TIMEOUT,
     *  so they help to moderate high numbers of special effects to keep the frames-per-second low.
     */ 
        method onLoopReverse takes nothing returns nothing
            call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Other\\StrongDrink\\BrewmasterMissile.mdl", .x, .y))
            call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Other\\Transmute\\GoldBottleMissile.mdl", .x, .y))
        endmethod
        
        
        implement RETRO // The module is below <onFinish> and <onLoopReverse> while above <allocate>
        
        
        static method Selection takes nothing returns boolean
            local thistype this
            
            // <allocate> and <deallocate> are provided by the RETRO module.
            set this = allocate(GetFilterUnit(), false, true)
            
            // <allocate> will return <0> if a unit is invalid; I advise checking that before any continuation;
            if this > 0 and GetHeroProperName(.subject) != "Master of Time" then
            
            /*
             *  <initiate> immediately launches a unit back through time for the
             *  specified duration.  This won't do anything for units created in
             *  the same instant; they haven't had time to record some movement.
             */ 
                call .initiate(2.00)
             
                // The unit you're manipulating is referenced as <.subject>
                set .attach = AddSpecialEffectTarget("Abilities\\Spells\\Other\\Drain\\ManaDrainTarget.mdl", .subject, "overhead")
                
                // <.restoreGoodHP> will revive the unit if its former HP was greater.
                set .restoreGoodHP = true
                
            /*
             *  <.restoreGoodMP> will do the same, but for MP. Un-commenting the line will provide a syntax
             *  error, as I have the Retro constant boolean RECORD_MP set to <false>, preventing the variable
             *  from even being compiled.
             */
                //set .restoreGoodMP = true
                
                call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl", .subject, "origin"))
            endif
            return false
        endmethod
        
        
        static method onInit takes nothing returns nothing
            local integer i = 0
            local trigger t = CreateTrigger()
            loop
                call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SELECTED, Filter(function thistype.Selection))
                exitwhen i == 11
                set i = i + 1
            endloop
        endmethod   // A normal initialization method.
        
        /*
         *  Note the <onLoop>, <onLoopForward> and <onStart> methods are nowhere in sight. They are optional,
         *  and so are <onLoopReverse> and <onFinish>
         *  
         *  Final Notes
         *  ¯¯¯¯¯¯¯¯¯¯¯
         *  ~ You should only implement an event-method if you have a use for it.
         *  ~ You don't have to call <destroy> on a RETRO-implemented struct unless you wish to call your onFinish method.
         */
         
    endstruct
    
endlibrary


Retro-Fade:
JASS:

//! zinc

library RetroFade {
/*
 *  The current fade-functionality is very primitive at the moment.  If you have dynamic fog in your
 *  map that changes sometimes, I don't recommend this library for you.
 */
    constant real
    
        DURATION                = 2.00      ,
        MAX_DISTANCE            = 1000.0    ,   /* Players whose cameras are out of this range will not see the fog fade */
        FLICKER_MAGNITUDE       = 300.0     ;   /* Factors between Z-End + this & Z-End - this */
        
    constant boolean
    
        FLICKER                 = true      ;
    
    real fog[];
    integer units[];
    boolean paused = true, want = false, to = true;
    constant integer Fz = 18, FZ = 19, Fd = 20, Fr = 21, Fg = 22, Fb = 23;
    
    function onInit() {
        integer i;  /*    Your fog settings     Retro's fog settings
    Fog type                     |                       |                   Allowed values
    ¯¯¯¯¯¯¯¯                     V                       V                   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    |  Z-Start */    fog[0]  = 3000.00   ;     fog[6]  = 1250.0    ; /*      0.00  to  ????
    ---------------------------------------------------------------------------------------
    |    Z-End */    fog[1]  = 5000.00   ;     fog[7]  = 3250.00   ; /*      0.00  to  ????
    ---------------------------------------------------------------------------------------
    |  Density */    fog[2]  = 0.50      ;     fog[8]  = 0.1       ; /*      0.00  to  1.00
    ---------------------------------------------------------------------------------------
    |      Red */    fog[3]  = 1.00      ;     fog[9]  = 0.35      ; /*      0.00  to  1.00
    ---------------------------------------------------------------------------------------
    |    Green */    fog[4]  = 1.00      ;     fog[10] = 0.35      ; /*      0.00  to  1.00
    ---------------------------------------------------------------------------------------
    |     Blue */    fog[5]  = 1.00      ;     fog[11] = 0.00      ; /*      0.00  to  1.00
    ---------------------------------------------------------------------------------------
 */
        for (i = 0; i < 24; i+= 1)  i:units = 0;
        for (i = 0; i < 6;  i+= 1) {
        
            if (i:fog==fog[i + 6]) {
                if (i:fog < 0.999)  i:fog+= 0.001;
                else                i:fog-= 0.001;
            }
            
            fog[i + 12] = (i:fog - fog[i + 6])/(DURATION / RETRO_TIMEOUT);
            fog[i + 18] =  i:fog;
        }
    }
        
    public struct retrofade [] {
    
        private static method handler()-> boolean {
            integer i = 18;
            
            if (!want && paused)
                return false;
         
            static if (FLICKER) {
                if (GetRandomReal(0.0, 2.0)<=RETRO_TIMEOUT)
                    SetTerrainFogEx(0, Fz:fog, GetRandomReal(FZ:fog - FLICKER_MAGNITUDE, FZ:fog + FLICKER_MAGNITUDE), Fd:fog, Fr:fog, Fg:fog, Fb:fog);
            }
            
            if (paused)
                return false;
            
            if (to) while (i < 24) { /* Fade into retro-fog */
            
                if   ( i:fog <= fog[i - 12]) {
                       i:fog  = fog[i - 12];        paused = true;  break;
                } else i:fog -= fog[i -  6];                        i+= 1;
            }
            else while (i < 24) { /* Fade into normal-fog */
            
                if   ( i:fog >= fog[i - 18]) {
                       i:fog  = fog[i - 18];        paused = true;  break;
                } else i:fog += fog[i -  6];                        i+= 1;
            }
            
            SetTerrainFogEx (0, Fz:fog, FZ:fog, Fd:fog, Fr:fog, Fg:fog, Fb:fog);
            
            return false;
        }
    
        module RetroTimerModule;
        
        static method CamCheck (real centerX, real centerY) -> boolean {
         real   cam_x= GetCameraTargetPositionX(), cam_y= GetCameraTargetPositionY();
         return(cam_x >= centerX - MAX_DISTANCE && cam_y >= centerY - MAX_DISTANCE &&
                cam_x <= centerX + MAX_DISTANCE && cam_y <= centerY + MAX_DISTANCE );
        }
        
        static method yes (player whichPlayer, real x, real y) {
            integer id = GetPlayerId(whichPlayer);
            if (GetLocalPlayer() != whichPlayer || whichPlayer == null || id > 11)
                return;
                
            if (CamCheck(x, y)) {
                to = true;
                want = true;
                if (paused)
                    paused = false;
            }
            
            units[id]+= 1;
        }
        
        static method no (player whichPlayer) {
            integer id = GetPlayerId(whichPlayer);
            if (GetLocalPlayer() != whichPlayer || whichPlayer==null || id > 11) 
                return;
                
            units[id]-= 1;
            if (units[id] <= 0) { 
                units[id] = 0;
                to = false;
                want = false;
                if (paused)
                    paused = false;
            }
        }
        
    }
}
//! endzinc


Time-Warp:
JASS:

library TimeWarp requires Retro, Projectile, optional Knockback, optional RetroFade, optional Recycle, optional GroupUtils
//************************************************************************************************************************
//   ___ ___ _   _  ___   _    _  _   ___  ___
//   /   /   /| /  /__    |   / /__/ /__/ /__/
//  /  _/_  / |/| /__     |/|/ /  / /  | /
//                                            Created by Bribe
//************************************************************
/*
 *  Requirements
 *  ¯¯¯¯¯¯¯¯¯¯¯¯
 *  Projectile by Berb ~ <a href="http://www.hiveworkshop.com/forums/jass-functions-413/custom-projectiles-162121/" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.hiveworkshop.com/forums/jass-functions-413/custom-projectiles-162121/</a>
 *  Vector by Anitarf  ~ <a href="http://www.wc3c.net/showthread.php?t=87027" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.wc3c.net/showthread.php?t=87027</a>
 *  Retro (provided)
 *  
 *  Optional Requirements
 *  ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 *  Knockback Lite by Berb    ~ <a href="http://www.hiveworkshop.com/forums/jass-functions-413/knock-back-lite-161831/" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.hiveworkshop.com/forums/jass-functions-413/knock-back-lite-161831/</a>
 *  GroupUtils by Rising_Dusk ~ <a href="http://www.wc3c.net/showthread.php?t=104464" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.wc3c.net/showthread.php?t=104464</a>
 *  Recycle by Nestharus      ~ <a href="http://www.thehelper.net/forums/showthread.php?t=136087" class="link link--internal">http://www.thehelper.net/forums/showthread.php?t=136087</a>
 *  RetroFade (provided)
 *  
 */
    globals
        private constant integer    SPELL_ID    = &#039;A003&#039;    /* The rawcode for the Time Travel spell */
        private constant integer    EXTRA_ID    = &#039;A001&#039;    /* An ability that collapses the caster&#039;s portals */
        private constant integer    DUMMY_ID    = &#039;n000&#039;    /* This should use the DUMMY.mdx model from XE */
    
//* &gt;&gt; Knockback Values;
        private constant real   KB_DURATION         = 1.125     /* Duration is in seconds */
        private constant real   KB_MIN_DISTANCE     = 225.0     /* Value in WC3 gridspace */
        private constant real   KB_MAX_DISTANCE     = 525.0
                                
//* &gt;&gt; TimeWarp Values;         
        private constant real   BASE_DURATION       = 3.00      /* Base value at level 1 */
        private constant real   LVL_INC_DURATION    = 1.15      /* Level increment value */
                                
        private constant real   BASE_DAMAGE         = 10.0
        private constant real   LVL_INC_DAMAGE      = 4.00
                                
        private constant real   BASE_AOE            = 150.0
        private constant real   LVL_INC_AOE         = 40.0
        
        private   group array   casterGroup
    /*
     *  If you have the xebasic library in your map, remove these two lines so they won&#039;t conflict:
     */ constant integer    XE_DUMMY_UNITID         = DUMMY_ID
        constant real       XE_MAX_COLLISION_SIZE   = 60.00
    endglobals

    static if LIBRARY_RetroFade then
        globals
            private sound callback = CreateMIDISound(&quot;FlashBack1Second&quot;, 12700, 12700)
        endglobals
    endif
    
    static if LIBRARY_Knockback then
        struct retroKB extends knockback
        
            effect attach
            static constant string fx = &quot;Abilities\\Spells\\Orc\\AncestralSpirit\\AncestralSpiritCaster.mdl&quot;
            
            private method onDestroy takes nothing returns nothing
                call DestroyEffect(this.attach)
            endmethod
            
            private static method onInit takes nothing returns nothing
                call Preload(fx)
            endmethod
            
        endstruct
    endif
    
    struct retroproj extends projectile
        
        static constant string launchSkin = &quot;Abilities\\Spells\\Undead\\Possession\\PossessionMissile.mdl&quot;
        static constant string attackSkin = &quot;Abilities\\Spells\\Undead\\DarkSummoning\\DarkSummonMissile.mdl&quot;
        static constant string simpleSkin = &quot;Abilities\\Spells\\NightElf\\Barkskin\\BarkSkinTarget.mdl&quot;
        
        static constant string simpImpact = &quot;Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl&quot;
        static constant string painImpact = &quot;Abilities\\Spells\\Demon\\DemonBoltImpact\\DemonBoltImpact.mdl&quot;
        
        private static method onInit takes nothing returns nothing
            call Preload(launchSkin)
            call Preload(attackSkin)
            call Preload(simpleSkin)
            call Preload(simpImpact)
            call Preload(painImpact)
        endmethod
        
        effect      skin
        group       units
        
        boolean     primary = true
        
        real        damage
        real        Time
        
        vector      carryVec
        timewarp    carryWarp
        
        private method onFinish takes nothing returns nothing
            call DestroyEffect(.skin)
            call SetUnitExploded(.toUnit, true)
            if .primary then
                if UnitAlive(.target) then
                    call timewarp.Initiate(this)
                endif
                call .carryVec.destroy()
            else
                set .carryWarp.go = true
                if UnitAlive(.target) and not .carryWarp.to then
                    call DestroyEffect(AddSpecialEffectTarget(painImpact, .target, &quot;overhead&quot;))
                    call UnitDamageTarget(.carryWarp.caster, .target, .carryWarp.damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
                elseif UnitAlive(.source) then
                    call DestroyEffect(AddSpecialEffectTarget(simpImpact, .source, &quot;origin&quot;))
                endif
            endif
        endmethod
        
    endstruct
    
    struct timewarp extends array
        
        unit        caster
        unit        oriUnit
        group       units
        
        player      casterOwner
        player      victimOwner
        
        effect      attach
        effect      gloomy
        effect      spooky
        
        boolean     go
        boolean     to
        vector      oriVec
        real        damage
        
        static constant string finalFX      = &quot;Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageDeathCaster.mdl&quot;
        static constant string callbackFX1  = &quot;Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl&quot;
        static constant string callbackFX2  = &quot;Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl&quot;
        
        static constant string forwardLoopFX  = &quot;Abilities\\Weapons\\FlyingMachine\\FlyingMachineImpact.mdl&quot;
        static constant string reverseLoopFX1 = &quot;Abilities\\Spells\\Other\\Transmute\\GoldBottleMissile.mdl&quot;
        static constant string reverseLoopFX2 = &quot;Abilities\\Spells\\Other\\StrongDrink\\BrewmasterMissile.mdl&quot;
        
        static constant string caughtFX = &quot;Abilities\\Spells\\Items\\AIso\\AIsoTarget.mdl&quot;
        static constant string gloomyFX = &quot;Abilities\\Spells\\Human\\Banish\\BanishTarget.mdl&quot;
        static constant string spookyFX = &quot;Abilities\\Spells\\NightElf\\shadowstrike\\shadowstrike.mdl&quot;
        static constant string attachFX = &quot;Abilities\\Spells\\Undead\\Possession\\PossessionTarget.mdl&quot;
        
        static constant string epicenterFX  = &quot;Objects\\Spawnmodels\\Undead\\UCancelDeath\\UCancelDeath.mdl&quot;
        static constant string recallFXCast = &quot;Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl&quot;
        static constant string recallFXTarg = &quot;Abilities\\Spells\\Human\\MarkOfChaos\\MarkOfChaosTarget.mdl&quot;
        
        private static method PreloadStrings takes nothing returns nothing
            call Preload(finalFX)
            call Preload(callbackFX1)
            call Preload(callbackFX2)
            call Preload(forwardLoopFX)
            call Preload(reverseLoopFX1)
            call Preload(reverseLoopFX2)
            call Preload(caughtFX)
            call Preload(gloomyFX)
            call Preload(spookyFX)
            call Preload(attachFX)
            call Preload(epicenterFX)
            call Preload(recallFXCast)
            call Preload(recallFXTarg)
        endmethod
        
        private method onFinish takes nothing returns nothing
            call DestroyEffect(AddSpecialEffect(finalFX, .x, .y))
            call DestroyEffect(.spooky)
            call DestroyEffect(.gloomy)
            call DestroyEffect(.attach)
            call ExplodeUnitBJ(.oriUnit)
            call GroupRemoveUnit(.units, .subject)
            call SetUnitTimeScale(.subject, 1.00)
            
            if .oriVec &gt; 0 then
                call .oriVec.destroy()
                set .oriVec = 0
            endif
            static if LIBRARY_RetroFade then
                call retrofade.no(.casterOwner)
                call retrofade.no(.victimOwner)
            endif
            
        endmethod
        
        private method onStart takes nothing returns nothing
            call DestroyEffect(AddSpecialEffectTarget(callbackFX1, .subject, &quot;origin&quot;))
            call DestroyEffect(AddSpecialEffectTarget(callbackFX2, .subject, &quot;origin&quot;))
            call SetUnitTimeScale(.subject, 4.00)
            
            set .restoreBadHP = true
            //set .restoreBadMP = true  &lt;- would throw a syntax error because I have RESTORE_MP set to &lt;false&gt;
            
            static if LIBRARY_RetroFade then
                if retrofade.CamCheck(.x, .y) then  // Only plays the sound if a player&#039;s camera is near.
                    call StartSound(callback)
                endif
            endif
            
        endmethod
        
        private method onLoopForward takes nothing returns nothing
            call DestroyEffect(AddSpecialEffectTarget(forwardLoopFX, .subject, &quot;overhead&quot;))
        endmethod
        private method onLoopReverse takes nothing returns nothing
            call DestroyEffect(AddSpecialEffectTarget(reverseLoopFX1, .subject, &quot;origin&quot;))
            call DestroyEffect(AddSpecialEffectTarget(reverseLoopFX2, .subject, &quot;origin&quot;))
        endmethod
        
        
        static vector regVec    // This gets &lt;vector.create&gt; during map init.
        
        static method operator bigVec takes nothing returns vector
            return 8191
        endmethod
        
        
        private method onLoop takes nothing returns nothing
            local real x2
            local real y2
            local retroproj pro
            // Will not launch until the other missile has expired.
            // Check the origin vector to make sure it&#039;s not a dud.
            if .go and .oriVec!=0 then
                /* Check if the distance is far enough */
                set x2 = .x - .oriVec.x
                set y2 = .y - .oriVec.y
                if ((x2*x2 + y2*y2) &gt; 0xF000) then
                    /* Yet another important check */
                    if UnitAlive(.subject) and UnitAlive(.oriUnit) then
                        /* bigVec = Location(.x, .y) */
                        call bigVec.getTerrainPoint(.x, .y)
                        /* Add flyheight and offset to vector.Z */
                        set  bigVec.z = bigVec.z + this.z + 90.0
                        if .to then
                            /* If flying toward the subject unit */
                            set .to = false
                            set pro = retroproj.create(CreateUnit(Player(15), DUMMY_ID, .oriVec.x, .oriVec.y, bj_RADTODEG * Atan2(.y - .oriVec.y, .x - .oriVec.x)))
                            set pro.target = .subject
                            /* Control the missile-art of the projectile */
                            set pro.skin = AddSpecialEffectTarget(retroproj.attackSkin, pro.toUnit, &quot;origin&quot;)
                            /* Control the dimensions and launch-properties of the projectile */
                            call SetUnitScale(pro.toUnit, 0.65, 0.65, 0.65)
                            call pro.doLaunch(.oriVec, bigVec, 900.0, 0.10)
                        else
                            /* If gliding towards the origin point */
                            set .to = true
                            set pro = retroproj.create(CreateUnit(Player(15), DUMMY_ID, .x, .y, bj_RADTODEG * Atan2(.oriVec.y - .y, .oriVec.x - .x)))
                            set pro.source = .oriUnit
                            /* Control the missile-art of the projectile */
                            set pro.skin = AddSpecialEffectTarget(retroproj.simpleSkin, pro.toUnit, &quot;origin&quot;)
                            /* Control the dimensions and launch-properties of the projectile */
                            call SetUnitScale(pro.toUnit, 0.85, 0.85, 0.85)
                            call pro.doLaunch(bigVec, .oriVec, 300.0, 0.10)
                        endif
                        
                        set .go             = false
                        set pro.primary     = false
                        set pro.carryWarp   = this
                        
                    endif
                endif
            endif
        endmethod
        
        implement RETRO
        
        static method Initiate takes retroproj h returns nothing
            local real dist
            local real x
            local real y
            local thistype this = allocate(h.target, true, true)
            
            if this == 0 then   /* The allocate method will return 0 for stationary units (buildings, wards) */
                return
            endif
            
            set .caster = h.source
            set .units  = h.units
            set .damage = h.damage
            
            static if LIBRARY_RetroFade then
                set .casterOwner = GetOwningPlayer(.caster)
                set .victimOwner = GetOwningPlayer(.subject)
                call retrofade.yes(.casterOwner, .x, .y)
                call retrofade.yes(.victimOwner, .x, .y)
            endif
            
            if .oriVec == 0 then
                set .oriVec = vector.createTerrainPoint(.x, .y)
                set .oriVec.z = .oriVec.z + this.z + 60.00
            endif
            
            set .oriUnit = CreateUnit(Player(15), DUMMY_ID, .oriVec.x, .oriVec.y, bj_RADTODEG * Atan2(.oriVec.y - .y, .oriVec.x - .x))
            set .go = true
            set .to = false
            call SetUnitScale(.oriUnit, 0.80, 0.80, 0.80)
            call GroupAddUnit(.units, .subject)
            call .capture(h.Time)
            
            call DestroyEffect(AddSpecialEffectTarget(caughtFX, .oriUnit, &quot;origin&quot;))
            set .gloomy = AddSpecialEffectTarget(gloomyFX, .oriUnit, &quot;chest&quot;)
            set .spooky = AddSpecialEffectTarget(spookyFX, .oriUnit, &quot;overhead&quot;)
            set .attach = AddSpecialEffectTarget(attachFX, .subject, &quot;overhead&quot;)
            
            if IsUnitType(.subject, UNIT_TYPE_FLYING) then
                call UnitAddAbility(.oriUnit, &#039;Amrf&#039;)
                call UnitRemoveAbility(.oriUnit, &#039;Amrf&#039;)
                call SetUnitFlyHeight(.oriUnit, .z, 0.00)
            endif   /* The origin turns into a floating menace for air victims */
            
            static if LIBRARY_Knockback then
                set x = .x - h.carryVec.x
                set y = .y - h.carryVec.y
                set dist = KB_MAX_DISTANCE - (SquareRoot(x*x + y*y) / 2.0)
                if dist &lt;= KB_MIN_DISTANCE then
                    set dist = KB_MIN_DISTANCE
                endif
                set retroKB.create(.subject, Atan2(y, x), dist, KB_DURATION).attach = AddSpecialEffectTarget(retroKB.fx, h.target, &quot;chest&quot;)
            endif
            
        endmethod
        
        static method enumAOE takes nothing returns boolean
            local retroproj p
            local unit u = GetFilterUnit()
            if UnitAlive(u) and IsUnitEnemy(u, thistype(0).casterOwner) and thistype(GetUnitId(u)).subject == u then
                
                call bigVec.getTerrainPoint(GetUnitX(u), GetUnitY(u))
                set bigVec.z    = bigVec.z + 60.0
                set p           = retroproj.create(CreateUnit(Player(15), DUMMY_ID, regVec.x, regVec.y, bj_RADTODEG * Atan2(bigVec.y - regVec.y, bigVec.x - regVec.x)))
                set p.skin      = AddSpecialEffectTarget(retroproj.launchSkin, p.toUnit, &quot;origin&quot;)
                set p.target    = u
                set p.source    = thistype(0).caster
                set p.units     = thistype(0).units
                set p.damage    = thistype(0).damage
                set p.Time      = retroproj(0).Time
                set p.carryVec  = vector.create(regVec.x, regVec.y, regVec.z)
                call p.doLaunch(regVec, bigVec, 900.0, 0.10)
                
            endif
            set u = null
            return false
        endmethod
        
        static method forceCollapse takes nothing returns boolean
            call thistype(GetUnitId(GetEnumUnit())).collapse()
            call DestroyEffect(AddSpecialEffectTarget(recallFXTarg, GetEnumUnit(), &quot;origin&quot;))
            return false
        endmethod
        
        static method onCast takes nothing returns boolean
            local real factor
            local integer id = GetSpellAbilityId()
            
            if (id == SPELL_ID) then
            
                set thistype(0).caster = GetTriggerUnit()
                set thistype(0).casterOwner = GetTriggerPlayer()
                set thistype(0).units = casterGroup[GetUnitId(thistype(0).caster)]
                
                call regVec.getTerrainPoint(GetSpellTargetX(), GetSpellTargetY())
                set regVec.z = regVec.z + 60.00
                
                call DestroyEffect(AddSpecialEffect(epicenterFX, regVec.x, regVec.y))
                
                set factor = GetUnitAbilityLevel(thistype(0).caster, SPELL_ID) - 1.00
                set thistype(0).damage = BASE_DAMAGE   + LVL_INC_DAMAGE   * factor
                set retroproj(0).Time  = BASE_DURATION + LVL_INC_DURATION * factor
                
                static if LIBRARY_GroupUtils then
                    if GetRandomInt(1, 10) == 1 then
                        call GroupRefresh(thistype(0).units)
                    endif
                    call GroupEnumUnitsInArea(ENUM_GROUP, regVec.x, regVec.y, BASE_AOE + LVL_INC_AOE * factor, Filter(function thistype.enumAOE))
                else
                    call GroupEnumUnitsInRange(bj_lastCreatedGroup, regVec.x, regVec.y, BASE_AOE + LVL_INC_AOE * factor, Filter(function thistype.enumAOE))
                endif
                
            elseif (id == EXTRA_ID) then
                call ForGroup(casterGroup[GetUnitId(GetTriggerUnit())], function thistype.forceCollapse)
                call DestroyEffect(AddSpecialEffectTarget(recallFXCast, GetTriggerUnit(), &quot;origin&quot;))
            endif
            
            return false
        endmethod
        
        static method learnSkill takes nothing returns boolean
            if GetLearnedSkill() == SPELL_ID and GetLearnedSkillLevel() == 1 then
                call UnitAddAbility(GetTriggerUnit(), EXTRA_ID)
                
                static if LIBRARY_Recycle then
                    set casterGroup[GetUnitId(GetTriggerUnit())] = Group.get()
                elseif LIBRARY_GroupUtils then
                    set casterGroup[GetUnitId(GetTriggerUnit())] = NewGroup()
                else
                    set casterGroup[GetUnitId(GetTriggerUnit())] = CreateGroup()
                endif
                
            endif
            return false
        endmethod
        
        static method cleanup takes unit caster returns nothing
            local integer id
            static if LIBRARY_AIDS then
                set id = AIDS_GetDecayingIndex()
            else
                set id = GetUnitId(caster)
            endif
            if casterGroup[id] != null then
                static if LIBRARY_Recycle then
                    call Group.release(casterGroup[id])
                elseif LIBRARY_GroupUtils then
                    call ReleaseGroup(casterGroup[id])
                else
                    call GroupClear(casterGroup[id])
                    call DestroyGroup(casterGroup[id])
                endif
                set casterGroup[id] = null
            endif
        endmethod
        
        static if LIBRARY_AIDS then
            private static method AIDS_OnDeallocate takes nothing returns boolean
                call cleanup(null)
                return false
            endmethod
        endif
        
        private static method onInit takes nothing returns nothing
            local trigger t
            
            set t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
            call TriggerAddCondition(t, Condition(function thistype.learnSkill))
            
            set t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.onCast))
            
            set regVec = vector.create(0.0, 0.0, 0.0)
            call PreloadStrings()
            
            static if LIBRARY_AIDS then
                call AIDS_RegisterOnDeallocate(Filter(function thistype.AIDS_OnDeallocate))
            else
                call OnUnitDeindexed(thistype.cleanup)
            endif
        endmethod
        
    endstruct
    
endlibrary
    
library_once xebasic
/* AutoIndex and GroupUtils will interpret this to set some default values */
endlibrary
 

Attachments

  • TimeWarp2.w3x
    143 KB · Views: 464

tooltiperror

Super Moderator
Reaction score
231
It would be nice if you actually linked to them.

[NOPARSE]Google is a popular search engine.[/NOPARSE]​

Edit: By the time I looked up [noparse] you edited.​
 

Laiev

Hey Listen!!
Reaction score
188
[YOUTUBE]8Un6VIypw04[/YOUTUBE]
[YOUTUBE]RiCqwNPTcMQ[/YOUTUBE]

quote this and get the videos :p
 

Viikuna

No Marlo no game.
Reaction score
265
I likes.

I think you should do fog changes only to players who are wathing that spell happening and have their camera targetting in that area.


Something like this maybe:

Create a region to that place where the spell is casted, and do:

JASS:


if IsPointInRegion(.region,GetCameraTargetPositionX(),GetCameraTargetPositionY()) then
    call FadeToFog( SpecialFog )
else
    call FadeToFog( DefaultFog )
endif


Something like this, and fog fades dont affect to players in other end of the map.


edit. Love the videos btw.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
hmm.gif

Try this, less laggy + Full HD resolution.
[YOUTUBE]<object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/SLVr31bB7sg&hl=en_US&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/SLVr31bB7sg&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object>[/YOUTUBE]
 

Bribe

vJass errors are legion
Reaction score
67
It is only using 1 hashtable.

With the current structure I've set up, a level 3 cast of this spell will need 45 array slots for each unit cast. Suppose you've got 50 instances of the spell (I had much more than 50 instances in one of the videos) -- you're already up to an array position of 2250. Here's some things:

There are three arrays being stored: x, y, and Unit-facing. That's 3 seperate arrays I would need instead of a hashtable already. If I were to consolidate and make a standard 2-D array, that number would be up to 7750. Ouch.

If the player wants to expand the duration to, I don't know, something more fun than the few seconds I made for this demo, that's really going to pile up a lot! If the spell even lasts 15 seconds, which is still not long enough to show off just how cool the data storage is, it's going to require ~187 array slots per unit (such as a high-level cast, or just someone having fun). If 50 instances are in play, that brings the array up to 9350. If this is 3 standard arrays -- it's now three arrays that are over 1150 past the array limit.

I need potentially-infinite storage for this to be workable for everyone; even someone crazy enough who wants to see a single unit's backtracking for an entire minute or more. I've thought about it :p

Most conveniently is it's multi-instanciability. Right now, each system has its own tab, and they all start at 0 and end at some arbitrary number. How would I track the arrays needed to make this work? I'd need a fourth and fifth array to track the start and end points of each struct, as well as another integer global to tell the next struct where to start on the array. That leaves no room for growth or flexiblity. A multiplayer map where each hero wants to control time is going to need this hashtable.
 

Bribe

vJass errors are legion
Reaction score
67
Yeah, thanks, I knew there was something else I wanted to add as an option :D

Version 2.0 (the next release) I'm going to add an interface with "onStart", "onCollapse", "onFinish" and a "while" method for both forward/reverse functions, which will make this more like a system than a normal spell. Hey, why not.
 

Bribe

vJass errors are legion
Reaction score
67
Yeah, not what I had in mind, though, as my globals block is getting really messy with things like that. I'm just going to make the core spell a minor system and the actual things like what triggers the spell to be sub-structs that extend the timeWarp spell. This way, I don't need so many static if's to do what could easily be added/removed with child structs.
 

Bribe

vJass errors are legion
Reaction score
67
JASS:


if IsPointInRegion(.region,GetCameraTargetPositionX(),GetCameraTargetPositionY()) then
    call FadeToFog( SpecialFog )
else
    call FadeToFog( DefaultFog )
endif

I've never used camera work like this (nor have I used IsPointInRegion) but I would like to implement this. Will this be a localized to a player just by using "GetCameraTargetPosition", or do I need a "GetLocalPlayer" to localize the fade effect?

In its current unpublished incarnation, I have the fog fade only for the caster of the spell and the target of the spell. Until I can get this working, that's the method I'm staying with.
 

Viikuna

No Marlo no game.
Reaction score
265
GetCameraTargetPositionX and Y just usually return different values for different computers. ( GetLocalPlayer does that too, it just returns a player. )

So, if you do a if/then/else block like the one I posted, the actions are only executed in some computers depending on their camera position.
This is how you get this fog effect for only the region you created around the area where the spell was casted.

Just remember not to do any stuff that causes desynchs there. Changing fog is perfectly asynchronous and safe, but for example creating some handles might be a bad idea.
 

Bribe

vJass errors are legion
Reaction score
67
This has been updated with (I think) all suggestions, and it's now a system. Updated video/image/test map/code :)
 

Bribe

vJass errors are legion
Reaction score
67
System further updated with awesomeness to 2.01. Check out the new video :)
 

Blackrage

Ultra Cool Member
Reaction score
25
This system (well, at least when I used the All-time template) stops working for heroes that revive.

EDIT: Nevermind, its just the All-time template.
 

Bribe

vJass errors are legion
Reaction score
67
That bug has a failsafe in this incredible new version.

This is hall-of-fame material, and it's ready to download.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top