| 05-27-2010, 03:28 PM | #1 |
The newest system on the market, Time Travel will work in any situation. You can log a unit's coordinates for an infinite amount of time, and when you decide it's time the unit will quickly retrace its steps :) Video I have included the primary Time Travel library, as well as two sub-libraries that utilize some of the capabilities this system has. The first system, Time-Warp, is a spell. The second system, All-Time, will throw a unit backwards in time for a couple of seconds when you click on it. The sub-libraries are optional and are templates for the grander scheme of things. You are not limited to using these pre-set libraries, and are more than welcome to extend the Time-Travel struct to develop cooler things than I can come up with The vJass code, its manual, and extensions required to work: Manual: JASS://********************************************************************************************************* //* //* Time-Travel Manual //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ //* Looking over the main Time Travel library you'll notice many bits of code that seem testy. The pur- //* pose of this manual is to identify what I feel are the areas that need the most explanation, as I //* want the user to have the greatest understanding possible of how I built this system. People ex- //* plained GUI, JASS, then vJass to me -- I will explain this to you. //* //* First, this library will not function by itself. To get any component to work, you must use struct //* creation. local timetravel t = timetravel.create(GetTriggerUnit(), 10. ) //* The above command will create an instance of the timetravel struct. This is directing the struct to //* make the "Triggering Unit" a time traveller, and this time traveller will fall "back in time" in 10 //* seconds. Any creation of timetravel requires these two parameters. static method create takes unit whichUnit,real duration returns thistype //* ^ function name ^ unit ^ specified time ^ returns a new instance //* While I will not re-type the entire JASSHelper manual to demonstrate to you how to manipulate these //* instances, I will tell you about the qualities unique to the time-travel struct :) //* //* In the Time Travel Library, scroll down to line 221 where the first ############# block appears. //* Notice the values below the line - they are key. Everything prefixed with "private" I have done //* intentionally either to protect the value from being edited by you, or it's just so obscure I don't //* expect anyone to dawdle with it. Point is, the "private" values are not meant to be used, so I will //* not explain them. //* //* "Readonly" variables - like a readonly file, you can reference them, but you cannot change their //* value. call KillUnit(.get_Victim) //this is valid. set .get_Victim = null //this will give you the syntax error ".get_Victim is readonly". //* The reason I made so many variables "readonly" is because several things need to be done internally //* in the library in order to truly make changes. Changing the "victim" is not as simple as a variable //* "set". What if the unit is already in motion, and has had its pathing removed? If you just set the //* variable to another unit, that other guy is going to have some weird movement for the rest of the //* game (walk over trees, walk through walls). Therefore, I built <Method Operators> to make changes //* you would otherwise do with a "set this=that" command. set .victim = GetTriggerUnit() //this is valid call KillUnit(.victim) //this is also valid :) //* The above functionality is made possible because <victim> is a unit operator. This unit operator //* calls a method within the library that instructs the old victim's pathing to be restored to normal //* (among other technical things). The new unit will resume where the old unit left off, and will even //* follow the "backwards-through-time" path that the old unit set for him. The method operators are //* there to protect you from experiencing in-game glitches - that's pretty much it. //* //* Here is the list of method operators at your disposal and an example of how to use each: unit operator victim set .victim = bj_lastCreatedUnit player operator extraPlayer //This is used to establish which players get to see set .extraPlayer = GetLocalPlayer() //fade effects from the instance. If a unit is set to //be a time traveller, the owner of that unit will see //the fog fading. However, if this is a spell, I think //you'll want to have the owner of the casting unit see //the fading, too. Just set "extraPlayer" to "owner of //caster" and the player will see the effect, or, as is //in this example, GetLocalPlayer() will set it to show //fog for every player :) real operator timeValue set .timeValue = 10. boolean operator forward set .forward = false boolean operator paused set .paused = true boolean operator wantAmbience set .wantAmbience = false boolean operator wantOnLoopEx set .wantOnLoopEx = true //* Public Methods //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯ //* You will find some of these very handy. Normally, if you want to store data to a unit, you'd need //* to make a new hashtable (subtracting from the 256 limit) or use someone's system to do it. Because //* I'm already using a hashtable for this system, I figured, since I am only using at most the first //* 25,000 parent keys, why not also store handles, which are much higher values and will not overwrite //* the instances in the library? //* //* Giving you direct access to the time-table can be hazardous (such as saving a null agent will over- //* write the first slot and wipe out an entire unit's x-coordinate history), so I've added three great //* methods that attach integer values (mostly for saving/loading a struct) to any handle-based object. //* ANY. Units, players, timers, whatever you want. static method SetAgentData takes agent a,string s,integer data returns nothing call .SetAgentData(GetTriggerUnit(), "index string", this ) static method GetAgentData takes agent a,string s returns thistype local thistype this = .GetAgentData(GetFilterUnit() ,"index string" ) static method FlushAgentData takes agent a returns nothing call .FlushAgentData(bj_lastCreatedGroup) //* "SetAgentData" attaches an integer value to an agent, which can be further indexed within the agent //* by inputting a string value. //* //* "GetAgentData" retrieves the integer value. //* //* "FlushAgentData" -- while this does not necessarily flush all of the agent's saved values, the time //* travel system keeps track of how many integers are attached to a given agent, and if that is 0, the //* data attached to the agent will be washed out. Please do not accidentally call this twice when it //* should have been called once, as that might trigger an unwanted purge of data that could really //* cause some annoying results. //* method destroyHistory takes integer delete returns nothing call .destroyHistory(10) method createHistory takes integer insert,real x,real y,real facing returns nothing call .createHistory(10, 1000., -500., 90. ) //* These methods are testy and I suggest you use them only with the purest intentions. As you are //* hacking the library's history of your unit with these calls, you could end up with really crazy //* results. Due to their obscure nature, I will not elaborate on what they do further than //* "destroyHistory" can be used to deallocate data you know you will not need, and "createHistory" //* can be used to manually plot a course. //* //* Interface Methods //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ //* Now here's where the real fun begins! The system-embedded interface creates some events that you //* can hack to your own needs. //* method onStart takes nothing returns nothing defaults nothing //Triggered by the "create" call. method onFinish takes nothing returns nothing defaults nothing //Triggered by the "destroy" call. method onCollapse takes nothing returns nothing defaults nothing //Triggered when the time-duration assigned to the unit expires -- will not be called if the //"override" boolean is set. method onLoop takes nothing returns nothing defaults nothing //Each loop through history. To seperate forward looping from reverse looping, you will want to //add an "if/then/else" block: if .is_Forward then //hai :) endif method onLoopEx takes nothing returns nothing defaults nothing //This happens during every loop, too, except it will only happen for *one* time traveller per //loop. This is done so that if you want effects to appear during the looping part, you want //them in the "onLoopEx" method because this will prevent effect pileup (so that 100 effects //aren't created every 0.04 seconds, this filters it so only 1 effect is created every 0.04 //seconds. //* //* //* ** //* //* I will update this further upon request. Please let me know what areas you need me to explain more. //* //********************************************************************************************************* JASS:library TimeTravel //********************************************************************************************************* //* //* WarCraft III: Time Travel Library //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ //* Author: Bribe //* Concept: teuncreemers //* Version: 2.0 //* //* Note: //* Many thanks to Berbanog for letting me use this dynamic layout. //* //* Special Community Recognition: //* • WC3Campaigns - For supplying the invaluable Jass New Gen and its components. //* • HiveWorkshop - For supporting & encouraging me through learning GUI to vJass. //* • TheHelper - For hosting many tutorials that have helped me tremendously. //* //* Requirements: //* • JassHelper 0.A.2.B //* //* Description: //* • A powerful utility that disrupts the balance of time! When the duration expires, the //* victims will be thrust backwards; retracing their steps to the start of the cycle :) //* //* Changelog: //* • 2.0 A) Added interface controls so that other structs can extend this parent struct. //* B) Created example child structs that demonstrate the enormous potential this has. //* C) Added many methods, method operators and configurable settings that eclipse the //* functionality of all previous versions. //* D) The system now wants a real value for duration instead of an integer. The value is //* the actual time you want the spell to last. A value of <2.> lasts 2 seconds. Prior //* to this change, it was not clear what to specify for the duration. //* E) Fog-fade effects are localized to each player; if a player's camera is not in 1000 //* range, that player's fog will remain unchanged :) //* //* • 1.00-1.05b //* -- Versions I built and modified before I decided to make this its own system. //* //* //********************************************************************************************************* globals //************************ //* Configation //* ¯¯¯¯¯¯¯¯¯¯¯ //* I will add more features to the configuration as per request. //* private constant real RVRS_TIMER_SPEED = 0.04 private constant real FWRD_TIMER_SPEED = 0.16 //* Must be a multiple of RVRS_TIMER_SPEED. //* //* Fog Configuration //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ private constant boolean FADE_ON = true //* <false> disables the ENTIRE fog system. private constant real FADE_DURATION = 2.00 private constant real FADE_TIMER_SPEED = 0.04 private constant boolean FADE_FLICKER_ON = true private constant real FADE_FLICKER_MAGNITUDE = 300. //* Factors between Z-End + this & Z-End - this. //* //* Default Instance Values //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ //* I have everything configured for demonstration purposes, but if you find yourself using a common //* setting that differs from the constant variable, it's more efficient to change the constant variable //* right here and use inlined settings for the exceptions. //* private constant boolean preset___Override = false private constant boolean preset___Ambience = FADE_ON private constant boolean preset___Pause_Unit = true private constant boolean preset___Do_Looping_Ex = true //* //* endglobals interface timetravelinterface //*************************** //* Time-Travel Interface //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ //* Optional "event-triggered" methods that can be used to implement special effects, damage utilities, //* data utilities, sound effects -- whatever you like. //* //* >> Events that accompany the <create> and <onDestroy> methods: method onStart takes nothing returns nothing defaults nothing method onFinish takes nothing returns nothing defaults nothing //* //* >> When the duration has been reached (right before it starts going backward): method onCollapse takes nothing returns nothing defaults nothing //* //* >> <onLoop> happens during every loop, whereas <onLoopEx> is "special effects"-friendly & occurs less //* frequently depending on how many units are active. Do not call <destroy> from these. method onLoop takes nothing returns nothing defaults nothing method onLoopEx takes nothing returns nothing defaults nothing //* //* //********************************************************************************************************* endinterface globals //******************** //* Time-Table //* ¯¯¯¯¯¯¯¯¯¯ //* Here's how I divide the time-table: //* Parent keys: 2-D Array that stores each instance. //* Higher keys can be used to attach data to any agent. //* Child keys: Sub-arrays assigned to each instance that store X,Y and UnitFacing values. //* private hashtable timeTable = InitHashtable() //* //* Internal Settings //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ //* In order to make this as user-friendly as possible, I let the user input a real timescale. These //* variables simply turn user-assigned values into integer values so the system can read them. //* ------------------------------------------------------------------------------------------------------- private constant real duration_I_O = 1./FWRD_TIMER_SPEED private constant integer forward_Mark = R2I(FWRD_TIMER_SPEED/RVRS_TIMER_SPEED) //* ------------------------------------------------------------------------------------------------------- //* //* //********************************************************************************************************* endglobals private struct Fade extends array //******************************* //* Fog Utilities //* ¯¯¯¯¯¯¯¯¯¯¯¯¯ static integer int = R2I(FADE_DURATION/FADE_TIMER_SPEED) static timer tim = null static boolean to_Spell = true static boolean paused = true static integer dex = 0 static integer count = 0 //* real set_Fog boolean player_Want integer player_Unit_Count //* //* Configurable Fade Values //* ======================================================================================================= //* 0 and 6 >> Z Start: 0. to ???? //* 1 and 7 >> Z End: 0. to ???? //* 2 and 8 >> Density: 0. to 1. //* 3 and 9 >> Red: 0. to 1. //* 4 and 10 >> Green: 0. to 1. //* 5 and 11 >> Blue: 0. to 1. private static method InitFadeValues takes nothing returns nothing //* //* >> Your fog settings: set Fade[ 0 ].set_Fog = 3000. set Fade[ 1 ].set_Fog = 5000. set Fade[ 2 ].set_Fog = 0.5 set Fade[ 3 ].set_Fog = 1. set Fade[ 4 ].set_Fog = 1. set Fade[ 5 ].set_Fog = 1. //* //* >> The spell's fog settings: set Fade[ 6 ].set_Fog = 0. set Fade[ 7 ].set_Fog = 3000. set Fade[ 8 ].set_Fog = 0.125 set Fade[ 9 ].set_Fog = 0.2 set Fade[ 10 ].set_Fog = 0. set Fade[ 11 ].set_Fog = 0.35 endmethod //* private static method onInit takes nothing returns nothing local integer i=0 static if FADE_ON then set Fade.tim=CreateTimer() call InitFadeValues() loop set Fade[i+6].set_Fog=(Fade[i].set_Fog-Fade[i+6].set_Fog)/Fade.int exitwhen i==5 set i=i+1 endloop endif endmethod //* //* endstruct //* //* Fade Sequence //* ======================================================================================================= private function doFade takes nothing returns nothing local integer i=0 if (Fade.to_Spell) then loop set Fade[i].set_Fog=Fade[i].set_Fog-Fade[i+6].set_Fog exitwhen i==5 set i=i+1 endloop set Fade.dex=Fade.dex+1 if Fade.dex>=Fade.int then set Fade.dex=Fade.int set Fade.paused=true call PauseTimer(Fade.tim) endif else loop set Fade[i].set_Fog=Fade[i].set_Fog+Fade[i+6].set_Fog exitwhen i==5 set i=i+1 endloop set Fade.dex=Fade.dex-1 if Fade.dex<=0 then set Fade.dex=0 set Fade.paused=true call PauseTimer(Fade.tim) endif endif call SetTerrainFogEx(0,Fade[0].set_Fog,Fade[1].set_Fog,Fade[2].set_Fog,Fade[3].set_Fog,Fade[4].set_Fog,Fade[5].set_Fog) endfunction native UnitAlive takes unit id returns boolean struct timetravel extends timetravelinterface //******************************************* //* Time Travel //* ¯¯¯¯¯¯¯¯¯¯¯ //* The more obscure or protected components I've set to <private> so you can't reference them. <public> //* components I encourage you to use liberally. Readonly components are mostly for calculations or for //* reference, although the important ones can be modified by setting the linked <method operator>. //* //* ####################################################################################################### //* //* Static Components //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ private static integer cacheIndex = 0 private static thistype array cacheStack private static timer loopTimer = CreateTimer() private static boolean array reserved private static integer fx_Dex = 0 private static thistype array fx_Cache //* //* Dynamic Components //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ public boolean override = preset___Override public real startx public real starty public boolean wantDestroy = false //* Setting this to <true> is the *only* way to destroy the instance from the // <onLoop> method. Calling <destroy> from that method will cause an error. //* private integer saveDex = 0 //* Hashtable save-point per loop. private integer realDex //* The private index of the unit. private integer tableDex //* The private hashtable index of the unit. private integer fx_Local_Dex = 0 //* For stack-and-pop use with fx_Caches. //* private integer diff_Delay = 0 //* Regulates the difference between forward & reverse times. //* //* Method Operators ** //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ //* Many of the components of this spell require more than one action to be performed in order to truly make //* the change, otherwise there will be errors. I have incorporated several operators that apply necessary //* setting & variable modifications for you. Below is the list of operator methods and their corresponding //* variables -- feel free to use any operator as if it were the actual variable. //* // public unit operator victim Because the fog is specific to each player, the system needs to be notified of change readonly unit get_Victim //of ownership of this unit, so it must be set using <victim>. // public player operator extraPlayer For spells where you want both the target's owner and the caster's owner to see fog readonly player get_Extra_Player //effects, use <set extraPlayer = GetOwningPlayer($caster$)> // public real operator timeValue The duration of forward-mode until it collapses into reverse-mode. The input value private integer sys_Duration //will be *added* to the duration. Negative values are also accepted, but if the value // is too low the destroy method will be called and the unit will not travel back through // time (so it can be used to cancel a spell). To prevent this, do a real comparison to // check if <timeValue> is higher than the value you're subtracting. // ** If the unit is in reverse & duration is added, it will switch back to forward-mode. // public boolean operator forward = true readonly boolean is_Forward = true // public boolean operator paused = preset___Pause_Unit readonly boolean is_Paused = preset___Pause_Unit // public boolean operator wantAmbience If the fog will change because of this unit. readonly boolean haveAmbience // public boolean operator wantOnLoopEx Let me explain this one: I have a filter that regulates how often <onLoopEx> is called; readonly boolean haveOnLoopEx //only one <onLoopEx> will be called per loop so effects don't pile up. The system will // use this boolean to filter out only units that want special effects; so if there are // 100 units that don't want <onLoopEx> and one unit that does, that one unit will have // all of his effects appear, instead of only appearing 1/101 times :) //* //* ####################################################################################################### //* //* Sub-System: Agent-Data Functions //* ======================================================================================================= //* Instead of requiring more libraries, this indexing system is inlined and makes additional use of the //* Time-Table. Any handle-based object can be assigned any integer, and is backed-up by a second indexer; //* this way, indexes can be easily saved and loaded without bumping into each other (and have names). //* static method GetAgentData takes agent a,string s returns thistype return LoadInteger(timeTable,GetHandleId(a),StringHash(s)) endmethod static method SetAgentData takes agent a,string s,integer data returns nothing local integer id=GetHandleId(a) if id>0 then call SaveInteger(timeTable,id,1,LoadInteger(timeTable,id,1)+1) call SaveInteger(timeTable,id,StringHash(s),data) else debug call BJDebugMsg("Error: cannot save data to null agent.") endif endmethod static method FlushAgentData takes agent a returns nothing local integer id=GetHandleId(a) local integer flushCount=LoadInteger(timeTable,id,1)-1 if id>0 then if flushCount<=0 then call FlushChildHashtable(timeTable,id) else call SaveInteger(timeTable,id,1,flushCount) endif else debug call BJDebugMsg("Error: cannot flush data from null agent.") endif endmethod //* //* Custom History //* ======================================================================================================= method destroyHistory takes integer delete returns nothing call RemoveSavedReal(timeTable,.tableDex*3,delete) call RemoveSavedReal(timeTable,.tableDex*3+1,delete) call RemoveSavedReal(timeTable,.tableDex*3+2,delete) endmethod method createHistory takes integer insert,real x,real y,real facing returns nothing call SaveReal(timeTable,.tableDex*3,insert,x) call SaveReal(timeTable,.tableDex*3+1,insert,y) call SaveReal(timeTable,.tableDex*3+2,insert,facing) endmethod //* //* Add Extra Player <player operator extraPlayer> //* ======================================================================================================= method operator extraPlayer takes nothing returns player return .get_Extra_Player endmethod method operator extraPlayer= takes player p returns nothing local integer i=GetPlayerId(.get_Extra_Player) local integer j=GetPlayerId(p) local boolean b=(.get_Extra_Player!=p) if p!=null and b then set Fade[j].player_Want=true set Fade[j].player_Unit_Count=Fade[j].player_Unit_Count+1 endif if .get_Extra_Player!=null and b then set Fade[i].player_Unit_Count=Fade[i].player_Unit_Count-1 if Fade[i].player_Unit_Count==0 then set Fade[i].player_Want=false endif endif set .get_Extra_Player=p endmethod //* //* Pause/Unpause Unit <boolean operator pause> //* ======================================================================================================= method operator paused takes nothing returns boolean return .is_Paused endmethod method operator paused= takes boolean b returns nothing if not .is_Forward then call SetUnitPathing(.get_Victim,not b) endif set .is_Paused=b endmethod //* //* Change Victim <unit operator victim> //* ======================================================================================================= method operator victim takes nothing returns unit return .get_Victim endmethod method operator victim= takes unit u returns nothing local integer i=GetPlayerId(GetOwningPlayer(.get_Victim)) local integer j=GetPlayerId(GetOwningPlayer(u)) local boolean b=(.get_Victim!=u) if u!=null and b then set Fade[j].player_Want=true set Fade[j].player_Unit_Count=Fade[j].player_Unit_Count+1 endif if .get_Victim!=null and b then if not .is_Forward and .is_Paused then call SetUnitPathing(.get_Victim,true) endif set Fade[i].player_Unit_Count=Fade[i].player_Unit_Count-1 if Fade[i].player_Unit_Count==0 then set Fade[i].player_Want=false endif endif set .get_Victim = u set .paused=.is_Paused set .wantAmbience=.haveAmbience endmethod //* //* Change "Going Forward" <boolean operator forward> //* ======================================================================================================= method operator forward takes nothing returns boolean return .is_Forward endmethod method operator forward= takes boolean b returns nothing if b and not .is_Forward then if (.is_Paused) then call SetUnitPathing(.get_Victim,true) call SetUnitPosition(.get_Victim,GetWidgetX(.get_Victim),GetWidgetY(.get_Victim)) endif elseif not b and .is_Forward then call .onCollapse() if (.is_Paused) then call SetUnitPathing(.get_Victim,false) endif endif set .is_Forward=b endmethod //* //* Add Duration <real operator timeValue> //* ======================================================================================================= method operator timeValue takes nothing returns real return I2R(.sys_Duration-.saveDex)/duration_I_O endmethod method operator timeValue= takes real v returns nothing local integer m=R2I(v*duration_I_O) local integer n=.sys_Duration-m if .is_Forward then if (v<0.) then if -m>(.sys_Duration-.saveDex) then call .destroy() return endif endif else set .forward=true endif set .sys_Duration=.sys_Duration+m endmethod //* //* Fog Manipulation <boolean operator wantAmbience> //* ======================================================================================================= private static method camCheck takes real ox,real oy returns boolean local real x=GetCameraTargetPositionX() local real y=GetCameraTargetPositionY() return x>=ox-1000. and x<=ox+1000. and y>=oy-1000. and y<=oy+1000. endmethod //* method operator wantAmbience takes nothing returns boolean return .haveAmbience endmethod method operator wantAmbience= takes boolean want returns nothing local boolean b=false static if FADE_ON then if want and not .haveAmbience then if Fade.count==0 and camCheck(.startx,.starty) then set b=true endif set Fade.count=Fade.count+1 elseif not want and .haveAmbience then set Fade.count=Fade.count-1 if Fade.count==0 then set b=true endif endif if b and Fade[GetPlayerId(GetLocalPlayer())].player_Want then if (Fade.paused) then call TimerStart(Fade.tim,FADE_TIMER_SPEED,true,function doFade) set Fade.paused=false endif set Fade.to_Spell=want endif endif set .haveAmbience=want endmethod //* //* Want onLoop Extra Method <boolean operator wantOnLoopEx> //* ======================================================================================================= method operator wantOnLoopEx takes nothing returns boolean return .haveOnLoopEx endmethod method operator wantOnLoopEx= takes boolean want returns nothing if want and not .haveOnLoopEx then set .fx_Local_Dex=.fx_Dex set .fx_Cache[.fx_Dex]=this set .fx_Dex=.fx_Dex+1 elseif not want and .haveOnLoopEx then set .fx_Dex=.fx_Dex-1 if (.fx_Dex>0) then set .fx_Cache[.fx_Local_Dex]=.fx_Cache[.fx_Dex] endif endif set .haveOnLoopEx = want endmethod //* //* Destructor //* ======================================================================================================= private method onDestroy takes nothing returns nothing call FlushChildHashtable(timeTable,.tableDex*3) call FlushChildHashtable(timeTable,.tableDex*3+1) call FlushChildHashtable(timeTable,.tableDex*3+2) set .reserved[.tableDex]=false call .onFinish() set .forward = true // boolean operator set .wantAmbience = false // boolean operator set .wantOnLoopEx = false // boolean operator set .victim = null // unit operator set .extraPlayer = null // player operator set .cacheIndex=.cacheIndex-1 if (.cacheIndex==0) then call PauseTimer(.loopTimer) else set .cacheStack[.realDex]=.cacheStack[.cacheIndex] set .cacheStack[.realDex].realDex=.realDex endif endmethod //* //* Time Machine //* ======================================================================================================= private static method doLoop takes nothing returns nothing local boolean toDestroy=false local boolean do local thistype flag=.fx_Cache[GetRandomInt(0,.fx_Dex-1)] local thistype w local integer i=0 loop set w=.cacheStack[i] set do=false if (w.is_Forward) then //* //* Forward //* set w.diff_Delay=w.diff_Delay+1 if w.diff_Delay==forward_Mark then set do=true set w.diff_Delay=0 set w.saveDex=w.saveDex+1 call SaveReal(timeTable,w.tableDex*3,w.saveDex,GetWidgetX(w.get_Victim)) call SaveReal(timeTable,w.tableDex*3+1,w.saveDex,GetWidgetY(w.get_Victim)) call SaveReal(timeTable,w.tableDex*3+2,w.saveDex,GetUnitFacing(w.get_Victim)) if w.saveDex>=w.sys_Duration and not w.override then set w.forward=false endif endif else //* //* Reverse //* set do=true if HaveSavedReal(timeTable,w.tableDex*3,w.saveDex) then if (w.is_Paused) then call SetUnitPosition(w.get_Victim,LoadReal(timeTable,w.tableDex*3,w.saveDex),LoadReal(timeTable,w.tableDex*3+1,w.saveDex)) else call SetUnitX(w.get_Victim,LoadReal(timeTable,w.tableDex*3,w.saveDex)) call SetUnitY(w.get_Victim,LoadReal(timeTable,w.tableDex*3+1,w.saveDex)) endif call SetUnitFacing(w.get_Victim,LoadReal(timeTable,w.tableDex*3+2,w.saveDex)) endif set w.saveDex=w.saveDex-1 if w.saveDex<=0 and not w.override then set toDestroy=true endif endif //* //* Shared //* if (do) then call w.onLoop() if (flag==w) then call w.onLoopEx() endif endif if toDestroy or w.wantDestroy or not UnitAlive(w.get_Victim) then if w.reserved[w.tableDex] then call w.destroy() endif set toDestroy=false else set i=i+1 endif exitwhen i>=.cacheIndex endloop static if FADE_ON and FADE_FLICKER_ON then if (Fade.count>0) then if Fade[GetPlayerId(GetLocalPlayer())].player_Want then if GetRandomReal(0.,2.)<=RVRS_TIMER_SPEED then call SetTerrainFogEx(0,Fade[0].set_Fog,GetRandomReal(Fade[1].set_Fog-FADE_FLICKER_MAGNITUDE,Fade[1].set_Fog+FADE_FLICKER_MAGNITUDE),Fade[2].set_Fog,Fade[3].set_Fog,Fade[4].set_Fog,Fade[5].set_Fog) endif endif endif endif endmethod //* //* Creation //* ======================================================================================================= static method create takes unit whichUnit,real duration returns thistype local thistype w = thistype.allocate() set w.victim = whichUnit set w.startx = GetWidgetX(whichUnit) set w.starty = GetWidgetY(whichUnit) set w.sys_Duration = R2I(duration*duration_I_O) set w.wantAmbience = preset___Ambience set w.wantOnLoopEx = preset___Do_Looping_Ex //* >> set w.realDex = .cacheIndex set w.tableDex = .cacheIndex loop exitwhen .reserved[w.tableDex]==null exitwhen not .reserved[w.tableDex] set w.tableDex=w.tableDex+1 endloop set .reserved[w.tableDex]=true //* >> if (.cacheIndex==0) then call TimerStart(.loopTimer,RVRS_TIMER_SPEED,true,function thistype.doLoop) endif set .cacheStack[.cacheIndex]=w set .cacheIndex=.cacheIndex+1 call w.onStart() return w endmethod //* //* //********************************************************************************************************* endstruct endlibrary Time Warp: JASS:library TimeWarp requires TimeTravel,GroupUtils private struct filt extends array static integer dex = 0 static real Real static unit Unit static unit Caster static player Play static integer Int group grp unit cast endstruct struct timewarp extends timetravel //******************************** //* Time Warp //* ¯¯¯¯¯¯¯¯¯ static constant integer SPELL_ID = 'A003' static constant integer EXTRA_ID = 'A001' real damage unit caster effect return_Fx effect attach_Fx //* //* End of Spell: //* ======================================================================================================= method onFinish takes nothing returns nothing call DestroyEffect(.return_Fx) call DestroyEffect(.attach_Fx) call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\WandOfNeutralization\\NeutralizationMissile.mdl",.get_Victim,"origin")) call GroupRemoveUnit(filt[GetAgentData(.caster,"time warp")].grp,.get_Victim) call FlushAgentData(.get_Victim) call SetUnitTimeScale(.get_Victim,1.) call SetUnitVertexColor(.get_Victim,255,255,255,255) endmethod //* //* Portal-Collapse Behavior: //* ======================================================================================================= method onCollapse takes nothing returns nothing call SetUnitTimeScale(.get_Victim,4.) call SetUnitVertexColor(.get_Victim,175,150,155,115) call DestroyEffect(.attach_Fx) call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl",.get_Victim,"origin")) set .attach_Fx = AddSpecialEffectTarget("Abilities\\Spells\\Undead\\Possession\\PossessionMissile.mdl",.get_Victim,"overhead") endmethod //* //* Looping Behavior //* ======================================================================================================= method onLoopEx takes nothing returns nothing if (.is_Forward) then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl",.get_Victim,"origin")) else call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Transmute\\GoldBottleMissile.mdl",.get_Victim,"origin")) call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\StrongDrink\\BrewmasterMissile.mdl",.get_Victim,"origin")) call UnitDamageTarget(.caster,.get_Victim,.damage,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS) endif endmethod //* //* Configurable Filter //* ======================================================================================================= static method GroupFilter takes nothing returns boolean local thistype dat set filt.Unit=GetFilterUnit() if IsUnitInGroup(filt.Unit,filt[filt.Int].grp) then set GetAgentData(filt.Unit,"time warp unit").timeValue=filt.Real elseif IsUnitEnemy(filt.Unit,filt.Play) and not IsUnitType(filt.Unit,UNIT_TYPE_STRUCTURE) and UnitAlive(filt.Unit) then set dat = .create(filt.Unit,filt.Real) set dat.extraPlayer = filt.Play set dat.caster = filt.Caster set dat.damage = filt.Real set dat.attach_Fx = AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\shadowstrike\\shadowstrike.mdl",filt.Unit,"overhead") set dat.return_Fx = AddSpecialEffect("Abilities\\Spells\\Human\\MagicSentry\\MagicSentryCaster.mdl",dat.startx,dat.starty) call GroupAddUnit(filt[filt.Int].grp,filt.Unit) call SetAgentData(filt.Unit,"time warp unit",dat) endif return false endmethod //* //* Open Portal //* ======================================================================================================= static method OpenPortal takes unit u returns nothing local real factor = GetUnitAbilityLevel(u,SPELL_ID)-1. local real x = GetSpellTargetX() local real y = GetSpellTargetY() set filt.Play = GetTriggerPlayer() set filt.Real = factor*1.+4. set filt.Caster = u set filt.Int = GetAgentData(u,"time warp") call GroupEnumUnitsInRange(ENUM_GROUP,x,y,factor*50.+150.,Filter(function thistype.GroupFilter)) call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl",x,y)) endmethod //* //* Early-Collapse Method //* ======================================================================================================= //* All of the caster's targets immediately enter reverse if they are in forward-mode: //* static method CollapseEach takes nothing returns nothing set GetAgentData(GetEnumUnit(),"time warp unit").forward=false endmethod //* //* Conditions //* ======================================================================================================= static method Conditions takes nothing returns boolean local integer id=GetSpellAbilityId() if id==SPELL_ID then call .OpenPortal(GetTriggerUnit()) elseif id==EXTRA_ID then call ForGroup(filt[GetAgentData(GetTriggerUnit(),"time warp")].grp,function thistype.CollapseEach) endif return false endmethod //* //* Add Bonus Skill //* ======================================================================================================= static method NewSkill takes nothing returns boolean if GetLearnedSkill()==SPELL_ID and GetLearnedSkillLevel()==1 then set filt[filt.dex].cast=GetTriggerUnit() set filt[filt.dex].grp=NewGroup() call SetAgentData(filt[filt.dex].cast,"time warp",filt.dex) call UnitAddAbility(filt[filt.dex].cast,EXTRA_ID) set filt.dex=filt.dex+1 endif return false endmethod //* //* //* ======================================================================================================= static method CasterDeath takes nothing returns boolean local integer data=GetAgentData(GetTriggerUnit(),"time warp") if data>0 then call ReleaseGroup(filt[data].grp) set filt.dex=filt.dex-1 if filt.dex>0 then call SetAgentData(filt[filt.dex].cast,"time warp",data) set filt[data].cast=filt[filt.dex].cast set filt[data].grp=filt[filt.dex].grp endif endif call FlushAgentData(GetTriggerUnit()) return false endmethod //* //* //* Initializer //* ======================================================================================================= static method onInit takes nothing returns nothing local trigger t=CreateTrigger() call TriggerAddCondition(t,Condition(function thistype.NewSkill)) call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_HERO_SKILL) set t=CreateTrigger() call TriggerAddCondition(t,Condition(function thistype.CasterDeath)) call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH) set t=CreateTrigger() call TriggerAddCondition(t,Condition(function thistype.Conditions)) call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT) endmethod //* //* //********************************************************************************************************* endstruct endlibrary JASS:library AllTime requires TimeTravel,GroupUtils struct alltime extends timetravel //******************************* //* The way this module works is that it grabs every non-structure unit on the map and turns it into a time //* traveller. Each time that time traveller attacks, it is thrown backwards through time :P //* You can use this as a template to do "instant" time travel. //* static constant integer time_Limit = 40 //* effect attach_Fx = null integer countdown = 0 //* //* onLoop Extra Method //* ======================================================================================================= method onLoopEx takes nothing returns nothing if not .is_Forward then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Transmute\\GoldBottleMissile.mdl",.get_Victim,"origin")) call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\StrongDrink\\BrewmasterMissile.mdl",.get_Victim,"origin")) endif endmethod //* //* onLoop Behavior //* ======================================================================================================= method onLoop takes nothing returns nothing if (.is_Forward) then if .countdown<time_Limit then set .countdown=.countdown+1 else if .countdown>time_Limit then set .countdown=time_Limit endif call .destroyHistory(.countdown-time_Limit-1) endif else set .countdown=.countdown-1 if (.countdown<=0) then set .forward=true set .wantOnLoopEx=false call DestroyEffect(.attach_Fx) call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\WandOfNeutralization\\NeutralizationMissile.mdl",.get_Victim,"origin")) endif endif endmethod //* //* On-Finish Method //* ======================================================================================================= method onFinish takes nothing returns nothing call DestroyEffect(.attach_Fx) call FlushAgentData(.get_Victim) endmethod //* //* Add All Units //* ======================================================================================================= static method addUnit takes unit u returns nothing local thistype dat if not IsUnitType(u,UNIT_TYPE_STRUCTURE) then set dat = .create(u,1.) set dat.override = true set dat.wantOnLoopEx = false set dat.wantAmbience = false call SetAgentData(u,"all time",dat) endif endmethod static method doEnum takes nothing returns boolean call .addUnit(GetFilterUnit()) return false endmethod static method addNew takes nothing returns boolean if GetAgentData(GetTriggerUnit(),"all time")==0 then call .addUnit(GetTriggerUnit()) endif return false endmethod //* //* Time Travel Instant-Launch //* ======================================================================================================= static method onSelection takes nothing returns boolean local thistype dat=GetAgentData(GetTriggerUnit(),"all time") if dat>0 then if dat.is_Forward and dat.countdown>=10 then set dat.forward=false set dat.wantOnLoopEx=true set dat.attach_Fx=AddSpecialEffectTarget("Abilities\\Spells\\Other\\Drain\\ManaDrainTarget.mdl",dat.get_Victim,"overhead") call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\Invisibility\\InvisibilityTarget.mdl",GetWidgetX(dat.get_Victim),GetWidgetY(dat.get_Victim))) endif endif return false endmethod //* //* //* Initialization //* ======================================================================================================= static method onInit takes nothing returns nothing local trigger t=CreateTrigger() local integer i=0 call TriggerAddCondition(t,Condition(function thistype.addNew)) call TriggerRegisterEnterRectSimple(t,bj_mapInitialPlayableArea) call GroupEnumUnitsInRect(ENUM_GROUP,bj_mapInitialPlayableArea,Filter(function thistype.doEnum)) set t=CreateTrigger() call TriggerAddCondition(t,Condition(function thistype.onSelection)) loop call TriggerRegisterPlayerUnitEvent(t,Player(0), EVENT_PLAYER_UNIT_SELECTED, null) exitwhen i==11 set i=i+1 endloop endmethod endstruct endlibrary |
| 05-27-2010, 03:43 PM | #2 |
Are you actually submitting this or just posting it as a demo? I ask because you've posted it in both forums, and depending upon your intent, it belongs in only one of them. |
| 05-27-2010, 04:01 PM | #3 |
This is a system submission, I posted it in the wrong forum yesterday. |
