Name | Type | is_array | initial_value |
Mapshitheroes | unit | Yes | |
TempEff | boolean | No | |
TempInt | integer | No | |
TempLoc | location | No | |
TempReal | real | No | |
TempUnit | unit | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
set tT[0]=CreateTimer()
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=135
//TESH.alwaysfold=0
library HeroRevival requires TimerUtils
//*******************************************************************************************************************************
//
// This is just a simple hero revival
// by baassee
// Credits is appreciated
// and please credit Bribe too for his brilliant remake.
//
// *Requires:
// TimerUtils by Vexorian
// A vJass Compiler
//
//
// Credits flies out to:
// Axarion for showing me his scope
// Hell Gate and Deaod for their Health Reserve system, taught me alot
// Vexorian for TimerUtils, JassHelper and vJass
// Bribe for recoding the system.
//
// How to use:
// This library provides you with these functions
// function HeroRevive takes unit hero, real time, real x, real y, boolean eff
// function HeroReviveLoc takes unit hero, real time, location loc, boolean eff
//
// The unit hero is obviously the hero you are going to revive.
// The real time is the time you want to revive your hero.
// ps. you can set this to 0 and use the GetTime func to make your formula.
// The real x states which x coordinate where you are going to revive your hero.
// The real y states which y coordinate where you are going to revive your hero.
// The location loc is for those who don't know to use coordinates.
// The boolean eff is for show or not show rebirth effect.
//
// Example 1:
// call HeroRevive(GetTriggerUnit(), 30., 0., 0., true)
//
// If you use this with an event "A Unit Dies" then it will
// Revive the dying unit, revive it after 30 seconds at coord (0,0) showing revival effect
//
// Example 2:
// call HeroRevive(GetTriggerUnit(), 0., GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), false)
//
// If you use this as said above it will
// Revive the dying unit, it will USE the formula function so you better customize it there.
// It will revive where it died and will not show revival effect.
//
// Example 3:
// call HeroReviveLoc(GetTriggerUnit(), 0., udg_TempLoc, true)
//
// If you use this as said above with a location for all GUI users it will
// Revive the dying unit, it will USE the formula function so you better customize it there.
// It will revive the unit at a location you've set
// Just remember to remove the location afterwards!
//
// End of Documentation
//
//***************************************************************************************************************************
//
// SETUP
//
//
globals
//
//*************GUI USERS LOOK BELOW HERE****************************
//
// This variable is where you can set how fast the camera should pan to the revived unit.
// As this usally is set to a low value, lower the greater the size is, you can set it
// to 0. if you want to, then it will be panned instantly.
//
private constant real PANCAM = 0.6
endglobals
private function GetAdjustedTime takes real time, unit hero returns real
return time + 0. * GetHeroLevel(hero)
//if you want something extra or you can set the time to 0
//and use this for a formula instead
//I call this function for the formula func in the documentation
endfunction
private function FilterHero takes unit u returns boolean
return IsUnitType(u, UNIT_TYPE_HERO) and IsUnitType(u, UNIT_TYPE_DEAD)
//just check if the unit is a hero
//and to check if the unit is already dead (thanks to axarion for this one)
//you can edit the filter if you want
endfunction
// END SETUP
//******************************************************************************************************************************
//
globals
//
// To make sure that the users wont run several instances with the same unit
//
private group NOSTACK = CreateGroup()
endglobals
private struct data extends array
static integer i = 0
static integer array r
unit hero
real x
real y
boolean eff
endstruct
private function finish takes nothing returns nothing
local timer t = GetExpiredTimer()
local data dat = GetTimerData(t)
call ReleaseTimer(t) //recycle timer
set t = null
call ReviveHero(dat.hero, dat.x, dat.y, dat.eff) //revive hero
call GroupRemoveUnit(NOSTACK, dat.hero)
if GetLocalPlayer() == GetOwningPlayer(dat.hero) then
call PanCameraToTimed(dat.x, dat.y, PANCAM)
call ClearSelection()
call SelectUnit(dat.hero, true)
endif
set data.r[0] = data.r[data.r[0]]
set data.r[data.r[0]] = dat
endfunction
function HeroRevive takes unit hero, real time, real x, real y, boolean eff returns nothing
local data dat
local timer t
if FilterHero(hero) and not IsUnitInGroup(hero, NOSTACK) then
if 0 == data.r[0] then
set data.i = data.i + 1
set dat = data.i
else
set dat = data.r[0]
set data.r[0] = data.r[data.r[0]]
endif
set t = NewTimer()
set dat.hero = hero
set dat.x = x
set dat.y = y
set dat.eff = eff
call GroupAddUnit(NOSTACK, hero)
call SetTimerData(t, dat)
call TimerStart(t, GetAdjustedTime(time, hero), false, function finish)
set t = null
debug else
debug call BJDebugMsg("HeroRevival Error: The unit is either alive or isn't a hero unit or is already in the system, please check your trigger calls.")
endif
endfunction
function HeroReviveLoc takes unit hero, real time, location loc, boolean eff returns nothing
call HeroRevive(hero, time, GetLocationX(loc), GetLocationY(loc), eff)
endfunction
endlibrary