Name | Type | is_array | initial_value |
//TESH.scrollpos=36
//TESH.alwaysfold=0
library_once TimerUtils initializer redInit
//*********************************************************************
//* TimerUtils (Red flavor)
//* ----------
//*
//* 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.wc3campaigns.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.
//*
//* Red flavor: Fastest, method in existence for timer attaching,
//* only takes an array lookup, H2I and subtraction.
//* However, all the code in your map requires extra care
//* not to forget to call ReleaseTimer. It also requires
//* to preload a lot of timers at map init, they use
//* memory and handle ids.
//*
//* I recommend you run your map in debug mode the first
//* time after adding it, make sure you can see map init messages
//* if nothing appears, all is done, if an error appears, it might
//* suggest you a value with OFFSET, in that case, update that value
//* if it still does not work after updating (rare), try a bigger
//* OFFSET by 1000 for example. (Sounds hard? Then use blue or purple
//* timerutils that are friendlier though not as fast)
//*
//********************************************************************
//================================================================
globals
private constant integer OFFSET = 0x100000
private constant integer QUANTITY = 256
private constant integer ARRAY_SIZE = 8191 //changing this to a higher value would effectively
//cripple the performance making this thing irrelevant
endglobals
//=================================================================================================
private function H2I takes handle h returns integer
return GetHandleId( h )
endfunction
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
debug if(H2I(t)-OFFSET<0) then
debug call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
debug endif
set data[H2I(t)-OFFSET]=value
endfunction
function GetTimerData takes timer t returns integer
debug if(H2I(t)-OFFSET<0) then
debug call BJDebugMsg("GetTimerData: Wrong handle id, only use GetTimerData on timers created by NewTimer")
debug endif
return data[H2I(t)-OFFSET]
endfunction
//==========================================================================================
globals
private timer array tT
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, please increase it for your map, fix your map's timer leaks or switch to blue flavor when applicable")
set tT[0]=CreateTimer()
if (H2I(tT[0])-OFFSET<0) or (H2I(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably switch to the blue flavor or fix timer leaks.")
return null
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==8191) 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 redInit takes nothing returns nothing
local integer i=0
local integer bestoffset=-1
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set bestoffset=H2I(tT[i])
endif
if (H2I(tT[i])-OFFSET>=ARRAY_SIZE) then
debug call BJDebugMsg("TimerUtils_redInit: Failed a initializing attempt")
debug call BJDebugMsg("The timer limit is "+I2S(i))
debug call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low, to change OFFSET to "+I2S(bestoffset) )
exitwhen true
endif
if (H2I(tT[i])-OFFSET>=0) then
set i=i+1
endif
endloop
set tN=i
endfunction
endlibrary
//TESH.scrollpos=44
//TESH.alwaysfold=0
library BoundSentinel initializer init
//*************************************************
//* BoundSentinel
//* -------------
//* Don't leave your units unsupervised, naughty
//* them may try to get out of the map bounds and
//* crash your game.
//*
//* To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//*************************************************
//==================================================
globals
// High enough so the unit is no longer visible, low enough so the
// game doesn't crash...
//
// I think you need 0.0 or soemthing negative prior to patch 1.22
//
private constant real EXTRA = 500.0
endglobals
//=========================================================================================
globals
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns nothing
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if(x>maxx) then
set x=maxx
elseif(x<minx) then
set x=minx
endif
if(y>maxy) then
set y=maxy
elseif(y<miny) then
set y=miny
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
set u=null
endfunction
private function init takes nothing returns nothing
local trigger t=CreateTrigger()
local region r=CreateRegion()
local rect rc
set minx=GetCameraBoundMinX() - EXTRA
set miny=GetCameraBoundMinY() - EXTRA
set maxx=GetCameraBoundMaxX() + EXTRA
set maxy=GetCameraBoundMaxY() + EXTRA
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddAction(t, function dis)
//this is not necessary but I'll do it anyway:
set t=null
set r=null
set rc=null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Heights
globals
private location loc = Location( 0.00, 0.00 )
endglobals
function GetFloorHeight takes real x, real y returns real
call MoveLocation( loc, x, y )
return GetLocationZ( loc )
endfunction
function GetUnitZ takes unit whichUnit returns real
local real z = ( GetFloorHeight( GetUnitX( whichUnit ), GetUnitY( whichUnit ) ) + GetUnitFlyHeight( whichUnit ) )
set whichUnit = null
return z
endfunction
function SetUnitZ takes unit whichUnit, real z returns nothing
local boolean whichUnitHasNotAmrf = ( GetUnitAbilityLevel( whichUnit, 'Amrf' ) <= 0 ) and IsUnitType(whichUnit, UNIT_TYPE_FLYING) == false
if ( whichUnitHasNotAmrf ) then
call UnitAddAbility( whichUnit, 'Amrf' )
endif
call SetUnitFlyHeight( whichUnit, z - GetFloorHeight( GetUnitX( whichUnit ), GetUnitY( whichUnit ) ), 0.00 )
if ( whichUnitHasNotAmrf ) then
call UnitRemoveAbility( whichUnit, 'Amrf' )
endif
set whichUnit = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ShadowVortex initializer init
//*************************************************************************************************************//
// ShadowVortex v0.01 //
// by //
// cedi //
// //
// needs: TimerUtils by Vexorian //
// Bound Sentinel by Vexorian //
// Dummy Model by //
// Heights by cedi //
//*************************************************************************************************************//
//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.
private keyword Shadow
private keyword Main
private keyword Missile
globals
//ID of the spell
private constant integer SPELL_ID = 'A000'
//ID of your dummy
private constant integer DUMMY_ID = 'h000'
//Amount of shadows created each time.
private constant integer SHADOW_COUNT = 4
//Amount of missiles created in the nova.
private constant integer MISSILE_COUNT = 16
//Interval of the moves
private constant real TIMER_INTERVAL = 0.035
//Time between the nova and the absorbing
private constant real SHADOW_NOVA_INT = 1.00
//Speed of the shadows. In wc3 ms.
private constant real SPEED = 400.00
//Interval of picking
private constant real PICK_INT = 0.10
//Floating height of the shadows.
private constant real SHADOW_HEIGHT = 50.00
//Speed of the rotating in angle per second.
private constant real ANGLE_CHANGE = 120.00
//Start Height
private constant real START_Z = 500.00
//Start distance
private constant real SHADOW_DISTANCE = 550.00
//Min Dist
private constant real SHADOW_MIN_DIST = 5.00
//Interval of the shadow creation.
private constant real SHADOW_INTERVAL = 0.5
//On Damage sfx
private constant string DAMAGE_SFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
//Model of the shadows.
private constant string SHADOW_MODEL = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
//SYSTEM
private Shadow SHADOW
private Main MAIN
private Missile MISSILE
private group GROUP = CreateGroup()
endglobals
private function DAMAGE takes integer level returns real
return 100.00 + 50.00 * level
endfunction
private function AOE takes integer level returns real
return 55.00 + 5.00 * level
endfunction
private function RANGE takes integer level returns real
return 1000.00 + 200.00 * level
endfunction
private function NEEDED takes integer level returns integer
return 8 + 4 * level
endfunction
private function HIT_FUNC takes Missile m, unit target returns nothing
endfunction
//*************************************************************************************************************//
// !SYSTEM! //
//*************************************************************************************************************//
private function AngleBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
private function DistanceBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
private function AngleBetweenUnits takes unit u, unit u2 returns real
return bj_RADTODEG * Atan2(GetUnitY( u2 ) - GetUnitY( u ), GetUnitX( u2 ) - GetUnitX( u ))
endfunction
private function IsAliveAndUnitAndNotMagicImmune takes nothing returns boolean
return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
private function ParabolaZ2 takes real y0, real y1, real h, real d, real x returns real
local real A = (2*(y0+y1)-4*h)/(d*d)
local real B = (y1-y0-A*d*d)/d
return A*x*x + B*x + y0
endfunction
private function MissileControl takes nothing returns nothing
set MISSILE = GetTimerData( GetExpiredTimer() )
call MISSILE.control()
endfunction
private function ShadowControl takes nothing returns nothing
set SHADOW = GetTimerData( GetExpiredTimer() )
call SHADOW.control()
endfunction
private function MainControl takes nothing returns nothing
set MAIN = GetTimerData( GetExpiredTimer() )
call MAIN.control()
endfunction
private struct Missile
unit caster = null
unit u = null
integer level = 1
real vx = 0.00
real vy = 0.00
real range = 0.00
real maxrange = 0.00
real x = 0.00
real y = 0.00
real interval = 0.00
effect model = null
timer t = null
group g = null
private method pick takes nothing returns nothing
local unit u = null
call GroupEnumUnitsInRange( GROUP, .x, .y, AOE( .level ), Condition( function IsAliveAndUnitAndNotMagicImmune ) )
loop
set u = FirstOfGroup( GROUP )
exitwhen u == null
if IsUnitEnemy( u, GetOwningPlayer( .caster ) ) then
if not IsUnitInGroup( u, .g ) then
call GroupAddUnit( .g, u )
call DestroyEffect( AddSpecialEffectTarget( DAMAGE_SFX, u, "chest" ) )
call UnitDamageTarget( .caster, u, DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
call HIT_FUNC( this, u )
endif
endif
call GroupRemoveUnit( GROUP, u )
set u = null
endloop
endmethod
method onDestroy takes nothing returns nothing
set .caster = null
call DestroyEffect( .model )
set .model = null
call KillUnit( .u )
set .u = null
call ReleaseTimer( .t )
set .t = null
call GroupClear( .g )
call DestroyGroup( .g )
set .g = null
endmethod
method control takes nothing returns nothing
if GetWidgetLife( .u ) <= 0.405 then
call .destroy()
return
endif
set .range = .range - SPEED * TIMER_INTERVAL
if .range <= 0.00 then
call .destroy()
return
endif
set .x = .x + .vx
set .y = .y + .vy
call SetUnitX( .u, .x )
call SetUnitY( .u, .y )
set .interval = .interval + TIMER_INTERVAL
if .interval >= PICK_INT then
set .interval = 0.00
call .pick()
endif
endmethod
static method create takes Main m, real angle returns thistype
local thistype this = thistype.allocate()
set angle = angle * bj_DEGTORAD
set .caster = m.caster
set .level = m.level
set .vx = Cos( angle ) * SPEED * TIMER_INTERVAL
set .vy = Sin( angle ) * SPEED * TIMER_INTERVAL
set .x = GetUnitX( .caster ) + .vx
set .y = GetUnitY( .caster ) + .vy
set .range = RANGE( .level )
set .maxrange = .range
set .u = CreateUnit( GetOwningPlayer( .caster ), DUMMY_ID, .x, .y, angle * bj_RADTODEG )
set .model = AddSpecialEffectTarget( SHADOW_MODEL, .u, "origin" )
set .t = NewTimer()
set .g = CreateGroup()
call SetUnitZ( .u, SHADOW_HEIGHT )
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function MissileControl )
return this
endmethod
endstruct
private struct Shadow
Main main = 0
unit caster = null
unit u = null
real distance = 0.00
real angle = 0.00
real z = 0.00
effect model = null
timer t = null
method control takes nothing returns nothing
local real x
local real y
local real z
if GetWidgetLife( .caster ) <= 0.405 then
call .destroy()
return
endif
set .angle = .angle + ANGLE_CHANGE * TIMER_INTERVAL
set .distance = .distance - SPEED * TIMER_INTERVAL
if .distance <= 0.00 then
call .destroy()
return
endif
set x = GetUnitX( .caster ) + Cos( .angle * bj_DEGTORAD ) * .distance
set y = GetUnitY( .caster ) + Sin( .angle * bj_DEGTORAD ) * .distance
set z = ParabolaZ2( GetUnitZ( .caster ), .z, START_Z / 2.00, SHADOW_DISTANCE, .distance )
call SetUnitX( .u, x )
call SetUnitY( .u, y )
call SetUnitZ( .u, z )
if IsUnitInRange( .u, .main.caster, SHADOW_MIN_DIST ) then
call .main.addCharge()
call .destroy()
endif
endmethod
method onDestroy takes nothing returns nothing
call DestroyEffect( .model )
set .model = null
call ReleaseTimer( .t )
set .t = null
call KillUnit( .u )
set .u = null
set .caster = null
endmethod
static method create takes Main m, real angle returns thistype
local thistype this = thistype.allocate()
local real x = GetUnitX( m.caster )
local real y = GetUnitY( m.caster )
set .main = m
set .distance = SHADOW_DISTANCE
set .angle = angle
set .t = NewTimer()
set x = x + Cos( angle * bj_DEGTORAD ) * .distance
set y = y + Sin( angle * bj_DEGTORAD ) * .distance
set .u = CreateUnit( GetOwningPlayer( m.caster ), DUMMY_ID, x, y, 0.00 )
call SetUnitZ( .u, START_Z )
set .model = AddSpecialEffectTarget( SHADOW_MODEL, .u, "origin" )
set .caster = m.caster
set .z = GetUnitZ( .u )
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function ShadowControl )
return this
endmethod
endstruct
private struct Main
unit caster = null
integer level = 1
integer needed = 0
real interval = 0.00
timer t = null
boolean enough = false
method addCharge takes nothing returns nothing
set .needed = .needed - 1
if .needed <= 0 then
set .enough = true
set .interval = SHADOW_NOVA_INT
endif
endmethod
method newShadows takes nothing returns nothing
local integer i = 0
local real r = 360.00 / SHADOW_COUNT
loop
exitwhen i > SHADOW_COUNT
call Shadow.create( this, r * i )
set i = i + 1
endloop
endmethod
method nova takes nothing returns nothing
local integer i = 0
local real r = 360.00 / MISSILE_COUNT
loop
exitwhen i > MISSILE_COUNT
call Missile.create( this, r * i )
set i = i + 1
endloop
endmethod
method control takes nothing returns nothing
if GetWidgetLife( .caster ) <= 0.405 then
call .destroy()
endif
set .interval = .interval - TIMER_INTERVAL
if not .enough then
if .interval <= 0.00 then
call .newShadows()
set .interval = SHADOW_INTERVAL
endif
else
if .interval <= 0.00 then
call .nova()
call .destroy()
endif
endif
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer( .t )
set .t = null
endmethod
static method create takes unit caster returns thistype
local thistype this = thistype.allocate()
set .caster = caster
set .level = GetUnitAbilityLevel( caster, SPELL_ID )
set .needed = NEEDED( .level )
set .t = NewTimer()
set .interval = SHADOW_INTERVAL
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function MainControl )
return this
endmethod
endstruct
private function IsSpell takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call Main.create( GetTriggerUnit() )
endif
return false
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function IsSpell ) )
set t = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Revive_Units_Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == false
endfunction
function Trig_Revive_Units_Actions takes nothing returns nothing
call TriggerSleepAction( 10.00 )
call CreateUnit( GetOwningPlayer( GetTriggerUnit() ), GetUnitTypeId( GetTriggerUnit() ), GetUnitX( GetTriggerUnit() ), GetUnitY( GetTriggerUnit() ), GetUnitFacing( GetTriggerUnit() ) )
endfunction
//===========================================================================
function InitTrig_Revive_Units takes nothing returns nothing
set gg_trg_Revive_Units = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Revive_Units, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Revive_Units, Condition( function Trig_Revive_Units_Conditions ) )
call TriggerAddAction( gg_trg_Revive_Units, function Trig_Revive_Units_Actions )
endfunction