Name | Type | is_array | initial_value |
//***************************************************************************
//* *
//* CSCache 14.1 http://wc3campaigns.net/vexorian *
//* ¯¯¯¯¯¯¯ *
//* From attach variables to Dynamic Arrays, not forgetting the tables, *
//* CSData and the Pools, this is a pack of storage options *
//* *
//***************************************************************************
//===========================================================================
//! library CSCache initializer InitCSCache
//=================================================================================================
// CSCache globals:
//
globals
gamecache cs_cache = null
integer array cs_array1
integer array cs_array3
integer array cs_array2
integer array cs_freeindexes
integer array cs_pairx
integer array cs_pairy
integer array cs_freepairs
gamecache udg_cscache = null //udg_ for compat!
endglobals
//=================================================================================================
// Note: //! define macro commands are used accross the script, they are usually to be parsed by
// WEHelper, no //! define parser is really required, but if present it would improve the
// performance of some calls.
//
//=================================================================================================
// a.k.a H2I, changed name to CS_H2I to prevent conflicts with other systems (I intended this
// system to be easy to copy
//
function CS_H2I takes handle h returns integer
return h
return 0
endfunction
//==================================================================================================
// Bunch of other return bug exploiters
//
function CS_i2r takes integer i returns real
return i
return 0.
endfunction
function CS_h2r takes handle h returns real
return h
return 0.
endfunction
function CS_r2i takes real r returns integer
return r
return 0
endfunction
function CS_lx takes location l returns location
return GetLocationX(l)
return null
endfunction
function CS_ly takes location l returns location
return GetLocationY(l)
return null
endfunction
function CS_i2l takes integer l returns location
return l
return null
endfunction
//==================================================================================================
// location linked list kit
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// Thanks: Pipedream | No thanks: Blizzard (for lame bug)
//
// It is a great irony, but locations are only useful when you don't use them as points but as
// structs thanks to the return bug. They only allow 2 values so they are limited in comparission
// to gamecache and arrays (see bellow) still useful for single linked lists.
//
// These functions are what I call enough to use locations as single list nodes, X holds values and
// Y can just hold a location (or real) . The Get functions use bj globals to fix an odd operator
// bug that can happen after converting pointer to real into pointer to integer.
//
// The Set functions can be replaced by the Location() constructor, the MoveLocation() native and
// the return bug exploiters up there.
//
//===================================================================================================
// Constructors
//
function Location_IntLoc takes integer x , location y returns location
return Location(CS_i2r(x),CS_h2r(y))
endfunction
//! define Location_IntLoc(x,y) Location(CS_i2r(x),CS_h2r(y))
function Location_ObjectLoc takes handle x , location y returns location
return Location(CS_h2r(x),CS_h2r(y))
endfunction
//! define Location_ObjectLoc(x,y) Location(CS_h2r(x),CS_h2r(y))
function Location_LocLoc takes handle x , location y returns location
return Location(CS_h2r(x),CS_h2r(y))
endfunction
//! define Location_LocLoc(x,y) Location(CS_h2r(x),CS_h2r(y))
function Location_RealLoc takes real x , location y returns location
return Location(x,CS_h2r(y))
endfunction
//! define Location_RealLoc(x,y) Location(x,CS_h2r(y))
//====================================================================================================
// Combined assigments
//
function SetLocation_IntLoc takes location loc, integer x , location y returns nothing
call MoveLocation(loc,CS_i2r(x),CS_h2r(y))
endfunction
//! define SetLocation_IntLoc(loc,x,y) MoveLocation(loc,CS_i2r(x),CS_h2r(y))
function SetLocation_ObjectLoc takes location loc, handle x , location y returns nothing
call MoveLocation(loc,CS_h2r(x),CS_h2r(y))
endfunction
//! define SetLocation_ObjectLoc(loc,x,y) MoveLocation(loc,CS_h2r(x),CS_h2r(y))
function SetLocation_LocLoc takes location loc, handle x , location y returns nothing //Funny name
call MoveLocation(loc,CS_h2r(x),CS_h2r(y))
endfunction
//! define SetLocation_LocLoc(loc,x,y) MoveLocation(loc,CS_h2r(x),CS_h2r(y))
function SetLocation_RealLoc takes location loc, real x , location y returns nothing
call MoveLocation(loc,x,CS_h2r(y))
endfunction
//! define SetLocation_RealLoc(loc,x,y) MoveLocation(loc,x,CS_h2r(y))
//===================================================================================================
// Lack of SetLocationX / SetLocationY natives is kind of lame
//
function SetLocationX_Object takes location loc, handle val returns nothing
call MoveLocation(loc,CS_h2r(val),GetLocationY(loc))
endfunction
// Notice how define SetLocationX_Object(loc,v) MoveLocation(loc,CS_h2r(v),GetLocationY(loc))
// would have a chance of messing sometimes since it has 2 loc in the result.
function SetLocationX_Loc takes location loc, location val returns nothing //just name candy
call MoveLocation(loc,CS_h2r(val),GetLocationY(loc))
endfunction
function SetLocationX_Real takes location loc, real val returns nothing
call MoveLocation(loc,val,GetLocationY(loc))
endfunction
function SetLocationX_Int takes location loc, integer val returns nothing
call MoveLocation(loc,CS_i2r(val),GetLocationY(loc))
endfunction
function SetLocationY_Loc takes location loc, location val returns nothing
call MoveLocation(loc,GetLocationX(loc),CS_h2r(val))
endfunction
//==================================================================================================
// All right, crazyness that started with Attacheable variables, and had to continue with everything
// from tables, arrays and now this. Sorry I can't help itç
//
// The good thing about these functions is that they are safe, you won't deal with real->(int/handle)
// conversion related bugs thanks to the use of bj variables these functions do
//
function GetLocationX_Loc takes location loc returns location
set bj_enumDestructableCenter=CS_lx(loc)
return bj_enumDestructableCenter
endfunction
function GetLocationY_Loc takes location loc returns location
set bj_enumDestructableCenter=CS_ly(loc)
return bj_enumDestructableCenter
endfunction
function GetLocationX_Int takes location loc returns integer
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
endfunction
function GetLocationX_Unit takes location loc returns unit
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Item takes location loc returns item
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Effect takes location loc returns effect
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Lightning takes location loc returns lightning
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Widget takes location loc returns widget
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Object takes location loc returns handle
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Rect takes location loc returns rect
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Region takes location loc returns region
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_TimerDialog takes location loc returns timerdialog
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Destructable takes location loc returns destructable
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Trigger takes location loc returns trigger
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Timer takes location loc returns timer
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Group takes location loc returns group
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_TriggerAction takes location loc returns triggeraction
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Image takes location loc returns image
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Ubersplat takes location loc returns ubersplat
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
function GetLocationX_Sound takes location loc returns sound
set bj_forLoopAIndex=CS_r2i(GetLocationX(loc))
return bj_forLoopAIndex
return null
endfunction
//
//That should be all we needed to abuse Locations, Love lists.
//
// CSCache initializer :
function InitCSCache takes nothing returns nothing
call FlushGameCache(InitGameCache("cscache"))
set cs_cache=InitGameCache("cscache")
set udg_cscache = cs_cache
call ExecuteFunc("InitArrayIndexes")
call ExecuteFunc("Pool_SetupCharMap")
endfunction
//==================================================================================================
// CSData
// ¯¯¯¯¯¯
// CSDatas are like UserData in units and items, they are faster than gamecache unless you have more
// than 8191 handles in your map. In that case it would be a little slower but only for those
// handles. And if you have more than 8191 handles your map is too slow already anyways.
//
// Notice that for public spells or systems to be distributed you should only use these
// for private objects (those who the mapper would never have access to) If you are making something
// for your map you can use them wherever you want.
//
// Best to be used in conjunction to CSArrays so you just specify an array id for a handle.
//
// DO NOT USE THIS ON THESE HANDLE TYPES: -lightning, -ubersplat, -image, -texttag,
// -any 'argument' handle (like playerstate, damagetype, etc)
//
function SetCSData takes handle h, integer v returns nothing
local integer i=CS_H2I(h)-0x100000
if (i>=8191) then
call StoreInteger(cs_cache,"csdata",I2S(i),v)
else
set cs_array3[i]=v
endif
endfunction
function GetCSData takes handle h returns integer
local integer i=CS_H2I(h)-0x100000
if (i>=8191) then
//can't use Get without Set
return GetStoredInteger(cs_cache,"csdata",I2S(i))
endif
return cs_array3[i]
endfunction
//=================================================================================================================
// CS Pairs
// ¯¯¯¯¯¯¯¯
// This is a sub system to assist csarrays, you can use them but CSArrays of size 2 have the same functionality
// although cspairs are be faster their space is limited and will start using gamecache if abused
//
function NewPair takes integer x, integer y returns integer
local integer i
if (cs_freepairs[0]==0) then
set cs_freepairs[8190]=cs_freepairs[8190]+1
set i= cs_freepairs[8190]
else
set i= cs_freepairs[cs_freepairs[0]]
set cs_freepairs[0]=cs_freepairs[0]-1
endif
if (i>=8189) then //because we can only recycle up to 8189 (free pairs array uses indexes 0 and 8190 for other purposes)
call StoreInteger(cs_cache,"pairx",I2S(i),x)
call StoreInteger(cs_cache,"pairy",I2S(i),y)
else
set cs_pairx[i]=x
set cs_pairy[i]=y
endif
return i
endfunction
function DestroyPair takes integer id returns nothing
if (id>=8189) then
call FlushStoredInteger(cs_cache,"pairx",I2S(id))
call FlushStoredInteger(cs_cache,"pairy",I2S(id))
else
set cs_freepairs[0]=cs_freepairs[0]+1
set cs_freepairs[cs_freepairs[0]] = id
endif
endfunction
function SetPairXY takes integer id, integer x, integer y returns nothing
if (id>=8189) then
call StoreInteger(cs_cache,"pairx",I2S(id),x)
call StoreInteger(cs_cache,"pairy",I2S(id),y)
else
set cs_pairx[id]=x
set cs_pairy[id]=y
endif
endfunction
function SetPairX takes integer id, integer x returns nothing
if (id>=8189) then
call StoreInteger(cs_cache,"pairx",I2S(id),x)
else
set cs_pairx[id]=x
endif
endfunction
function SetPairY takes integer id, integer y returns nothing
if (id>=8189) then
call StoreInteger(cs_cache,"pairy",I2S(id),y)
else
set cs_pairy[id]=y
endif
endfunction
function GetPairX takes integer id returns integer
if (id>=8189) then
return GetStoredInteger(cs_cache,"pairy",I2S(id))
endif
return cs_pairx[id]
endfunction
function GetPairY takes integer id returns integer
if (id>=8189) then
return GetStoredInteger(cs_cache,"pairx",I2S(id))
endif
return cs_pairy[id]
endfunction
//=================================================================================================================
// CS Dynamic Arrays
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// Thanks: Pipedream, Peppar
//
// We can now create arrays in game! , also pass them as arguments or return values!
// a 1 length array is a pointer!
//
function Array_TryFree takes nothing returns nothing
local integer i
local integer N=cs_array1[0]
local integer k
local boolean cleaned=false
local integer loc
local integer q
local integer r
set i=cs_array1[146]
if (i>144) then
call TimerStart(GetExpiredTimer(),60.,false,function Array_TryFree)
return
endif
set loc=cs_freeindexes[i]
set q=0
loop
exitwhen (loc==0)
// we could just have used:
//set k=GetPairX(loc)
//set r=GetPairY(loc) But it is slower than direct usage:
if (loc>=8192) then
set k=GetStoredInteger(cs_cache,"pairx",I2S(loc))
set r=GetStoredInteger(cs_cache,"pairy",I2S(loc))
else
set k=cs_pairx[loc]
set r=cs_pairy[loc]
endif
if (k+i-1==N) then
//we found one we can remove from the list
set cleaned=true
//decrement N
set N=k-2
//Remove from the list:
if (q==null) then
//That was the first, update the array as well
set cs_freeindexes[i]=r
else
//Update the next of the previous one
//We could use : call SetPairY(q,,r) but it is slower
if (q>=8189) then
call StoreInteger(cs_cache,"pairy",I2S(q),r)
else
set cs_pairy[q]=r
endif
endif
if (r==null) then
//This was the last one, update it in the array as well
set cs_freeindexes[i+4096]=q
endif
call DestroyPair(loc)
set loc=q
endif
set q=loc
set loc=r
endloop
if (cleaned) then
set cs_array1[0]=N
set cs_array1[146]=1
else
set cs_array1[146]=cs_array1[i+1]
endif
call TimerStart(GetExpiredTimer(),0.2,false,function Array_TryFree)
endfunction
function InitArrayIndexes2 takes nothing returns nothing
local integer i=0
loop
exitwhen (i==8191)
set cs_pairx[i]=777
set cs_pairy[i]=777
set i=i+1
endloop
endfunction
function InitArrayIndexes takes nothing returns nothing
local integer i=0
local integer a=1
local integer b=1
local integer c
//By placing 777 there instead of 0 it is easier to recognize non correctly initialized bugs
loop
exitwhen (i== 8191)
set cs_array1[i]=777
set cs_array2[i]=777
set cs_array3[i]=777
//set cs_pairx[i]=777
//set cs_pairy[i]=777
set i=i+1
endloop
call ExecuteFunc("InitArrayIndexes2")
set cs_freeindexes[0]=0 //The stack for the table indexes.
set cs_freepairs[0]=0
set cs_freepairs[8190]=0
set i=1
loop
set c=a+b
set a=b
set b=c
exitwhen (b>144) //max size is 144
set cs_freeindexes[b]=0 //the first of the list
set cs_freeindexes[b+4096]=0 //the last of the list
loop
exitwhen (i>b)
set cs_array1[i]=b
set i=i+1
endloop
endloop
set cs_array1[i]=b //i is 145
set cs_array1[146]=1
set cs_array1[147]=101 //initial table index is 101
set cs_array1[0]=147
//index 0: Last used index
// 1 to 145 : Fibonacci sequence
// 146 : last check
// 147 : Table indexes check
//This has a good chance to compress the thing when necesary
call TimerStart(CreateTimer(),60.,false,function Array_TryFree)
endfunction
//=============================================================================================
// Create an array of size, max size is 144, if doinit is true it will put a bunch of zeros
// in the indexes
//
function NewArray takes integer size, boolean doinit returns integer
local integer i
local integer rsize=cs_array1[size]
local integer loc
set loc=cs_freeindexes[rsize]
if (loc!=0) then
set cs_freeindexes[rsize]= GetPairY(loc)
if (cs_freeindexes[rsize]==0) then
set cs_freeindexes[4096+rsize]=0
endif
set i=GetPairX(loc)
call DestroyPair(loc)
if (i==0) then
//this code was probably a good idea when we used locations for the free indexes list, now we use pairs which should not ever
//do this unless someone modiffied the pair array incorrectly
call BJDebugMsg("Caster System: Unexpected error (5): corrupt stack, attempt to recover "+I2S(rsize))
// recovering involves forgetting about the stack which got corrupted and start again from zero, it will leak
// and probably get slow due to usage of gamecache but it is better than the problems that a corrupt stack might cause
set cs_freeindexes[rsize]=0
set cs_freeindexes[4096+rsize]=0
return NewArray(size,doinit)
endif
else
//sz i i+1 i+2
//[ ][ ][ ][ ]
set i=cs_array1[0]+2
set cs_array1[0]=i+rsize-1
endif
//It used to store size in the index equal to the array's id
// but that required the get/set functions to increment 1 in every index
// calculation. Instead, making size the previous index to the array works
if (i<=8191) then
set cs_array1[i-1]=size
elseif (i<=16382) then
set cs_array2[i-8192]=size
else
call StoreInteger(cs_cache,I2S(-i),"size",size)
endif
if (not doinit) then
return i
endif
// 3
//[i][i+1][i+2]
set size=i+size-1
if (size>=16382) then
set size=16381
endif
loop
exitwhen (size<i) or (size<8191)
set cs_array2[size-8191]=0
set size=size-1
endloop
loop
exitwhen (size<i)
set cs_array1[size]=0
set size=size-1
endloop
//call DisplayTextToPlayer(GetLocalPlayer(),0,0,I2S(i))
return i
endfunction
//===============================================================================================================
// Remember to destroy arrays when you no longer need them, else new arrays will get slower after a bunch of
// arrays are active
//
function DestroyArray takes integer id returns nothing
local integer L
local integer loc
// local string k=I2S(-id)
local integer lstpace
if (id<=8191) then
set L=cs_array1[cs_array1[id-1]]
elseif (id<=16382) then
set L=cs_array1[cs_array2[id-8191]]
else
set L=cs_array1[GetStoredInteger(cs_cache,I2S(-id),"size")]
//No way you are gonna call DestroyArray without calling
//NewArray first, so we can use the gamecache variable directly instead
endif
set lstpace=id+L-1
call FlushStoredMission(cs_cache,I2S(-id))
if (lstpace>16382) then
if (lstpace==cs_array1[0]) then
//We just destroyed the array that happens to be at the end of the heap.
//Just get it back
set cs_array1[0]=id-2
set cs_array1[146]=1
else
//Add to the last
set loc=cs_freeindexes[L+4096]
if (loc==0) then
set loc=NewPair(id,0)
set cs_freeindexes[L]=loc
set cs_freeindexes[L+4096]=loc
else
set cs_freeindexes[L+4096]= NewPair(id,0)
//we could just use: call SetPairY(loc, cs_freeindexes[L+4096] ) //but that's slower
if (loc>=8189) then
call StoreInteger(cs_cache,"pairy",I2S(loc), cs_freeindexes[L+4096] )
else
set cs_pairy[loc]=cs_freeindexes[L+4096]
endif
endif
endif
elseif (lstpace==cs_array1[0]) then
//We just destroyed the array that happens to be at the end of the heap.
//Just get it back
set cs_array1[0]=id-2
set cs_array1[146]=1
else
set loc=cs_freeindexes[L]
set cs_freeindexes[L]=NewPair(id,loc)
if (loc==0) then
set cs_freeindexes[L+4096]=cs_freeindexes[L]
endif
endif
endfunction
//================================================================================================================
// Int Set/Get array usage prototypes.
//
// These are the actual functions, the rest are just the result of copy paste, if these functions are updated
// the other ones should be updated as well (They are just return bugged variations)
//
function SetArrayInt takes integer id, integer index, integer val returns nothing
set index=id+index
if (index<8191) then
set cs_array1[index]=val
elseif (index<16382) then
set cs_array2[index-8191]=val
else
call StoreInteger(cs_cache,I2S(-id),I2S(index),val)
endif
endfunction
function GetArrayInt takes integer id, integer index returns integer
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
endfunction
//================================================================================================================
// String Set/Get array
//
// Due String related return bug issues, these are forced to use gamecache
//
function SetArrayString takes integer id, integer index, string val returns nothing
call StoreString(cs_cache,I2S(-id),I2S(index),val)
endfunction
function GetArrayString takes integer id, integer index returns string
return GetStoredString(cs_cache,I2S(-id),I2S(index))
endfunction
//(Boolean is not needed)
//===================================================================================================
// Indexes of real types
//
function SetArrayReal takes integer id, integer index, real val returns nothing
set index=id+index
if (index<8191) then
set cs_array1[index]=CS_r2i(val)
elseif (index<16382) then
set cs_array2[index-8191]=CS_r2i(val)
else
call StoreInteger(cs_cache,I2S(-id),I2S(index),CS_r2i(val))
endif
endfunction
function GetArrayReal takes integer id, integer index returns real
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return 0.0
endfunction
//===================================================================================================
// <Indexes of handle types>
//
function SetArrayObject takes integer id, integer index, handle val returns nothing
set index=id+index
if (index<8191) then
set cs_array1[index]=CS_H2I(val)
elseif (index<16382) then
set cs_array2[index-8191]=CS_H2I(val)
else
call StoreInteger(cs_cache,I2S(-id),I2S(index),CS_H2I(val))
endif
endfunction
//
//
//Yep, I am crazy. But These are FASTER than using the function and a return bug exploiter separatedly.
function GetArrayObject takes integer id, integer index returns handle
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
function GetArrayWidget takes integer id, integer index returns widget
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
function GetArrayTimer takes integer id, integer index returns timer
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
function GetArrayUnit takes integer id, integer index returns unit
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
function GetArrayLoc takes integer id, integer index returns location
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
function GetArrayTrigger takes integer id, integer index returns trigger
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
function GetArrayTriggerAction takes integer id, integer index returns triggeraction
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
function GetArrayGroup takes integer id, integer index returns group
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
function GetArrayEffect takes integer id, integer index returns effect
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
function GetArrayItem takes integer id, integer index returns item
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
function GetArrayLightning takes integer id, integer index returns lightning
set index=id+index
if (index<8191) then
return cs_array1[index]
elseif (index<16382) then
return cs_array2[index-8191]
endif
return GetStoredInteger(cs_cache,I2S(-id),I2S(index))
return null
endfunction
//The rest are not used that much and they are a waste of space instead of a save of speed
//most of the times. THEY ARE STILL MUCH FASTER THAN GAMECACHE
function GetArrayRect takes integer id, integer index returns rect
return GetArrayInt(id,index)
return null
endfunction
function GetArrayRegion takes integer id, integer index returns region
return GetArrayInt(id,index)
return null
endfunction
function GetArrayTimerDialog takes integer id, integer index returns timerdialog
return GetArrayInt(id,index)
return null
endfunction
function GetArrayDestructable takes integer id, integer index returns destructable
return GetArrayInt(id,index)
return null
endfunction
function GetArrayImage takes integer id, integer index returns image
return GetArrayInt(id,index)
return null
endfunction
function GetArrayUbersplat takes integer id, integer index returns ubersplat
return GetArrayInt(id,index)
return null
endfunction
function GetArraySound takes integer id, integer index returns sound
return GetArrayInt(id,index)
return null
endfunction
// </Indexes of handle types>
// The horror!
//
//==========================================================================================================================
// Returns the size of an array (the specified by player one, not the actual size of it) should be useful.
//
function GetArraySize takes integer id returns integer
if (id<=8191) then
return cs_array1[id-1]
elseif (id<=16382) then
return cs_array2[id-8192]
endif
return GetStoredInteger(cs_cache,I2S(-id),"size")
endfunction
//===========================================================================================================================
// Returns an array that is an exact copy of the given array
//
function CloneArray takes integer id returns integer
local integer sz
local integer i
local integer sz2
local integer x
local integer y
if (id<=8191) then
set sz=cs_array1[id-1]
elseif (id<=16382) then
set sz=cs_array2[id-8192]
else
set sz=GetStoredInteger(cs_cache,I2S(-id),"size")
//No way you are gonna call DestroyArray without calling
//NewArray first, so we can use the gamecache variable directly instead
endif
set i=NewArray(sz,false)
set sz2=i+sz-1
set sz=id+sz-1
set x=i
set y=id
loop
exitwhen ((y>sz) or (y>=8191) or (x>=8191))
set cs_array1[x]=cs_array1[y]
set y=y+1
set x=x+1
endloop
loop
exitwhen ((y>sz) or (y>=8191) or (x>=16382))
set cs_array2[x-8191]=cs_array1[y]
set y=y+1
set x=x+1
endloop
loop
exitwhen ((y>sz) or (y>=8191))
call StoreInteger(cs_cache,I2S(-i),I2S(x-i),cs_array1[y])
set x=y+1
set y=y+1
endloop
//...
loop
exitwhen ((y>sz) or (y>=16382) or (x>=8191))
set cs_array1[x]=cs_array2[y-8191]
set y=y+1
set x=x+1
endloop
loop
exitwhen ((y>sz) or (y>=16382) or (x>=16382))
set cs_array2[x-8191]=cs_array2[y-8191]
set y=y+1
set x=x+1
endloop
loop
exitwhen ((y>sz) or (y>=16382))
call StoreInteger(cs_cache,I2S(-i),I2S(x-i),cs_array2[y-8191])
set y=y+1
set x=x+1
endloop
//...
loop
exitwhen ((y>sz) or (x>=8191))
set cs_array1[x]=GetStoredInteger(cs_cache,I2S(-id),I2S(y-id))
set y=y+1
set x=x+1
endloop
loop
exitwhen ((y>sz) or (x>=16382))
set cs_array2[x-8191]=GetStoredInteger(cs_cache,I2S(-id),I2S(y-id))
set y=y+1
set x=x+1
endloop
loop
exitwhen (y>sz)
call StoreInteger(cs_cache,I2S(-i),I2S(x-i),GetStoredInteger(cs_cache,I2S(-id),I2S(y-id)))
set y=y+1
set x=x+1
endloop
return i
endfunction
//==================================================================================================
// Attachable vars : Attacheable variables are what most other people call Handle Variables, they
// allow to relate data with any handle, using a label, and its value, the stuff auto flushes if
// the value is 0, false, "", or null .
//
// Differences between Attacheable variables and "Local Handle Variables" :
// - The names of the functions
// - The name of the function group does not cause confusion, it is difficult to say:
// "you should set local handle variables to null at the end of a function" since
// it sounds as if you were talking about the "Local Handle Variables"
// - And can work together with Tables.
//
// Gamecache stuff are NOT Case Sensitive, don't ever use "" for label (Crashes game!)
//
//
// Although locations and dynamic arrays are faster than gamecache, gamecache still keeps the flexibility
// Best thing to do in my opinion is to combine these options. By combining you can acquire gamecache
// flexibility and arrays/locs speed to solve a problem
//
//============================================================================================================
// For integers
//
function AttachInt takes handle h, string label, integer x returns nothing
if x==0 then
call FlushStoredInteger(cs_cache,I2S(CS_H2I(h)),label)
else
call StoreInteger(cs_cache,I2S(CS_H2I(h)),label,x)
endif
endfunction
function GetAttachedInt takes handle h, string label returns integer
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
endfunction
//=============================================================================================================
function AttachReal takes handle h, string label, real x returns nothing
if x==0 then
call FlushStoredReal(cs_cache,I2S(CS_H2I(h)),label)
else
call StoreReal(cs_cache,I2S(CS_H2I(h)),label,x)
endif
endfunction
function GetAttachedReal takes handle h, string label returns real
return GetStoredReal(cs_cache,I2S(CS_H2I(h)),label)
endfunction
//=============================================================================================================
function AttachBoolean takes handle h, string label, boolean x returns nothing
if not x then
call FlushStoredBoolean(cs_cache,I2S(CS_H2I(h)),label)
else
call StoreBoolean(cs_cache,I2S(CS_H2I(h)),label,x)
endif
endfunction
function GetAttachedBoolean takes handle h, string label returns boolean
return GetStoredBoolean(cs_cache,I2S(CS_H2I(h)),label)
endfunction
//=============================================================================================================
function AttachString takes handle h, string label, string x returns nothing
if ((x=="") or (x==null)) then
call FlushStoredString(cs_cache,I2S(CS_H2I(h)),label)
else
call StoreString(cs_cache,I2S(CS_H2I(h)),label,x)
endif
endfunction
function GetAttachedString takes handle h, string label returns string
return GetStoredString(cs_cache,I2S(CS_H2I(h)),label)
endfunction
//=============================================================================================================
function AttachObject takes handle h, string label, handle x returns nothing
if (x==null) then
call FlushStoredInteger(cs_cache,I2S(CS_H2I(h)),label)
else
call StoreInteger(cs_cache,I2S(CS_H2I(h)),label,CS_H2I(x))
endif
endfunction
function GetAttachedObject takes handle h, string label returns handle
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedWidget takes handle h, string label returns widget
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedRect takes handle h, string label returns rect
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedRegion takes handle h, string label returns region
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedTimerDialog takes handle h, string label returns timerdialog
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedUnit takes handle h, string label returns unit
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedItem takes handle h, string label returns item
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedEffect takes handle h, string label returns effect
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedDestructable takes handle h, string label returns destructable
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedTrigger takes handle h, string label returns trigger
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedTimer takes handle h, string label returns timer
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedGroup takes handle h, string label returns group
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedTriggerAction takes handle h, string label returns triggeraction
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedLightning takes handle h, string label returns lightning
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedImage takes handle h, string label returns image
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedUbersplat takes handle h, string label returns ubersplat
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedSound takes handle h, string label returns sound
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
function GetAttachedLoc takes handle h, string label returns location
return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label)
return null
endfunction
//============================================================================================================
function CleanAttachedVars takes handle h returns nothing
call FlushStoredMission(cs_cache,I2S(CS_H2I(h)))
endfunction
//! define CleanAttachedVars(h) FlushStoredMission(cs_cache,I2S(CS_H2I(h)))
//============================================================================================================
// Left for compat
function CleanAttachedVars_NoSets takes handle h returns nothing
call FlushStoredMission(cs_cache,I2S(CS_H2I(h)))
endfunction
//! define CleanAttachedVars_NoSets(h) FlushStoredMission(cs_cache,I2S(CS_H2I(h)))
//=============================================================================================
// Tables
//
// Tables are lame, the real name would be hash tables, they are just abbreviated usage
// of gamecache natives with the addition that you can also Copy the values of a table to
// another one, but don't expect it to be automatic, it must use a FieldData object to know
// which fields and of wich types to copy, Copying a table to another, with a lot of Fields,
// should surelly be lag friendly.
//
// The other thing about tables is that I can say that the Attached variables of a handle work
// inside a table and GetAttachmentTable which is just return bug and I2S , works to allow you
// to manipulate a handle's attached variables through a table.
//
// NewTable and DestroyTable were created to allow to create tables in the fly, but you can
// simply use strings for tables, but place the table names should be between "("")" for example
// "(mytable)" to avoid conflicts with other caster system stuff.
//
function NewTableIndex takes nothing returns integer
local integer loc=cs_freeindexes[0]
local integer i
if (loc!=0) then
set i=GetPairX(loc)
set cs_freeindexes[0]=GetPairY(loc)
call DestroyPair(loc)
return i
endif
set i=cs_array1[147]+1
set cs_array1[147]=i
return i
endfunction
function NewTable takes nothing returns string
local integer loc=cs_freeindexes[0]
local integer i
if (loc!=0) then
set i=GetPairX(loc)
set cs_freeindexes[0]=GetPairY(loc)
call DestroyPair(loc)
return I2S(i)
endif
set i=cs_array1[147]+1
set cs_array1[147]=i
return I2S(i)
endfunction
function GetAttachmentTable takes handle h returns string
return I2S(CS_H2I(h))
endfunction
//! define GetAttachmentTable(h) I2S(CS_H2I(h))
//============================================================================================================
function DestroyTable takes string table returns nothing
local integer i=S2I(table)
local integer n
call FlushStoredMission(cs_cache,table)
if ((i>100) and (i<1000000)) then //All right, more than 1000000 tables is just wrong.
if (i==cs_array1[147]) then
set cs_array1[147]=cs_array1[147]-1
else
set cs_freeindexes[0]= NewPair(i,cs_freeindexes[0])
endif
endif
endfunction
//============================================================================================================
function ClearTable takes string table returns nothing
call FlushStoredMission(cs_cache,table)
endfunction
//============================================================================================================
function SetTableInt takes string table, string field, integer val returns nothing
if (val==0) then
call FlushStoredInteger(cs_cache,table,field)
else
call StoreInteger(cs_cache,table,field,val)
endif
endfunction
function GetTableInt takes string table, string field returns integer
return GetStoredInteger(cs_cache,table,field)
endfunction
//! define GetTableInt(table,field) GetStoredInteger(cs_cache,table,field)
//============================================================================================================
function SetTableReal takes string table, string field, real val returns nothing
if (val==0) then
call FlushStoredReal(cs_cache,table,field)
else
call StoreReal(cs_cache,table,field,val)
endif
endfunction
function GetTableReal takes string table, string field returns real
return GetStoredReal(cs_cache,table,field)
endfunction
//! define GetTableReal(table,field) GetStoredReal(cs_cache,table,field)
//============================================================================================================
function SetTableBoolean takes string table, string field, boolean val returns nothing
if (not(val)) then
call FlushStoredBoolean(cs_cache,table,field)
else
call StoreBoolean(cs_cache,table,field,val)
endif
endfunction
function GetTableBoolean takes string table, string field returns boolean
return GetStoredBoolean(cs_cache,table,field)
endfunction
//! define GetTableBoolean(table,field) GetStoredBoolean(cs_cache,table,field)
//============================================================================================================
function SetTableString takes string table, string field, string val returns nothing
if (val=="") or (val==null) then
call FlushStoredString(cs_cache,table,field)
else
call StoreString(cs_cache,table,field,val)
endif
endfunction
function GetTableString takes string table, string field returns string
return GetStoredString(cs_cache,table,field)
endfunction
//! define GetTableString(table,field) GetStoredString(cs_cache,table,field)
//============================================================================================================
// You may ask why am I using thousands of functions instead of multi-use return bug exploiters? Well,
// these make the thing much easier to read (in my opinion) and it is also better in performance since we
// have less function calls (H2U(GetTableObject("table","unit"))) would be worse than GetTableUnit that is
// quite direct.
//
function SetTableObject takes string table, string field, handle val returns nothing
if (val==null) then
call FlushStoredInteger(cs_cache,table,field)
else
call StoreInteger(cs_cache,table,field,CS_H2I(val))
endif
endfunction
function GetTableObject takes string table, string field returns handle
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableWidget takes string table, string field returns widget
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableRect takes string table, string field returns rect
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableRegion takes string table, string field returns region
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableTimerDialog takes string table, string field returns timerdialog
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableUnit takes string table, string field returns unit
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableItem takes string table, string field returns item
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableEffect takes string table, string field returns effect
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableDestructable takes string table, string field returns destructable
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableTrigger takes string table, string field returns trigger
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableTimer takes string table, string field returns timer
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableGroup takes string table, string field returns group
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableTriggerAction takes string table, string field returns triggeraction
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableLightning takes string table, string field returns lightning
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableImage takes string table, string field returns image
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableUbersplat takes string table, string field returns ubersplat
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableSound takes string table, string field returns sound
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
function GetTableLoc takes string table, string field returns location
return GetStoredInteger(cs_cache,table,field)
return null
endfunction
//============================================================================================================
// Returns true if the fiel contains a value different from 0, false, null, or "" (depending on the type)
// it is worthless to use this with boolean, since it would be the same as reading the boolean value
//
function HaveSetField takes string table, string field, integer fieldType returns boolean
if (fieldType == bj_GAMECACHE_BOOLEAN) then
return HaveStoredBoolean(cs_cache,table,field)
elseif (fieldType == bj_GAMECACHE_INTEGER) then
return HaveStoredInteger(cs_cache,table,field)
elseif (fieldType == bj_GAMECACHE_REAL) then
return HaveStoredReal(cs_cache,table,field)
elseif (fieldType == bj_GAMECACHE_STRING) then
return HaveStoredString(cs_cache,table,field)
endif
return false
endfunction
//============================================================================================================
// Allows to copy a table to another one, but it needs a FieldData object to know which fields of which type
// it is supposed to copy.
//
function CopyTable takes integer FieldData, string sourceTable, string destTable returns nothing
local integer i=1
local string k=I2S(FieldData)
local string k2
local string k3
local integer n=GetStoredInteger(cs_cache,k,"N")
local integer t
loop
exitwhen (i>n)
set k2=I2S(i)
set t=GetStoredInteger(cs_cache,k,k2)
set k3=GetStoredString(cs_cache,k,k2)
if (t==bj_GAMECACHE_BOOLEAN) then
if (HaveStoredBoolean(cs_cache,sourceTable,k3)) then
call StoreBoolean(cs_cache,destTable,k3,GetStoredBoolean(cs_cache,sourceTable,k3))
else
call FlushStoredBoolean(cs_cache,destTable,k3)
endif
elseif (t==bj_GAMECACHE_INTEGER) then
if (HaveStoredInteger(cs_cache,sourceTable,k3)) then
call StoreInteger(cs_cache,destTable,k3,GetStoredInteger(cs_cache,sourceTable,k3))
else
call FlushStoredInteger(cs_cache,destTable,k3)
endif
elseif (t==bj_GAMECACHE_REAL) then
if (HaveStoredReal(cs_cache,sourceTable,k3)) then
call StoreReal(cs_cache,destTable,k3,GetStoredReal(cs_cache,sourceTable,k3))
else
call FlushStoredReal(cs_cache,destTable,k3)
endif
elseif (t==bj_GAMECACHE_STRING) then
if (HaveStoredString(cs_cache,sourceTable,k3)) then
call StoreString(cs_cache,destTable,k3,GetStoredString(cs_cache,sourceTable,k3))
else
call FlushStoredString(cs_cache,destTable,k3)
endif
endif
set i=i+1
endloop
endfunction
//=============================================================================================
// FieldData inherits from Table, was just designed to be used by CopyTable.
//
function FieldData_Create takes nothing returns integer
return NewTableIndex()
endfunction
//! define FieldData_Create NewTableIndex
//============================================================================================================
// valueType uses the same integer variables from blizzard.j :
// bj_GAMECACHE_BOOLEAN, bj_GAMECACHE_INTEGER, bj_GAMECACHE_REAL and bj_GAMECACHE_STRING
//
function FieldData_AddField takes integer fielddata, string field, integer valueType returns nothing
local string k=I2S(fielddata)
local integer n=GetStoredInteger(cs_cache,k,"N")+1
local string k2=I2S(n)
call StoreString(cs_cache,k,k2,field)
call StoreInteger(cs_cache,k,k2,valueType)
call StoreInteger(cs_cache,k,"N",n)
endfunction
//=============================================================================================
// Destroys Field Data
function FieldData_Destroy takes integer fielddata returns nothing
call DestroyTable(I2S(fielddata))
endfunction
//! define FieldData_Destroy(fielddata) DestroyTable(I2S(fielddata))
//=============================================================================================
// Pools
//
// A better name for pools would be sets, but by the time I made them I couldn't think of that
// name, besides the word set is already a JASS syntax word so it would have been problematic.
//
// Another naming failure is that values of a pool are called "items" but that conflicts with
// the word item that points to wc3 items, Pools can only store integer values, but if you want
// you can go and use the return bug on them.
//
function CreatePool takes nothing returns integer
local integer i=NewArray(34,false)
call SetArrayInt(i,0,0)
return i
endfunction
function ClearPool takes integer poolid returns nothing
call SetArrayInt(poolid,0,0) //[0:integer:n]
call FlushStoredMission(cs_cache,I2S(-poolid))
endfunction
function DestroyPool takes integer poolid returns nothing
call DestroyArray(poolid)
endfunction
//! define DestroyPool(p) DestroyArray(p)
function PoolAddItem takes integer poolid, integer value returns nothing
local integer n
local string k=I2S(-poolid)
local string vk="#"+I2S(value)
if not HaveStoredInteger(cs_cache,k,vk) then
set n=GetArrayInt(poolid,0)+1 //[0:integer:N]
call StoreInteger(cs_cache,k,vk,n)
if (n>33) then
call StoreInteger(cs_cache,k,I2S(n),value)
else
call SetArrayInt(poolid,n,value)
endif
call SetArrayInt(poolid,0,n) //[0:integer:N]
endif
endfunction
function PoolRemoveItem takes integer poolid, integer value returns nothing
local string k=I2S(-poolid)
local string vk="#"+I2S(value)
local integer p=GetStoredInteger(cs_cache,k,vk)
local integer n
if (p!=0) then
set n=GetArrayInt(poolid,0) //[0:integer:N]
call FlushStoredInteger( cs_cache, k, vk)
if (n>p) then
if (n>33) then
set vk=I2S(n)
set value=GetStoredInteger(cs_cache,k,vk)
call FlushStoredInteger(cs_cache,k,vk)
else
set value=GetArrayInt(poolid,n)
endif
call StoreInteger(cs_cache,k,"#"+I2S(value),p)
if (p>33) then
call StoreInteger(cs_cache,k,I2S(p),value)
else
call SetArrayInt(poolid,p,value)
endif
elseif (p>33) then
call FlushStoredInteger(cs_cache,k,I2S(p))
endif
call SetArrayInt( poolid,0,n - 1) //[0:integer:N]
endif
endfunction
//===================================================================================
function PoolGetItem takes integer poolid, integer itemn returns integer
if (itemn>33) then
return GetStoredInteger( cs_cache, I2S(-poolid), I2S(itemn))
endif
return GetArrayInt(poolid,itemn)
endfunction
//===================================================================================
function CountItemsInPool takes integer poolid returns integer
return GetArrayInt(poolid,0) //[0:integer:N]
endfunction
//! define CountItemsInPool(p) GetArrayInt(p,0)
//===================================================================================
// Removed : GetEnumPoolItem , ForPool and ForPool2 they are much worse than just
// using CountItemsInPool and PoolGetItem to iterate the pool
//
//===================================================================================
function GetFirstOfPool takes integer poolid returns integer
return GetArrayInt(poolid,1) //[1 is just the first of the pool]
endfunction
//! define GetFirstOfPool(p) GetArrayInt(p,1)
//===================================================================================
function PoolPickRandomItem takes integer poolid returns integer
local integer p=GetRandomInt( 1, GetArrayInt(poolid,0) )
if (p>33) then
return GetStoredInteger( cs_cache, I2S(-poolid), I2S(p))
endif
return GetArrayInt(poolid,p)
endfunction
//===================================================================================
function GetItemPositionInPool takes integer poolid, integer it returns integer
return GetStoredInteger( cs_cache, I2S(-poolid), "#"+I2S(it))
endfunction
//! define GetItemPositionInPool(p,i) GetStoredInteger( cs_cache, I2S(- (p) ), "#"+I2S(i))
//===================================================================================
function IsItemInPool takes integer poolid, integer it returns boolean
return(HaveStoredInteger( cs_cache, I2S(-poolid), "#"+I2S(it)) )
endfunction
//! define IsItemInPool(p,i) HaveStoredInteger( cs_cache, I2S(- (p) ), "#"+I2S(i))
//===================================================================================
// This had to be optimized for speed, if it was just a loop using the above functions
// that would have been too slow to be worth keeping. That's a bad thing about JASS
// it is such an slow language that code reusability always has the cost of speed
//
function PoolAddPool takes integer sourcepoolid, integer destpoolid returns nothing
local integer a=1
local integer n=GetArrayInt( sourcepoolid,0) //[0:integer:N]
local integer dn=GetArrayInt( destpoolid,0) //[0:integer:N]
local string sk=I2S(-sourcepoolid)
local string k=I2S(-destpoolid)
local integer v
local string vk
loop
exitwhen (a>n)
if (a>33) then
set v=GetStoredInteger(cs_cache,sk,I2S(a))
else
set v=GetArrayInt(sourcepoolid,a)
endif
set vk="#"+I2S(v)
if not HaveStoredInteger(cs_cache,k,vk) then
set dn=dn+1
call StoreInteger(cs_cache,k,vk,dn)
if (dn>33) then
call StoreInteger(cs_cache,k,I2S(dn),v)
else
call SetArrayInt(destpoolid,dn,v)
endif
endif
set a=a+1
endloop
call SetArrayInt(destpoolid,0,dn) //[0:integer:N]
endfunction
//=============================================================================================
// Oh darn, After making PoolAddPool I don't feel like writting this one
// All right I am at least make the get code
//
function PoolRemovePool takes integer sourcepoolid, integer destpoolid returns nothing
local integer a=1
local integer n=GetArrayInt( sourcepoolid,0) //[0:integer:N]
local integer v
local string sk=I2S(-sourcepoolid)
loop
exitwhen a>n
if (a>33) then
set v=GetStoredInteger(cs_cache,sk,I2S(a) )
else
set v=GetArrayInt(sourcepoolid,a)
endif
call PoolRemoveItem( destpoolid, v)
set a=a+1
endloop
endfunction
//===================================================================================
// Adds a tokenized string to a pool,
// Example: PoolAddS(udg_p, "1;2;3;4") will add to the udg_p pool : 1,2,3 and 4
//
function PoolAddS takes integer poolid, string s returns nothing
local integer i=0
local integer st
local string c
set s=s+";"
set st=0
loop
set c=SubString(s, i, i+1)
exitwhen (c == "") or (c == null)
if (c == ";") then
call PoolAddItem( poolid, S2I(SubString(s, st, i)) )
set st=i+1
endif
set i=i+1
endloop
endfunction
//===================================================================================
// Converts a tokenized string into a pool,
// Example: S2Pool( "1;2;3;4") will return a pool that has 1,2,3 and 4 inside
//
function S2Pool takes string s returns integer
local integer spool= CreatePool()
call PoolAddS(spool,s)
return spool
endfunction
//===================================================================================
// Does the opposite of S2Pool, debugging is a good use for this function.
//
function Pool2S takes integer P returns string
local integer N=CountItemsInPool(P)
local integer i
local string s
if (N>=1) then
set s=I2S(PoolGetItem(P,1) )
set i=2
else
return ""
endif
loop
exitwhen (i>N)
set s=s+";"+I2S(PoolGetItem(P,i))
set i=i+1
endloop
return s
endfunction
//=============================================================================================================
// Fixes a lame bug by blizzard related to the custom script section (The condition of the if statement might
// actually be true.
//
function Pool_Percent takes nothing returns string
if ("%"=="") then
return "%%"
endif
return "%"
endfunction
function Pool_SetupCharMap takes nothing returns nothing
local string cm=".................................!.#$"+Pool_Percent()+"&'()*+,-./0123456789:;<=>.@ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^_`abcdefghijklmnopqrstuvwxyz{|}~................................................................................................................................."
local integer i=0
local string c
if HaveStoredInteger(cs_cache,"charmap_upper","A") then
return
endif
loop
set c=SubString(cm,i,i+1)
exitwhen (c==null) or (c=="")
if (c!=".") then
if c==StringCase(c,true) then
call StoreInteger(cs_cache,"charmap_upper",c,i)
else
call StoreInteger(cs_cache,"charmap_lower",c,i)
endif
endif
set i=i+1
endloop
endfunction
function Pool_Rawcode2Int takes string s returns integer
local string c
local integer i=0
local integer r=0
loop
exitwhen i>3
set c=SubString(s,i,i+1)
set r=r*256
if c==StringCase(c,true) then
set r=r+GetStoredInteger(cs_cache,"charmap_upper",c)
else
set r=r+GetStoredInteger(cs_cache,"charmap_lower",c)
endif
set i=i+1
endloop
return r
endfunction
function PoolAddRawcodes_thread takes nothing returns nothing
//Threaded because I don't want it to halt execution for no reason
//
local string s=bj_lastPlayedMusic
local integer poolid=bj_groupEnumTypeId
local string c
local integer i=0
local integer st=0
set s=s+";"
loop
set c=SubString(s, i, i+1)
exitwhen (c == "") or (c == null)
if c == ";" then
call PoolAddItem(poolid, Pool_Rawcode2Int(SubString(s,st,i) ))
set st=i+1
endif
set i=i+1
endloop
endfunction
//=====================================================================================================================
// Adds a string of tokenized rawcodes to a pool
// Example: PoolAddRawcodes(udg_p,"A000;A001") will add 'A000' and 'A001' to the pool
//
// (Saves some lines, but is not as good efficiency wise)
//
function PoolAddRawcodes takes integer poolid, string s returns nothing
local string b=bj_lastPlayedMusic
set bj_groupEnumTypeId=poolid
set bj_lastPlayedMusic=s
call ExecuteFunc("PoolAddRawcodes_thread")
set bj_lastPlayedMusic=b
endfunction
//===================================================================================================================
// Converts a tokenized string of rawcodes into a pool,
// Example: Rawcodes2Pool( "A000;A001;AHbz;S000") will return a pool that has 'A000,'A001','AHbx' and 'S000' inside
//
// (Saves some lines, but is not as good efficiency wise)
//
function Rawcodes2Pool takes string s returns integer
local integer spool= CreatePool()
call PoolAddRawcodes(spool,s)
return spool
endfunction
//===================================================================================================================
// A subproduct of the Pool's Rawcode support is that we can easily have this function so I am including it even if
// it has nothing to do with data storage.
//
// takes "Aloc" and converts it into 'Aloc'
// it is different to the Pool_Rawcode2Int function in that it is safe to use it when it is the first CSCache
// function ever used. But it is a little slower (wc3mapoptimizer should make it as fast though)
//
function CS_Rawcode2Int takes string s returns integer
local string c
local integer i=0
local integer r=0
loop
exitwhen i>3
set c=SubString(s,i,i+1)
set r=r*256
if c==StringCase(c,true) then
set r=r+GetStoredInteger(cs_cache,"charmap_upper",c)
else
set r=r+GetStoredInteger(cs_cache,"charmap_lower",c)
endif
set i=i+1
endloop
return r
endfunction
function CSCache takes nothing returns gamecache
return cs_cache //Left for compat.
endfunction
//! endlibrary
//Forced by WE
function InitTrig_CSCache takes nothing returns nothing
endfunction
//! library CSSafety requires CSCache
//******************************************************************************************
//*
//* CSSafety 14.1
//* ¯¯¯¯¯¯¯¯
//*
//* Utilities to make things safer. Currently this simply includes a timer recycling
//* Stack. Once you replace CreateTimer with NewTimer and DestroyTimer with ReleaseTimer
//* you no longer have to care about setting timers to null nor about timer related issues
//* with the handle index stack.
//*
//******************************************************************************************
//==========================================================================================
globals
private timer array T
private integer N = 0
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
local timer t
if (N==0) then
set t= CreateTimer()
else
set N=N-1
set t=T[N]
endif
debug call AttachBoolean(t,"released",false)
return t
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
call PauseTimer(t)
if (N==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
debug if (GetAttachedBoolean(t,"released")) then
debug call BJDebugMsg("BUGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
debug else
debug call AttachBoolean(t,"released",true)
debug endif
set T[N]=t
set N=N+1
endif
endfunction
//! endlibrary
//Forced by WE
function InitTrig_CSSafety takes nothing returns nothing
endfunction
//! library CasterSystem initializer InitCasterSystem, needs CSCache, CSSafety
//***************************************************************************
//* *
//* Caster System 14.1 *
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ http://wc3campaigns.net/vexorian *
//* Requires: *
//* ¯¯¯¯¯¯¯¯¯ *
//* *
//* - The CSCache Module *
//* *
//* - The caster unit from this map Can be found in this map's unit editor *
//* ( Custom Units\Neutral Passive\Units\Caster ) *
//* *
//* ( Update the cs_CasterUnitId constant next:) *
//* *
//* - the war3mapImported\dummy.mdx imported file (find it in this map) *
//* *
//***************************************************************************
//====================================================================================================================================================================
// Caster System Configuration constants :
//
globals
//
// Caster Unit type rawcode (changes betwen maps, always use it inside '')
//
constant integer cs_CasterUnitId = 'e000'
// cs_TIMER_CYCLE : Cycle value for the projectile movement in seconds (Each 0.04 the projectiles get moved)
// 0.01 looks smooth but is lag friendly
// 0.025 looks smooth and probably matches wc3's frame rate (so in theory, lower values than it are not needed)
// 0.1 looks horrible but is not laggy
// 0.04 is decent for the human eye and very efficient.
// 0.035 is ... well, a little smoother than 0.04
// 0.05 would be an improvement in efficiency but probably doesn't look too well )
//
constant real cs_TIMER_CYCLE = 0.035
//
// The eat tree ability, don't need to change this rawcode unless you modiffied that ability in your map, in that case copy it, reset the copied one and use its rawcode here.
//
constant integer cs_DamageTreeDetectorId = 'Aeat'
//
// Medivh's Crow form ability, don't need to change this rawcode unless you
// modiffied that ability in your map, in that case copy it, reset the copied one and use its rawcode here:
//
constant integer cs_FlyingHeightHack = 'Amrf'
//
// This must point to an inventory ability with 6 slots that does not add bonuses, you don't need one unless
// the caster system item hiding functions are used in your map
//
constant integer cs_DummyInventory_Id = 'null'
//
//Maximum collision size in your map - Affects the caster system's area cast/damage functions
//
constant real cs_MaxUnitCollisionSize = 55.0
//
// Next are default attack and damage types for the old caster system functions or when using 0 as damageoptions
//
constant attacktype cs_DefaultAttackType = ATTACK_TYPE_CHAOS
constant damagetype cs_DefaultDamageType = DAMAGE_TYPE_UNIVERSAL
//
// cs_InitialCastersNumber: Number of casters to create on map init:
//
constant integer cs_InitialCastersNumber = 12
endglobals
//
//=================================================================================================
// Caster System script:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// Note: many //! defines are distributed along the script, these defines are optional, and are
// just an optimization, which means that if saved in WEHelper , the caster system will be able to
// replace wrapper versions of functions to direct calls and save some overhead.
//
//=================================================================================================
// main Caster System global variables:
//
globals
//old ones (udg_ preffix forced for compat ( )
unit udg_currentcaster = null
real array udg_castervars
group udg_casters = null
integer udg_currentabi = 0
unit udg_currenthurter = null
real udg_delayhack = 0.
location udg_sourcehack = null
//--
integer array cs_missiles
integer cs_missilecount = 0
timer cs_movementtimer = CreateTimer()
boolean cs_movementtimer_active = false
endglobals
//=================================================================================================
function CS_Rawcode2Real takes integer i returns real
return i
return 0.
endfunction
function CS_LoadRawcodeFromReal takes integer n returns integer
return udg_castervars[n]
return 0
endfunction
function CS_CopyGroup takes group g returns group
set bj_groupAddGroupDest=CreateGroup()
call ForGroup(g, function GroupAddGroupEnum)
return bj_groupAddGroupDest
endfunction
function CS_IsUnitVisible takes unit u, player p returns boolean
return IsUnitVisible(u,Player(bj_PLAYER_NEUTRAL_VICTIM)) or IsUnitVisible(u,p)
endfunction
globals
constant real cs_RectLimitOffSet = 50.0
real cs_game_maxx
real cs_game_maxy
real cs_game_miny
real cs_game_minx
endglobals
function CS_SafeXY_Init takes nothing returns nothing
set cs_game_maxx=GetRectMaxX(bj_mapInitialPlayableArea)-cs_RectLimitOffSet
set cs_game_maxy=GetRectMaxY(bj_mapInitialPlayableArea)-cs_RectLimitOffSet
set cs_game_miny=GetRectMinY(bj_mapInitialPlayableArea)+cs_RectLimitOffSet
set cs_game_minx=GetRectMinX(bj_mapInitialPlayableArea)+cs_RectLimitOffSet
endfunction
function CS_SafeX takes real x returns real
if (x<cs_game_minx) then
return cs_game_minx
elseif (x>cs_game_maxx) then
return cs_game_maxx
endif
return(x)
endfunction
function CS_SafeY takes real y returns real
if (y<cs_game_miny) then
return cs_game_minx
elseif (y>cs_game_maxy) then
return cs_game_maxy
endif
return(y)
endfunction
function CS_MoveUnit takes unit u, real x, real y returns boolean
local boolean b=true
if (x<cs_game_minx) then
set b=false
elseif (x>cs_game_maxx) then
set b=false
elseif (y>cs_game_maxy) then
set b=false
elseif (y<cs_game_miny) then
set b=false
endif
if (b) then
call SetUnitX(u, x)
call SetUnitY(u, y)
endif
return b
endfunction
function CS_MoveUnitLoc takes unit u, location loc returns boolean
return CS_MoveUnit(u,GetLocationX(loc),GetLocationY(loc))
endfunction
//==================================================================================================
function CS_EnumUnitsInAOE_Filter takes nothing returns boolean
return IsUnitInRangeLoc(GetFilterUnit(), bj_enumDestructableCenter ,bj_enumDestructableRadius)
endfunction
//==================================================================================================
// Use this version when you only have coordinates of the point.
//
function CS_EnumUnitsInAOE takes group g, real x, real y, real area, boolexpr bx returns nothing
local boolexpr cond
local boolexpr aux=Condition(function CS_EnumUnitsInAOE_Filter)
if (bx==null) then
set cond=aux
else
set cond=And(aux,bx)
endif
set bj_enumDestructableCenter=Location(x,y)
set bj_enumDestructableRadius=area
call GroupEnumUnitsInRange(g,x,y,cs_MaxUnitCollisionSize+area,cond)
call DestroyBoolExpr(cond)
if (bx!=null) then
call DestroyBoolExpr(aux)
endif
call RemoveLocation(bj_enumDestructableCenter)
set aux=null
set cond=null
endfunction
//==================================================================================================
// Use this version whenever you already have a location for that point, to save some steps
//
function CS_EnumUnitsInAOELoc takes group g, location loc, real area, boolexpr bx returns nothing
local boolexpr cond
local boolexpr aux=Condition(function CS_EnumUnitsInAOE_Filter)
if (bx==null) then
set cond=aux
else
set cond=And(aux,bx)
endif
set bj_enumDestructableCenter=loc
set bj_enumDestructableRadius=area
call GroupEnumUnitsInRangeOfLoc(g,loc,cs_MaxUnitCollisionSize+area,cond)
call DestroyBoolExpr(cond)
if (bx!=null) then
call DestroyBoolExpr(aux)
endif
set aux=null
set cond=null
endfunction
//==================================================================================================
// Angle Calculations
//
// I decided to add them to the caster system, because I found myself using them everytime, I am
// trying to convert the caster system into a Spell Development Framework (hehe)
//
//=================================================================================================
// Returns the angle distance between angles a1 and a2 (For example: a1=30 , a2=60 , return= 30 )
//
function Angles_GetAngleDifference takes real a1, real a2 returns real
local real x
set a1=ModuloReal(a1,360)
set a2=ModuloReal(a2,360)
if a1>a2 then
set x=a1
set a1=a2
set a2=x
endif
set x=a2-360
if a2-a1 > a1-x then
set a2=x
endif
set x=a1-a2
if (x<0) then
return -x
endif
return x
endfunction
//=================================================================================================
// Returns the mid angle between a1 and a2 (For example: a1=30 , a2=60 , return= 45 )
//
function Angles_GetMidAngle takes real a1, real a2 returns real
local real x
set a1=ModuloReal(a1,360)
set a2=ModuloReal(a2,360)
if a1>a2 then
set x=a1
set a1=a2
set a2=x
endif
set x=a2-360
if a2-a1 > a1-x then
set a2=x
endif
return (a1+a2)/2
endfunction
//=================================================================================================
// Makes angle a1 advance i units towards angle a2 (For Example: a1=30, a2=60, i=10, return=40 )
//
function Angles_MoveAngleTowardsAngle takes real a1, real a2, real i returns real
local real x
set a1=ModuloReal(a1,360)
set a2=ModuloReal(a2,360)
if a1>a2 then
set x=a1-360
if a1-a2 > a2-x then
set a1=x
endif
else
set x=a2-360
if a2-a1 > a1-x then
set a2=x
endif
endif
if a1>a2 then
set x=a1-i
if x<=a2 then
return a2
endif
return x
endif
set x=a1+i
if x>=a2 then
return a2
endif
return x
endfunction
//=================================================================================================
// Returns true if the angle 'angle' is between 'angle1' and 'angle2'
//
function Angles_IsAngleBetweenAngles takes real angle, real angle1, real angle2 returns boolean
local real x
set angle=ModuloReal(angle,360)
set angle1=ModuloReal(angle1,360)
set angle2=ModuloReal(angle2,360)
if (angle1>angle2) then
set x=angle1
set angle1=angle2
set angle2=x
endif
if (angle2-angle1)>(angle1 - (angle2-360)) then
set angle2=angle2-360
if angle > 180 then
set angle=angle-360
endif
return angle>=angle2 and angle<=angle1
endif
return (angle>=angle1) and (angle<=angle2)
endfunction
//====================================================================================================================================================================
function CreateCaster takes real fac, real x , real y returns unit
local unit m
if (x!=0) then
set x=CS_SafeX(x)
endif
if (y!=0) then
set y=CS_SafeY(y)
endif
set m=CreateUnit( Player(15), cs_CasterUnitId, x ,y ,fac)
call UnitAddAbility(m, 'Aloc')
call UnitAddAbility(m, cs_FlyingHeightHack)
call UnitRemoveAbility(m, cs_FlyingHeightHack )
set udg_currentcaster=m
set m=null
return udg_currentcaster
endfunction
function AddCasterFacing takes real fac returns unit
return CreateCaster(fac,0,0)
endfunction
function AddCaster takes nothing returns unit
return CreateCaster(0,0,0)
endfunction
///! define AddCaster() CreateCaster(0,0,0) maybe in a future wehelper version this works
//====================================================================================================================================================================
function CS_KillTrigger takes trigger t returns nothing
if (t!=null) then
call TriggerRemoveAction(t,GetAttachedTriggerAction(t,"ac"))
call CleanAttachedVars(t)
call DestroyTrigger(t)
endif
endfunction
function CS_KillTimer takes timer t returns nothing
if (t!=null) then
call PauseTimer(t)
call CleanAttachedVars(t)
call DestroyTimer(t)
endif
endfunction
//====================================================================================================================================================================
function CreateCasters takes integer n returns nothing
local integer a=0
local unit c
loop
exitwhen a>=n
set c=CreateCaster(0,0,0)
call GroupAddUnit( udg_casters, c)
set a=a+1
endloop
set c=null
endfunction
private function InitCasterSystem takes nothing returns nothing
set udg_casters=CreateGroup()
call CS_SafeXY_Init()
call CreateCasters(cs_InitialCastersNumber)
set udg_castervars[100]=-1
set udg_castervars[101]=-1
set udg_castervars[102]=-1
set udg_castervars[103]=-1
set udg_castervars[104]=-1
set cs_dmg_caster=CreateCaster(0.,0.,0.)
call UnitRemoveAbility(cs_dmg_caster,'Aloc') //Otherwise the units would flee like crazy
endfunction
//====================================================================================================================================================================
function GetACaster takes nothing returns unit
set udg_currentcaster=FirstOfGroup( udg_casters)
if udg_currentcaster == null then
set udg_currentcaster=CreateCaster(0,0,0)
endif
call GroupRemoveUnit( udg_casters,udg_currentcaster)
call SetUnitState( udg_currentcaster, UNIT_STATE_MANA, 1000)
return udg_currentcaster
endfunction
//====================================================================================================================================================================
function Caster_SetZAngle takes unit caster, real ang returns nothing
local real a=(ModuloReal(GetUnitFacing(caster),360)*bj_DEGTORAD)
local real x
set ang=ModuloReal(ang,360)
if ( ang == 90 ) then
set ang = 89
endif
if ( ang == 270 ) then
set ang = 271
endif
if (ang>90) and (ang<270) then
set x=-1
else
set x=1
endif
set ang=ang*bj_DEGTORAD
call SetUnitLookAt(caster,"Bone_Chest",caster, 10000.0*Cos(a)*Cos(ang), 10000.0*Sin(a)*Cos(ang), x*(10000.0*Tan(ang)+90.0) )
endfunction
//====================================================================================================================================================================
function Caster_SetZAngle2 takes unit caster, integer ang returns nothing
call SetUnitAnimationByIndex(caster,ang+90) //Thanks infrane!
endfunction
//====================================================================================================================================================================
function RecycleCaster takes unit caster returns nothing
if GetWidgetLife(caster)>=0.405 then
call ResetUnitLookAt(caster)
call SetUnitOwner( caster, Player(15), true)
call SetUnitVertexColor( caster, 255,255,255,255)
call SetUnitScale( caster, 1,1,1)
call SetUnitTimeScale( caster, 1)
call SetUnitMoveSpeed( caster, 522)
call SetUnitFlyHeight( caster, 0,0)
call UnitAddAbility(caster, 'Aloc')
call SetUnitTurnSpeed( caster, 0.6)
call GroupAddUnit( udg_casters, caster)
endif
endfunction
function RecycleCaster_Light takes unit caster returns nothing
if GetWidgetLife(caster)>=0.405 then
call SetUnitOwner( caster, Player(15), true)
call GroupAddUnit( udg_casters, caster)
endif
endfunction
function RecicleCaster takes unit caster returns nothing
call RecycleCaster(caster)
endfunction
function RecicleCaster_Light takes unit caster returns nothing
call RecycleCaster_Light(caster)
endfunction
//! define RecicleCaster RecycleCaster
//! define RecicleCaster_Light RecycleCaster_Light
globals
constant integer cs_recy_CASTER =0
constant integer cs_recy_ABIL =1
constant integer cs_recy_ARRAYSIZE=2
endglobals
function CasterRecycleTimed_X takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer k=GetCSData(t)
local unit c=GetArrayUnit(k, cs_recy_CASTER )
local integer a=GetArrayInt(k, cs_recy_ABIL )
if (a!=0) then
call UnitRemoveAbility(c,a)
endif
call RecycleCaster(c)
call DestroyArray(k)
call ReleaseTimer(t)
set c=null
endfunction
function CasterRecycleTimed takes unit caster, integer abi, real delay returns nothing
local timer t=NewTimer()
local integer k=NewArray(cs_recy_ARRAYSIZE,false)
call SetArrayObject(k, cs_recy_CASTER ,caster)
call SetArrayInt (k, cs_recy_ABIL ,abi)
call SetCSData(t,k)
call TimerStart(t,delay,false,function CasterRecycleTimed_X)
endfunction
function CasterWaitForEndCast takes nothing returns nothing
local unit caster=udg_currentcaster
local integer abilid=udg_currentabi
local real delay=udg_castervars[0]
local boolean activeability=(udg_castervars[1]>0)
loop
exitwhen GetUnitCurrentOrder(caster) == 0
call TriggerSleepAction(0)
endloop
if (delay>0) then
if activeability then
call CasterRecycleTimed(caster,abilid,delay)
else
call UnitRemoveAbility( caster, abilid)
call CasterRecycleTimed(caster,0,delay)
endif
else
call UnitRemoveAbility( caster, abilid)
call RecycleCaster(caster)
endif
set caster=null
endfunction
function RecycleCasterAfterCastEx takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing
set udg_castervars[0]=delaytime
set udg_castervars[1]=IntegerTertiaryOp(activeability,1,0)
set udg_currentabi=abilid
set udg_currentcaster=caster
call ExecuteFunc("CasterWaitForEndCast" )
endfunction
function RecicleCasterAfterCastEx takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing
call RecycleCasterAfterCastEx(caster,delaytime,abilid,activeability)
endfunction
//! define RecicleCasterAfterCastEx RecycleCasterAfterCastEx
function CasterWaitForEndCast_Light takes nothing returns nothing
local unit caster=udg_currentcaster
local integer abilid=udg_currentabi
local real delay=udg_castervars[0]
local boolean activeability=(udg_castervars[1]>0)
loop
exitwhen GetUnitCurrentOrder(caster) == 0
call TriggerSleepAction(0)
endloop
if (delay>0) then
if activeability then
call CasterRecycleTimed(caster,abilid,delay)
else
call UnitRemoveAbility( caster, abilid)
call CasterRecycleTimed(caster,0,delay)
endif
else
call UnitRemoveAbility( caster, abilid)
call RecycleCaster_Light(caster)
endif
set caster=null
endfunction
function RecycleCasterAfterCastEx_Light takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing
set udg_castervars[0]=delaytime
set udg_castervars[1]=IntegerTertiaryOp(activeability,1,0)
set udg_currentabi=abilid
set udg_currentcaster=caster
call ExecuteFunc("CasterWaitForEndCast_Light" )
endfunction
function RecicleCasterAfterCastEx_Light takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing
call RecycleCasterAfterCastEx_Light(caster,delaytime,abilid,activeability)
endfunction
function RecicleCasterAfterCast takes unit caster, integer abilid returns nothing
call RecycleCasterAfterCastEx(caster,udg_delayhack,abilid,false)
endfunction
function RecycleCasterAfterCast takes unit caster, integer abilid returns nothing
call RecycleCasterAfterCastEx(caster,udg_delayhack,abilid,false)
endfunction
//! RecicleCasterAfterCastEx_Light RecycleCasterAfterCastEx_Light
//! define RecicleCasterAfterCast(c,a) RecycleCasterAfterCastEx(c,udg_delayhack,a,false)
//! define RecycleCasterAfterCast(c,a) RecycleCasterAfterCastEx(c,udg_delayhack,a,false)
//====================================================================================================================================================================
function PreloadAbility takes integer abilid returns integer
local unit u=FirstOfGroup(udg_casters)
if u==null then
set u=GetACaster()
call UnitAddAbility(u, abilid)
call UnitRemoveAbility(u, abilid)
call RecycleCaster_Light( u)
else
call UnitAddAbility(u, abilid)
call UnitRemoveAbility(u, abilid)
endif
set u=null
return abilid
endfunction
//====================================================================================================================================================================
function CasterCastAbilityEx takes player owner, real x, real y, real z, integer abilid, integer level, string order, widget target, real delay returns unit
local unit caster=GetACaster()
local boolean done=false
call SetUnitOwner( caster, owner, false)
call UnitAddAbility( caster, abilid)
call SetUnitAbilityLevel(caster,abilid,level)
call CS_MoveUnit( caster, x,y)
call SetUnitFlyHeight(caster,z,0)
if S2I(order) != 0 then
set done=IssueTargetOrderById( caster, S2I(order), target )
else
set done=IssueTargetOrder( caster, order, target )
endif
if (delay<=0) or not(done) then
call UnitRemoveAbility( caster, abilid)
call RecycleCaster_Light( caster)
else
call RecycleCasterAfterCastEx_Light(caster, delay, abilid, true)
endif
set udg_currentcaster=caster
set caster=null
return udg_currentcaster
endfunction
//====================================================================================================================================================================
function CasterCastAbilityExLoc takes player owner, location loc, real z, integer abilid, integer level, string order, widget target, real delay returns unit
return CasterCastAbilityEx(owner,GetLocationX(loc),GetLocationY(loc),z,abilid,level,order,target,delay)
endfunction
//====================================================================================================================================================================
function CasterCastAbilityLevel takes player owner, integer abilid, integer level, string order, widget target, boolean instant returns unit
local real x
local real y
local real d
if udg_sourcehack!=null then
set x=GetLocationX(udg_sourcehack)
set y=GetLocationY(udg_sourcehack)
else
set x=GetWidgetX(target)
set y=GetWidgetY(target)
endif
if not(instant) then
set d=udg_delayhack+0.01
else
set d=0
endif
return CasterCastAbilityEx(owner,x,y,0,abilid,level,order,target,d)
endfunction
//====================================================================================================================================================================
function CasterCastAbility takes player owner, integer abilid, string order, widget target, boolean instant returns unit
return CasterCastAbilityLevel( owner, abilid, 1, order, target, instant )
endfunction
//====================================================================================================================================================================
function CasterCastAbilityPointEx takes player owner, real x1, real y1, real z1, integer abilid, integer level, string order, real x2, real y2, real delay returns unit
local unit caster=GetACaster()
call SetUnitOwner( caster, owner, false)
call UnitAddAbility( caster, abilid)
call SetUnitAbilityLevel(caster,abilid,level)
call CS_MoveUnit( caster, x1, y1)
call SetUnitFlyHeight(caster,z1,0)
if S2I(order) != 0 then
if not IssuePointOrderById( caster, S2I(order), x2,y2 ) then
call IssueImmediateOrderById( caster, S2I(order) )
endif
else
if not IssuePointOrder( caster, order, x2,y2 ) then
call IssueImmediateOrder( caster, order )
endif
endif
if (delay<=0) then
call UnitRemoveAbility( caster, abilid)
call RecycleCaster_Light( caster)
else
call RecicleCasterAfterCastEx_Light(caster, delay, abilid, true)
endif
set udg_currentcaster=caster
set caster=null
return udg_currentcaster
endfunction
//====================================================================================================================================================================
function CasterCastAbilityPointExLoc takes player owner, location loc1, real z1, integer abilid, integer level, string order, location loc2, real delay returns unit
return CasterCastAbilityPointEx(owner,GetLocationX(loc1),GetLocationY(loc1),z1,abilid,level,order,GetLocationX(loc2),GetLocationY(loc2),delay)
endfunction
//====================================================================================================================================================================
function CasterCastAbilityLevelPoint takes player owner, integer abilid, integer level, string order, real x, real y, boolean instant returns unit
local real sx
local real sy
local real d
if udg_sourcehack!=null then
set sx=GetLocationX(udg_sourcehack)
set sy=GetLocationY(udg_sourcehack)
else
set sx=x
set sy=y
endif
if instant then
set d=0
else
set d=udg_delayhack+0.01
endif
return CasterCastAbilityPointEx(owner,sx,sy,0,abilid,level,order,x,y,d)
endfunction
function CasterCastAbilityPoint takes player owner, integer abilid, string order, real x, real y, boolean instant returns unit
return CasterCastAbilityLevelPoint(owner,abilid,1,order,x,y,instant)
endfunction
function CasterCastAbilityPointLoc takes player owner, integer abilid, string order, location loc, boolean instant returns unit
return CasterCastAbilityLevelPoint( owner, abilid, 1,order, GetLocationX(loc), GetLocationY(loc), instant )
endfunction
function CasterCastAbilityLevelPointLoc takes player owner, integer abilid, integer level, string order, location loc, boolean instant returns unit
return CasterCastAbilityLevelPoint( owner, abilid, level,order, GetLocationX(loc), GetLocationY(loc), instant )
endfunction
//====================================================================================================================================================================
globals
constant integer cs_sabi_FX = 0 //effect, fx
constant integer cs_sabi_CASTER = 1 //unit,caster
constant integer cs_sabi_ABILITY = 2 //integer,ability
constant integer cs_sabi_ARRAYSIZE = 3
endglobals
function CasterUseAbilityLevelStatic_Rec takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer k=GetCSData(t)
call RecycleCaster(GetArrayUnit(k, cs_sabi_CASTER ))
call DestroyArray(k)
call ReleaseTimer(t)
endfunction
function CasterUseAbilityLevelStatic_X takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer k=GetCSData(t)
call DestroyEffect(GetArrayEffect(k, cs_sabi_FX ) )
call UnitRemoveAbility( GetArrayUnit(k, cs_sabi_CASTER ), GetArrayInt(k, cs_sabi_ABILITY ) )
call TimerStart(t,2,false, function CasterUseAbilityLevelStatic_Rec)
endfunction
function CasterUseAbilityLevelStatic takes player owner, string modelpath, integer abilityid, integer level, real duration, real x, real y returns unit
local timer t=NewTimer()
local unit c=GetACaster()
local integer k=NewArray(cs_sabi_ARRAYSIZE,false)
call SetUnitPosition( c, x, y)
call SetArrayObject(k, cs_sabi_FX , AddSpecialEffectTarget( modelpath, c,"origin" ))
call SetArrayObject(k, cs_sabi_CASTER ,c)
call SetArrayInt(k, cs_sabi_ABILITY ,abilityid)
call SetUnitOwner(c, owner, true)
call UnitAddAbility(c, abilityid)
call SetUnitAbilityLevel(c, abilityid, level)
call SetCSData(t,k)
call TimerStart(t,duration,false,function CasterUseAbilityLevelStatic_X)
set udg_currentcaster=c
set c=null
return udg_currentcaster
endfunction
function CasterUseAbilityStatic takes player owner, string modelpath, integer abilityid, real duration, real x, real y returns unit
return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,1,duration,x,y)
endfunction
//! define CasterUseAbilityStatic(o,m,a,d,x,y) CasterUseAbilityLevelStatic(o,m,a,1,d,x,y)
function CasterUseAbilityStaticLoc takes player owner, string modelpath, integer abilityid, real duration, location loc returns unit
return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,1,duration, GetLocationX(loc), GetLocationY(loc))
endfunction
//! define CasterUseAbilityStaticLoc(o,m,a,d,L) CasterUseAbilityLevelStatic(o,m,a,1,d,GetLocationX(L),GetLocationY(L))
function CasterUseAbilityLevelStaticLoc takes player owner, string modelpath, integer abilityid, integer level,real duration, location loc returns unit
return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,level,duration, GetLocationX(loc), GetLocationY(loc))
endfunction
//! define CasterUseAbilityLevelStaticLoc(o,m,a,lev,d,L) CasterUseAbilityLevelStatic(o,m,a,lev,d,GetLocationX(L),GetLocationY(L))
//====================================================================================================================================================================
function CasterCastAbilityLevelGroup takes player owner, integer abilid, integer level,string order, group targetgroup, boolean instant returns nothing
local group affected
local unit tempunit
local unit caster=null
if bj_wantDestroyGroup then
set bj_wantDestroyGroup=false
set affected=targetgroup
else
set affected=CreateGroup()
call GroupAddGroup( targetgroup, affected)
endif
loop
set tempunit=FirstOfGroup(affected)
exitwhen tempunit == null
if instant then
if caster==null then
set caster=GetACaster()
call SetUnitOwner( caster, owner, false)
call UnitAddAbility( caster, abilid)
call SetUnitAbilityLevel( caster, abilid,level)
endif
if udg_sourcehack != null then
call CS_MoveUnit(caster,GetLocationX(udg_sourcehack),GetLocationY(udg_sourcehack))
else
//If the unit exists then it is in a safe place, so we don't need the checks of CS_MoveUnit.
call SetUnitX(caster,GetUnitX(tempunit))
call SetUnitY(caster,GetUnitY(tempunit))
endif
if S2I(order) != 0 then
call IssueTargetOrderById( caster, S2I(order), tempunit )
else
call IssueTargetOrder( caster, order, tempunit )
endif
else
call CasterCastAbilityLevel( owner, abilid,level, order, tempunit, false)
endif
call GroupRemoveUnit(affected, tempunit)
endloop
if caster != null then
call UnitRemoveAbility( caster, abilid)
call RecycleCaster(caster)
endif
call DestroyGroup(affected)
set affected=null
set tempunit=null
set caster=null
endfunction
function CasterCastAbilityGroup takes player owner, integer abilid, string order, group targetgroup, boolean instant returns nothing
call CasterCastAbilityLevelGroup(owner,abilid,1,order,targetgroup,instant)
endfunction
//! define CasterCastAbilityGroup(o,a,or,t,i) CasterCastAbilityLevelGroup(o,a,1,or,t,i)
//====================================================================================================================================================================
function CasterAOE_IsFilterEnemy takes nothing returns boolean
return IsUnitEnemy( GetFilterUnit(), bj_groupEnumOwningPlayer ) and ( GetWidgetLife(GetFilterUnit()) > 0.405)
endfunction
function CasterAOE_IsFilterAlly takes nothing returns boolean
return IsUnitAlly( GetFilterUnit(), bj_groupEnumOwningPlayer ) and ( GetWidgetLife(GetFilterUnit()) > 0.405)
endfunction
//====================================================================================================================================================================
function CasterCastAbilityLevelAOE takes player owner, integer abilid, integer level, string order, real x, real y, real radius, boolean goodeffect, boolean instant returns nothing
local boolexpr b
local group aoe=CreateGroup()
set bj_groupEnumOwningPlayer=owner
if goodeffect then
set b=Condition(function CasterAOE_IsFilterAlly)
else
set b=Condition(function CasterAOE_IsFilterEnemy)
endif
call CS_EnumUnitsInAOE(aoe, x,y, radius, b)
set bj_wantDestroyGroup=true
call CasterCastAbilityLevelGroup( owner, abilid, level, order, aoe, instant)
call DestroyBoolExpr(b)
set b=null
set aoe=null
endfunction
function CasterCastAbilityAOE takes player owner, integer abilid, string order, real x, real y, real radius, boolean goodeffect, boolean instant returns nothing
call CasterCastAbilityLevelAOE(owner,abilid,1,order,x,y,radius,goodeffect,instant)
endfunction
//! define CasterCastAbilityAOE(o,a,or,x,y,r,g,i) CasterCastAbilityLevelAOE(o,a,1,or,x,y,r,g,i)
function CasterCastAbilityAOELoc takes player owner, integer abilid, string order, location center, real radius, boolean goodeffect, boolean instant returns nothing
call CasterCastAbilityLevelAOE(owner, abilid,1, order, GetLocationX(center), GetLocationY(center), radius, goodeffect, instant)
endfunction
//! define CasterCastAbilityAOELoc(o,a,or,L,r,g,i) CasterCastAbilityLevelAOE(o,a,1,or,GetLocationX(L),GetLocationY(L),r,g,i)
function CasterCastAbilityLevelAOELoc takes player owner, integer abilid, integer level, string order, location center, real radius, boolean goodeffect, boolean instant returns nothing
call CasterCastAbilityLevelAOE(owner, abilid,level, order, GetLocationX(center), GetLocationY(center), radius, goodeffect, instant)
endfunction
//! define CasterCastAbilityLevelAOELoc(o,a,lev,or,L,r,g,i) CasterCastAbilityLevelAOE(o,a,lev,or,GetLocationX(L),GetLocationY(L),r,g,i)
//====================================================================================================================================================================
globals
timer cs_sourcehacktimer = CreateTimer()
timer cs_delayhacktimer = CreateTimer()
endglobals
function ResetSourceHack takes nothing returns nothing
if (udg_sourcehack!=null) then
call RemoveLocation(udg_sourcehack)
set udg_sourcehack=null
endif
endfunction
function CasterSetCastSource takes real x, real y returns nothing
if (udg_sourcehack==null) then
set udg_sourcehack=Location(x,y)
else
call MoveLocation(udg_sourcehack,x,y)
endif
call TimerStart(cs_sourcehacktimer,0.,false,function ResetSourceHack)
endfunction
function CasterSetCastSourceLoc takes location loc returns nothing
call CasterSetCastSource( GetLocationX(loc), GetLocationY(loc) )
endfunction
//! define CasterSetCastSourceLoc(loc) CasterSetCastSource(GetLocationX(loc),GetLocationY(loc))
function ResetDelayHack takes nothing returns nothing
set udg_delayhack=0.
endfunction
function CasterSetRecycleDelay takes real Delay returns nothing
set udg_delayhack=Delay
call TimerStart(cs_delayhacktimer,0.,false,function ResetDelayHack)
endfunction
//====================================================================================================================================================================
//Super DamageOptions structure!
globals
attacktype cs_dopt_Atype = null
damagetype cs_dopt_Dtype = null
unittype cs_dopt_ExceptionUtype = null
real cs_dopt_ExceptionFct = 1.0
unittype cs_dopt_OnlyUtype = null
unittype cs_dopt_IgnoreUtype = null
integer cs_dopt_EnemyAlly = 0 //[ 0 = onlyenemies, 1= forceall, 2=onlyallies]
integer cs_dopt_dfab1 = 'null'
real cs_dopt_dfab1_fc = 1.0
integer cs_dopt_dfab2 = 'null'
real cs_dopt_dfab2_fc = 1.
integer cs_dopt_dfab3 = 'null'
real cs_dopt_dfab3_fc = 1.
real cs_dopt_Ally_fc = 1.
endglobals
function DamageTypes takes attacktype attT, damagetype dmgT returns integer
// set udg_castervars[100] = CS_H2I(attT)
// set udg_castervars[101] = CS_H2I(dmgT)
set cs_dopt_Atype=attT
set cs_dopt_Dtype=dmgT
return 1
endfunction
function DamageException takes unittype Exception, real ExceptionFactor returns integer
set cs_dopt_ExceptionUtype=Exception
set cs_dopt_ExceptionFct = ExceptionFactor
// set udg_castervars[102] = CS_H2I(Exception)
// set udg_castervars[103] = ExceptionFactor
return 2
endfunction
function DamageOnlyTo takes unittype ThisUnitType returns integer
set cs_dopt_OnlyUtype = ThisUnitType
// set udg_castervars[104] = CS_H2I(ThisUnitType)
return 4
endfunction
constant function DontDamageSelf takes nothing returns integer
return 8
endfunction
constant function DamageTrees takes nothing returns integer
return 16
endfunction
constant function DamageOnlyVisibles takes nothing returns integer
return 32
endfunction
function DamageOnlyEnemies takes nothing returns integer
set cs_dopt_EnemyAlly=0
// ouch, forgot what it was
return 64
endfunction
function ForceDamageAllies takes nothing returns integer
set cs_dopt_EnemyAlly=1
return 64
endfunction
function DamageOnlyAllies takes nothing returns integer
set cs_dopt_EnemyAlly=2
return 64
endfunction
function DamageFactorAbility1 takes integer spellid, real factor returns integer
set cs_dopt_dfab1=spellid
set cs_dopt_dfab1_fc=factor
// set udg_castervars[106]=CS_Rawcode2Real(spellid)
// set udg_castervars[107]=factor
return 128
endfunction
function DamageFactorAbility2 takes integer spellid, real factor returns integer
set cs_dopt_dfab2=spellid
set cs_dopt_dfab2_fc=factor
// set udg_castervars[108]=CS_Rawcode2Real(spellid)
// set udg_castervars[109]=factor
return 256
endfunction
function DamageFactorAbility3 takes integer spellid, real factor returns integer
set cs_dopt_dfab3=spellid
set cs_dopt_dfab3_fc=factor
//set udg_castervars[110]=CS_Rawcode2Real(spellid)
// set udg_castervars[111]=factor
return 512
endfunction
function DamageIgnore takes unittype ThisUnitType returns integer
set cs_dopt_IgnoreUtype = ThisUnitType
// set udg_castervars[112] = CS_H2I(ThisUnitType)
return 1024
endfunction
function DamageAlliedFactor takes real fct returns integer
set cs_dopt_Ally_fc = fct
// set udg_castervars[113] = fct
return 2048
endfunction
constant function ConsiderOnlyDeadUnits takes nothing returns integer
return 4096
endfunction
constant function IgnoreDeadState takes nothing returns integer
return 8192
endfunction
//===============================================================================================
function IsDamageOptionIncluded takes integer DamageOptions, integer whichDamageOption returns boolean
local integer i=8192
if (DamageOptions==0) then
return false
endif
loop
exitwhen (i<=whichDamageOption)
if (DamageOptions>=i) then
set DamageOptions=DamageOptions-i
endif
set i=i/2
endloop
return (DamageOptions>=whichDamageOption)
endfunction
//=================================================================================================
globals
unit cs_dmg_caster=null
endglobals
function GetDamageFactor takes unit u,attacktype a, damagetype d returns real
local real hp=GetWidgetLife(u)
local real mana=GetUnitState(u,UNIT_STATE_MANA)
local real r
//Since a unit is in that point, we don't need checks.
call SetUnitX(cs_dmg_caster,GetUnitX(u))
call SetUnitY(cs_dmg_caster,GetUnitY(u))
call SetUnitOwner(cs_dmg_caster,GetOwningPlayer(u),false)
set r=hp
if (hp<1) then
call SetWidgetLife(u,1)
set r=1
endif
call UnitDamageTarget(cs_dmg_caster,u,0.01,true,false,a,d,null)
call SetUnitOwner(cs_dmg_caster,Player(15),false)
if (mana>GetUnitState(u,UNIT_STATE_MANA)) then
//Unit had mana shield, return 1 and restore mana too.
call SetUnitState(u,UNIT_STATE_MANA,mana)
set r=1
else
set r= (r-GetWidgetLife(u))*100
endif
call SetWidgetLife(u,hp)
return r
endfunction
//======================================================================================================
// Fix for the unit type bugs from blizzard, amphibious units aren't considered ground for some reason
// so this considers any non flying unit as ground.
//
// Also heroes are resistant too, so in case UNIT_TYPE_RESISTANT is used it will return true in case the
// unit is a hero too.
//
function CS_IsUnitType takes unit u, unittype ut returns boolean
if (ut==UNIT_TYPE_GROUND) then
return not(IsUnitType(u,UNIT_TYPE_FLYING))
elseif (ut==UNIT_TYPE_RESISTANT) then
return IsUnitType(u,ut) or IsUnitType(u,UNIT_TYPE_HERO)
endif
return IsUnitType(u,ut)
endfunction
function GetDamageFactorByOptions takes unit hurter, unit target, integer d returns real
local real r=1
if (d>=8192) then
set d=d-8192
elseif (d>=4096) then
if (GetWidgetLife(target)>0.405) then
return 0.0
endif
set d=d-4096
elseif (GetWidgetLife(target)<=0.405) then
return 0.0
endif
if d>=2048 then
if IsUnitAlly(target,GetOwningPlayer(hurter)) then
set r=r* cs_dopt_Ally_fc
endif
set d=d-2048
endif
if d>=1024 then
if CS_IsUnitType(target, cs_dopt_IgnoreUtype ) then
return 0.0
endif
set d=d-1024
endif
if d>=512 then
if GetUnitAbilityLevel(target, cs_dopt_dfab1 )>0 then
set r=r*cs_dopt_dfab1_fc
endif
set d=d-512
endif
if d>=256 then
if GetUnitAbilityLevel(target, cs_dopt_dfab2 )>0 then
set r=r*cs_dopt_dfab2_fc
endif
set d=d-256
endif
if d>=128 then
if GetUnitAbilityLevel(target, cs_dopt_dfab3 )>0 then
set r=r*cs_dopt_dfab3_fc
endif
set d=d-128
endif
if d>=64 then
if (cs_dopt_EnemyAlly==0) and IsUnitAlly(target,GetOwningPlayer(hurter)) then
return 0.0
elseif (cs_dopt_EnemyAlly==2) and IsUnitEnemy(target,GetOwningPlayer(hurter)) then
return 0.0
endif
set d=d-64
endif
if d>=32 then
set d=d-32
if not CS_IsUnitVisible(target,GetOwningPlayer(hurter)) then
return 0.0
endif
endif
if d>=16 then
set d=d-16
endif
if d>=8 then
set d=d-8
if hurter==target then
return 0.0
endif
endif
if d>=4 then
set d=d-4
if not CS_IsUnitType( target,cs_dopt_OnlyUtype) then
return 0.0
endif
endif
if d>=2 then
set d=d-2
if CS_IsUnitType( target, cs_dopt_ExceptionUtype ) then
set r=r* cs_dopt_ExceptionFct
endif
endif
if d>=1 then
set d=d-1
set r=r*GetDamageFactor(target,cs_dopt_Atype,cs_dopt_Dtype)
endif
return r
endfunction
//======================================================================================================================
// This used to be needed because in 1.17 UnitDamageTarget didn't consider the damagetype argument, this bug
// was fixed in 1.18, and we no longer need this function, left for compatibility.
//
function DamageUnitByTypes takes unit hurter, unit target, real dmg, attacktype attT, damagetype dmgT returns boolean
return UnitDamageTarget(hurter,target,dmg,true,false,attT,dmgT,null)
endfunction
//! define DamageUnitByTypes(h,t,d,a,dmt) UnitDamageTarget(h,t,d,true,false,a,dmt,null)
//=============================================================================================================================
function DamageUnitByOptions takes unit hurter, unit target, real dmg, integer DamageOptions returns boolean
local real f=GetDamageFactorByOptions(hurter,target,DamageOptions)
if (f==0) then
return false
endif
return UnitDamageTarget(hurter,target,dmg*f,true,false,null,null,null)
endfunction
//=============================================================================================================================
function DamageUnit takes player hurter, real damage, unit victim returns boolean
call SetUnitX(cs_dmg_caster,GetUnitX(victim))
call SetUnitY(cs_dmg_caster,GetUnitY(victim))
call SetUnitOwner(cs_dmg_caster,hurter,false)
call DamageUnitByTypes(cs_dmg_caster,victim,damage,cs_DefaultAttackType,cs_DefaultDamageType)
call SetUnitOwner(cs_dmg_caster,Player(15),false)
return GetWidgetLife(victim)<=0 // I thought UnitDamageTarget returned true when it killed the unit, but nope, it returns true when it was able to do the damage.
endfunction
//====================================================================================================================================================================
function UnitDamageUnitTimed_Child takes nothing returns nothing
local real damage = udg_castervars[0]
local real damageperiod= udg_castervars[2]
local effect fx=bj_lastCreatedEffect
local timer t=NewTimer()
local unit hurter=udg_currenthurter
local real next=0
local integer i=0
local real c
local unit target=udg_currentcaster
local damagetype dmgT=ConvertDamageType(R2I(udg_castervars[4]))
local attacktype attT=ConvertAttackType(R2I(udg_castervars[3]))
call TimerStart(t, udg_castervars[1]-0.01, false,null)
loop
if TimerGetElapsed(t) >= next then
exitwhen not UnitDamageTarget(hurter, target, damage,true,false, attT, dmgT,null)
exitwhen GetWidgetLife(target)<=0.405
set i=i+1
set next=i*damageperiod
endif
exitwhen (TimerGetRemaining(t) <= 0) or GetWidgetLife(target)<=0.405
call TriggerSleepAction(0)
endloop
call DestroyEffect(fx)
call ReleaseTimer(t)
set fx=null
set dmgT=null
set attT=null
endfunction
function UnitDamageUnitTimed takes unit hurter, real damageps, real damageperiod, real duration, unit target, string modelpath, string attachPointName, attacktype attT, damagetype dmgT returns nothing
local unit c=udg_currentcaster
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, target,attachPointName )
set udg_currentcaster=target
set udg_castervars[0]=damageps
set udg_castervars[1]=duration
set udg_castervars[2]=damageperiod
set udg_castervars[3]=CS_H2I(attT)
set udg_castervars[4]=CS_H2I(dmgT)
set udg_currenthurter=hurter
call ExecuteFunc("UnitDamageUnitTimed_Child")
set udg_currentcaster=c
set c=null
endfunction
//=============================================================================================================
// Left for compatibility
//
function DamageUnitTimedEx_Child takes nothing returns nothing
local real damage = udg_castervars[0]
local real damageperiod= udg_castervars[2]
local effect fx=bj_lastCreatedEffect
local timer t=NewTimer()
local integer id=udg_currentabi
local real next=0
local integer i=0
local real c
local unit target=udg_currentcaster
call TimerStart(t, udg_castervars[1]-0.01, false,null)
loop
if TimerGetElapsed(t) >= next then
exitwhen DamageUnit( Player(id), damage, target)
set i=i+1
set next=i*damageperiod
endif
exitwhen (TimerGetRemaining(t) <= 0) or GetWidgetLife(target)<=0.405
call TriggerSleepAction(0)
endloop
call DestroyEffect(fx)
call ReleaseTimer(t)
set fx=null
endfunction
function DamageUnitTimedEx takes player owner, real damageps, real damageperiod, real duration, unit target, string modelpath, string attachPointName returns nothing
local unit c=udg_currentcaster
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, target,attachPointName )
set udg_currentcaster=target
set udg_castervars[0]=damageps
set udg_castervars[1]=duration
set udg_castervars[2]=damageperiod
set udg_currentabi=GetPlayerId( owner )
call ExecuteFunc("DamageUnitTimedEx_Child")
set udg_currentcaster=c
set c=null
endfunction
function DamageUnitTimed takes player owner, real damageps, real duration, unit target, string modelpath, string attachPointName returns nothing
call DamageUnitTimedEx(owner , damageps, 1, duration, target, modelpath, attachPointName )
endfunction
//[
function SetDamageOptions_i takes integer k, integer DamageOptions returns nothing
local integer d=DamageOptions
call SetArrayInt(k,0,d) //[0=value]
if (d>=8192) then
set d=d-8192
endif
if (d>=4096) then
set d=d-4096
endif
if d>=2048 then
call SetArrayReal(k,14, cs_dopt_Ally_fc ) //[14=allf]
set d=d-2048
endif
if d>=1024 then
call SetArrayObject(k,13, cs_dopt_IgnoreUtype ) //[13=ign]
set d=d-1024
endif
if d>=512 then
call SetArrayInt(k,11, cs_dopt_dfab3 ) //[11=ab3]
call SetArrayReal(k,12, cs_dopt_dfab3_fc ) //[12=fc3]
set d=d-512
endif
if d>=256 then
call SetArrayInt(k,9, cs_dopt_dfab2 ) //[9=ab2]
call SetArrayReal(k,10, cs_dopt_dfab2_fc ) //[10=fc2]
set d=d-256
endif
if d>=128 then
call SetArrayInt(k,7, cs_dopt_dfab1 ) //[7=ab1]
call SetArrayReal(k,8, cs_dopt_dfab1_fc ) //[8=fc1]
set d=d-128
endif
//[0 integer value][1 integer attT][2 integer dmgT][3 integer excp][4 real excf][5 integer only]
//[6 integer allied][7 integer ab1][8 real fc1][9 integer ab2][10 real fc2][11 integer ab3][12 real fc3]
//[13 integer ign][14 real allf]
if d >= 64 then
set d=d-64
call SetArrayInt(k,6,cs_dopt_EnemyAlly) //[6=allied]
endif
if d >= 32 then
set d=d-32
endif
if d >= 16 then
set d=d-16
endif
if d >= 8 then
set d=d-8
endif
if d >= 4 then
call SetArrayObject(k,5,cs_dopt_OnlyUtype ) //[5=only]
set d=d-4
endif
if d >= 2 then
call SetArrayObject(k,3, cs_dopt_ExceptionUtype ) //[3=excp]
call SetArrayReal(k,4,cs_dopt_ExceptionFct) //[4=excf]
set d=d-2
endif
if d >= 1 then
call SetArrayInt(k,1, CS_H2I(cs_dopt_Atype) ) //[1=Attt]
call SetArrayInt(k,2, CS_H2I(cs_dopt_Dtype) ) //[2=dmgT]
endif
endfunction
function SetDamageOptions takes integer id, integer DamageOptions returns nothing
call SetDamageOptions_i(id,DamageOptions)
endfunction
//! define SetDamageOptions(i,d) SetDamageOptions_i(i,d)
function CreateDamageOptions takes integer DamageOptions returns integer
local integer n =NewArray(15,false) //I am sure this won't access any non-initialized value
call SetDamageOptions_i(n,DamageOptions)
return n
endfunction
function DestroyDamageOptions takes integer id returns nothing
call DestroyArray(id)
endfunction
//! define DestroyDamageOptions(i) DestroyArray(i)
function LoadDamageOptions takes integer id returns integer
local integer opt=GetArrayInt(id,0) //[0=value]
local integer v=opt
if v>=8192 then
set v=v-8192
endif
if v>=4096 then
set v=v-4096
endif
if v>=2048 then
set cs_dopt_Ally_fc = GetArrayReal(id,14) //[14=allf]
set v=v-2028
endif
if v>=1024 then
set cs_dopt_IgnoreUtype = ConvertUnitType( GetArrayInt(id,13) ) //[13=ign]
set v=v-1024
endif
if v>=512 then
set cs_dopt_dfab3 =GetArrayInt(id,11) //[11=ab3]
set cs_dopt_dfab3_fc=GetArrayReal(id,12) //[12=fc3]
set v=v-512
endif
if v>=256 then
set cs_dopt_dfab2 =GetArrayInt(id,9) //[9=ab2]
set cs_dopt_dfab2_fc=GetArrayReal(id,10) //[10=fc2]
set v=v-256
endif
if v>=128 then
set cs_dopt_dfab1 =GetArrayInt(id,7) //[7=ab1]
set cs_dopt_dfab1_fc=GetArrayReal(id,8) //[8=fc1]
set v=v-128
endif
if v >= 64 then
set v=v-64
set cs_dopt_EnemyAlly= GetArrayInt(id,6) //[6==allied]
endif
if v >= 32 then
set v=v-32
endif
if v >= 16 then
set v=v-16
endif
if v >= 8 then
set v=v-8
endif
//[0 integer value][1 integer attT][2 integer dmgT][3 integer excp][4 real excf][5 integer only]
//[6 integer allied][7 integer ab1][8 real fc1][9 integer ab2][10 real fc2][11 integer ab3][12 real fc3]
//[13 integer ign][14 real allf]
if v >= 4 then
set cs_dopt_OnlyUtype = ConvertUnitType( GetArrayInt(id,5)) //only
set v=v-4
endif
if v >= 2 then
set cs_dopt_ExceptionUtype= ConvertUnitType(GetArrayInt(id,3)) //excp
set cs_dopt_ExceptionFct=GetArrayReal(id,4) //excf
set v=v-2
endif
if v >= 1 then
set cs_dopt_Atype= ConvertAttackType(GetArrayInt(id,1)) //aTTt
set cs_dopt_Dtype= ConvertDamageType(GetArrayInt(id,2)) //dmgT
endif
return opt
endfunction
//==================================================================================================
function IsDestructableTree_withcs takes destructable d returns boolean
local boolean b
local boolean i=IsDestructableInvulnerable(d)
call CS_MoveUnit(cs_dmg_caster,GetWidgetX(d),GetWidgetY(d))
if i then
call SetDestructableInvulnerable(d,false)
endif
call UnitAddAbility(cs_dmg_caster,cs_DamageTreeDetectorId)
set b=(IssueTargetOrder(cs_dmg_caster,"eattree",d))
call UnitRemoveAbility(cs_dmg_caster,cs_DamageTreeDetectorId)
if i then
call SetDestructableInvulnerable(d,true)
endif
return b
endfunction
function IsDestructableTree takes destructable d returns boolean
local string k=I2S(GetDestructableTypeId(d))
local boolean b
if HaveStoredBoolean(cs_cache,"trees",k) then
set b=GetStoredBoolean(cs_cache,"trees",k)
return b
else
set b=IsDestructableTree_withcs(d)
call StoreBoolean(cs_cache,"trees",k,b)
endif
return b
endfunction
//===============================================================================================
function DamageDestructablesInCircleEnum takes nothing returns nothing
local destructable d=GetEnumDestructable()
local unit u=udg_currentcaster
if (GetWidgetLife(d)>0) and not(IsDestructableInvulnerable(d)) and ((Pow(GetDestructableX(d)-udg_castervars[200],2)+Pow(GetDestructableY(d)-udg_castervars[201],2)) <= udg_castervars[202]) then
call SetWidgetLife(d,GetWidgetLife(d)-udg_castervars[203])
endif
set udg_currentcaster=u
set u=null
set d=null
endfunction
function DamageDestructablesInCircle takes real x, real y, real radius, real dmg returns nothing
local rect r=Rect(x - radius,y - radius,x + radius,y + radius)
set udg_castervars[200]=x
set udg_castervars[201]=y
set udg_castervars[202]=radius*radius
set udg_castervars[203]=dmg
call EnumDestructablesInRect(r,null,function DamageDestructablesInCircleEnum)
call RemoveRect(r)
set r=null
endfunction
function DamageDestructablesInCircleLoc takes location loc, real radius, real dmg returns nothing
call DamageDestructablesInCircle(GetLocationX(loc),GetLocationY(loc),radius,dmg)
endfunction
function DamageTreesInCircleEnum takes nothing returns nothing
local destructable d=GetEnumDestructable()
if (GetWidgetLife(d)>0) and not(IsDestructableInvulnerable(d)) and ((Pow(GetDestructableX(d)-udg_castervars[200],2)+Pow(GetDestructableY(d)-udg_castervars[201],2)) <= udg_castervars[202]) and (IsDestructableTree(d)) then
call KillDestructable(d)
endif
set d=null
endfunction
function DamageTreesInCircle takes real x, real y, real radius returns nothing
local rect r=Rect(x - radius,y - radius,x + radius,y + radius)
set udg_castervars[200]=x
set udg_castervars[201]=y
set udg_castervars[202]=radius*radius
call EnumDestructablesInRect(r,null,function DamageTreesInCircleEnum)
call RemoveRect(r)
set r=null
endfunction
function DamageTreesInCircleLoc takes location loc, real radius returns nothing
call DamageTreesInCircle(GetLocationX(loc),GetLocationY(loc),radius)
endfunction
function DamageUnitGroupEx takes unit hurter, real damage, group targetgroup, integer DamageOptions returns nothing
local group affected
local unit p
if bj_wantDestroyGroup then
set bj_wantDestroyGroup=false
set affected=targetgroup
else
set affected=CreateGroup()
call GroupAddGroup( targetgroup, affected)
endif
loop
set p=FirstOfGroup(affected)
exitwhen p==null
call DamageUnitByOptions(hurter,p,damage,DamageOptions)
call GroupRemoveUnit(affected,p)
endloop
call DestroyGroup(affected)
set affected=null
set p=null
endfunction
function DamageUnitsInAOEEx takes unit hurter, real damage, real x, real y, real radius, boolean affectallied, integer DamageOptions returns nothing
local boolexpr b=null
local group aoe=CreateGroup()
local integer d=DamageOptions
set bj_groupEnumOwningPlayer=GetOwningPlayer(hurter)
if d>=8192 then
set d=d-8192
endif
if d>=4096 then
set d=d-4096
endif
if d>=2048 then
set d=d-2048
endif
if d>=1024 then
set d=d-1024
endif
if d>=512 then
set d=d-512
endif
if d>=256 then
set d=d-256
endif
if d>=128 then
set d=d-128
endif
if d>=64 then
if (cs_dopt_EnemyAlly==2) then
set b=Condition(function CasterAOE_IsFilterAlly)
elseif (cs_dopt_EnemyAlly==1) then
else
set b=Condition(function CasterAOE_IsFilterEnemy)
endif
set d=d-64
elseif not(affectallied) then
set b=Condition(function CasterAOE_IsFilterEnemy)
endif
if d>=32 then
set d=d-32
endif
if d>=16 then
call DamageTreesInCircle(x,y,radius)
endif
call CS_EnumUnitsInAOE(aoe, x,y, radius, b)
set bj_wantDestroyGroup=true
call DamageUnitGroupEx( hurter, damage, aoe,DamageOptions)
call DestroyBoolExpr(b)
set b=null
set aoe=null
endfunction
function DamageUnitsInAOEExLoc takes unit hurter, real damage, location loc, real radius, boolean affectallied, integer DamageOptions returns nothing
call DamageUnitsInAOEEx(hurter,damage, GetLocationX(loc), GetLocationY(loc), radius, affectallied,DamageOptions)
endfunction
//! define DamageUnitsInAOEExLoc(h,d,l,r,a,do) DamageUnitsInAOEEx(h,d,GetLocationX(l),GetLocationY(l),r,a,do)
function DamageUnitGroup takes player hurter, real damage, group targetgroup returns nothing
call SetUnitOwner(cs_dmg_caster,hurter,false)
call DamageUnitGroupEx(cs_dmg_caster,damage,targetgroup,0)
call SetUnitOwner(cs_dmg_caster,Player(15),false)
endfunction
//====================================================================================================================================================================
function DamageUnitsInAOE takes player hurter, real damage, real x, real y, real radius, boolean affectallied returns nothing
call SetUnitOwner(cs_dmg_caster,hurter,false)
call DamageUnitsInAOEEx(cs_dmg_caster,damage,x,y,radius,affectallied,0)
call SetUnitOwner(cs_dmg_caster,Player(15),false)
endfunction
function DamageUnitsInAOELoc takes player hurter, real damage, location loc, real radius, boolean affectallied returns nothing
call DamageUnitsInAOE( hurter, damage, GetLocationX(loc), GetLocationY(loc), radius, affectallied)
endfunction
//! define DamageUnitsInAOELoc(h,d,l,r,a) DamageUnitsInAOEEx(h,d,GetLocationX(l),GetLocationY(l),r,a)
//====================================================================================================================================================================
function AddAreaDamagerForUnit_Child takes nothing returns nothing
local real D
local real damageps = udg_castervars[0]
local real area = udg_castervars[2]
local real damageperiod = udg_castervars[3]
local real excd=udg_castervars[8]
local boolean affectallies = (udg_castervars[4]>=1)
local boolean onlyallies = (udg_castervars[4]==2)
local boolean self = (udg_castervars[5]==1)
local unit hurter=udg_currenthurter
local unit fire = udg_currentcaster
local player owner = GetOwningPlayer(fire)
local timer t = NewTimer()
local real next = 0
local integer a = 0
local group inrange = CreateGroup()
local string c
local string art=bj_lastPlayedMusic
local string attach=""
local unit picked
local boolean recicled=false
local unittype only=null
local unittype ign=null
local unittype exce=null
local attacktype attT
local damagetype dmgT
local boolean trees=(udg_castervars[11]==1)
local boolean inv=(udg_castervars[12]==1)
local integer a1=0
local integer a2=0
local integer a3=0
local real f1=udg_castervars[107]
local real f2=udg_castervars[109]
local real f3=udg_castervars[111]
local real allf=udg_castervars[113]
local effect array fx
local integer deadcond=R2I(udg_castervars[114])
local boolean deadeval=false
local integer fxn=0
set fx[0]=bj_lastCreatedEffect
if f1!=1 then
set a1=CS_LoadRawcodeFromReal(106)
endif
if f2!=1 then
set a2=CS_LoadRawcodeFromReal(108)
endif
if f3!=1 then
set a3=CS_LoadRawcodeFromReal(110)
endif
if udg_castervars[112]!=-1 then
set ign=ConvertUnitType(R2I(udg_castervars[112]))
endif
if udg_castervars[6]!=-1 then
set only=ConvertUnitType(R2I(udg_castervars[6]))
endif
if udg_castervars[7]!=-1 then
set exce=ConvertUnitType(R2I(udg_castervars[7]))
endif
if udg_castervars[9]!=-1 then
set attT=ConvertAttackType(R2I(udg_castervars[9]))
else
set attT=cs_DefaultAttackType
endif
if udg_castervars[10]!=-1 then
set dmgT=ConvertDamageType(R2I(udg_castervars[10]))
else
set dmgT=cs_DefaultDamageType
endif
loop
set c=SubString(art,a,a+1)
exitwhen c=="!" or c==""
set attach=attach+c
set a=a+1
endloop
set art=SubString(art,a+1,10000)
call TimerStart(t, udg_castervars[1]-0.01, false,null)
set a=0
loop
loop
exitwhen fxn<=0
call DestroyEffect(fx[fxn])
set fx[fxn]=null
set fxn=fxn-1
endloop
if IsUnitInGroup( fire, udg_casters) then
set recicled=true
call GroupRemoveUnit( udg_casters,fire)
endif
exitwhen recicled
if TimerGetElapsed(t) >= next then
set a=a+1
set next=a*damageperiod
call CS_EnumUnitsInAOE(inrange, GetUnitX(fire), GetUnitY(fire), area, null )
if trees then
call DamageTreesInCircle(GetUnitX(fire), GetUnitY(fire), area)
endif
loop
set picked=FirstOfGroup(inrange)
exitwhen picked==null
if (deadcond==0) then
set deadeval=(GetWidgetLife(picked)>0.405)
elseif(deadcond==1)then
set deadeval=(GetWidgetLife(picked)<=0.405)
else
set deadeval=true
endif
if (self or picked!=hurter) and not(GetWidgetLife(picked)<=0.405) and ( ((affectallies or onlyallies) and IsUnitAlly(picked, owner)) or (not(onlyallies) and IsUnitEnemy(picked, owner)) ) and (only==null or CS_IsUnitType(picked,only)) and (ign==null or not(CS_IsUnitType(picked,ign))) then
set D=damageps
if (allf!=1) and IsUnitAlly(picked, owner) then
set D=D*allf
endif
if (exce!=null) and CS_IsUnitType(picked,exce) then
set D=D*excd
endif
if inv and not(CS_IsUnitVisible(picked,owner)) then
set D=0
endif
if (a1!=0) and (GetUnitAbilityLevel(picked,a1)>0) then
set D=D*f1
endif
if (a2!=0) and (GetUnitAbilityLevel(picked,a2)>0) then
set D=D*f2
endif
if (a3!=0) and (GetUnitAbilityLevel(picked,a3)>0) then
set D=D*f3
endif
if D!=0 then
call DamageUnitByTypes(hurter,picked,D,attT,dmgT )
if (art!="") and (art!=null) then
set fxn=fxn+1
set fx[fxn]=AddSpecialEffectTarget(art,picked,attach)
endif
endif
endif
call GroupRemoveUnit(inrange,picked)
endloop
endif
exitwhen TimerGetRemaining(t)<=0
call TriggerSleepAction(0)
endloop
call DestroyGroup(inrange)
call DestroyEffect(fx[0])
call TriggerSleepAction(2)
call RecicleCaster(fire)
call ReleaseTimer(t)
set inrange=null
set fire=null
set owner=null
set fx[0]=null
set picked=null
set hurter=null
set only=null
set ign=null
set exce=null
set attT=null
set dmgT=null
endfunction
function AddAreaDamagerForUnit takes unit hurter, string modelpath, string targetart, string targetattach, real x, real y, real damage , real damageperiod, real duration, real area, boolean affectallies, integer DamageOptions returns unit
local string s=bj_lastPlayedMusic
local integer v=DamageOptions
set bj_lastPlayedMusic=targetattach+"!"+targetart
set udg_currentcaster=GetACaster()
call SetUnitPosition( udg_currentcaster, x, y)
set bj_lastCreatedEffect = AddSpecialEffectTarget( modelpath, udg_currentcaster,"origin" )
set udg_castervars[0]=damage
set udg_castervars[1]=duration
set udg_castervars[2]=area
set udg_castervars[3]=damageperiod
if(v>=8192)then
set udg_castervars[114]=2
set v=v-8192
elseif (v>=4096)then
set udg_castervars[114]=1
set v=v-4096
else
set udg_castervars[114]=0
endif
if v>=2048 then
set v=v-2048
else
set udg_castervars[113]=1
endif
if v >= 1024 then
set v=v-1024
else
set udg_castervars[112]=-1
endif
if v >= 512 then
set v=v-512
else
set udg_castervars[111]=0
endif
if v >= 256 then
set v=v-256
else
set udg_castervars[109]=0
endif
if v >= 128 then
set v=v-128
else
set udg_castervars[107]=0
endif
if v >= 64 then
set v=v-64
set udg_castervars[4]=cs_dopt_EnemyAlly
else
set udg_castervars[4]=IntegerTertiaryOp(affectallies,1,0)
endif
if v >= 32 then
set udg_castervars[12]=1
set v=v-32
else
set udg_castervars[12]=0
endif
if v >= 16 then
set udg_castervars[11]=1
set v=v-16
else
set udg_castervars[11]=0
endif
if v >= 8 then
set udg_castervars[5]=0
set v=v-8
else
set udg_castervars[5]=1
endif
if v >= 4 then
set udg_castervars[6]=CS_H2I(cs_dopt_OnlyUtype)
set v=v-4
else
set udg_castervars[6]=-1
endif
if v >= 2 then
set udg_castervars[7]=CS_H2I(cs_dopt_ExceptionUtype)
set udg_castervars[8]=damage*cs_dopt_ExceptionFct
set v=v-2
else
set udg_castervars[7]=-1
set udg_castervars[8]=-1
endif
if v >= 1 then
set udg_castervars[9]= CS_H2I(cs_dopt_Atype)
set udg_castervars[10]= CS_H2I(cs_dopt_Dtype)
else
set udg_castervars[9]=-1
set udg_castervars[10]=-1
endif
set udg_currenthurter=hurter
call SetUnitOwner( udg_currentcaster, GetOwningPlayer(hurter), true)
call ExecuteFunc("AddAreaDamagerForUnit_Child")
set bj_lastPlayedMusic=s
return udg_currentcaster
endfunction
function AddAreaDamagerForUnitLoc takes unit hurter, string modelpath, string targetart, string targetattach, location loc, real damage , real damageperiod, real duration, real area, boolean affectallies, integer DamageOptions returns unit
return AddAreaDamagerForUnit(hurter,modelpath,targetart,targetattach,GetLocationX(loc),GetLocationY(loc), damage , damageperiod, duration, area,affectallies, DamageOptions)
endfunction
function AddDamagingEffectEx takes player owner, string modelpath, string targetart, string targetattach, real x, real y, real damage , real damageperiod, real duration, real area, boolean affectallies returns unit
local string s=bj_lastPlayedMusic
set bj_lastPlayedMusic=targetattach+"!"+targetart
set udg_currentcaster=GetACaster()
call SetUnitPosition( udg_currentcaster, x, y)
set bj_lastCreatedEffect = AddSpecialEffectTarget( modelpath, udg_currentcaster,"origin" )
set udg_castervars[0]=damage
set udg_castervars[1]=duration
set udg_castervars[2]=area
set udg_castervars[3]=damageperiod
set udg_castervars[4]=IntegerTertiaryOp(affectallies,1,0)
set udg_castervars[5]=1
set udg_castervars[6]=-1
set udg_castervars[7]=-1
set udg_castervars[8]=-1
set udg_castervars[9]=-1
set udg_castervars[10]=-1
set udg_castervars[107]=0
set udg_castervars[109]=0
set udg_castervars[111]=0
set udg_castervars[112]=-1
set udg_castervars[113]=1
set udg_currenthurter=udg_currentcaster
call SetUnitOwner( udg_currentcaster, owner, true)
call ExecuteFunc("AddAreaDamagerForUnit_Child")
set bj_lastPlayedMusic=s
return udg_currentcaster
endfunction
function AddDamagingEffectExLoc takes player owner, string modelpath, string targetart, string targetattach, location loc, real damage , real damageperiod, real duration, real area, boolean affectallies returns unit
return AddDamagingEffectEx( owner, modelpath, targetart, targetattach, GetLocationX(loc), GetLocationY(loc), damage , damageperiod, duration, area, affectallies )
endfunction
function AddDamagingEffect takes player owner, string modelpath, real x, real y, real damageps , real duration, real area, boolean affectallies returns unit
return AddDamagingEffectEx( owner, modelpath, "", "", x, y, damageps , 1, duration, area, affectallies )
endfunction
function AddDamagingEffectLoc takes player owner, string modelpath, location loc, real damageps , real duration, real area, boolean affectallies returns unit
return AddDamagingEffectEx( owner, modelpath, "", "", GetLocationX(loc), GetLocationY(loc), damageps ,1, duration, area, affectallies)
endfunction
//============================================================================================================
function UnitMoveToAsProjectileAnySpeed_Move takes unit m, integer k returns boolean
local boolean tounit = (GetArrayInt(k,cs_PROJ_TOUNIT)==1)
local unit tg
local real x2
local real y2
local real z2
local real x1=GetUnitX(m)
local real y1=GetUnitY(m)
local real z1=GetUnitFlyHeight(m)
local real g
local real d
local real od
local real v
local real time
local integer n
local boolean done=false
local effect fx
if tounit then
set tg=GetArrayUnit(k, cs_PROJ_TARGET )
if (GetWidgetLife(tg)<=0.405) then
set tounit=false
call SetArrayInt(k, cs_PROJ_TOUNIT ,0)
else
set x2=GetUnitX(tg)
set y2=GetUnitY(tg)
set z2=GetUnitFlyHeight(tg)+GetArrayReal(k, cs_PROJ_Z2O )
set n=GetArrayInt(k,cs_PROJ_N)
if (n==0) then
//Using the counter prevents us to save z2,x2,y2 too much times and saves speed
call SetArrayReal(k, cs_PROJ_Z2 ,z2)
call SetArrayReal(k, cs_PROJ_X2 ,x2) // Backup stuff just in case
call SetArrayReal(k, cs_PROJ_Y2 ,y2)
elseif (n==25) then
set n=0
else
set n=n+1
endif
call SetArrayInt(k, cs_PROJ_N ,n)
endif
set tg=null
endif
if not(tounit) then
set z2=GetArrayReal(k, cs_PROJ_Z2)
set x2=GetArrayReal(k, cs_PROJ_X2)
set y2=GetArrayReal(k, cs_PROJ_Y2)
endif
set g=Atan2(y2-y1,x2-x1)
call SetUnitFacing(m,g*bj_RADTODEG)
set v=GetArrayReal(k, cs_PROJ_SPEED)
set d= v * cs_TIMER_CYCLE
set od=SquareRoot(Pow(x1-x2,2) + Pow(y1-y2,2))
if( od <=d )then
call CS_MoveUnit(m , x2, y2 )
set done=true
else
call CS_MoveUnit(m , x1+d*Cos(g), y1+d*Sin(g) )
endif
set g=GetArrayReal(k, cs_PROJ_ACEL )
set time= od / v
set d=v
set v=(z2-z1+0.5*g*time*time)/time //z speed
if (GetUnitTypeId(m)==cs_CasterUnitId) then
call SetUnitAnimationByIndex(m,R2I(Atan2(v,d)* bj_RADTODEG)+90) //Thanks infrane!
endif
call SetUnitFlyHeight(m,z1+v*cs_TIMER_CYCLE,0)
set d=( Pow(GetUnitX(m)-x2,2) + Pow(GetUnitY(m)-y2,2) )
if (done or (d<=400)) then //So the actual distance is less than or equal to 20
set done=true
call SetArrayInt(k, cs_PROJ_DONE ,1)
set fx=GetArrayEffect(k, cs_PROJ_FX )
if (fx!=null) then
call SetUnitAnimationByIndex(m,91)
call DestroyEffect(fx)
set fx=null
endif
endif
return done
endfunction
// CollisionMissiles array constants
// The wc3 map optimizer can inline them so we don't lose anything in exchange of ease to read
// and maintainability.
//
globals
constant integer cs_MOVE_TYPE = 0 //Is it a collisionmissile or a 'normal' projectile? //shared between collisionmissiles and projectiles
constant integer cs_MOVE_TYPE_COLLISIONMISSILE = 2
constant integer cs_MOVE_TYPE_PROJECTILE = 1
constant integer cs_COLM_STATE = 1
constant integer cs_COLM_T = 2
constant integer cs_COLM_COLLISION = 3
constant integer cs_COLM_SPEED = 4
constant integer cs_COLM_F = 5
constant integer cs_COLM_ASPEED = 6
constant integer cs_COLM_TTYPE = 7 //Integer, homing target type (widget or point?)
constant integer cs_COLM_TTYPE_WIDGET = 2
constant integer cs_COLM_TTYPE_POINT = 1
constant integer cs_COLM_TTYPE_NONE = 0
constant integer cs_COLM_TX = 8 //real, homing target X
constant integer cs_COLM_TY = 9 //real, homing target Y
constant integer cs_COLM_TW = 10 //widget , homing target
constant integer cs_COLM_M = 11 //unit - the collisionmissile itself
constant integer cs_COLM_MAXD = 12
constant integer cs_COLM_PFX = 13 //real
constant integer cs_COLM_PFX_CURRENT = 14 //real
constant integer cs_COLM_PFX_DUR = 15 //real
constant integer cs_COLM_PFX_PATH = 16 //string, path of the periodic effect
constant integer cs_COLM_FX = 17 //effect
constant integer cs_COLM_AC = 18 //triggeraction , action of the trigger
constant integer cs_COLM_NEW = 19 //integer - Does it use a new caster?
constant integer cs_COLM_ARRAYSIZE = 20
endglobals
function CollisionMissile_Destroyer takes unit m, integer k, trigger T returns nothing
local effect fx= GetArrayEffect(k, cs_COLM_FX )
local trigger tr = T
local triggeraction ta = GetArrayTriggerAction(k,cs_COLM_AC)
if (fx!=null) then
call DestroyEffect(fx)
set fx=null
endif
if (GetArrayInt(k,19)==1) then //[19=new]
call ExplodeUnitBJ(m)
else
call RecicleCasterAfterCastEx(m,4,0,true)
endif
call TriggerRemoveAction(tr,ta)
//call TriggerRemoveAction(T,GetArrayTriggerAction(k,18)) //[18=triggeraction]
call DestroyArray(k)
//call Hostage(CS_H2I(tr))
call DestroyTrigger(tr)
//call CleanAttachedVars(T)
//call DestroyTrigger(T)
set tr = null
set ta = null
endfunction
function GetTriggerCollisionMissile takes nothing returns unit
return GetArrayInt(GetCSData(GetTriggeringTrigger()), cs_COLM_M )
return null
endfunction
function CollisionMissile_Move takes unit m, integer k returns boolean
local integer state=GetArrayInt(k,cs_COLM_STATE)
local boolean done
local real d
local real F
local real asp
local real x
local real nx
local real y
local real ny
local integer tt
local widget wd
local trigger TTT
if (state==2) then
set TTT=GetArrayTrigger(k,cs_COLM_T)
call TriggerExecute(TTT)
set TTT=null
call SetArrayInt(k,1,3) //[1:state]
return false
elseif (state==3) then
call CollisionMissile_Destroyer(m,k,GetArrayTrigger(k,cs_COLM_T))
return true
else
if (state==1) then
call TriggerRegisterUnitInRange(GetArrayTrigger(k,cs_COLM_T),m,GetArrayReal(k,cs_COLM_COLLISION),null)
call SetArrayInt(k,cs_COLM_STATE,0)
endif
set d=GetArrayReal(k,cs_COLM_SPEED) * cs_TIMER_CYCLE
set F=GetArrayReal(k,cs_COLM_F)
set asp=GetArrayReal(k,cs_COLM_ASPEED)
set x=GetUnitX(m)
set y=GetUnitY(m)
if (asp!=0) then
set tt=GetArrayInt(k,cs_COLM_TTYPE)
if (tt==cs_COLM_TTYPE_POINT) or (tt==cs_COLM_TTYPE_WIDGET) then
if (tt==cs_COLM_TTYPE_POINT) then
set nx=GetArrayReal(k,cs_COLM_TX)
set ny=GetArrayReal(k,cs_COLM_TY)
set F=Angles_MoveAngleTowardsAngle(F,Atan2(ny-y,nx-x)*bj_RADTODEG, asp * cs_TIMER_CYCLE)
else
set wd=GetArrayWidget(k,cs_COLM_TW)
if (GetWidgetLife(wd)<=0.405) then
call SetArrayInt(k,cs_COLM_TTYPE,cs_COLM_TTYPE_NONE)
set nx=x+0.001
set ny=y+0.001
set F=F+ asp * cs_TIMER_CYCLE
else
set nx=GetWidgetX(wd)
set ny=GetWidgetY(wd)
set F=Angles_MoveAngleTowardsAngle(F,Atan2(ny-y,nx-x)*bj_RADTODEG, asp * cs_TIMER_CYCLE)
endif
set wd=null
endif
else
set F=F+ asp * cs_TIMER_CYCLE
endif
call SetArrayReal(k,cs_COLM_F,F)
call SetUnitFacing(m,F)
endif
set F=F*bj_DEGTORAD
set nx=x+d*Cos(F)
set ny=y+d*Sin(F)
set d=GetArrayReal(k,cs_COLM_MAXD)-d
call SetArrayReal(k,cs_COLM_MAXD,d)
set done=(d<=0)
if (not done) then
if not(CS_MoveUnit(m,nx,ny)) then
set done=true
elseif (GetArrayInt(k,cs_COLM_PFX)==1) then
set F=GetArrayReal(k, cs_COLM_PFX_CURRENT )+cs_TIMER_CYCLE
if (F>=GetArrayReal(k, cs_COLM_PFX_DUR )) then
call DestroyEffect(AddSpecialEffectTarget(GetArrayString(k,cs_COLM_PFX_PATH), m, "origin" ))
call SetArrayReal(k, cs_COLM_PFX_CURRENT ,0)
else
call SetArrayReal(k, cs_COLM_PFX_CURRENT ,F)
endif
endif
endif
endif
if done then
call DisableTrigger(GetArrayTrigger(k,cs_COLM_T))
call DestroyEffect(GetArrayEffect(k,cs_COLM_FX))
call SetArrayObject(k,cs_COLM_FX,null)
call SetArrayInt(k,cs_COLM_STATE,2)
return false
endif
return false
endfunction
function CasterSystemMovementTimer takes nothing returns nothing
local timer ti
local integer n=cs_missilecount
local integer i=1
local unit p
local integer k
local integer mtype
loop
exitwhen (i>n)
set k=cs_missiles[i]
set mtype=GetArrayInt(k, cs_MOVE_TYPE)
if (mtype==cs_MOVE_TYPE_COLLISIONMISSILE) then
set p=GetArrayUnit(k,cs_COLM_M)
if not(CollisionMissile_Move(p,k)) then
set i=i+1
else
set cs_missiles[i]=cs_missiles[n]
set n=n-1
endif
elseif (mtype==cs_MOVE_TYPE_PROJECTILE) then
set p=GetArrayUnit(k, cs_PROJ_M)
if not(UnitMoveToAsProjectileAnySpeed_Move(p,k )) then
set i=i+1
else
set cs_missiles[i]=cs_missiles[n]
set n=n-1
endif
else
set i=i+1
call BJDebugMsg("Caster System: Unexpected Error (1) Wrong Array:"+I2S(k)+" ; "+I2S(mtype))
endif
endloop
if (n==0) then
call PauseTimer(cs_movementtimer)
set cs_movementtimer_active=false
endif
set cs_missilecount=n
set p=null
endfunction
// projectiles array constants
globals
// constant integer cs_MOVE_TYPE =0 already declared
constant integer cs_PROJ_TOUNIT = 1 //Is it directed towards a unit ?
constant integer cs_PROJ_TARGET = 2
constant integer cs_PROJ_Z2O = 3
constant integer cs_PROJ_Z2 = 5
constant integer cs_PROJ_N = 4
constant integer cs_PROJ_X2 =6
constant integer cs_PROJ_Y2 =7
constant integer cs_PROJ_SPEED = 8
constant integer cs_PROJ_ACEL = 9
constant integer cs_PROJ_DONE = 10
constant integer cs_PROJ_FX = 11
constant integer cs_PROJ_M = 12
constant integer cs_PROJ_ARRAYSIZE = 13
endglobals
function UnitMoveToAsProjectileAnySpeed_Effect takes unit m, effect fx, real speed, real arc, real x2, real y2, unit target, real z2 returns nothing
//
// The internal projectile system used by all the projectile functions
//
local timer t //=GetTableTimer("CasterSystem","MOVEMENT_TIMER")
local string km
local integer k
set km=I2S(CS_H2I(m))
set k=GetTableInt("MOVEMENT_TABLES",km)
if (k>0) then
call SetArrayInt(k, cs_PROJ_DONE ,1) //[10=done]
endif
set k=NewArray(cs_PROJ_ARRAYSIZE,true)
call SetArrayObject(k,cs_PROJ_M,m)
call StoreInteger(cs_cache,"MOVEMENT_TABLES",km,k)
set cs_missilecount=cs_missilecount+1
set cs_missiles[cs_missilecount]=k
if (not cs_movementtimer_active) then
call TimerStart(cs_movementtimer,cs_TIMER_CYCLE,true,function CasterSystemMovementTimer)
set cs_movementtimer_active=true
endif
call SetArrayInt(k, cs_MOVE_TYPE , cs_MOVE_TYPE_PROJECTILE)
if (target!=null) then
call SetArrayInt(k,cs_PROJ_TOUNIT,1)
call SetArrayObject(k, cs_PROJ_TARGET , target )
call SetArrayReal(k,cs_PROJ_X2,GetUnitX(target))
call SetArrayReal(k,cs_PROJ_Y2,GetUnitY(target))
call SetArrayReal(k,cs_PROJ_Z2O,z2)
else
call SetArrayReal(k,cs_PROJ_X2,x2)
call SetArrayReal(k,cs_PROJ_Y2,y2)
endif
call SetArrayReal(k, cs_PROJ_Z2 ,z2)
call SetArrayReal(k, cs_PROJ_SPEED , speed)
call SetArrayReal(k, cs_PROJ_ACEL ,arc*8000)
if (fx!=null) then
call SetArrayObject(k, cs_PROJ_FX ,fx)
set fx=null
endif
loop
exitwhen GetArrayInt(k, cs_PROJ_DONE )==1
call TriggerSleepAction(0)
endloop
call FlushStoredInteger(cs_cache,"MOVEMENT_TABLES",km)
call DestroyArray(k)
endfunction
function UnitMoveToAsProjectileAnySpeed takes unit m, real speed, real arc, real x2, real y2, unit target, real z2 returns nothing
//Left for compat
call UnitMoveToAsProjectileAnySpeed_Effect(m,null,speed,arc,x2,y2,target,z2)
endfunction
//========================================================================================================================
function UnitMoveToAsProjectileGen takes unit m, real arc, real x2, real y2, unit target, real z2 returns nothing
//
// The internal projectile system used by all the projectile functions
//
local real x1=GetUnitX(m)
local real y1=GetUnitY(m)
local real acel=arc*1600
local real speed=GetUnitMoveSpeed(m)
local real z1=GetUnitFlyHeight(m)
local real d
local real d1
local real d2
local real t
local real vel
local real dif=0
local boolean tounit= (target!=null)
local boolean b=false
local boolean mode=false
if tounit then
set x2=GetUnitX(target)
set y2=GetUnitY(target)
set z2=GetUnitFlyHeight(target)+z2
endif
set mode=(z2>z1)
set d=SquareRoot(Pow(x2-x1,2)+Pow(y2-y1,2))
set d1=1000000
set d2=0
set t=d/speed
if t==0 then
set t=0.001
endif
set vel=(z2-z1+0.5*acel*t*t)/t
call SetUnitFacing( m, Atan2BJ(y2 - y1, x2 - x2) )
call IssuePointOrder( m, "move", x2,y2)
set t=0
loop
set d2=d1
if tounit then
if (GetWidgetLife(target)<=0.405) then
set tounit=false
else
set x2=GetUnitX(target)
set y2=GetUnitY(target)
endif
endif
set d1=SquareRoot(Pow(x2-GetUnitX(m),2)+Pow(y2-GetUnitY(m),2))
exitwhen b or d1==0
set b=(d1<=speed*(t-dif))
exitwhen (mode and b) or (GetUnitCurrentOrder(m) != OrderId("move"))
if tounit then
call IssuePointOrder( m, "move", x2,y2)
endif
set dif=t
if dif==0.001 then
set t=0.1
else
set t= (d-d1)/speed
endif
set t= 2*t-dif
call SetUnitFlyHeight( m, z1+(vel*t-0.5*acel*t*t), RAbsBJ( vel-acel*(t+dif)/2) )
set t=(t+dif)/2
call TriggerSleepAction(0)
endloop
if tounit then
set x2=GetUnitX(target)
set y2=GetUnitY(target)
endif
call SetUnitFlyHeight( m,z2,0)
call CS_MoveUnit(m,x2,y2)
endfunction
function UnitMoveToAsProjectile takes unit m, real arc, real x2, real y2, real z2 returns nothing
call UnitMoveToAsProjectileGen(m, arc,x2,y2,null,z2)
endfunction
//============================================================================================================
function ProjectileLaunchEx takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc,real x1, real y1, real z1, real x2, real y2, real z2 returns nothing
local unit m=CreateCaster( Atan2BJ(y2 - y1, x2 - x1),x1,y1 )
local effect fx=null
call SetUnitScale( m, scale, scale, scale)
call SetUnitVertexColor(m, red, green, blue, alpha)
call SetUnitFlyHeight( m, z1, 0)
set fx= AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, owner, true)
if (speed<=522) then
call SetUnitMoveSpeed(m, speed)
call UnitMoveToAsProjectile(m, arc, x2, y2, z2)
call DestroyEffect(fx)
else
call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed,arc,x2,y2,null,z2)
endif
call ExplodeUnitBJ(m)
set owner=null
set fx=null
set m=null
endfunction
function ProjectileLaunchExLoc takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, location loc1, real z1, location loc2, real z2 returns nothing
call ProjectileLaunchEx( owner, modelpath, scale, red, green, blue, alpha, speed, arc,GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2)
endfunction
//============================================================================================================
function ProjectileLaunch takes string modelpath, real speed, real arc,real x1, real y1, real z1, real x2, real y2, real z2 returns nothing
call ProjectileLaunchEx( Player(15), modelpath, 1, 255, 255, 255, 255, speed, arc,x1,y1,z1,x2,y2,z2)
endfunction
function ProjectileLaunchLoc takes string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2 returns nothing
call ProjectileLaunchExLoc( Player(15), modelpath, 1,255,255,255,255,speed,arc,loc1,z1,loc2,z2)
endfunction
//============================================================================================================
function DamagingProjectileLaunchAOE_Child takes nothing returns nothing
local unit m=udg_currentcaster
local effect fx=bj_lastCreatedEffect
local real x2=udg_castervars[0]
local real y2=udg_castervars[1]
local real aoeradius=udg_castervars[3]
local real damage=udg_castervars[4]
local boolean affectallied=bj_isUnitGroupInRectResult
local integer V=CreateDamageOptions(R2I(udg_castervars[5]))
local unit hurter=udg_currenthurter
local real speed=udg_castervars[6]
if (speed<=522) then
call SetUnitMoveSpeed(m, speed)
call UnitMoveToAsProjectile(m, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], udg_castervars[2])
call DestroyEffect(fx)
else
call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed,bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1],null, udg_castervars[2])
endif
call DamageUnitsInAOEEx(hurter,damage,x2,y2,aoeradius,affectallied,LoadDamageOptions(V))
call DestroyDamageOptions(V)
call ExplodeUnitBJ(m)
set m=null
set fx=null
endfunction
function DamagingProjectileLaunchAOE takes unit hurter, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2, real aoeradius, real damage, boolean affectallied, integer DamageOptions returns unit
local unit m=CreateCaster( Atan2BJ(y2 - y1, x2 - x1) ,x1,y1)
call SetUnitFlyHeight( m, z1, 0)
set udg_currentcaster=m
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, GetOwningPlayer(hurter), true)
set bj_meleeNearestMineDist = arc
set udg_castervars[0] = x2
set udg_castervars[1] = y2
set udg_castervars[2] = z2
set udg_castervars[3] =aoeradius
set udg_castervars[4] =damage
set udg_castervars[5] =DamageOptions
set udg_castervars[6] =speed
set udg_currenthurter=hurter
set bj_isUnitGroupInRectResult=affectallied
call ExecuteFunc("DamagingProjectileLaunchAOE_Child")
set m=null
return udg_currentcaster
endfunction
function DamagingProjectileLaunchAOELoc takes unit hurter, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2, real aoeradius, real damage, boolean affectallied, integer DamageOptions returns unit
return DamagingProjectileLaunchAOE(hurter,modelpath,speed,arc,GetLocationX(loc1),GetLocationY(loc1),z1,GetLocationX(loc2),GetLocationY(loc2),z2, aoeradius, damage, affectallied, DamageOptions )
endfunction
function ProjectileLaunchDamage takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2, real aoeradius, real damage, boolean affectallied returns unit
local unit m=CreateCaster( Atan2BJ(y2 - y1, x2 - x1) ,x1,y1 )
call SetUnitFlyHeight( m, z1, 0)
set udg_currentcaster=m
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, owner, true)
set bj_meleeNearestMineDist = arc
set udg_castervars[0] = x2
set udg_castervars[1] = y2
set udg_castervars[2] = z2
set udg_castervars[3] =aoeradius
set udg_castervars[4] =damage
set udg_castervars[5] =0
set udg_castervars[6]= speed
set bj_isUnitGroupInRectResult=affectallied
set udg_currenthurter=m
call ExecuteFunc("DamagingProjectileLaunchAOE_Child")
set m=null
return udg_currentcaster
endfunction
function ProjectileLaunchDamageLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2, real aoeradius, real damage, boolean affectallied returns unit
return ProjectileLaunchDamage( owner, modelpath, speed, arc, GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2, aoeradius, damage, affectallied)
endfunction
//============================================================================================================
function ProjectileLaunchKill_Child takes nothing returns nothing
local unit m=udg_currentcaster
local effect fx=bj_lastCreatedEffect
local real x2=udg_castervars[0]
local real y2=udg_castervars[1]
local real speed=udg_castervars[3]
if (speed<=522) then
call SetUnitMoveSpeed( m, speed)
call UnitMoveToAsProjectile(m, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], udg_castervars[2])
call DestroyEffect( fx)
else
call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], null, udg_castervars[2])
endif
call ExplodeUnitBJ(m)
set m=null
set fx=null
endfunction
function ProjectileLaunchKill takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2 returns unit
local unit m=CreateCaster( Atan2BJ(y2 - y1, x2 - x1),x1,y1 )
call SetUnitFlyHeight( m, z1, 0)
set udg_currentcaster=m
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, owner, true)
set bj_meleeNearestMineDist = arc
set udg_castervars[0] = x2
set udg_castervars[1] = y2
set udg_castervars[2] = z2
set udg_castervars[3] = speed
call ExecuteFunc("ProjectileLaunchKill_Child")
set m=null
return udg_currentcaster
endfunction
function ProjectileLaunchKillLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2 returns unit
return ProjectileLaunchKill( owner, modelpath, speed, arc, GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2)
endfunction
//====================================================================================================================================================================
function UnitMoveToUnitAsProjectile takes unit m, real arc, unit target, real zoffset returns nothing
call UnitMoveToAsProjectileGen(m, arc,0,0,target,zoffset)
endfunction
//====================================================================================================================================================================
function ProjectileLaunchToUnitEx takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset returns nothing
local unit m=CreateCaster( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1),x1,y1 )
local effect fx=null
call SetUnitFlyHeight( m, z1, 0)
call SetUnitScale( m, scale, scale, scale)
call SetUnitVertexColor(m, red, green, blue, alpha)
set fx=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m , owner, true)
if (speed<=522) then
call SetUnitMoveSpeed( m, speed)
call UnitMoveToUnitAsProjectile(m,arc,target, zoffset)
call DestroyEffect(fx)
else
call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed, arc,0,0,target,zoffset)
endif
call ExplodeUnitBJ(m)
set m=null
set fx=null
endfunction
function ProjectileLaunchToUnitExLoc takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, location loc1, real z1, unit target, real zoffset returns nothing
call ProjectileLaunchToUnitEx( owner, modelpath, scale, red, green, blue, alpha, speed, arc, GetLocationX(loc1),GetLocationY(loc1), z1, target, zoffset)
endfunction
function ProjectileLaunchToUnit takes string modelpath, real speed, real arc,real x1, real y1, real z1, unit target, real zoffset returns nothing
call ProjectileLaunchToUnitEx( Player(15), modelpath, 1, 255,255,255,255,speed,arc,x1,y1,z1,target,zoffset)
endfunction
function ProjectileLaunchToUnitLoc takes string modelpath, real speed, real arc, location loc1, real z1, unit target, real zoffset returns nothing
call ProjectileLaunchToUnitExLoc( Player(15), modelpath, 1, 255,255,255,255, speed, arc, loc1, z1, target,zoffset)
endfunction
//====================================================================================================================================================================
function DamagingProjectileLaunchTarget_Child takes nothing returns nothing
local unit m=udg_currentcaster
local unit target=bj_meleeNearestMine
local effect fx=bj_lastCreatedEffect
local real damage=udg_castervars[4]
local damagetype dmgT=ConvertDamageType(R2I(udg_castervars[6]))
local attacktype attT=ConvertAttackType(R2I(udg_castervars[5]))
local unit hurter=udg_currenthurter
local real speed=udg_castervars[7]
if (speed<=522) then
call SetUnitMoveSpeed( m, speed)
call UnitMoveToUnitAsProjectile(m, bj_meleeNearestMineDist, target, udg_castervars[2])
call DestroyEffect( fx)
else
call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed, bj_meleeNearestMineDist,0,0,target,udg_castervars[2])
endif
call DamageUnitByTypes(hurter,target,damage,attT,dmgT)
call ExplodeUnitBJ(m)
set m=null
set hurter=null
set target=null
set fx=null
set dmgT=null
set attT=null
endfunction
function DamagingProjectileLaunchTarget takes unit hurter, string modelpath, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset, real damage, attacktype attT, damagetype dmgT returns unit
local unit m=CreateCaster( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1),x1,y1 )
set udg_castervars[7]=speed
call SetUnitFlyHeight( m, z1, 0)
set udg_currentcaster=m
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, GetOwningPlayer(hurter), true)
set bj_meleeNearestMineDist = arc
set udg_castervars[2]= zoffset
set bj_meleeNearestMine=target
set udg_castervars[4]=damage
set udg_castervars[5]=CS_H2I(attT)
set udg_castervars[6]=CS_H2I(dmgT)
set udg_currenthurter=hurter
call ExecuteFunc("DamagingProjectileLaunchTarget_Child")
set m=null
return udg_currentcaster
endfunction
function DamagingProjectileLaunchTargetLoc takes unit hurter, string modelpath, real speed, real arc, location loc, real z1, unit target, real zoffset, real damage, attacktype attT, damagetype dmgT returns unit
return DamagingProjectileLaunchTarget(hurter,modelpath,speed,arc,GetLocationX(loc),GetLocationY(loc), z1, target, zoffset, damage, attT, dmgT)
endfunction
//! define DamagingProjectileLaunchTargetLoc(h,m,s,a,L,z1,target,zoffset,damage,att,dtt) DamagingProjectileLaunchTarget(h,m,s,a,GetLocationX(L),GetLocationY(L),z1,target,zoffset,damage,att,dtt)
function ProjectileLaunchToUnitDamage takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset, real damage returns unit
local unit m=CreateCaster( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1),x1,y1 )
set udg_castervars[7]=speed
call SetUnitFlyHeight( m, z1, 0)
set udg_currentcaster=m
set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" )
call SetUnitOwner( m, owner, true)
set bj_meleeNearestMineDist = arc
set udg_castervars[2]= zoffset
set bj_meleeNearestMine=target
set udg_castervars[4]=damage
set udg_castervars[5]=CS_H2I(cs_DefaultAttackType)
set udg_castervars[6]=CS_H2I(cs_DefaultDamageType)
set udg_currenthurter=m
call ExecuteFunc("DamagingProjectileLaunchTarget_Child")
set m=null
return udg_currentcaster
endfunction
function ProjectileLaunchToUnitDamageLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, unit target, real zoffset, real damage returns unit
return ProjectileLaunchToUnitDamage( owner, modelpath, speed, arc,GetLocationX(loc1),GetLocationY(loc1),z1,target,zoffset,damage)
endfunction
//! define ProjectileLaunchToUnitDamageLoc(owner,modelpath,speed,arc,loc1,z1,target,zoffset,damage) ProjectileLaunchToUnitDamage(owner,modelpath,speed,arc,GetLocationX(loc),GetLocationY(loc),z1,target,zoffset,damage)
//==============================================================================================================================================================================
// Caster System Class: CollisionMissile
//
function CollisionMissile_Destroy takes unit m returns nothing
local integer k=GetUnitUserData(m)
local effect fx=GetArrayEffect(k,cs_COLM_FX)
if (fx!=null) then
call DestroyEffect(fx)
call SetArrayObject(k,cs_COLM_FX,null) //[17=fx]
set fx=null
endif
//For convenience, always wait for next tic to destroy the thing. But destroy the effect so
//players don't ever notice it.
call SetArrayInt(k,cs_COLM_STATE,2)
call DisableTrigger(GetArrayTrigger(k,cs_COLM_T))
endfunction
function CollisionMissile_Create takes string MissileModelPath, real x, real y, real dirangle, real speed, real AngleSpeed, real MaxDist, real height, boolean UseNewCaster, real Collision, code OnImpact returns unit
local timer t
local integer k
local trigger R
local unit m
set k=NewArray(cs_COLM_ARRAYSIZE,true)
if UseNewCaster then
set m=CreateCaster(dirangle,x,y)
call SetArrayInt(k,cs_COLM_NEW,1)
else
set m=GetACaster()
call SetUnitFacing(m,dirangle)
call SetUnitPosition(m,CS_SafeX(x),CS_SafeY(y))
endif
set cs_missilecount=cs_missilecount+1
set cs_missiles[cs_missilecount]=k
if (not cs_movementtimer_active) then
call TimerStart(cs_movementtimer,cs_TIMER_CYCLE,true,function CasterSystemMovementTimer)
set cs_movementtimer_active=true
endif
call SetUnitUserData(m,k)
call SetArrayInt(k,cs_MOVE_TYPE, cs_MOVE_TYPE_COLLISIONMISSILE)
call SetArrayReal(k,cs_COLM_SPEED,speed)
call SetArrayReal(k,cs_COLM_ASPEED,AngleSpeed)
call SetArrayReal(k,cs_COLM_F,dirangle)
call SetArrayReal(k,cs_COLM_MAXD,MaxDist)
call SetUnitFlyHeight(m,height,0)
set R=CreateTrigger()
call SetArrayReal(k,cs_COLM_COLLISION,Collision)
call SetArrayInt(k,cs_COLM_STATE,1)
call SetArrayObject(k,cs_COLM_T,R)
call SetCSData(R,k)
call SetArrayObject(k,cs_COLM_FX, AddSpecialEffectTarget(MissileModelPath,m,"origin") )
call SetArrayObject(k,cs_COLM_M,m)
call SetArrayObject(k,cs_COLM_AC,TriggerAddAction(R,OnImpact))
set R=null
set udg_currentcaster=m
set m=null
return udg_currentcaster
endfunction
function CollisionMissile_CreateLoc takes string MissileModelPath, location loc, real dirangle, real speed, real AngleSpeed, real MaxDist, real height, boolean UseNewCaster, real Collision, code OnImpact returns unit
return CollisionMissile_Create(MissileModelPath,GetLocationX(loc),GetLocationY(loc),dirangle,speed,AngleSpeed,MaxDist,height,UseNewCaster,Collision,OnImpact)
endfunction
//! CollisionMissile_CreateLoc(MissileModelPath,loc,dirangle,speed,AngleSpeed,MaxDist,height,UseNewCaster,Collision,OnImpact) CollisionMissile_Create(MissileModelPath,GetLocationX(loc),GetLocationY(loc),dirangle,speed,AngleSpeed,MaxDist,height,UseNewCaster,Collision,OnImpact)
//=========================================================================================================================================================
function CollisionMissile_SetAngleSpeed takes unit m, real newAspeed returns nothing
call SetArrayReal( GetUnitUserData(m) , cs_COLM_ASPEED ,newAspeed )
endfunction
//! CollisionMissile_SetAngleSpeed(m,s) SetArrayReal( GetUnitUserData(m). cs_COLM_ASPEED, s)
//=========================================================================================================================================================
function CollisionMissile_SetSpeed takes unit m, real newspeed returns nothing
call SetArrayReal( GetUnitUserData(m) , cs_COLM_SPEED ,newspeed)
endfunction
//! CollisionMissile_SetSpeed(m,s) SetArrayReal( GetUnitUserData(m). cs_COLM_SPEED, s)
//=========================================================================================================================================================
function CollisionMissile_SetTargetPoint takes unit m, real tx, real ty returns nothing
local integer k= GetUnitUserData(m)
call SetArrayReal(k,cs_COLM_TX,tx)
call SetArrayReal(k,cs_COLM_TY,ty)
call SetArrayInt(k,cs_COLM_TTYPE, cs_COLM_TTYPE_POINT )
endfunction
function CollisionMissile_SetTargetPointLoc takes unit m, location tloc returns nothing
call CollisionMissile_SetTargetPoint(m,GetLocationX(tloc),GetLocationY(tloc))
endfunction
//! define CollisionMissile_SetTargetPointLoc(m,l) CollisionMissile_SetTargetPoint(m,GetLocationX(l),GetLocationY(l))
//=========================================================================================================================================================
function CollisionMissile_SetTarget takes unit m, widget Target returns nothing
local integer k= GetUnitUserData(m)
call SetArrayObject(k,cs_COLM_TW,Target)
call SetArrayInt(k, cs_COLM_TTYPE, cs_COLM_TTYPE_WIDGET )
endfunction
//=========================================================================================================================================================
function CollisionMissile_ForgetTarget takes unit m returns nothing
call SetArrayInt( GetUnitUserData(m) ,cs_COLM_TTYPE, cs_COLM_TTYPE_NONE )
endfunction
//! define CollisionMissile_ForgetTarget(m) SetArrayInt( GetUnitUserData(m) ,cs_COLM_TTYPE, cs_COLM_TTYPE_NONE )
//=========================================================================================================================================================
function CollisionMissile_SetDirAngle takes unit m, real f returns nothing
local integer k= GetUnitUserData(m)
call SetArrayReal(k, cs_COLM_F ,f)
call SetUnitFacing(m,f)
endfunction
//=========================================================================================================================================================
function CollisionMissile_ResetMaxDist takes unit m, real maxdist returns nothing
call SetArrayReal( GetUnitUserData(m) , cs_COLM_MAXD ,maxdist)
endfunction
//! CollisionMissile_ResetMaxDist(m,d) SetArrayReal( GetUnitUserData(m). cs_COLM_MAXD, s)
//=========================================================================================================================================================
function CollisionMissile_PeriodicFX takes unit m, string fx, real dur returns nothing
// [1 integer state][2 trigger T][3 real collision][4 real speed][5 real F][6 real aspeed][7 integer TType]
// [8 real Tx][9 real Ty][10 widget Tw][11 real F][12 real maxd][13 boolean pfx][14 real pfx_current][15 real pfx_dur][16 pfx_path]
// [17 fx][18 ac][19 boolean new][20 m]
local integer k= GetUnitUserData(m)
call SetArrayInt(k, cs_COLM_PFX,1)
call SetArrayString(k , cs_COLM_PFX_PATH ,fx)
call SetArrayReal(k , cs_COLM_PFX_DUR ,dur)
call SetArrayReal(k , cs_COLM_PFX_CURRENT ,0)
endfunction
//==============================================================================================================================================================================
// Caster System Class: Damager
//
function Damager_SetAbility takes unit Damager, integer abilid, integer l returns nothing
local string k=GetAttachmentTable(Damager)
local integer i
if (GetTableBoolean(k,"CS_IsDamager")) then
set i=GetTableInt(k,"CS_abil")
if (i!=0) then
call UnitRemoveAbility(Damager,i)
endif
call UnitAddAbility(Damager,abilid)
call SetUnitAbilityLevel(Damager,abilid,l)
call SetTableInt(k,"CS_abil",abilid)
endif
endfunction
function Damager_Removage takes unit u, timer t, group g returns nothing
local string k=GetAttachmentTable(u)
if (t!=null) then
call CleanAttachedVars(t)
call ReleaseTimer(t)
endif
call GroupRemoveUnit(g,u)
call DestroyEffect( GetTableEffect(k,"CS_fx") )
call RecicleCasterAfterCastEx(u,4,GetTableInt(k,"CS_abil"),false)
call ClearTable(k)
endfunction
function Damager_Remove takes unit Damager returns nothing
local string k=GetAttachmentTable(Damager)
local timer dg
local group g
if (GetTableBoolean(k,"CS_IsDamager")) then
set g=GetTableGroup(I2S( GetTableInt(k,"CS_DG") ),"G")
if (IsUnitInGroup(Damager,g)) then
call Damager_Removage(Damager,GetTableTimer(k,"CS_t"),g)
endif
endif
set g=null
set dg=null
endfunction
function Damager_Expire takes nothing returns nothing
local timer t=GetExpiredTimer()
local unit u=GetAttachedUnit(t,"u")
call Damager_Removage(u,t, GetAttachedGroup( GetAttachedObject(u,"CS_DG") ,"G") )
set u=null
endfunction
function Damager_SetLifeSpan takes unit Damager, real lifespan returns nothing
local timer t
if (GetAttachedBoolean(Damager,"CS_IsDamager")) then
set t=GetAttachedTimer(Damager,"CS_t")
if (lifespan==0) then
call PauseTimer(t)
else
call TimerStart(t,lifespan,false, function Damager_Expire)
endif
set t=null
endif
endfunction
//============================================================================================================
// Caster System Class: DamagerGroup
//
function DamagerGroup_Destroy takes timer DamagerGroup returns nothing
local string k=I2S(CS_H2I(DamagerGroup))
local group g=GetTableGroup(k,"G")
local unit p
call DestroyDamageOptions(GetStoredInteger(cs_cache,k,"dop") )
call CS_KillTimer( GetTableTimer(k,"lifespan") )
loop
set p=FirstOfGroup(g)
exitwhen (p==null)
call Damager_Removage(p, GetAttachedTimer(p,"CS_t") ,g)
endloop
call DestroyGroup(g)
call FlushStoredMission(cs_cache,k)
call ReleaseTimer(DamagerGroup)
set g=null
endfunction
function DamagerGroup_Enum takes nothing returns nothing
call GroupAddUnit(bj_groupAddGroupDest, GetFilterUnit() )
endfunction
function DamagerGroup_DoDamage takes nothing returns nothing
local timer t=GetExpiredTimer()
local string k=I2S(CS_H2I(t))
local group g=CreateGroup()
local group a=CS_CopyGroup(GetTableGroup(k,"G"))
local group arg=CreateGroup()
local unit p
local unit u=GetTableUnit(k,"hur")
local real x=GetStoredReal(cs_cache,k,"are")
local real dm
local integer d
local boolean trees=GetStoredBoolean(cs_cache,k,"trees")
local boolexpr bex=Condition(function DamagerGroup_Enum)
set bj_groupAddGroupDest=g
if (FirstOfGroup(a)!=null) then
loop
set p=FirstOfGroup(a)
exitwhen (p==null)
call GroupRemoveUnit(a,p)
call CS_EnumUnitsInAOE(arg,GetUnitX(p),GetUnitY(p),x,bex)
if trees then
call DamageTreesInCircle(GetUnitX(p),GetUnitY(p),x)
endif
endloop
if (FirstOfGroup(g)!=null) then
set d=LoadDamageOptions( GetStoredInteger(cs_cache,k,"dop") )
set dm=GetStoredReal(cs_cache,k,"dmg")
loop
set p=FirstOfGroup(g)
exitwhen (p==null)
set x=GetDamageFactorByOptions(u,p,d)
if (x!=0) then
call UnitDamageTarget(u,p,dm*x,true,false,null,null,null)
endif
call GroupRemoveUnit(g,p)
endloop
endif
elseif GetStoredBoolean(cs_cache,k,"autodestruct") then
call DamagerGroup_Destroy(t)
endif
call DestroyBoolExpr(bex)
call DestroyGroup(g)
call DestroyGroup(arg)
call DestroyGroup(a)
set bex=null
set t=null
set g=null
set arg=null
set a=null
set u=null
endfunction
function DamagerGroup_Create takes unit hurter, real damage, real damageperiod, real area, integer DamageOptions returns timer
local timer t=NewTimer()
local string k=I2S(CS_H2I(t))
if (damageperiod<0.01) then
set damageperiod=0.01
endif
call StoreInteger(cs_cache,k,"dop",CreateDamageOptions(DamageOptions))
call StoreInteger(cs_cache,k,"hur",CS_H2I(hurter))
call StoreReal(cs_cache,k,"dmg",damage)
call StoreReal(cs_cache,k,"are",area)
call StoreInteger(cs_cache,k,"G",CS_H2I(CreateGroup()))
if IsDamageOptionIncluded(DamageOptions, DamageTrees() ) then
call StoreBoolean(cs_cache,k,"trees", true )
endif
call TimerStart(t,damageperiod,true,function DamagerGroup_DoDamage)
return t //Since the timer is a recyclable one, it won't be destroyed, then there is no need to set it to null
//then we can just return it
endfunction
function DamagerGroup_Update takes timer DamagerGroup, unit hurter, real damage, real damageperiod, real area, integer DamageOptions returns nothing
local integer i
local string k=GetAttachmentTable(DamagerGroup)
local unit p=GetTableUnit(k,"hur")
local player ow
local group g
if (damageperiod<0.01) then
set damageperiod=0.01
endif
if (p!=hurter) then
set g=CS_CopyGroup( GetTableGroup(k,"G") )
call SetTableObject(k,"hur",hurter)
set ow=GetOwningPlayer(hurter)
loop
set p=FirstOfGroup(g)
exitwhen (p==null)
call GroupRemoveUnit(g,p)
call SetUnitOwner(p,ow,true)
endloop
call DestroyGroup(g)
set g=null
set ow=null
endif
call SetTableBoolean(k,"trees",IsDamageOptionIncluded(DamageOptions, DamageTrees() ) )
call SetDamageOptions(GetTableInt(k,"dop") , DamageOptions )
call SetTableReal(k,"dmg",damage)
call SetTableReal(k,"are",area)
call TimerStart(DamagerGroup,damageperiod,true,function DamagerGroup_DoDamage)
set p=null
endfunction
function DamagerGroup_AddDamager takes timer DamagerGroup, string modelpath, real x, real y, real LifeSpan returns unit
local unit c=GetACaster()
local string k=GetAttachmentTable(c)
local string dk=GetAttachmentTable(DamagerGroup)
local timer t=NewTimer()
call SetUnitPosition(c,x,y)
call SetTableObject(k,"CS_fx",AddSpecialEffectTarget( modelpath,c,"origin") )
call SetTableObject(k,"CS_t", t)
call SetTableObject(k,"CS_DG", DamagerGroup)
call AttachObject(t,"u", c)
if (LifeSpan>0) then
call TimerStart(t,LifeSpan,false, function Damager_Expire)
endif
call SetUnitOwner(c,GetOwningPlayer(GetTableUnit(dk,"hur")),true)
call GroupAddUnit(GetTableGroup(dk,"G"),c)
call SetTableBoolean(k,"CS_IsDamager",true)
set udg_currentcaster=c
set c=null
return udg_currentcaster
endfunction
function DamagerGroup_AddDamagerLoc takes timer DamagerGroup, string modelpath, location loc, real LifeSpan returns unit
return DamagerGroup_AddDamager(DamagerGroup,modelpath,GetLocationX(loc),GetLocationY(loc),LifeSpan)
endfunction
function DamagerGroup_OnLifeSpanExpire takes nothing returns nothing
call DamagerGroup_Destroy( GetAttachedTimer(GetExpiredTimer() , "t") )
endfunction
function DamagerGroup_SetLifeSpan takes timer DamagerGroup, real lifespan returns nothing
local string k=GetAttachmentTable(DamagerGroup)
local timer t
if (HaveSetField(k,"lifespan",bj_GAMECACHE_INTEGER)) then
set t=GetTableTimer(k,"lifespan")
else
set t=NewTimer()
call SetTableObject(k,"lifespan",t)
set k=GetAttachmentTable(t)
call AttachObject(t,"t",DamagerGroup)
endif
call TimerStart(t,lifespan,false, function DamagerGroup_OnLifeSpanExpire)
set t=null
endfunction
function DamagerGroup_AutoDestruct takes timer DamagerGroup, boolean auto returns nothing
call AttachBoolean(DamagerGroup,"autodestruct",auto)
endfunction
//**************************************************************************************************
//*
//* Caster System Special Events:
//*
//*
//**************************************************************************************************
//==================================================================================================
// Event: OnAbilityLearn
//
function Event_OnLearn1 takes nothing returns nothing
local integer s=GetLearnedSkill()
local string k=I2S(s)
if HaveStoredString( cs_cache, "events_onlearn",k) then
call ExecuteFunc( GetStoredString( cs_cache, "events_onlearn",k) )
endif
endfunction
function Event_OnLearn2 takes nothing returns nothing
local integer s=GetLearnedSkill()
local string k=I2S(s)
if HaveStoredString( cs_cache, "events_onlearn",k) then
call StoreInteger(cs_cache,"events_variables","unit",CS_H2I(GetTriggerUnit()))
call StoreInteger(cs_cache,"events_variables","current",s)
call ExecuteFunc( GetStoredString( cs_cache, "events_onlearn",k) )
endif
endfunction
function InitLearnEvent takes gamecache g, integer i returns nothing
local trigger t=CreateTrigger()
local integer j=0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(j),EVENT_PLAYER_HERO_SKILL, null)
set j=j+1
exitwhen j==bj_MAX_PLAYER_SLOTS
endloop
if (i==1) then
call StoreInteger(g,"Events_ProbablyTemp","learntrig",CS_H2I(t))
call StoreInteger(g,"Events_ProbablyTemp","learntriga",CS_H2I(TriggerAddAction(t, function Event_OnLearn1)))
else
call TriggerAddAction(t, function Event_OnLearn2)
endif
call StoreInteger(g,"eventhandlers","learn",i)
set t=null
endfunction
function OnAbilityLearn takes integer abilid, string funcname returns nothing
if (not HaveStoredInteger(cs_cache,"eventhandlers","learn")) then
call InitLearnEvent(cs_cache,1)
endif
call StoreString(cs_cache,"events_onlearn", I2S(abilid), funcname)
endfunction
//==================================================================================================
// Event: OnAbilityGet
//
function GetAbilityAcquiringUnit takes nothing returns unit
return GetStoredInteger(cs_cache,"events_variables","unit")
return null
endfunction
function GetAcquiredAbilityId takes nothing returns integer
return GetStoredInteger(cs_cache,"events_variables","current")
endfunction
///! define GetAcquiredAbilityId() GetStoredInteger(cs_cache,"events_variables","current") probably later
function UnitAddAbility_ConsiderEvent takes unit whichUnit, integer abilid, integer level returns nothing
local string k=I2S(abilid)
call UnitAddAbility(whichUnit,abilid)
call SetUnitAbilityLevel(whichUnit,abilid,level)
if (HaveStoredString(cs_cache,"events_onlearn",k)) then
call StoreInteger(cs_cache,"events_variables","units",CS_H2I(whichUnit))
call StoreInteger(cs_cache,"events_variables","current",abilid)
call ExecuteFunc(GetStoredString(cs_cache,"events_onlearn",k))
endif
endfunction
function Event_OnPassive_Browse takes unit u, string k returns nothing
local integer n=GetStoredInteger(cs_cache,"events_passives","n")
local integer un=0
local integer i=1
local integer s
loop
exitwhen (i>n)
set s=GetStoredInteger(cs_cache,"events_passives",I2S(i))
if (GetUnitAbilityLevel(u,s)>0) then
if (un==0) then
set un=1
call StoreInteger(cs_cache,"events_variables","unit",CS_H2I(u))
else
set un=un+1
endif
call StoreInteger(cs_cache,"events_unit_passive"+I2S(un),k,s)
call StoreInteger(cs_cache,"events_variables","current",s)
call ExecuteFunc(GetStoredString(cs_cache,"events_onlearn",I2S(s)))
endif
set i=i+1
endloop
if (un==0) then
set un=-1
endif
call StoreInteger(cs_cache,"events_unit_passives",k,un)
endfunction
function Event_OnPassive_Do takes unit u, string k, integer n returns nothing
local integer i=1
local integer s
call StoreInteger(cs_cache,"events_variables","unit",CS_H2I(u))
loop
exitwhen (i>n)
set s=GetStoredInteger(cs_cache,"events_unit_passive"+I2S(i),k)
if (GetUnitAbilityLevel(u,s)>0) then
call StoreInteger(cs_cache,"events_variables","current",s)
call ExecuteFunc(GetStoredString(cs_cache,"events_onlearn",I2S(s)))
endif
set i=i+1
endloop
endfunction
function Event_OnPassive_EnterRect takes nothing returns nothing
local unit u=GetTriggerUnit()
local string k=I2S(GetUnitTypeId(u))
local integer n=GetStoredInteger(cs_cache,"events_unit_passives",k)
if (n>0) then
call Event_OnPassive_Do(u,k,n)
elseif (n==0) then
call Event_OnPassive_Browse(u,k)
endif
set u=null
endfunction
function Event_OnPassive_NoCasters takes nothing returns boolean
return (GetUnitTypeId(GetTriggerUnit())!=cs_CasterUnitId)
endfunction
function Event_OnPassive_InitEnum takes nothing returns nothing
local trigger t
local integer n=GetStoredInteger(cs_cache,"events_passives","n")
local integer i=1
local integer array p
local string array s
local unit u
local group a=CreateGroup()
local boolean saved
call ReleaseTimer(GetExpiredTimer())
loop
exitwhen (i>n)
set p[i]=GetStoredInteger(cs_cache,"events_passives",I2S(i))
set s[i]=GetStoredString(cs_cache,"events_onlearn", I2S(p[i]))
set i=i+1
endloop
call GroupEnumUnitsInRect(a,bj_mapInitialPlayableArea,null)
loop
set u=FirstOfGroup(a)
exitwhen (u==null)
set i=1
set saved=false
loop
exitwhen (i>n)
if (GetUnitAbilityLevel(u,p[i])>0) then
if (not saved) then
set saved=true
call StoreInteger(cs_cache,"events_variables","unit",CS_H2I(u))
endif
call StoreInteger(cs_cache,"events_variables","current",p[i])
call ExecuteFunc(s[i])
endif
set i=i+1
endloop
call GroupRemoveUnit(a,u)
endloop
set t=CreateTrigger()
call TriggerRegisterEnterRectSimple(t,bj_mapInitialPlayableArea)
call TriggerAddAction(t,function Event_OnPassive_EnterRect)
call TriggerAddCondition(t,Condition(function Event_OnPassive_NoCasters))
call DestroyGroup(a)
set t=null
set a=null
endfunction
function InitPassiveEvent takes nothing returns nothing
local trigger t
local triggeraction a
call TimerStart(NewTimer(),0,false,function Event_OnPassive_InitEnum)
call StoreInteger(cs_cache,"eventhandlers","passives",1)
if (not HaveStoredInteger(cs_cache,"eventhandlers","learn")) then
call InitLearnEvent(cs_cache,2)
else
set t=GetTableTrigger("Events_ProbablyTemp","learntrig")
set a=GetTableTriggerAction("Events_ProbablyTemp","learntriga")
call TriggerRemoveAction(t,a )
call FlushStoredMission(cs_cache,"Events_ProbablyTemp")
call TriggerAddAction(t, function Event_OnLearn2)
call StoreInteger(cs_cache,"eventhandlers","learn",2)
set t=null
set a=null
endif
endfunction
function OnAbilityGet takes integer abilid, string funcname returns nothing
local integer n=GetStoredInteger(cs_cache,"events_passives","n")+1
if (not HaveStoredInteger(cs_cache,"eventhandlers","passives")) then
call InitPassiveEvent()
endif
call StoreString( cs_cache,"events_onlearn", I2S(abilid), funcname)
call StoreInteger(cs_cache,"events_passives","n",n)
call StoreInteger(cs_cache,"events_passives",I2S(n),abilid)
endfunction
//==================================================================================================
// Event: OnAbilityEffect
//
function Event_OnEffect takes nothing returns nothing
local string k=I2S(GetSpellAbilityId())
if HaveStoredString(cs_cache, "events_oneffect",k) then
call ExecuteFunc( GetStoredString(cs_cache, "events_oneffect",k))
endif
endfunction
function InitEffectEvent takes gamecache g returns nothing
local trigger t=CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set i=i+1
exitwhen i==bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction(t,function Event_OnEffect)
call StoreInteger(g,"eventhandlers","effect",1)
set t=null
endfunction
function OnAbilityEffect takes integer abilid, string funcname returns nothing
if (not HaveStoredInteger(cs_cache,"eventhandlers","effect")) then
call InitEffectEvent(cs_cache)
endif
call StoreString(cs_cache,"events_oneffect",I2S(abilid),funcname)
endfunction
//==================================================================================================
// Event: OnAbilityCast
//
function Event_OnCast takes nothing returns nothing
local string k=I2S(GetSpellAbilityId())
if HaveStoredString(cs_cache, "events_oncast",k) then
call ExecuteFunc( GetStoredString(cs_cache, "events_oncast",k))
endif
endfunction
function InitCastEvent takes nothing returns nothing
local trigger t=CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(i),EVENT_PLAYER_UNIT_SPELL_CAST, null)
set i=i+1
exitwhen i==bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction(t,function Event_OnCast)
call StoreInteger(cs_cache,"eventhandlers","cast",1)
set t=null
endfunction
function OnAbilityPreCast takes integer abilid, string funcname returns nothing
if (not HaveStoredInteger(cs_cache,"eventhandlers","cast")) then
call InitCastEvent()
endif
call StoreString(cs_cache,"events_oncast",I2S(abilid),funcname)
endfunction
//==================================================================================================
// Event: OnAbilityEndCast
//
function Event_OnEndCast takes nothing returns nothing
local string k=I2S(GetSpellAbilityId())
if HaveStoredString(cs_cache, "events_onendcast",k) then
call ExecuteFunc( GetStoredString(cs_cache, "events_onendcast",k))
endif
endfunction
function InitEndCastEvent takes nothing returns nothing
local trigger t=CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(i),EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
set i=i+1
exitwhen i==bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction(t,function Event_OnEndCast)
call StoreInteger(cs_cache,"eventhandlers","endcast",1)
set t=null
endfunction
function OnAbilityEndCast takes integer abilid, string funcname returns nothing
if (not HaveStoredInteger(cs_cache,"eventhandlers","endcast")) then
call InitEndCastEvent()
endif
call StoreString(cs_cache,"events_onendcast",I2S(abilid),funcname)
endfunction
//==================================================================================================
// Spell Helpers
//
function IsPointWater takes real x, real y returns boolean
return IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x,y,PATHING_TYPE_AMPHIBIOUSPATHING))
endfunction
function IsPointWaterLoc takes location loc returns boolean
return IsPointWater(GetLocationX(loc),GetLocationY(loc))
endfunction
//==================================================================================================
function IsUnitSpellImmune takes unit u returns boolean
return IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)
endfunction
function IsUnitImmuneToPhisical takes unit u returns boolean
return (GetDamageFactor(u,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_DEMOLITION)==0)
endfunction
function IsUnitInvulnerable takes unit u returns boolean
return (GetDamageFactor(u,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL)==0)
endfunction
//## Utility functions ##
//====================================================================================================
// Mimic an interface error message
// ForPlayer : The player to show the error
// msg : The error
//
function CS_Error takes player ForPlayer, string msg returns nothing
local sound error=CreateSoundFromLabel( "InterfaceError",false,false,false,10,10)
if (GetLocalPlayer() == ForPlayer) then
if (msg!="") and (msg!=null) then
call ClearTextMessages()
call DisplayTimedTextToPlayer( ForPlayer, 0.52, -1.00, 2.00, "|cffffcc00"+msg+"|r" )
endif
call StartSound( error )
endif
call KillSoundWhenDone( error)
set error=null
endfunction
//## Safe item hiding system ##
//===============================
// Hides an item, it keeps it safe while leaving other units unable to use it
// (unless an (attached) variable / table field points to it and user does
// something with it) - THIS IS HIGHLY DISCOURAGED
//
// * Don't use it with tomes that increase hero stats
// * Make triggers with item acquire/lose events ignore when a
// Caster is triggering unit.
//
function CS_HideItem takes item i returns integer
local unit s
local group gr=GetTableGroup("CSItemStorage","gr")
local integer k=NewTableIndex()
local string ks=I2S(k)
if (gr==null) then
set gr=CreateGroup()
call StoreInteger(cs_cache,"CSItemStorage","gr",CS_H2I(gr))
endif
set s=FirstOfGroup(gr)
if (s==null) then
set s=CreateCaster(0,0,0)
call UnitAddAbility(s,cs_DummyInventory_Id)
if (UnitInventorySize(s)<bj_MAX_INVENTORY) then
call BJDebugMsg("CASTER SYSTEM ERROR: Please use a correct ability for cs_DummyInventory_Id ")
loop //crash the thread
endloop
endif
call GroupAddUnit(gr,s)
endif
call UnitAddItem(s,i)
call StoreInteger(cs_cache,ks,"s",CS_H2I(s))
call StoreInteger(cs_cache,ks,"i",CS_H2I(i))
if(UnitInventorySize(s)==UnitInventoryCount(s)) then
call GroupRemoveUnit(gr,s)
endif
set s=null
set gr=null
return (k)
endfunction
function CS_FromIntegerToItem takes integer i returns item
return i
return null
endfunction
//===============================
// Restores an item
//
function CS_RestoreItem takes integer hiddenindex, real x, real y returns item
local group gr=GetTableGroup("CSItemStorage","gr")
local string k=I2S(hiddenindex)
local unit s=GetTableUnit(k,"s")
local integer r=GetStoredInteger(cs_cache,k,"i")
local item i=CS_FromIntegerToItem(r)
local integer c
call UnitRemoveItem(s,i)
set c=UnitInventoryCount(s)
if (c==0) then
call UnitRemoveAbility(s,cs_DummyInventory_Id)
call GroupRemoveUnit(gr,s)
call ExplodeUnitBJ(s)
else
call GroupAddUnit(gr,s)
endif
call SetItemPosition(i,x,y)
call DestroyTable(k)
set i=null
set s=null
return r
return null
endfunction
function CS_RestoreItemLoc takes integer hiddenindex, location loc returns item
return CS_RestoreItem(hiddenindex,GetLocationX(loc),GetLocationY(loc))
endfunction
//=============================================================================================================
// More convenient than CS_HideItem not compatible with CS_HideItem / CS_RestoreItem(loc)
//
function CS_SetItemVisible takes item it, boolean flag returns nothing
local unit s
local string k=I2S(CS_H2I(it))
local group gr
local integer x
if (flag) then
if (HaveStoredInteger(cs_cache,"CSItemStorage",k )) then
//DO SHOW:
set s=GetTableUnit("CSItemStorage",k)
set gr=GetTableGroup("CSItemStorage","gr")
if (gr==null) then
set gr=CreateGroup()
call StoreInteger(cs_cache,"CSItemStorage","gr",CS_H2I(gr))
endif
call FlushStoredInteger(cs_cache,"CSItemStorage",k)
call UnitRemoveItem(s,it)
call SetItemVisible(it,true) //Just in case
set x=GetUnitUserData(s)-1
if (x==0) then
call UnitRemoveAbility(s,cs_DummyInventory_Id)
call GroupRemoveUnit(gr,s)
call ExplodeUnitBJ(s)
else
call SetUnitUserData(s,x)
call GroupAddUnit(gr,s)
endif
set s=null
set gr=null
else //What? Trying to show an item that was not hidden using this method?
endif
elseif (HaveStoredInteger(cs_cache,"CSItemStorage",k )) then
//What? Trying to hide an item that was already hidden by this method?
else //DO HIDE:
set gr=GetTableGroup("CSItemStorage","gr")
if (gr==null) then
set gr=CreateGroup()
call StoreInteger(cs_cache,"CSItemStorage","gr",CS_H2I(gr))
endif
set s=FirstOfGroup(gr)
if (s==null) then
set s=CreateCaster(0,0,0)
call UnitAddAbility(s,cs_DummyInventory_Id)
if (UnitInventorySize(s)<bj_MAX_INVENTORY) then
call BJDebugMsg("CASTER SYSTEM ERROR: Please use a correct ability for cs_DummyInventory_Id ")
set x=x
endif
call SetUnitUserData(s,0) //UserData will now hold total items
call GroupAddUnit(gr,s)
endif
call UnitAddItem(s,it)
call StoreInteger(cs_cache,"CSItemStorage",k,CS_H2I(s))
set x=GetUnitUserData(s)+1
call SetUnitUserData(s,x)
if (x==bj_MAX_INVENTORY) then
call GroupRemoveUnit(gr,s)
endif
set s=null
set gr=null
endif
endfunction
function CS_IsItemVisible takes item it returns boolean
return not HaveStoredInteger(cs_cache,"CSItemStorage",I2S(CS_H2I(it)) )
endfunction
//=============================================================================================================
// Obsolette functions: (Left for compatibility)
//
constant function WaterDetectorId takes nothing returns integer
return 'Asb2'
endfunction
//! define WaterDetectorId() 'Asb2'
function SpellEffectModelPath takes integer abilityid, effecttype t returns string
return GetAbilityEffectById(abilityid,t, 0)
endfunction
constant function Caster_DefaultAttackType takes nothing returns attacktype
return cs_DefaultAttackType
endfunction
constant function Caster_DefaultDamageType takes nothing returns damagetype
return cs_DefaultDamageType
endfunction
constant function Caster_UnitId takes nothing returns integer
return cs_CasterUnitId
endfunction
constant function DamageTreeDetectorId takes nothing returns integer
return cs_DamageTreeDetectorId
endfunction
constant function ChangeableFlyingHeightAllowerId takes nothing returns integer
return cs_FlyingHeightHack
endfunction
constant function CS_MaxCollisionSize takes nothing returns real
return cs_MaxUnitCollisionSize
endfunction
constant function CS_Cycle takes nothing returns real
return cs_TIMER_CYCLE
endfunction
constant function CS_InventoryId takes nothing returns integer
return cs_DummyInventory_Id
endfunction
constant function CS_RectLimitOffSet takes nothing returns real
return cs_RectLimitOffSet
endfunction
//! endlibrary
//Forced by WE
function InitTrig_CasterSystem takes nothing returns nothing
endfunction
function InitTrig_vectorsystem takes nothing returns nothing
endfunction
//===========================================================================
library vectorsystem initializer init
// **********************
// ** VECTOR SYSTEM **
// **********************
// Original concept by iNfraNe
// Then Made by Anitarf
// ported to structs by vexorian (actually just copied the math)
globals
private location stupid
endglobals
struct vector
real x=0.
real y=0.
real z=0.
private boolean safety=true
private method onDestroy takes nothing returns nothing
set this.safety=false
endmethod
method created takes nothing returns boolean
return this.safety
endmethod
method length takes nothing returns real
return SquareRoot(this.x*this.x + this.y*this.y+this.z*this.z)
endmethod
method add takes vector B returns nothing
set this.x=this.x+B.x
set this.y=this.y+B.y
set this.z=this.z+B.z
endmethod
method add_factored takes vector B, real fc returns nothing
set this.x=this.x+fc*B.x
set this.y=this.y+fc*B.y
set this.z=this.z+fc*B.z
endmethod
method substract takes vector B returns nothing
set this.x=this.x-B.x
set this.y=this.y-B.y
set this.z=this.z-B.z
endmethod
static method sum takes vector A, vector B returns vector
local vector C=vector.create()
set C.x=A.x+B.x
set C.y=A.y+B.y
set C.z=A.z+B.z
return C
endmethod
static method difference takes vector A, vector B returns vector
local vector C=vector.create()
set C.x=A.x-B.x
set C.y=A.y-B.y
set C.z=A.z-B.z
return C
endmethod
method scale takes real factor returns nothing
set this.x=this.x*factor
set this.y=this.y*factor
set this.z=this.z*factor
endmethod
static method amplify takes vector A, real factor returns vector
local vector C=vector.create()
set C.x=A.x*factor
set C.y=A.y*factor
set C.z=A.z*factor
return C
endmethod
static method productScalar takes vector A, vector B returns real
return A.x*B.x+A.y*B.y+A.z*B.z
endmethod
method dot takes vector B returns real
return this.x*B.x+this.y*B.y+this.z*B.z
endmethod
static method productVector takes vector A, vector B returns vector
local vector C=vector.create()
set C.x= A.y*B.z - A.z*B.y
set C.y= A.z*B.x - A.x*B.z
set C.z= A.x*B.y - A.y*B.x
return C
endmethod
method project takes vector B returns vector
local vector C=vector.create()
local real r=this.dot(B)
local real l=B.dot(B)
if (l==0.) then
return 0
endif
return vector.amplify(B,r/l)
endmethod
method projectPlane takes vector planeNormal returns vector
local vector vect= this.project(planeNormal)
local vector vect2= vector.difference(this,vect)
call vect.destroy()
return vect2
endmethod
method setLength takes real length returns boolean
local real l=this.length()
if (l==0) then
return false
endif
call this.scale(length/l)
return true
endmethod
method clone takes nothing returns vector
local vector C=vector.create()
set C.x=this.x
set C.y=this.y
set C.z=this.z
return C
endmethod
static method angle takes vector A, vector B returns real
local real l1=A.length()
local real l2=B.length()
if (l1==0) or (l2==0) then
return 0.
endif
return Acos(vector.productScalar(A,B)/(l1*l2) )
endmethod
static method distance takes vector A, vector B returns real
return SquareRoot((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z))
endmethod
static method distanceSquare takes vector A, vector B returns real
return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z)
endmethod
method rotate takes vector axis, real angle returns vector
local vector locX
local vector locY
local vector locZ= this.project(axis)
local vector result
if locZ == 0 then
return 0
endif
set locX = vector.difference(this,locZ)
set locY = vector.productVector(this, locX)
call locY.setLength(locX.length())
call locX.scale(Cos(angle))
call locY.scale(Sin(angle))
set result= vector.sum(locX,locY)
call result.add(locZ)
call locX.destroy()
call locY.destroy()
call locZ.destroy()
return result
endmethod
static method createFrom takes real x, real y, real z returns vector
local vector C=vector.create()
set C.x=x
set C.y=y
set C.z=z
return C
endmethod
static method getTerrainPosition takes real x, real y returns vector
local integer C=vector.create()
call MoveLocation(stupid,x,y)
set C.x=x
set C.y=y
set C.z=GetLocationZ(stupid)
return C
endmethod
static method getTerrainNormal takes real x, real y, real sampleRadius returns vector
local real z1
local real z2
local real z3
local real z4
local vector xvect
local vector yvect
local vector normvect
call MoveLocation(stupid, x-sampleRadius, y)
set z1=GetLocationZ(stupid)
call MoveLocation(stupid, x+sampleRadius, y)
set z2=GetLocationZ(stupid)
call MoveLocation(stupid, x, y-sampleRadius)
set z3=GetLocationZ(stupid)
call MoveLocation(stupid, x, y+sampleRadius)
set z4=GetLocationZ(stupid)
set xvect = vector.createFrom(2*sampleRadius, 0., z2-z1)
set yvect = vector.createFrom(0., 2*sampleRadius, z4-z3)
set normvect = vector.productVector(xvect, yvect)
call xvect.destroy()
call yvect.destroy()
return normvect
endmethod
method inCylinder takes vector cylinderOriginV, vector cylinderHeightV, real cylinderRadius returns boolean
local vector v1
local vector v2
local vector v3
local boolean b = false
local real l = cylinderHeightV.length()
if (l > 0.) then
set v1=vector.difference(this, cylinderOriginV)
set v2=vector.difference(v1, cylinderHeightV)
set v3=v1.projectPlane( cylinderHeightV)
if vector.productScalar(v1, cylinderHeightV)>=0 and vector.productScalar(v2, cylinderHeightV)<=0 and vector.productScalar(v3, v3)<=cylinderRadius*cylinderRadius then
set b = true
endif
call v1.destroy()
call v2.destroy()
call v3.destroy()
endif
return b
endmethod
method move takes real x, real y, real z returns nothing
set this.x=x
set this.y=y
set this.z=z
endmethod
method inCone takes vector coneOriginV, vector coneHeightV, vector coneRadius returns boolean
local vector v1
local vector v2
local vector v3
local vector v4
local boolean b = false
local real r
local real l = coneHeightV.length()
if (l>0.0) then
set v1=vector.difference(this, coneOriginV)
set v2=vector.difference(v1, coneHeightV)
set v3=v1.project( coneHeightV)
set v4=vector.difference(v1,v3)
set r = 1.0-( v3.length()/l )
if vector.productScalar(v1, coneHeightV)>=0 and v4.length()<=(coneRadius*r) then
set b = true
endif
call v1.destroy()
call v2.destroy()
call v3.destroy()
call v4.destroy()
endif
return b
endmethod
method inSphere takes vector sphereOriginV, real sphereRadius returns boolean
local vector v
local boolean b
set v=vector.difference(this, sphereOriginV)
set b= (vector.productScalar(v,v)<= sphereRadius*sphereRadius)
call v.destroy()
return b
endmethod
endstruct
private function init takes nothing returns nothing
set stupid=Location(0.,0.)
endfunction
endlibrary
function InitTrig_config takes nothing returns nothing
call Preload(MODEL_STAR)
call Preload(MODEL_BALL)
call Preload(MODEL_DEBUG)
call Preload(MODEL_PRESENT)
call Preload(MODEL_BIG_EXPLOSION)
call Preload(MODEL_HUGE_EXPLOSION)
call Preload(MODEL_SMALL_EXPLOSION)
call Preload(MODEL_BANANA)
call Preload(MODEL_SMALL_WATERIMPACT)
call Preload(MODEL_SNOW)
call Preload(MODEL_BELL)
call Preload(MODEL_MISSILE)
call Preload(MODEL_LIGHTNING_1)
call Preload(MODEL_LIGHTNING_2)
call Preload(MODEL_LIGHTNING_SHIELD)
call Preload(MODEL_LIGHTNING_BALL)
call Preload(MODEL_REVIVE)
call PreloadAbility('A006') //flamestrike thing
call PreloadAbility('A000') //storm bolt
endfunction
globals
playercolor PLAYER_COLOR_BLACK = ConvertPlayerColor(12)
endglobals
globals
constant string MODEL_STAR = "war3mapimported\\star.mdl"
constant string MODEL_LIGHTNING_SHIELD = "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldTarget.mdl"
constant string MODEL_BANANA = "war3mapimported\\bananabomb.mdl"
constant string MODEL_REVIVE= "Abilities\\Spells\\NightElf\\ReviveNightElf\\ReviveNightElf.mdl"
constant string MODEL_PRESENT = "war3mapimported\\present.mdl"
constant string MODEL_BALL = "war3mapimported\\christmasball.mdl"
constant string MODEL_LIGHTNING_BALL = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
constant string MODEL_BELL = "war3mapimported\\jinglebell.mdl"
constant string MODEL_BIG_EXPLOSION = "Abilities\\Weapons\\DemolisherFireMissile\\DemolisherFireMissile.mdl"
constant string MODEL_HUGE_EXPLOSION = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
constant string MODEL_SMALL_EXPLOSION = "Abilities\\Spells\\Other\\TinkerRocket\\TinkerRocketMissile.mdl"
constant string MODEL_SNOW="war3mapimported\\snowballmissile.mdl"
constant string MODEL_LIGHTNING_1="Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
constant string MODEL_LIGHTNING_2="Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
constant string MODEL_SMALL_WATERIMPACT="Objects\\Spawnmodels\\Other\\IllidanFootprint\\IllidanWaterSpawnFootPrint.mdl"
// constant string MODEL_BALL = "war3mapimported\\present.mdl"
// constant string MODEL_STAR = "units\\nightelf\\Wisp\\Wisp.mdl"
// constant string MODEL_STAR = "units\\human\\Peasant\\Peasant.mdl"
// constant string MODEL_DEBUG = "units\\undead\\Abomination\\Abomination.mdl"
// constant string MODEL_DEBUG = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl"
constant string MODEL_DEBUG = ""
constant string MODEL_MISSILE = "war3mapImported\\ChristmasDrop.mdx" //"Abilities\\Weapons\\GyroCopter\\GyroCopterMissile.mdl"
constant string MODEL_INVULNERABILITY="Abilities\\Spells\\Human\\DivineShield\\DivineShieldTarget.mdl"
constant integer ANIMATION_SINK = 7
constant integer ANIMATION_THROW = 3
endglobals
function InitTrig_movement takes nothing returns nothing
endfunction
//===================================================================================================================
library mobileengine initializer initMobileEngine requires CasterSystem, vectorsystem, buffs, utils
//======================================================================
// variables and constants
//
globals
private constant real period=0.025
private constant real fadeduration=0.5
private mobile array mobs
private integer N=0
private real maxx
private real maxy
private real minx
private real miny
private real missilemaxx
private real missilemaxy
private real missileminx
private real missileminy
private real middlex
private real middley
private real placeholdx
private real placeholdy
private trigger impact=null
private triggeraction impactac=null
private real terrainheight = 59.0 //the actual max terrainheight
private location terrainloc
endglobals
//======================================================================
// mobile interface, is the root of everything, holy fake inheritance!
//
// to be created after init, otherwise thread crash since middlex/y are
// not initialized
//
interface mobile
unit u=null
effect fx=null
real x=0.0
real y=0.0
real px=middlex
real py=middley
real fac=0.0
real wantedheight=terrainheight
boolean terminate=false
integer red
integer green
integer blue
integer alpha
//========================================================
// The anim method does the AI/movement and the call of
// anim() methods of possible sub objects
//
method anim takes nothing returns boolean
//========================================================
// The fade method does the fading away and the call of
// fade() methods of possible sub objects
//
method fade takes nothing returns boolean
endinterface
//======================================================================
// Good for debugging
//
//
public function mobilecount takes nothing returns integer
return N
endfunction
//======================================================================
// mobile system movement
//
//
private function movemobiles takes nothing returns nothing
local integer i=0
loop
exitwhen i==N
if (mobs[i].terminate) then
if (mobs[i].fade()) then
call mobs[i].destroy()
set mobs[i]=mobs[N-1]
set N=N-1
else
set i=i+1
endif
elseif (mobs[i].anim()) then
call mobs[i].destroy()
set mobs[i]=mobs[N-1]
set N=N-1
else
set i=i+1
endif
endloop
if (( N==0) and (impact!=null) ) then
call TriggerRemoveAction(impact,impactac)
call DestroyTrigger(impact)
set impact=null
endif
endfunction
//======================================================================
// Adding a mobile
//
//
public function addmobile takes mobile m returns nothing
set mobs[N]=m
set N=N+1
endfunction
private function mobileimpact takes nothing returns nothing
if (GetUnitAbilityLevel(GetTriggerUnit(),buffs_ID_INVULNERABLE)==0) then
call KillUnit(GetTriggerUnit())
endif
endfunction
//======================================================================
// Register a mobile range event
//
//
private function RegisterMobileEvent takes unit u, real range returns nothing
if (range<=0.001) then
return
endif
if(impact==null) then
set impact=CreateTrigger()
set impactac= TriggerAddAction(impact,function mobileimpact)
endif
call TriggerRegisterUnitInRange(impact,u,range,null)
endfunction
//==========================================================================
// dummy
//
private function getTerrainHeight takes real x, real y returns real
// return 100.
call MoveLocation(terrainloc,x,y)
return GetLocationZ(terrainloc)
endfunction
//==========================================================================
// It makes things easier
//
struct graphicdata
string model=MODEL_DEBUG
real scale=1.
playercolor color=PLAYER_COLOR_RED
integer red=255
real radius=0.
integer green=255
integer blue=255
integer alpha=255
integer auxiliarid1=0 //depends on stuff
integer auxiliarid2=0 //depends on stuff
real height=30.0
real range=0.0
integer zangle=0
static unit lastunit
static effect lastfx
method apply takes mobile m, real f, real x, real y returns nothing
if(this==null) then
set graphicdata.lastunit=CreateCaster(f,x,y)
set graphicdata.lastfx=AddSpecialEffectTarget("",graphicdata.lastunit,"origin")
set m.u=graphicdata.lastunit
set m.red=255
set m.green=255
set m.blue=255
set m.alpha=255
return
endif
set graphicdata.lastunit=CreateCaster(f,x,y)
if (this.zangle!=0) then
call Caster_SetZAngle2(graphicdata.lastunit,this.zangle)
endif
set graphicdata.lastfx=AddSpecialEffectTarget(this.model,graphicdata.lastunit,"origin")
call SetUnitColor(graphicdata.lastunit,this.color)
call SetUnitVertexColor(graphicdata.lastunit,this.red,this.green,this.blue,this.alpha)
call SetUnitFlyHeight(graphicdata.lastunit, (terrainheight-getTerrainHeight(x,y))+ this.height ,0)
call RegisterMobileEvent(graphicdata.lastunit, this.range)
call SetUnitScale(.lastunit, .scale, .scale, .scale)
set m.u=graphicdata.lastunit
set m.red=this.red
set m.green=this.green
set m.blue=this.blue
set m.alpha=this.alpha
endmethod
endstruct
//! textmacro createfrom takes type
static method createfrom takes graphicdata G returns $type$
local $type$ s=$type$.create()
call G.apply(s , 0., placeholdx,placeholdy)
set s.fx=graphicdata.lastfx
set s.wantedheight=terrainheight+G.height
return s
endmethod
static method createfrom_c takes graphicdata G, playercolor c returns $type$
local $type$ s=$type$.create()
call G.apply(s, 0., placeholdx,placeholdy)
call SetUnitColor(s.u,c)
set s.fx=graphicdata.lastfx
set s.wantedheight=terrainheight+G.height
return s
endmethod
//! endtextmacro
//==========================================================================
// struct gotozero, just focuses on going to 0,0
//
struct gotozero extends mobile
real speed
boolean changenodefac
mobile node
real ox
real oy
//! runtextmacro createfrom("gotozero")
//gotozero.anim()
method anim takes nothing returns boolean
local real x
local real y
local real d
if (this.x==0.0) and (this.y==0.0) then
if(this.node!=null) then
call this.node.anim()
endif
return false
endif
set this.fac=Atan2(-this.y,-this.x)
set d=this.speed*period
set x=this.x+Cos(this.fac)*d
set y=this.y+Sin(this.fac)*d
set this.fac=this.fac*bj_RADTODEG
if( x*x+y*y<=100.0) then
set x=0
set y=0
endif
set this.x=x
set this.y=y
if(this.node!=null) then
set this.node.px= this.px+x
set this.node.py= this.py+y
if(this.changenodefac) then
set this.node.fac=this.fac
endif
call this.node.anim()
endif
set x=x+this.px+this.ox
set y=y+this.py+this.oy
call CS_MoveUnit(this.u,x,y)
call SetUnitFlyHeight(this.u, this.wantedheight-getTerrainHeight(x,y),0.)
call SetUnitFacing(this.u,this.fac)
return false
endmethod
//gotozero.fade()
method fade takes nothing returns boolean
if (this.node!=null) then
call this.node.fade()
endif
set this.alpha=this.alpha-R2I( (255*period)/fadeduration)
if (this.alpha<=0) then
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,0)
return true
endif
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,this.alpha)
return false
endmethod
method onDestroy takes nothing returns nothing
if(this.node!=null) then
call this.node.destroy()
endif
call DestroyEffect(this.fx)
call RemoveUnit(this.u)
endmethod
endstruct
//==========================================================================
// struct wander, just wander around the whole map
//
struct wander extends mobile
mobile node=0
real ox=0.0
real oy=0.0
real speed=0.0
real movedist=0.0
integer ignoreturn=0
boolean changenodefac=false
//! runtextmacro createfrom("wander")
method anim takes nothing returns boolean
local real x
local real y
local real d
set d=this.speed*period
if(this.movedist<=0.0) and (this.ignoreturn<=0) then
set this.movedist= GetRandomReal(100.0, maxx-minx)
if (GetRandomInt(0,1)==0) then
set this.fac= this.fac+ GetRandomInt(45,90)
else
set this.fac= this.fac- GetRandomInt(45,90)
endif
else
set this.movedist=this.movedist-d
endif
set x=this.x+d*Cos(this.fac*bj_DEGTORAD)
set y=this.y+d*Sin(this.fac*bj_DEGTORAD)
if(this.ignoreturn>0) then
set this.ignoreturn=this.ignoreturn-1
endif
if(x>maxx) then
set x=this.x-d
set y=this.y
if(this.ignoreturn<=0) then
set this.fac=180.0
//set this.fac = this.fac+180.0
// set this.ignoreturn=20
endif
endif
if(x<minx) then
set x=this.x+d
set y=this.y
if(this.ignoreturn<=0) then
//set this.fac = this.fac+180.0
set this.fac=0.0
// set this.ignoreturn=20
endif
endif
if(y>maxy) then
set x=this.x
set y=this.y-d
if(this.ignoreturn<=0) then
//set this.fac = this.fac+180.0
set this.fac=270.0
// set this.ignoreturn=20
endif
endif
if(y<miny) then
set x=this.x
set y=this.y+d
if(this.ignoreturn<=0) then
//set this.fac = this.fac+180.0
set this.fac=90.0
// set this.ignoreturn=20
endif
endif
set this.x=x
set this.y=y
if(this.node!=null) then
set this.node.px= this.px+x
set this.node.py= this.py+y
if(this.changenodefac) then
set this.node.fac=this.fac
endif
call this.node.anim()
endif
set x=x+this.px+this.ox
set y=y+this.py+this.oy
call CS_MoveUnit(this.u,x,y)
call SetUnitFlyHeight(this.u, this.wantedheight-getTerrainHeight(x,y),0.)
call SetUnitFacing(this.u,this.fac)
return false
endmethod
method fade takes nothing returns boolean
if (this.node!=null) then
call this.node.fade()
endif
set this.alpha=this.alpha-R2I( (255*period)/fadeduration)
if (this.alpha<=0) then
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,0)
return true
endif
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,this.alpha)
return false
endmethod
method onDestroy takes nothing returns nothing
if(this.node!=null) then
call this.node.destroy()
endif
call DestroyEffect(this.fx)
call RemoveUnit(this.u)
endmethod
endstruct
//==========================================================================
// struct elipse, eliptical movement
//
struct elipse extends mobile
mobile node=0
real ox=0.0
real oy=0.0
real speed=0.0
real vertical=0.0
real horizontal=0.0
boolean sign=false
boolean correct=false
boolean changenodefac=false
// elipse.createform
//! runtextmacro createfrom("elipse")
//elipse.anim
method anim takes nothing returns boolean
local real x
local real y
local real d
local real r
local real f
local real dy
local real dx
local boolean tsign=this.sign
// set this.speed=5000.
set d=(this.speed*period)
//set c=Cos( Atan2( this.y , this.x) )
if(this.sign) then
set x= this.x-d
if(x<=-this.horizontal) then
set x=-2*this.horizontal-x
set tsign=false
endif
else
set x= this.x+d
if(x>=this.horizontal) then
set x=2*this.horizontal-x
set tsign=true
endif
endif
if(tsign) then
set y= - this.vertical * SquareRoot(1 - (x*x) / (this.horizontal*this.horizontal) )
else
set y= this.vertical * SquareRoot(1 - (x*x) / (this.horizontal*this.horizontal) )
endif
if(tsign!=this.sign) then
if(tsign) then
set r= SquareRoot( this.y*this.y+(this.x-this.horizontal)*(this.x-this.horizontal) )
set d= d*(( this.horizontal-this.x )/r)
else
set r= SquareRoot( this.y*this.y+(this.x+this.horizontal)*(this.x+this.horizontal) )
set d= d*(( this.x+this.horizontal )/r)
endif
//if(d<=0.001) then
// set d=0.001
//endif
//call BJDebugMsg(R2S(d))
else
set r=SquareRoot( (y-this.y)*(y-this.y)+(x-this.x)*(x-this.x) )
set d=(d*d)/r
endif
if(this.sign) then
set x= this.x-d
if(x<=-this.horizontal) then
set x=-2*this.horizontal-x*0.99
set this.sign=false
endif
else
set x= this.x+d
if(x>=this.horizontal) then
set x=2*this.horizontal-x*0.99
set this.sign=true
endif
endif
if(this.sign) then
set y= - this.vertical * SquareRoot(1 - (x*x) / (this.horizontal*this.horizontal) )
else
set y= this.vertical * SquareRoot(1 - (x*x) / (this.horizontal*this.horizontal) )
endif
set dy=y-this.y
set dx=x-this.x
// I actually don't understand why does this work, but it does
if(dy==0) and (((dx<0) and (dx>-2)) or ((dx>0) and (dx<2))) then
if(this.sign) then
set f=-90.0
else
set f=90.0
endif
if(this.vertical<0) then
set f=-f
endif
else
set f=Atan2BJ(y-this.y,x-this.x)
endif
if (this.correct) then
set this.fac=f
set this.x=x
set this.y=y
elseif ( (this.x-x)*(this.x-x) + (this.y-y)*(this.y-y) <= (this.speed*period*4)) then
set this.fac=f
set this.x=x
set this.y=y
set this.correct=true
else
set this.fac = Atan2(y-this.y,x-this.x)*bj_RADTODEG
set this.x= this.x+ Cos(this.fac*bj_DEGTORAD)*(this.speed*period)
set this.y= this.y+ Sin(this.fac*bj_DEGTORAD)*(this.speed*period)
set x=this.x
set y=this.y
endif
if(this.node!=null) then
set this.node.px= this.px+x+this.ox
set this.node.py= this.py+y+this.oy
if(this.changenodefac) then
set this.node.fac=this.fac
endif
call this.node.anim()
endif
set x=x+this.px
set y=y+this.py
call CS_MoveUnit(this.u,x,y)
call SetUnitFlyHeight(this.u, this.wantedheight-getTerrainHeight(x,y),0.)
call SetUnitFacing(this.u,this.fac)
return false
endmethod
method fade takes nothing returns boolean
if (this.node!=null) then
call this.node.fade()
endif
set this.alpha=this.alpha-R2I( (255*period)/fadeduration)
if (this.alpha<=0) then
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,0)
return true
endif
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,this.alpha)
return false
endmethod
//elipse.onDestroy
method onDestroy takes nothing returns nothing
if(this.node!=null) then
call this.node.destroy()
endif
call DestroyEffect(this.fx)
call RemoveUnit(this.u)
endmethod
endstruct
//==========================================================================
// Struct stay, something that stays in its position
//
struct stay extends mobile
real duration=1000000.
//! runtextmacro createfrom("stay")
method anim takes nothing returns boolean
local real x=this.x+this.px
local real y=this.y+this.py
set .duration = .duration - period
if (.duration<0) then
set this.terminate=true
endif
call CS_MoveUnit(this.u,x,y)
call SetUnitFlyHeight(this.u, this.wantedheight-getTerrainHeight(x,y),0.)
call SetUnitFacing(this.u,this.fac)
return false
endmethod
method fade takes nothing returns boolean
set this.alpha=this.alpha-R2I( (255*period)/fadeduration)
if (this.alpha<=0) then
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,0)
return true
endif
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,this.alpha)
return false
endmethod
method onDestroy takes nothing returns nothing
call DestroyEffect(this.fx)
call RemoveUnit(this.u)
set this.u=null
set this.fx=null
endmethod
endstruct
//==========================================================================
// Spin, up to 4 branches
//
// Spin is great for cycling things as well as expanding/dexpanding stuff
//
struct spin extends mobile
mobile left=0
mobile right=0
mobile up=0
mobile down=0
real tanspeed=0.0
real angle=0
real radius=0.0
real minradius=0.0
real maxradius=0.0
real radiusspeed=0.0
boolean expand=false
// spin.createfrom
//! runtextmacro createfrom("spin")
// spin.anim
method anim takes nothing returns boolean
local real x
local real y
local real a
local real dir
if (this.radiusspeed != 0.0 ) then
set a=this.radiusspeed*period
if (this.expand) then
set this.radius=this.radius+a
if(this.radius>=this.maxradius) then
set this.radius=this.maxradius
set this.expand=false
endif
else
set this.radius=this.radius-a
if(this.radius<=this.minradius) then
set this.radius=this.minradius
set this.expand=true
endif
endif
endif
set this.angle = this.angle + period* (this.tanspeed/this.radius)* bj_RADTODEG
set dir=(this.fac+this.angle)*bj_DEGTORAD
set x=Cos(dir)*this.radius
set y=Sin(dir)*this.radius
set dir=dir*bj_RADTODEG
if(this.left!=null) then
set this.left.px= x + this.px
set this.left.py= y + this.py
set this.left.fac=dir
call this.left.anim()
endif
if(this.right!=null) then
set this.right.px= -x + this.px
set this.right.py= -y + this.py
set this.right.fac=180.0+dir
call this.right.anim()
endif
//sin(a+pi/2) = cos(a)
//cos(a+pi/2) = -sin(a)
if(this.down!=null) then
set this.down.py= x + this.py
set this.down.px= -y + this.px
set this.down.fac=dir+90.0
call this.down.anim()
endif
if(this.up!=null) then
set this.up.py= -x + this.py
set this.up.px= y + this.px
set this.up.fac=270+dir
call this.up.anim()
endif
set x=this.px
set y=this.py
call CS_MoveUnit(this.u,x,y)
call SetUnitFlyHeight(this.u, this.wantedheight-getTerrainHeight(x,y),0.)
call SetUnitFacing(this.u,this.fac)
return false
endmethod
method fade takes nothing returns boolean
if (this.left!=null) then
call this.left.fade()
endif
if (this.right!=null) then
call this.right.fade()
endif
if (this.up!=null) then
call this.up.fade()
endif
if (this.down!=null) then
call this.down.fade()
endif
set this.alpha=this.alpha-R2I( (255*period)/fadeduration)
if (this.alpha<=0) then
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,0)
return true
endif
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,this.alpha)
return false
endmethod
method onDestroy takes nothing returns nothing
if(this.left!=null) then
call this.left.destroy()
endif
if(this.right!=null) then
call this.right.destroy()
endif
if(this.down!=null) then
call this.down.destroy()
endif
if(this.up!=null) then
call this.up.destroy()
endif
call DestroyEffect(this.fx)
call RemoveUnit(this.u)
endmethod
endstruct
//=================================================================
// a line of mobiles, up to 4 (not counting the first one)
//
struct branch extends mobile
mobile one=0
mobile two=0
mobile three=0
mobile four=0
real dis=0.0
real facoffset=0.
//! runtextmacro createfrom("branch")
method onDestroy takes nothing returns nothing
if(this.one!=null) then
call this.one.destroy()
endif
if(this.two!=null) then
call this.two.destroy()
endif
if(this.three!=null) then
call this.three.destroy()
endif
if(this.four!=null) then
call this.four.destroy()
endif
call DestroyEffect(this.fx)
call RemoveUnit(this.u)
endmethod
method anim takes nothing returns boolean
local real f=(this.fac+this.facoffset)*bj_DEGTORAD
local real x=Cos(f)*this.dis
local real y=Sin(f)*this.dis
if(this.one!=null) then
set this.one.px=x + this.px
set this.one.py=y + this.py
set this.one.fac=this.fac
call this.one.anim()
endif
if(this.two!=null) then
set this.two.px=x+x + this.px
set this.two.py=y+y + this.py
set this.two.fac=this.fac
call this.two.anim()
endif
if(this.three!=null) then
set this.three.px=x+x+x + this.px
set this.three.py=y+y+y + this.py
set this.three.fac=this.fac
call this.three.anim()
endif
if(this.four!=null) then
set this.four.px=x+x+x+x + this.px
set this.four.py=y+y+y+y + this.py
set this.four.fac=this.fac
call this.four.anim()
endif
call CS_MoveUnit(this.u,this.px,this.py)
call SetUnitFlyHeight(this.u, this.wantedheight-getTerrainHeight(this.px,this.py),0.)
call SetUnitFacing(this.u,this.fac)
return false
endmethod
method fade takes nothing returns boolean
if (this.one!=null) then
call this.one.fade()
endif
if (this.two!=null) then
call this.two.fade()
endif
if (this.three!=null) then
call this.three.fade()
endif
if (this.four!=null) then
call this.four.fade()
endif
set this.alpha=this.alpha-R2I( (255*period)/fadeduration)
if (this.alpha<=0) then
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,0)
return true
endif
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,this.alpha)
return false
endmethod
endstruct
interface bouncylistener
method onUnitInRange takes unit u returns boolean
method onExplode takes real x, real y returns nothing
method wantDestroy takes nothing returns boolean
endinterface
//=================================================================
// The bouncy, completelly ignores px,py
// thanks to anitarf for the inspiration that came from
// the vector system's demo map
//
struct bouncy extends mobile
private vector pos
private vector dpos
private vector ddpos
real radius=0.0
private integer actpos
private integer impactcool=0
private unit rangedummy
private boolean inplacehold=true
private static integer cycle=0
integer maxbounces=1000
boolean explode=false
real impheight=100.0
real requiredheightforimpact=300.
boolean changefac=false
boolean disablekillevent=false
bouncylistener listen=0
private unit shadow=null
string watereffect="Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl"
private static group enumgroup=CreateGroup()
static bouncy array actives
static integer activeN=0
static real lastcollisioncheck=0.
static method createfrom takes graphicdata G, real fac returns bouncy
local bouncy s=bouncy.create()
set s.actpos=bouncy.activeN
set bouncy.actives[bouncy.activeN]=s
set bouncy.activeN=bouncy.activeN+1
call G.apply(s, fac , placeholdx,placeholdy)
if (G.auxiliarid1!=0) then
set s.shadow=CreateUnit(Player(12),G.auxiliarid1,placeholdx,placeholdy,0.)
endif
set s.rangedummy=CreateCaster(0,placeholdx,placeholdy)
call RegisterMobileEvent(s.rangedummy,G.radius)
set s.fx=graphicdata.lastfx
set s.radius=G.radius
set s.pos=vector.create()
set s.dpos=vector.create()
set s.ddpos=vector.createFrom(0.,0.,-800.*period*period) //let's think that -800 is gravity accel
return s
endmethod
method setPos takes real x, real y, real z returns nothing
set this.x=x
set this.y=y
set this.pos.x=x
set this.pos.y=y
set this.pos.z=z
endmethod
static method checkcollisions takes nothing returns nothing
local integer i=0
local integer j=0
local integer bn=bouncy.activeN
local vector tp
local real rad
local integer cycle = bouncy.cycle+1
local vector p
local vector n
local vector npos1
local vector npos2
local real rs
local real ds
set bouncy.lastcollisioncheck=TimerGetElapsed(TIME)
set bouncy.cycle=bouncy.cycle+1
loop
exitwhen i==bn-1
if(bouncy.actives[i].impactcool<cycle) then
set j=i+1
set tp=bouncy.actives[i].pos
set rad=bouncy.actives[i].radius
loop
exitwhen j==bn
set rs=rad+bouncy.actives[j].radius
set ds=vector.distanceSquare(tp,bouncy.actives[j].pos)
if (ds<= rs*rs) then
set npos1=vector.sum(tp,bouncy.actives[i].dpos)
set npos2=vector.sum(bouncy.actives[j].pos,bouncy.actives[j].dpos)
if( vector.distanceSquare(npos1,npos2) < ds) then //they are approaching
set n=vector.difference(bouncy.actives[j].pos, tp)
set p=bouncy.actives[i].dpos.project(n)
call bouncy.actives[i].dpos.add_factored(p,-2.)
call bouncy.actives[j].dpos.add_factored(p,2.)
call n.destroy()
call p.destroy()
set bouncy.actives[i].impactcool = cycle + 5
set bouncy.actives[j].impactcool = cycle + 5
endif
call npos1.destroy()
call npos2.destroy()
endif
set j=j+1
endloop
endif
set i=i+1
endloop
endmethod
private method dohitcheck takes real x, real y returns boolean
local unit picked
call GroupClear(.enumgroup)
call GroupEnumUnitsInRange(.enumgroup,x,y,this.radius, BOOLEXPR_TRUE)
loop
set picked=FirstOfGroup(.enumgroup)
exitwhen picked==null
//debug call BJDebugMsg("(debug) "+GetUnitName(picked))
call GroupRemoveUnit(.enumgroup,picked)
if (this.listen.onUnitInRange(picked)) then
return true
endif
endloop
return false
endmethod
method anim takes nothing returns boolean
local real h
local real x
local real y
local real z
local vector p
local vector n
if (bouncy.lastcollisioncheck<TimerGetElapsed(TIME)) then
call bouncy.checkcollisions()
endif
if (this.changefac) then
call SetUnitFacing(this.u , Atan2(this.dpos.y,this.dpos.x)*bj_RADTODEG )
endif
call this.dpos.add_factored(this.ddpos,0.5)
call this.pos.add(this.dpos)
call this.dpos.add_factored(this.ddpos,0.5)
set z=this.dpos.z //z speed
if ( (z>=0) and (z<1)) or ( (z<0) and (z>-1)) then
set this.impheight=this.pos.z
endif
set x=this.pos.x
set y=this.pos.y
set z=this.pos.z
set this.x=x
set this.y=y
set h=getTerrainHeight(x,y)
if (h>=z) then
if (IsPointWater(x,y)) then
call DestroyEffect(AddSpecialEffect(this.watereffect,x,y))
return true
endif
set this.maxbounces=this.maxbounces-1
if(this.maxbounces<=0) then
set this.explode=true
return true
endif
set n=vector.getTerrainNormal(x,y,32.0)
set p=this.dpos.project(n)
call this.dpos.add_factored(p,-2.)
call n.destroy()
call p.destroy()
if (this.impheight-h > this.requiredheightforimpact ) then
call DestroyEffect(AddSpecialEffect("war3mapimported\\impact.mdl", x,y))
call buffs_doStun(x,y)
endif
set this.impheight=h
endif
//if (not this.disablekillevent) then
if(h>=z-this.radius) then
if (this.inplacehold) then
set this.inplacehold=false
endif
if (not this.disablekillevent) then
call CS_MoveUnit(this.rangedummy,x,y)
endif
if (this.listen!=0) then
if .dohitcheck(x,y) then
return true
endif
endif
elseif (not this.inplacehold) then
set this.inplacehold=true
if (not this.disablekillevent) then
call CS_MoveUnit(this.rangedummy,placeholdx,placeholdy)
endif
endif
//endif
if not CS_MoveUnit(this.u,x,y) then
return true
endif
if (this.shadow!=null ) then
call CS_MoveUnit(this.shadow,x,y)
endif
call SetUnitFlyHeight(this.u, z-h,0.)
return false
endmethod
method fade takes nothing returns boolean
set this.alpha=this.alpha-R2I( (255*period)/fadeduration)
if (this.alpha<=0) then
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,0)
return true
endif
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,this.alpha)
return false
endmethod
method onDestroy takes nothing returns nothing
local bouncy tm=bouncy.actives[bouncy.activeN-1]
set bouncy.actives[this.actpos]=tm
set tm.actpos=this.actpos
set bouncy.activeN=bouncy.activeN-1
call this.pos.destroy()
call this.dpos.destroy()
call this.ddpos.destroy()
call RemoveUnit(this.rangedummy)
if (this.shadow!=null ) then
call RemoveUnit(this.shadow)
endif
if(this.explode) then
call ExplodeUnitBJ(this.u)
call this.listen.onExplode(this.x,this.y)
// call this.castondeath.execute(this.x,this.y)
//endif
else
call RemoveUnit(this.u)
endif
if (this.listen!=0) and (this.listen.wantDestroy()) then
call this.listen.destroy()
endif
call DestroyEffect(this.fx)
endmethod
method setXYAngleSpeed takes real f, real sp returns nothing
set this.dpos.x=sp*Cos(f)*period
set this.dpos.y=sp*Sin(f)*period
endmethod
method setZSpeed takes real sp returns nothing
set this.dpos.z=sp*period
endmethod
endstruct
//=================================================================
// A missile, ignores ox and oy
//
struct missile extends mobile
real dx=0.0
real dy=0.0
method change takes real fac, real speed returns nothing
local real d=period*speed
set this.fac=fac
set fac=fac*bj_DEGTORAD
set this.dx=d*Cos(fac)
set this.dy=d*Sin(fac)
endmethod
static method createfrom takes graphicdata G, real fac returns missile
local missile s=missile.create()
call G.apply(s, fac, placeholdx,placeholdy)
set s.fac=fac
set s.fx=graphicdata.lastfx
set s.wantedheight=terrainheight+G.height
return s
endmethod
method anim takes nothing returns boolean
local real x=this.x+this.dx
local real y=this.y+this.dy
if (x>missilemaxx) or (y>missilemaxy) or (x<missileminx) or (y<missileminy) then
return true
endif
set this.x=x
set this.y=y
call CS_MoveUnit(this.u,x,y)
call SetUnitFlyHeight(this.u, this.wantedheight-getTerrainHeight(x,y),0.)
call SetUnitFacing(this.u,this.fac)
return false
endmethod
method fade takes nothing returns boolean
set this.alpha=this.alpha-R2I( (255*period)/fadeduration)
if (this.alpha<=0) then
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,0)
return true
endif
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,this.alpha)
return false
endmethod
method onDestroy takes nothing returns nothing
call DestroyEffect(this.fx)
call RemoveUnit(this.u)
endmethod
endstruct
//=================================================================
// A missile launcher
//
struct missilelauncher extends mobile
//timing stuff:
private real lperiod=0.0
private real nextperiod=0.0
private real current=0.0
real missilespeed
real spawndist=100.
graphicdata missilegraphicdata
//! runtextmacro createfrom("missilelauncher")
method setperiod takes real p returns nothing
set this.lperiod=p
set this.nextperiod=this.current+p
endmethod
method anim takes nothing returns boolean
local missile m
local real x=this.x+this.px
local real y=this.y+this.py
call CS_MoveUnit(this.u,x,y)
call SetUnitFlyHeight(this.u, this.wantedheight-getTerrainHeight(x,y),0.)
call SetUnitFacing(this.u,this.fac)
set this.current = this.current + period
if(this.current>=this.nextperiod) then
set this.nextperiod = this.current+this.lperiod
//launch:
set m=missile.createfrom(this.missilegraphicdata, this.fac)
set m.x=this.x+this.px+CosBJ(this.fac)*this.spawndist
set m.y=this.y+this.py+SinBJ(this.fac)*this.spawndist
call m.change(this.fac, this.missilespeed)
call addmobile(m)
endif
return false
endmethod
method fade takes nothing returns boolean
set this.alpha=this.alpha-R2I( (255*period)/fadeduration)
if (this.alpha<=0) then
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,0)
return true
endif
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,this.alpha)
return false
endmethod
method onDestroy takes nothing returns nothing
call DestroyEffect(this.fx)
call RemoveUnit(this.u)
endmethod
endstruct
//=================================================================
// doer: something that does stuff
//
//interface for doers
interface doeraction
method wantDestroy takes nothing returns boolean
method execute takes real x, real y, real fac returns nothing
endinterface
struct doer extends mobile
//timing stuff:
private real lperiod=0.0
private real nextperiod=10000000.0
private real current=0.0
private static doer array A
private static integer An=0
doeraction do=0
static method createfrom takes graphicdata G returns doer
local doer s=doer.create()
call G.apply(s , 0., placeholdx,placeholdy)
set s.fx=graphicdata.lastfx
set s.wantedheight=terrainheight+G.height
set .A[.An]=s
set .An=.An+1
return s
endmethod
static method createfrom_c takes graphicdata G, playercolor c returns doer
local doer s=doer.create()
call G.apply(s, 0., placeholdx,placeholdy)
call SetUnitColor(s.u,c)
set s.fx=graphicdata.lastfx
set s.wantedheight=terrainheight+G.height
set .A[.An]=s
set .An=.An+1
return s
endmethod
method setperiod takes real p returns nothing
set this.lperiod=p
set this.nextperiod=this.current+p
endmethod
method anim takes nothing returns boolean
local real x=this.x+this.px
local real y=this.y+this.py
call CS_MoveUnit(this.u,x,y)
call SetUnitFlyHeight(this.u, this.wantedheight-getTerrainHeight(x,y),0.)
call SetUnitFacing(this.u,this.fac)
set this.current = this.current + period
if(this.current>=this.nextperiod) then
set this.nextperiod = this.current+this.lperiod
//launch:
if (this.do!=null) then
call this.do.execute(this.x+this.px,this.y+this.py,this.fac)
endif
endif
return false
endmethod
method fade takes nothing returns boolean
set this.alpha=this.alpha-R2I( (255*period)/fadeduration)
if (this.alpha<=0) then
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,0)
return true
endif
call SetUnitVertexColor(this.u,this.red,this.green,this.blue,this.alpha)
return false
endmethod
method onDestroy takes nothing returns nothing
local integer i=0
loop
exitwhen i==.An
if (.A[i] == this) then
set .An = .An-1
set .A[i] = .A[.An]
exitwhen true
endif
set i=i+1
endloop
if (this.do!=null) and (this.do.wantDestroy()) then
call this.do.destroy()
endif
call DestroyEffect(this.fx)
call RemoveUnit(this.u)
endmethod
static method doall takes nothing returns nothing
local integer i=0
loop
exitwhen i==.An
if (.A[i].do!=null) then
call .A[i].do.execute(.A[i].x+.A[i].px,.A[i].y+.A[i].py,.A[i].fac)
endif
set i=i+1
endloop
endmethod
endstruct
//=================================================================
// The ini function
//
function initMobileEngine takes nothing returns nothing
set terrainloc=Location(0.,0.)
call TimerStart(CreateTimer(),period,true,function movemobiles)
set middlex=GetRectCenterX(gg_rct_game)
set middley=GetRectCenterY(gg_rct_game)
set maxx=GetRectMaxX(gg_rct_game)-middlex
set maxy=GetRectMaxY(gg_rct_game)-middley
set minx=GetRectMinX(gg_rct_game)-middlex
set miny=GetRectMinY(gg_rct_game)-middley
set missilemaxx=GetRectMaxX(gg_rct_missilelimit)
set missilemaxy=GetRectMaxY(gg_rct_missilelimit)
set missileminx=GetRectMinX(gg_rct_missilelimit)
set missileminy=GetRectMinY(gg_rct_missilelimit)
set placeholdx=GetRectCenterX(gg_rct_placehold)
set placeholdy=GetRectCenterY(gg_rct_placehold)
endfunction
endlibrary
globals
timer TIME=null
endglobals
//===========================================================================
function InitTrig_time takes nothing returns nothing
set TIME=CreateTimer()
call TimerStart(TIME,10000,false, null)
endfunction
function InitTrig_game takes nothing returns nothing
endfunction
//---
library game initializer iniplayers requires buffs, utils
//*************************************************
//* Config
//*
//*************************************************
//
globals
public constant integer MAXPLAYERS = 12
constant string SOUND_SUBMERGE="SubmergeSound"
private constant real requiredwateroffset=32.0
private constant integer REMATCHTIME=26
private constant real INITIALMANA=20.
private string HEROGLOW= "war3mapimported\\heroglow.mdl" //not adding the constant prefix prevents inlining which, in theory would be harmful here
endglobals
public function getRaceUnitId takes race r returns integer
if(r==RACE_ORC) then
return 'H000'
endif
if(r==RACE_UNDEAD) then
return 'H003'
endif
if(r==RACE_HUMAN) then
return 'H004'
endif
if(r==RACE_NIGHTELF) then
return 'H005'
endif
return 'nshe'
endfunction
private function getIconByRace takes race r returns string
if (r==RACE_HUMAN) then
return "war3mapImported\\BTNXmasFootman.blp"
elseif(r==RACE_UNDEAD) then
return "war3mapImported\\BTNXmasSpirit.blp"
elseif(r==RACE_NIGHTELF) then
return "war3mapImported\\BTNXmastreant.blp"
elseif(r==RACE_ORC) then
return "war3mapImported\\BTNGoblinElf.blp"
endif
return "textures\\black32.blp"
endfunction
//*************************************************
//* Player globals
//*
//***********************************************
globals
public boolean array active
public unit array hero
private integer array unittypes
public integer array points
public integer activeplayers=0
private boolean endgame=false
endglobals
//*************************************************
//* Multiboard system
//*
//*************************************************
//
globals
private multiboard mult
private string array mbicon
private multiboarditem array mi_names
private multiboarditem array mi_deaths1
private multiboarditem array mi_deaths2
private multiboarditem array mi_deaths3
private multiboarditem array mi_deaths4
private multiboarditem array mi_icons
private real ICONWIDTH=0.02
private integer array tmarray
endglobals
//================
// Thank blizzard for not having a right align option
//
private function multiboard_outputdeaths takes integer i, integer val returns nothing
local integer d
local integer a
set a=val/10
set d=val-a*10
set val=a
if(d==1) then
call MultiboardSetItemValue(mi_deaths1[i]," 1")
else
call MultiboardSetItemValue(mi_deaths1[i],I2S(d))
endif
set a=val/10
set d=val-a*10
set val=a
if(d==0) and (val==0) then
call MultiboardSetItemValue(mi_deaths2[i],"")
elseif(d==1) then
call MultiboardSetItemValue(mi_deaths2[i]," 1")
else
call MultiboardSetItemValue(mi_deaths2[i],I2S(d))
endif
set a=val/10
set d=val-a*10
set val=a
if(d==0) and (val==0) then
call MultiboardSetItemValue(mi_deaths3[i],"")
elseif(d==1) then
call MultiboardSetItemValue(mi_deaths3[i]," 1")
else
call MultiboardSetItemValue(mi_deaths3[i],I2S(d))
endif
set a=val/10
set d=val-a*10
set val=a
if(d==0) and (val==0) then
call MultiboardSetItemValue(mi_deaths4[i],"")
elseif(d==1) then
call MultiboardSetItemValue(mi_deaths4[i]," 1")
else
call MultiboardSetItemValue(mi_deaths4[i],I2S(d))
endif
endfunction
private function updateMultiboard takes nothing returns nothing
local integer i=0
local integer j=0
// initialize temp array
loop
exitwhen i==MAXPLAYERS
if (not active[i]) then
set points[i]=0x0FFFFFFF
endif
set tmarray[i]=0
set i=i+1
endloop
// sort
set i=0
loop
exitwhen i==MAXPLAYERS-1
set j=i+1
loop
exitwhen j==MAXPLAYERS
if(points[i]>points[j]) then
set tmarray[i]=tmarray[i]+1
else
set tmarray[j]=tmarray[j]+1
endif
set j=j+1
endloop
set i=i+1
endloop
//output
set i=0
loop
exitwhen i==MAXPLAYERS
set j=tmarray[i]
if (active[i]) then
call MultiboardSetItemValue(mi_names[j],GetPlayerName(Player(i)))
call MultiboardSetItemStyle(mi_icons[i],false,true)
call MultiboardSetItemIcon(mi_icons[j],mbicon[i])
call multiboard_outputdeaths(j,points[i])
else
call MultiboardSetItemValue(mi_names[j],"")
call MultiboardSetItemStyle(mi_icons[i],false,false)
call MultiboardSetItemValue(mi_deaths1[j],"")
call MultiboardSetItemValue(mi_deaths2[j],"")
call MultiboardSetItemValue(mi_deaths3[j],"")
call MultiboardSetItemValue(mi_deaths4[j],"")
endif
set i=i+1
endloop
endfunction
private function multiboardinit takes nothing returns nothing
local integer i
call ReleaseTimer(GetExpiredTimer())
set mult = CreateMultiboard()
//==========================================================
// Name Deads
// [] Name Deads
//
call MultiboardSetTitleText(mult,"Deaths")
call MultiboardSetRowCount(mult, activeplayers)
call MultiboardSetColumnCount(mult, 6)
set i=0
loop
exitwhen i==MAXPLAYERS
set mi_names[i]=MultiboardGetItem(mult,i,1)
set mi_deaths1[i]=MultiboardGetItem(mult,i,5)
set mi_deaths2[i]=MultiboardGetItem(mult,i,4)
set mi_deaths3[i]=MultiboardGetItem(mult,i,3)
set mi_deaths4[i]=MultiboardGetItem(mult,i,2)
set mi_icons[i]=MultiboardGetItem(mult,i,0)
call MultiboardSetItemWidth(mi_names[i],ICONWIDTH*7)
call MultiboardSetItemWidth(mi_icons[i],ICONWIDTH)
call MultiboardSetItemWidth(mi_deaths1[i],ICONWIDTH/4)
call MultiboardSetItemWidth(mi_deaths2[i],ICONWIDTH/4)
call MultiboardSetItemWidth(mi_deaths3[i],ICONWIDTH/4)
call MultiboardSetItemWidth(mi_deaths4[i],ICONWIDTH/4)
call MultiboardSetItemStyle(mi_names[i],true,false)
call MultiboardSetItemStyle(mi_icons[i],false,true)
call MultiboardSetItemStyle(mi_deaths1[i],true,false)
call MultiboardSetItemStyle(mi_deaths2[i],true,false)
call MultiboardSetItemStyle(mi_deaths3[i],true,false)
call MultiboardSetItemStyle(mi_deaths4[i],true,false)
set i=i+1
endloop
call updateMultiboard()
call MultiboardDisplay(mult,true)
endfunction
public function addPoint takes player i returns nothing
local integer k=GetPlayerId(i)
set points[k]=points[k]+1
call updateMultiboard()
endfunction
//======================================================================================
// player events
//
private function onleave takes nothing returns nothing
local integer p=GetPlayerId(GetTriggerPlayer())
call ExplodeUnitBJ(hero[p])
set hero[p]=null
set active[p]=false
set points[p]=0x0FFFFFFF
set activeplayers=activeplayers-1
call Print(GetPlayerName(GetTriggerPlayer())+" leaves the game")
if (activeplayers==1) then
call Print("... Everybody left, aren't you feeling lonely? Unless you actually love the map so much you want to play it alone you better leave.")
endif
call MultiboardSetRowCount(mult, activeplayers)
call updateMultiboard()
endfunction
public function ispointwater takes real x, real y returns boolean
local real r=requiredwateroffset
if ( IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x,y,PATHING_TYPE_AMPHIBIOUSPATHING))) then
if ( IsTerrainPathable(x+r,y+r,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x+r,y+r,PATHING_TYPE_AMPHIBIOUSPATHING))) then
if ( IsTerrainPathable(x-r,y-r,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x-r,y-r,PATHING_TYPE_AMPHIBIOUSPATHING))) then
if ( IsTerrainPathable(x+r,y-r,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x+r,y-r,PATHING_TYPE_AMPHIBIOUSPATHING))) then
if ( IsTerrainPathable(x-r,y+r,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x-r,y+r,PATHING_TYPE_AMPHIBIOUSPATHING))) then
return true
endif
endif
endif
endif
endif
return false
endfunction
private function ondeath takes nothing returns nothing
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if (not endgame) then
call Print(GetPlayerName(GetOwningPlayer(u))+" dies")
call addPoint(GetOwningPlayer(u))
endif
call PolledWait(3.0)
if (not active[GetPlayerId(GetOwningPlayer(u))]) then
set u=null
return
endif
// IsTerrainPathable returns false if it is pathable and true if it isn't (yes, that's retarded)
if (ispointwater(x,y)) then
//In water?
call ReviveHero(u, GetRandomReal(GetRectMinX(gg_rct_afterwater),GetRectMaxX(gg_rct_afterwater)) , GetRandomReal(GetRectMinY(gg_rct_afterwater),GetRectMaxY(gg_rct_afterwater)) , false)
else
call ReviveHero(u, x, y, false)
endif
if (not endgame) then
call DestroyEffect(AddLocalSpecialEffectTarget( GetOwningPlayer(u), MODEL_REVIVE, u, "origin") )
endif
if (GetLocalPlayer()==GetOwningPlayer(u)) then
call SelectUnit(u,true)
endif
if(endgame) then
call ShowUnit(u,false)
else
call buffs_fxInvulnerability(u,4.5)
endif
endfunction
globals
private sound submergesound
endglobals
private function waterloop takes nothing returns nothing
local integer i=0
local real x
local real y
loop
exitwhen i==MAXPLAYERS
if(active[i] and (GetWidgetLife(hero[i])>0.405) and not buffs_isInvulnerable(hero[i])) then
set x=GetUnitX(hero[i])
set y=GetUnitY(hero[i])
if (ispointwater(x,y)) then
call SetSoundPosition(submergesound,x,y,0.0)
call StartSound(submergesound)
call KillUnit(hero[i])
call SetUnitAnimationByIndex(hero[i],ANIMATION_SINK)
endif
endif
set i=i+1
endloop
endfunction
private function iniplayers0 takes nothing returns nothing
local integer i=0
loop
exitwhen i==MAXPLAYERS
if active[i] and (GetLocalPlayer()==Player(i)) then
call SelectUnit(hero[i],true)
endif
set i=i+1
endloop
call ReleaseTimer(GetExpiredTimer())
endfunction
private function onescape takes nothing returns nothing
if (GetLocalPlayer()==GetTriggerPlayer()) then
call CameraSetupApply(gg_cam_cam,true,false)
endif
endfunction
private function iniplayers takes nothing returns nothing
local integer i=0
local trigger t=CreateTrigger()
local trigger t2=CreateTrigger()
local trigger t3=CreateTrigger()
local string k
call FogMaskEnable(false)
call FogEnable(false)
call CameraSetupApply(gg_cam_cam,false,false)
call SetFloatGameState(GAME_STATE_TIME_OF_DAY, 12.0)
call SuspendTimeOfDay(true)
call EnableDragSelect(false,false)
//call EnablePreSelect (false,false)
call EnableSelect(false,false)
set submergesound=CreateSoundFromLabel( SOUND_SUBMERGE,false,false,false,10,10)
call StartSound( submergesound) //bugged war3 doesn't play the sound the first time
call TriggerAddAction(t,function onleave)
call TriggerAddAction(t2,function ondeath)
call TriggerAddAction(t3,function onescape)
loop
exitwhen i==MAXPLAYERS
set active[i]=((GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING) and (MAP_CONTROL_USER==GetPlayerController(Player(i))))
debug set active[i]=true
if (active[i]) then
set activeplayers=activeplayers+1
set mbicon[i]=getIconByRace(GetPlayerRace(Player(i)))
set k=PlayerColor2HexColor(GetPlayerColor(Player(i)))
call SetPlayerName(Player(i),"|c"+k+GetPlayerName(Player(i))+"|r")
set points[i]=0
call TriggerRegisterPlayerEvent(t,Player(i),EVENT_PLAYER_LEAVE)
set hero[i]=CreateUnit(Player(i), getRaceUnitId(GetPlayerRace(Player(i))) , GetStartLocationX(i), GetStartLocationY(i),0)
if (GetLocalPlayer()==Player(i)) then
call AddSpecialEffectTarget(HEROGLOW,hero[i],"chest")
else
call AddSpecialEffectTarget("",hero[i],"chest")
endif
call SetUnitColor(hero[i],GetPlayerColor(Player(i)) )
debug if ((GetPlayerSlotState(Player(i)) != PLAYER_SLOT_STATE_PLAYING) or (MAP_CONTROL_USER!=GetPlayerController(Player(i)))) then
debug //this only happens on debug mode
debug call UnitAddAbility(hero[i],'Awan') //tornado wander
debug endif
call SetUnitState(hero[i],UNIT_STATE_MANA,INITIALMANA)
call TriggerRegisterUnitEvent(t2, hero[i], EVENT_UNIT_DEATH)
call TriggerRegisterPlayerEventEndCinematic( t3, Player(i) )
else
set mbicon[i]="textures\\black32.blp"
call SetPlayerName(Player(i),"|c"+k+"missing"+"|r")
endif
set i=i+1
endloop
call TimerStart(NewTimer(),0,false, function iniplayers0)
call TimerStart(NewTimer(),0.,false, function multiboardinit)
call TimerStart(CreateTimer(),0.2,true, function waterloop)
endfunction
globals
private timerdialog restartwin
endglobals
private function removeEnumItem takes nothing returns nothing
call RemoveItem(GetEnumItem())
endfunction
private function removeAllItems takes nothing returns nothing
call EnumItemsInRect(bj_mapInitialPlayableArea,BOOLEXPR_TRUE,function removeEnumItem)
endfunction
private function restartExpire takes nothing returns nothing
local integer i=0
local integer j
//Remove filter
call SetCineFilterStartColor(0,0,0,255)
call SetCineFilterEndColor(255,255,255,0)
call SetCineFilterDuration(1.)
call DisplayCineFilter(true)
call StopSound(gg_snd_theend,false,true)
call ResumeMusic()
call ReleaseTimer(GetExpiredTimer())
call DestroyTimerDialog(restartwin)
call ClearTextMessages()
loop
exitwhen i==MAXPLAYERS
set points[i]=0
if(active[i]) then
call ShowUnit(hero[i],true)
if(GetLocalPlayer()==Player(i)) then
call SelectUnit(hero[i],true)
endif
call SetUnitState(hero[i],UNIT_STATE_MANA,INITIALMANA)
call SetUnitX(hero[i],GetStartLocationX(i))
call SetUnitY(hero[i],GetStartLocationY(i))
set j=0
loop
exitwhen j==6
call RemoveItem(UnitItemInSlot(hero[i],j))
set j=j+1
endloop
else
set points[i]=0x0FFFFFFF
endif
set i=i+1
endloop
call removeAllItems()
call updateMultiboard()
call ExecuteFunc("setup_levels")
set endgame=false
endfunction
private function prepareRestart takes nothing returns nothing
local timer t=NewTimer()
local integer i=0
call TimerStart(t,REMATCHTIME,false, function restartExpire )
set restartwin=CreateTimerDialog(t)
call TimerDialogSetTitle(restartwin,"Rematch")
call TimerDialogDisplay(restartwin,true)
loop
exitwhen i==MAXPLAYERS
if (active[i]) then
call ShowUnit(hero[i],false)
endif
set i=i+1
endloop
endfunction
public function end takes nothing returns nothing
local integer i=0
local integer array winners
local integer winnercount=0
local integer min=0x0FFFFFFF
local string s
//black filter
call SetCineFilterTexture("textures\\black32.blp")
call SetCineFilterStartColor(255,255,255,0)
call SetCineFilterEndColor(0,0,0,255)
call SetCineFilterDuration(1.)
call DisplayCineFilter(true)
call StopMusic(true)
call StartSound(gg_snd_theend)
call ClearTextMessages()
set endgame=true
call Print("\nThe game has ended!\n\n|cffC0C0C0You can stay in game for a rematch or just leave.\nThe game will restart in |r|cffFfff00"+I2S(REMATCHTIME)+" seconds|r\n")
//get min:
loop
exitwhen i==MAXPLAYERS
if (active[i]) then
if (points[i]<min) then
set winnercount=1
set winners[0]=i
set min=points[i]
elseif (points[i]==min) then
set winners[winnercount]=i
set winnercount=winnercount+1
endif
endif
set i=i+1
endloop
if (winnercount==activeplayers) then
if (activeplayers==1) then
call Print("So, you win, congratulations! Now try winning when playing AGAINST PEOPLE...")
elseif(min==0) then
call Print("What? Are you somekind of freak group, do you cheat? Is the map so bugged that it ended before you died?, how did you all manage to survive?")
elseif(min==1) then
call Print("Awesome! It is a tie! everybody died once, how odd\n")
else
call Print("Awesome! It is a tie! everybody died "+I2S(min)+" times, everybody lost!\n")
endif
elseif (winnercount>1) then
set s="It is a tie between "+GetPlayerName(Player(winners[0]))
set i=1
loop
exitwhen i==winnercount-1
set s=s+", "+GetPlayerName(Player(winners[i]))
set i=i+1
endloop
set s=s+" and "+GetPlayerName(Player(winners[i]))+" "
if (min==0) then
set s=s+"with zero deaths! What a shame for the other players..."
elseif(min==1) then
set s=s+"with one death!... ... They could have done better..."
else
set s=s+"with "+I2S(min)+" deaths."
endif
call Print(s)
else
set s=GetPlayerName(Player(winners[0]))+" wins "
if (min==0) then
set s=s+"with zero deaths! What a shame for the other players..."
elseif(min==1) then
set s=s+"with one death!... ... Could have done better..."
else
set s=s+"with "+I2S(min)+" deaths."
endif
call Print(s)
endif
if (min>=100) then
call Print("... and I thought this map was easy.")
endif
call prepareRestart()
call TriggerSleepAction(5.)
call Print("\n|cFF2020FFVexorian|r made this map he is also admin at |cffC0C0ffhttp://www.wc3campaigns.net|r")
call TriggerSleepAction(2.)
call Print("\n|cFFFFC000Mc !|r actually made all of this map's custom models, unless you count the thunderclap without ubersplat one which is just an mdl edit made by vexorian.")
call TriggerSleepAction(2.)
call Print("\nVexorian wouldn't make this map without tools like |cFF8080FFJassHelper|r, |cFF8080FFGrimoire|r and |cFF8080FFgVim|r, did you know this map is actually meant as a demonstration of JassHelper's power?")
call TriggerSleepAction(2.)
call Print("\n|cFFFFFF80Anitarf|r made a vector system map with stuff Vexorian eventually ported for this map.")
call TriggerSleepAction(2.)
call Print("\n|cFFFFFF80Pipedream|r is extremely helpful and probably helped during the development of this map as well. He is also the creator of grimoire so he deserves a lot of credit.")
endfunction
endlibrary
function aaaaaaaaaaaa takes nothing returns nothing
call game_end()
endfunction
//===========================================================================
function InitTrig_agagasdg takes nothing returns nothing
set gg_trg_agagasdg = CreateTrigger( )
call TriggerRegisterPlayerEventEndCinematic( gg_trg_agagasdg, Player(0) )
call TriggerAddAction( gg_trg_agagasdg, function aaaaaaaaaaaa)
endfunction
function InitTrig_utilityfunctions takes nothing returns nothing
endfunction
//============================================================================
library utils initializer initutils
globals
boolexpr BOOLEXPR_TRUE
boolexpr BOOLEXPR_FALSE
endglobals
function Print takes string s returns nothing
call DisplayTextToPlayer(GetLocalPlayer(),0.,0.,s)
endfunction
function PlayerColor2HexColor takes playercolor c returns string
if (c==PLAYER_COLOR_BLUE) then
return "FF0042FF"
elseif(c==PLAYER_COLOR_RED) then
return "FFFF0303"
elseif (c==PLAYER_COLOR_CYAN) then
return "FF1CE6B9"
elseif (c==PLAYER_COLOR_PURPLE) then
return "FF8430B1"
elseif( c==PLAYER_COLOR_YELLOW) then
return "FFFFFC01"
elseif (c==PLAYER_COLOR_ORANGE) then
return "FFFE8A0E"
elseif (c==PLAYER_COLOR_GREEN) then
return "FF20C000"
elseif (c==PLAYER_COLOR_PINK) then
return "FFE55BB0"
elseif (c==PLAYER_COLOR_LIGHT_GRAY) then
return "FF959697"
elseif (c==PLAYER_COLOR_LIGHT_BLUE) then
return "FF7EBFF1"
elseif (c==PLAYER_COLOR_AQUA) then
return "FF106246"
elseif(c==PLAYER_COLOR_BROWN) then
return "FF6E4A24"
endif
return "FF000000"
endfunction
private function returnfalse takes nothing returns boolean
return false
endfunction
private function returntrue takes nothing returns boolean
return true
endfunction
private function initutils takes nothing returns nothing
set BOOLEXPR_TRUE = Condition(function returntrue)
set BOOLEXPR_FALSE = Condition(function returnfalse)
endfunction
function AddLocalSpecialEffectTarget takes player p, string modelName, widget targetWidget, string attachPointName returns effect
if (GetLocalPlayer()==p) then
return AddSpecialEffectTarget(modelName,targetWidget,attachPointName)
endif
return AddSpecialEffectTarget("",targetWidget,attachPointName)
endfunction
endlibrary
function InitTrig_buffs takes nothing returns nothing
endfunction
//===========================================================================
library buffs requires CasterSystem, vectorsystem
globals
private unitbuffdata array data
private integer N=0
private constant real INTERMITENT_PERIOD = 0.1
public constant integer ID_INVULNERABLE = 'Avul'
private constant integer ID_SWAP = 'A004'
private constant integer ID_DISABLED_SWAP = 'A007'
private unitbuffdata array knockback_V
private integer knockback_N=0
private timer knockback_T = CreateTimer()
private constant real KNOCKBACKPERIOD=0.04
private constant real SNOWDEACCEL = 384.
endglobals
struct unitbuffdata
integer invulnerable=0
unit u
timer fxinvuln_t=null
real fxinvuln_rem=0
timer fx2invuln_t=null
real fx2invuln_rem=0
effect fx2invuln=null
vector knockback_dpos=0
real pausedur=0.
real timerpausedur=0.
endstruct
public function getData takes unit u returns unitbuffdata
local integer i=GetUnitUserData(u)
if (i==0) then
set i=N
set N=N+1
call SetUnitUserData(u,i)
set data[i]=unitbuffdata.create()
set data[i].u=u
endif
return data[i]
endfunction
public function doStun takes real x, real y returns nothing
call CasterCastAbilityLevelAOE(Player(12),'A000',1,"thunderbolt",x,y,250.,false,true)
endfunction
public function isInvulnerable takes unit u returns boolean
return (GetUnitAbilityLevel(u,ID_INVULNERABLE)>0)
endfunction
private function addInvulnerability takes unit u returns nothing
call UnitAddAbility(u,ID_INVULNERABLE)
if (GetUnitAbilityLevel(u,ID_SWAP)>0) then
call UnitRemoveAbility(u,ID_SWAP)
call UnitAddAbility(u,ID_DISABLED_SWAP)
endif
endfunction
private function removeInvulnerability takes unit u returns nothing
call UnitRemoveAbility(u,ID_INVULNERABLE)
if (GetUnitAbilityLevel(u,ID_DISABLED_SWAP)>0) then
call UnitRemoveAbility(u,ID_DISABLED_SWAP)
call UnitAddAbility(u,ID_SWAP)
endif
endfunction
function fxinvuln_expire takes nothing returns nothing
local timer t=GetExpiredTimer()
local unitbuffdata d=GetCSData(t)
if (d.fxinvuln_rem==0.) then
call ReleaseTimer(t)
set d.fxinvuln_t=null
call SetUnitVertexColor(d.u,255,255,255,255)
if (d.invulnerable<=1) then
set d.invulnerable=0
call removeInvulnerability(d.u)
else
set d.invulnerable=d.invulnerable-1
endif
else
call TimerStart(t,d.fxinvuln_rem,false,function fxinvuln_expire)
set d.fxinvuln_rem=0.
endif
endfunction
public function fxInvulnerability takes unit u, real dur returns nothing
local unitbuffdata d=getData(u)
set d.invulnerable=d.invulnerable+1
if(d.invulnerable==1) then
call addInvulnerability(u)
endif
if( d.fxinvuln_t!=null) then
set d.fxinvuln_rem=d.fxinvuln_rem+ dur
else
set d.fxinvuln_rem=0.
set d.fxinvuln_t=NewTimer()
call SetCSData(d.fxinvuln_t,d)
call TimerStart(d.fxinvuln_t, dur ,false, function fxinvuln_expire)
call SetUnitVertexColor(u,255,255,255,75)
endif
endfunction
function fx2invuln_expire takes nothing returns nothing
local timer t=GetExpiredTimer()
local unitbuffdata d=GetCSData(t)
if (d.fx2invuln_rem==0.) then
call ReleaseTimer(t)
set d.fx2invuln_t=null
call DestroyEffect(d.fx2invuln)
if (d.invulnerable<=1) then
set d.invulnerable=0
call removeInvulnerability(d.u)
else
set d.invulnerable=d.invulnerable-1
endif
else
call TimerStart(t,d.fx2invuln_rem,false,function fx2invuln_expire)
set d.fx2invuln_rem=0.
endif
endfunction
public function fx2Invulnerability takes unit u, real dur returns nothing
local unitbuffdata d=getData(u)
set d.invulnerable=d.invulnerable+1
if(d.invulnerable==1) then
call addInvulnerability(u)
endif
if( d.fx2invuln_t!=null) then
set d.fx2invuln_rem=d.fx2invuln_rem+ dur
else
set d.fx2invuln_rem=0.
set d.fx2invuln_t=NewTimer()
set d.fx2invuln = AddSpecialEffectTarget(MODEL_INVULNERABILITY,u,"origin")
call SetCSData(d.fx2invuln_t,d)
call TimerStart(d.fx2invuln_t, dur ,false, function fx2invuln_expire)
endif
endfunction
function doKnockback takes nothing returns nothing
local integer i=0
local unitbuffdata picked
local unit u
local real x
local real y
local vector opos
loop
exitwhen knockback_N==i
set picked=knockback_V[i]
set u=picked.u
set x=GetUnitX(u)
set y=GetUnitY(u)
set x=x+picked.knockback_dpos.x
set y=y+picked.knockback_dpos.y
call CS_MoveUnit(u,x,y)
//now deaccelerate
set opos=vector.amplify(picked.knockback_dpos,-1)
call opos.setLength(SNOWDEACCEL * KNOCKBACKPERIOD)
set x=picked.knockback_dpos.x
set y=picked.knockback_dpos.y
if (x>0) then
set x=x+opos.x
if (x<0) then
set x=0.
endif
elseif (picked.knockback_dpos.x<0) then
set x=x+opos.x
if (x>0) then
set x=0.
endif
endif
if (y>0) then
set y=y+opos.y
if (y<0) then
set y=0.
endif
elseif (picked.knockback_dpos.y<0) then
set y=y+opos.y
if (y>0) then
set y=0.
endif
endif
if (x==0.) and (y==0.) then
//end this charade
call picked.knockback_dpos.destroy()
set picked.knockback_dpos=0
set knockback_N=knockback_N-1
set knockback_V[i]=knockback_V[knockback_N]
else
set picked.knockback_dpos.x=x
set picked.knockback_dpos.y=y
//must continue
set i=i+1
endif
call opos.destroy()
endloop
if (knockback_N==0) then
call PauseTimer(knockback_T)
endif
endfunction
public function addKnockback takes unit u, real accel, real dir returns nothing
local unitbuffdata d=getData(u)
local integer i=0
local integer f=-1
if (knockback_N==0) then
call TimerStart(knockback_T,KNOCKBACKPERIOD,true,function doKnockback)
endif
//find in V, this map has few units so it wouldn't matter to have O(n) , but in long maps it would be
//better to use a hash table (aka gamecache) and have O(1)
loop
exitwhen ((i==knockback_N) or (f!=-1))
if (knockback_V[i]==d) then
//found
set f=i
endif
set i=i+1
endloop
if (f==-1) then
set knockback_V[knockback_N]=d
set knockback_N=knockback_N+1
set d.knockback_dpos=vector.create()
endif
set d.knockback_dpos.x=d.knockback_dpos.x+ accel*Cos(dir)*KNOCKBACKPERIOD
set d.knockback_dpos.y=d.knockback_dpos.y+ accel*Sin(dir)*KNOCKBACKPERIOD
endfunction
private function temPauseExpire takes nothing returns nothing
local timer t=GetExpiredTimer()
local unitbuffdata d=GetCSData(t)
if (d.pausedur<=d.timerpausedur) then
call ReleaseTimer(t)
set d.pausedur=0.
set d.timerpausedur=0.
call PauseUnit(d.u,false)
else
set d.pausedur=d.pausedur-d.timerpausedur
set d.timerpausedur=d.pausedur
call TimerStart(t,d.timerpausedur,false, function temPauseExpire)
endif
endfunction
public function temPauseUnit takes unit u, real duration returns nothing
local timer t
local unitbuffdata d=getData(u)
if(d.pausedur!=0.) then
set d.pausedur=d.pausedur+duration
else
call PauseUnit(u,true)
set t=NewTimer()
call SetCSData(t,d)
set d.timerpausedur=duration
set d.pausedur=duration
call TimerStart(t,duration,false, function temPauseExpire)
endif
endfunction
endlibrary
function AnimationTest_Actions takes nothing returns nothing
local group g=CreateGroup()
local player p=GetTriggerPlayer()
local unit u
local trigger t
local string k
local integer i
local boolean b
call GroupEnumUnitsSelected(g,p,null)
set u=FirstOfGroup(g)
if (GetTableBoolean("[animtest]", "viewing")) then
call CinematicModeBJ(false,bj_FORCE_ALL_PLAYERS)
call SetTableBoolean(GetTableString("[animtest]","current"),"skip",true)
call SetTableString("[animtest]","current","")
call SetTableBoolean("[animtest]","viewing",false)
call ClearTextMessages()
elseif (u!=null) then
call CinematicModeBJ(true,bj_FORCE_ALL_PLAYERS)
call VolumeGroupReset()
set k=NewTable()
call SetTableString("[animtest]","current",k)
call SetTableBoolean("[animtest]","viewing",true)
call SetCameraPosition(GetUnitX(u),GetUnitY(u))
call PauseUnit(u,true)
set b=(GetUnitAbilityLevel(u,'Avul')==0)
if (b) then
call UnitAddAbility(u,'Avul')
endif
set i=0
call TriggerSleepAction(0)
loop
exitwhen (GetTableBoolean(k,"skip"))
call ClearTextMessages()
call BJDebugMsg("Currently playing Animation "+I2S(i)+"\nPress ESC again to exit")
call SetUnitAnimationByIndex(u,i)
call PolledWait(3)
set i=i+1
endloop
call PauseUnit(u,false)
if (b) then
call UnitRemoveAbility(u,'Avul')
endif
call DestroyTable(k)
else
call BJDebugMsg("Please select a unit before pressing ESC")
endif
call DestroyGroup(g)
set g=null
set u=null
endfunction
//===========================================================================
function InitTrig_AnimationTest takes nothing returns nothing
local integer a=0
set gg_trg_AnimationTest = CreateTrigger( )
loop
exitwhen (a>11)
call TriggerRegisterPlayerEventEndCinematic( gg_trg_AnimationTest, Player(a) )
set a=a+1
endloop
call TriggerAddAction( gg_trg_AnimationTest, function AnimationTest_Actions )
endfunction
function Trig_GetMaxTerrainHeight_Actions takes nothing returns nothing
local location loc=Location(0.,0.)
local real minx=GetRectMinX(bj_mapInitialPlayableArea)
local real maxx=GetRectMaxX(bj_mapInitialPlayableArea)
local real miny=GetRectMinY(bj_mapInitialPlayableArea)
local real maxy=GetRectMaxY(bj_mapInitialPlayableArea)
local real i=minx
local real j=miny
local real maximum=-1
local real h
loop
exitwhen i>=maxx
set j=miny
loop
exitwhen j>=maxy
call MoveLocation(loc,i,j)
set h=GetLocationZ(loc)
if (h>maximum) then
set maximum=h
endif
set j=j+64.
endloop
if(GetRandomInt(1,5)<2) then
call TriggerSleepAction(0.)
endif
set i=i+64.
endloop
call BJDebugMsg(R2S(maximum))
endfunction
//===========================================================================
function InitTrig_GetMaxTerrainHeight takes nothing returns nothing
set gg_trg_GetMaxTerrainHeight = CreateTrigger( )
call TriggerRegisterPlayerEventEndCinematic( gg_trg_GetMaxTerrainHeight, Player(0) )
call TriggerAddAction( gg_trg_GetMaxTerrainHeight, function Trig_GetMaxTerrainHeight_Actions )
endfunction
function InitTrig_gifts takes nothing returns nothing
endfunction
library gifts initializer init requires mobileengine
globals
private graphicdata array gift
private integer array itemid
private integer N=0
private real MINSPEED = 300.
private real MAXSPEED = 800.
private real ZSPEED = 300.
private real LAUNCHHEIGHT = 200.
endglobals
private function add takes integer id, playercolor c returns nothing
local graphicdata g=graphicdata.create()
set g.model=MODEL_PRESENT
set g.color=c
set g.scale=1.
set g.radius=110.0
set g.auxiliarid1='h001'
set g.range=0.0
set itemid[N]=id
set gift[N]=g
set N=N+1
endfunction
private function init takes nothing returns nothing
call add('pnvu',PLAYER_COLOR_GREEN )
call add('pman',PLAYER_COLOR_BLUE)
call add('I000',PLAYER_COLOR_YELLOW)
call add('pspd',PLAYER_COLOR_ORANGE)
debug call ExecuteFunc("gifts_test")
endfunction
private struct giftevents extends bouncylistener
integer itemid=0
method wantDestroy takes nothing returns boolean
return true
endmethod
method onUnitInRange takes unit u returns boolean
return false
endmethod
method onExplode takes real x, real y returns nothing
call DamageUnitsInAOE(Player(12),1000.,x,y,150.0,true)
call DestroyEffect(AddSpecialEffect(MODEL_BIG_EXPLOSION,x,y))
call CreateItem(this.itemid,x,y)
endmethod
endstruct
public function creategift takes real x, real y, real z, real xyanglerad, real speedxy, real zspeed returns bouncy
local integer gi=GetRandomInt(0,N-1)
local bouncy b
local giftevents ev=giftevents.create()
set ev.itemid=itemid[gi]
set b=bouncy.createfrom(gift[gi],xyanglerad*bj_RADTODEG)
call b.setXYAngleSpeed(xyanglerad, speedxy)
call b.setPos(x,y,z)
call b.setZSpeed(zspeed)
set b.maxbounces=GetRandomInt(0,3)
set b.radius=30.
set b.listen=ev
call mobileengine_addmobile(b)
return b
endfunction
public function launch takes nothing returns nothing
local integer gi= GetRandomInt(0,N-1)
local bouncy b
local giftevents ev=giftevents.create()
local integer corner=GetRandomInt(0,3)
set ev.itemid=itemid[gi]
//set corner=0
if (corner==0) then
set b=bouncy.createfrom(gift[gi], -45. )
call b.setXYAngleSpeed( -0.25*bj_PI, GetRandomReal(MINSPEED,MAXSPEED))
call b.setPos( GetRectCenterX(gg_rct_giftlaunchTL),GetRectCenterY(gg_rct_giftlaunchTL), LAUNCHHEIGHT)
elseif( corner==1) then
set b=bouncy.createfrom(gift[gi], 225. )
call b.setXYAngleSpeed( 1.25*bj_PI, GetRandomReal(MINSPEED,MAXSPEED))
call b.setPos( GetRectCenterX(gg_rct_giftlaunchTR),GetRectCenterY(gg_rct_giftlaunchTR), LAUNCHHEIGHT)
elseif(corner==2) then
set b=bouncy.createfrom(gift[gi], 45. )
call b.setXYAngleSpeed( 0.25*bj_PI, GetRandomReal(MINSPEED,MAXSPEED))
call b.setPos( GetRectCenterX(gg_rct_giftlaunchBL),GetRectCenterY(gg_rct_giftlaunchBL), LAUNCHHEIGHT)
else
set b=bouncy.createfrom(gift[gi], 135. )
call b.setXYAngleSpeed( 0.75*bj_PI, GetRandomReal(MINSPEED,MAXSPEED))
call b.setPos( GetRectCenterX(gg_rct_giftlaunchBR),GetRectCenterY(gg_rct_giftlaunchBR), LAUNCHHEIGHT)
endif
call b.setZSpeed(ZSPEED)
set b.changefac=true
set b.listen = ev
set b.requiredheightforimpact=10000000.
set b.maxbounces=GetRandomInt(0,3)
call mobileengine_addmobile(b)
set b.radius=30.
endfunction
function gifts_test takes nothing returns nothing
loop
call launch()
call TriggerSleepAction(GetRandomReal(10,15))
endloop
endfunction
endlibrary
function InitTrig_setup takes nothing returns nothing
endfunction
//===========================================================================
// Setting up the engine so it is actually a playable map...
//
library setup initializer init requires mobileengine, game, gifts
globals
private real spawnx
private real spawny
private graphicdata cmissile
private graphicdata cbiggermissile
private graphicdata cstar
private graphicdata cball
private graphicdata clightningball
private graphicdata credball
private graphicdata cblueball
private graphicdata cbell
private graphicdata cbigbell
private graphicdata cbellup
private graphicdata cbigball
private graphicdata clightningshield
private timerdialog roundd
private timer roundt
endglobals
//=================================================
// Bah give them losers a break, let the game wait
// 10 seconds between levels
function break takes nothing returns nothing
call TimerStart(roundt,10.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Next Level")
call PolledWait(10.)
call TimerDialogDisplay(roundd,false)
endfunction
//===============================================================
// Level 1, first one star, then 2 and finally 3 stars
//
function level1 takes nothing returns nothing
local stay s= stay.createfrom(cstar)
local wander w=wander.createfrom(0)
local wander w2
local wander w3
call TimerStart(roundt,33.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 1")
set w.x=spawnx
set w.y=spawny
set w.node=s
set w.speed= 500.
call mobileengine_addmobile(w)
call StopMusic(true)
call StartSound(gg_snd_theme1)
call PolledWait(11.)
set s= stay.createfrom(cstar)
set w2=wander.createfrom(cstar)
set w2.x=spawnx
set w2.y=spawny
set w2.node=s
set w2.speed= 600.
call mobileengine_addmobile(w2)
call PolledWait(11.)
set s= stay.createfrom(cstar)
set w3=wander.createfrom(0)
set w3.x=spawnx
set w3.y=spawny
set w3.node=s
set w3.speed= 700.
call mobileengine_addmobile(w3)
call PolledWait(11.)
call TimerDialogDisplay(roundd,false)
set w.terminate=true
set w2.terminate=true
set w3.terminate=true
call ResumeMusic()
endfunction
//===============================================================
// Level 2, a 5 stars formation, 2 variations
//
function level2 takes nothing returns nothing
local spin s= spin.createfrom(cstar)
local branch b
local wander w=wander.createfrom(0)
local boolean mode =(GetRandomInt(0,1)==0)
call TimerStart(roundt,50.,false,null)
call StopMusic(true)
call StartSound(gg_snd_theme2)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 2")
set w.x=spawnx
set w.y=spawny
set w.node=s
if mode then
set b=branch.createfrom_c(cstar,PLAYER_COLOR_RED)
set b.one=stay.createfrom_c(cstar,PLAYER_COLOR_RED)
set b.two=stay.createfrom_c(cstar,PLAYER_COLOR_RED)
set b.three=stay.createfrom_c(cstar,PLAYER_COLOR_RED)
set b.dis=100.
set s.up = b
else
set b=branch.createfrom_c(cstar,PLAYER_COLOR_RED)
set b.one=stay.createfrom_c(cstar,PLAYER_COLOR_RED)
set b.dis=100.
set s.left = b
set b=branch.createfrom_c(cstar,PLAYER_COLOR_RED)
set b.one=stay.createfrom_c(cstar,PLAYER_COLOR_RED)
set b.dis=100.
set s.right = b
endif
set s.radius=100.
if(mode) then
set s.tanspeed = 200.
set w.speed= 100.
else
set s.tanspeed = 200.
set w.speed= 200.
endif
call mobileengine_addmobile(w)
call PolledWait(20.0)
if(mode) then
set s.tanspeed = -200.
set w.speed= 150.
else
set s.tanspeed = -200.
set w.speed= 300.
endif
call PolledWait(10.0)
set s.tanspeed = 300.
set w.speed= 400.
if(mode) then
set s.tanspeed = 200.
set w.speed= 200.
else
set s.tanspeed = 300.
set w.speed= 400.
endif
call PolledWait(10.0)
if(mode) then
set s.tanspeed = -200.
else
set s.tanspeed = -400.
set w.speed= 800.
set s.maxradius=200.0
set s.minradius=100.0
set s.radiusspeed=100.
endif
call PolledWait(10.0)
call StopSound(gg_snd_theme2,false,true)
call ResumeMusic()
set w.terminate=true
call TimerDialogDisplay(roundd,false)
endfunction
//=============================================================================
// Level 3, there are three variations here cross, first missile launcher and spiral lines
//
function level3_cross takes nothing returns nothing
local spin s= spin.createfrom_c(cstar,PLAYER_COLOR_YELLOW)
local branch b
local wander w=wander.createfrom(0)
local boolean mode =(GetRandomInt(0,1)==0)
call TimerStart(roundt,55.,false,null)
call StopMusic(true)
call StartSound(gg_snd_theme3)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 3")
set w.x=spawnx
set w.y=spawny
set w.node=s
set b=branch.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.one=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.two=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.dis=100.
set s.up = b
set b=branch.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.one=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.two=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.dis=100.
set s.down = b
set b=branch.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.one=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.two=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.dis=100.
set s.left = b
set b=branch.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.one=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.two=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.dis=100.
set s.right = b
set s.radius=100.
set s.tanspeed = 200.
set w.speed= 300.
call mobileengine_addmobile(w)
call PolledWait(55.0)
call StopSound(gg_snd_theme3,false,true)
call ResumeMusic()
set w.terminate=true
call TimerDialogDisplay(roundd,false)
endfunction
function level3_missileformation takes nothing returns nothing
local spin s= spin.createfrom(0)
local branch b
local wander w=wander.createfrom(0)
local missilelauncher ml
local boolean mode =(GetRandomInt(0,1)==0)
call TimerStart(roundt,55.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 3")
call StopMusic(true)
call StartSound(gg_snd_theme3)
set w.x=spawnx
set w.y=spawny
set w.node=s
set b=branch.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.one=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.dis=100.
set s.left = b
set b=branch.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.one=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set b.dis=100.
set s.right = b
set ml=missilelauncher.createfrom(cbell)
call ml.setperiod(0.75)
set ml.missilespeed=800.
set ml.missilegraphicdata=cmissile
set b=branch.createfrom(0)
set b.one=ml
set b.dis=-150.
set s.down= b
set s.radius=100.
set s.tanspeed = 100.
set w.speed= 300.
call mobileengine_addmobile(w)
call PolledWait(30.0)
call ml.setperiod(0.3)
call PolledWait(25.0)
set w.terminate=true
call StopSound(gg_snd_theme3,false,true)
call ResumeMusic()
call TimerDialogDisplay(roundd,false)
endfunction
function level3_espiralpair takes nothing returns nothing
local gotozero z=gotozero.createfrom(0)
local spin s=spin.createfrom(0)
local branch b
call TimerStart(roundt,55.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 3")
call StopMusic(true)
call StartSound(gg_snd_theme3)
set z.node=s
set z.speed=300.
set z.x=spawnx
set z.y=spawny
set s.tanspeed=10.
set s.minradius=50.
set s.maxradius=1000.
set s.radiusspeed=10.
set s.radius=50.
set b=branch.createfrom(cstar)
set b.one=stay.createfrom(cstar)
set b.two=stay.createfrom(cstar)
set b.three=stay.createfrom(cstar)
set b.four=stay.createfrom(cstar)
set b.dis=100.
set s.left=b
set b=branch.createfrom(cstar)
set b.one=stay.createfrom(cstar)
set b.two=stay.createfrom(cstar)
set b.three=stay.createfrom(cstar)
set b.four=stay.createfrom(cstar)
set b.dis=100.
set s.right=b
call mobileengine_addmobile(z)
call PolledWait(10.)
set s.tanspeed=200.
set s.radiusspeed=100.
call PolledWait(20.0)
set s.tanspeed=-225
call PolledWait(25.0)
set z.terminate=true
call StopSound(gg_snd_theme3,false,true)
call ResumeMusic()
call TimerDialogDisplay(roundd,false)
endfunction
function level3 takes nothing returns nothing
local integer i=GetRandomInt(0,2)
if (i==0) then
call level3_cross()
elseif(i==1) then
call level3_missileformation()
else
call level3_espiralpair()
endif
endfunction
//=============================================================================
// Level 4, Another one with variations, missile launcher pair, nova and clap
//
function level4_nova takes nothing returns nothing
local spin s1
local spin s2
local branch m
local wander w
call StopMusic(true)
call StartSound(gg_snd_theme4)
call SetSoundPlayPosition(gg_snd_theme4,63000)
set w=wander.createfrom(0)
set m=branch.createfrom(0)
set m.dis=0.
set s1=spin.createfrom(0)
set s2=spin.createfrom(0)
set m.one=s1
set m.two=s2
set w.speed=200.
set w.x=spawnx
set w.y=spawny
set w.node=m
set s1.radius=50.
set s1.minradius=50.
set s1.maxradius=500.
set s1.tanspeed=800.
set s1.up=stay.createfrom(cstar)
set s1.down=stay.createfrom(cstar)
set s1.right=stay.createfrom(cstar)
set s1.left=stay.createfrom(cstar)
set s1.radiusspeed=100.
//repeat for s2
set s2.radius=50.
set s2.minradius=50.
set s2.maxradius=500.
set s2.tanspeed=800.
set s2.up=stay.createfrom(cstar)
set s2.down=stay.createfrom(cstar)
set s2.right=stay.createfrom(cstar)
set s2.left=stay.createfrom(cstar)
set s2.radiusspeed=100.
//this is the trick:
set s2.angle=45.0
call mobileengine_addmobile(w)
call TimerStart(roundt,64.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 4")
call PolledWait(22.)
set s1.tanspeed=-800.
set s2.tanspeed=-800
set s1.maxradius=550.
set s2.maxradius=550.
call PolledWait(22.)
set s1.tanspeed=800.
set s2.tanspeed=800
set s1.radiusspeed=150.
set s2.radiusspeed=150.
set s1.maxradius=600.
set s2.maxradius=600.
call PolledWait(20.)
call StopSound(gg_snd_theme4,false,true)
call ResumeMusic()
set w.terminate=true
call TimerDialogDisplay(roundd,false)
endfunction
function level4_clap takes nothing returns nothing
local spin s1
local spin s2
local branch m
local branch b1
local branch b2
local wander w
call StopMusic(true)
call StartSound(gg_snd_theme4)
call SetSoundPlayPosition(gg_snd_theme4,63000)
set w=wander.createfrom(0)
set m=branch.createfrom(0)
set m.dis=0.
set s1=spin.createfrom(cstar)
set s2=spin.createfrom(0)
set m.one=s1
set m.two=s2
set w.speed=300.
set w.x=spawnx
set w.y=spawny
set w.node=m
set s1.radius=100.
set s1.tanspeed=100.
set b1=branch.createfrom(cstar)
set b1.one=stay.createfrom(cstar)
set b1.two=stay.createfrom(cstar)
set b1.three=stay.createfrom(cstar)
set b1.four=stay.createfrom(cstar)
set b1.dis=100.
set s1.up=b1
set s2.radius=100.
set s2.tanspeed=-25.
set b2=branch.createfrom(cstar)
set b2.one=stay.createfrom(cstar)
set b2.two=stay.createfrom(cstar)
set b2.three=stay.createfrom(cstar)
set b2.four=stay.createfrom(cstar)
set b2.dis=100.
set s2.up=b2
call mobileengine_addmobile(w)
call TimerStart(roundt,64.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 4")
call PolledWait(22.)
set s1.tanspeed=-100.
set s2.tanspeed=25.
call PolledWait(22.)
set s1.tanspeed=100.
set s2.tanspeed=-25.
set w.speed=500.
call PolledWait(20.)
call StopSound(gg_snd_theme4,false,true)
call ResumeMusic()
set w.terminate=true
call TimerDialogDisplay(roundd,false)
endfunction
function level4_missiledudes takes nothing returns nothing
local elipse es1=elipse.createfrom(0)
local elipse es2=elipse.createfrom(0)
local spin s1=spin.createfrom(0)
local spin s2=spin.createfrom(0)
local missilelauncher ml1=missilelauncher.createfrom(cbell)
local missilelauncher ml2=missilelauncher.createfrom(cbell)
call StopMusic(true)
call StartSound(gg_snd_theme4)
call SetSoundPlayPosition(gg_snd_theme4,63000)
set es1.x=spawnx
set es1.horizontal=1000.
set es1.vertical=500.
set es1.speed=100.
set es2.x=spawnx
set es2.horizontal=600.
set es2.vertical=-1000.
set es2.speed=100.
set es1.y=spawny
set es2.y=spawny
set es1.node=s1
set es2.node=s2
set s1.tanspeed=10
set s2.tanspeed=-10
set s1.up=ml1
set s1.radius=20.
set s2.down=ml2
set s2.radius=20.
set ml1.missilegraphicdata=cbiggermissile
set ml2.missilegraphicdata=cbiggermissile
call ml1.setperiod(0.75)
set ml1.missilespeed=500.
call ml2.setperiod(0.75)
set ml2.missilespeed=500.
call mobileengine_addmobile(es1)
call mobileengine_addmobile(es2)
call TimerStart(roundt,64.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 4")
call PolledWait(22.)
set s1.tanspeed=-10.
set s2.tanspeed=10.
call ml1.setperiod(0.4)
call ml2.setperiod(0.4)
call PolledWait(22.)
set s1.tanspeed=15
set s2.tanspeed=-15
call PolledWait(20.)
call TimerDialogDisplay(roundd,false)
set es1.terminate=true
set es2.terminate=true
call StopSound(gg_snd_theme4,false,true)
call ResumeMusic()
endfunction
function level4 takes nothing returns nothing
local integer i=GetRandomInt(0,2)
if (i==0) then
call level4_nova()
elseif(i==1) then
call level4_clap()
else
call level4_missiledudes()
endif
endfunction
//=====================================================
// Level 5
// ------
// This one is a rotating square, guess it is cool
//
globals
private constant real SQUAREDIST=100. //distance between each of the square's parts
endglobals
function level5 takes nothing returns nothing
local spin s=spin.createfrom(0)
local wander w=wander.createfrom(0)
local branch b1=branch.createfrom(cstar)
local branch b2=branch.createfrom(cstar)
local branch b3=branch.createfrom(cstar)
local branch b4=branch.createfrom(cstar)
call StopMusic(true)
call StartSound(gg_snd_theme5)
set w.node=s
set w.speed=200.
set s.radius = SQUAREDIST*5*0.5* SquareRoot(2) //hey it is only called once
// setup the branches:
//! textmacro level5_branch takes index
set b$index$.dis=SQUAREDIST
set b$index$.one=stay.createfrom(cstar)
set b$index$.two=stay.createfrom(cstar)
set b$index$.three=stay.createfrom(cstar)
set b$index$.four=stay.createfrom(cstar)
set b$index$.facoffset=135.
//! endtextmacro
//! runtextmacro level5_branch("1")
//! runtextmacro level5_branch("2")
//! runtextmacro level5_branch("3")
//! runtextmacro level5_branch("4")
set s.up=b1
set s.down=b2
set s.right=b3
set s.left=b4
set s.tanspeed=100.
set w.x=spawnx
set w.y=spawny
call mobileengine_addmobile(w)
call TimerStart(roundt,55.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 5")
call PolledWait(10.)
call gifts_launch()
call PolledWait(20.)
call gifts_launch()
call PolledWait(15.)
set s.radiusspeed=400.
set s.minradius=s.radius
set s.maxradius=1000.0
call gifts_launch()
call gifts_launch()
call PolledWait(10.)
call TimerDialogDisplay(roundd,false)
call StopSound(gg_snd_theme5,false,true)
call ResumeMusic()
set w.terminate=true
endfunction
//=============================================================
// Level 6 - Introducing the crazy bouncing christmas balls
//
// We are using the doer object which requires to use the doeraction interface
struct level6_launch extends doeraction
method wantDestroy takes nothing returns boolean
return true
endmethod
// create a bouncy that points up
method execute takes real x,real y, real fac returns nothing
local bouncy b=bouncy.createfrom(cball,fac)
call b.setPos(x,y,140.)
call b.setXYAngleSpeed(fac*bj_DEGTORAD,GetRandomReal(100.,500.))
call b.setZSpeed(800.)
call mobileengine_addmobile(b)
endmethod
endstruct
function level6 takes nothing returns nothing
local level6_launch d=level6_launch.create()
local wander w=wander.createfrom(0)
local doer launcher = doer.createfrom(cbellup)
call StopMusic(true)
call StartSound(gg_snd_theme6)
set w.node=launcher
set w.speed=100.
set w.x=spawnx
set w.y=spawny
set w.changenodefac=true
set launcher.do=d
call launcher.setperiod(0.8)
call mobileengine_addmobile(w)
call TimerStart(roundt,55.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 6")
call PolledWait(40.)
call gifts_launch()
set w.speed=300.
call PolledWait(15.)
call TimerDialogDisplay(roundd,false)
set w.terminate=true
call StopSound(gg_snd_theme6,false,true)
call ResumeMusic()
endfunction
//=============================================================================
// Level 7, variations again, 2 this time, huge hole nova and the parasite
//
function level7_nova takes nothing returns nothing
local spin s1
local spin s2
local branch m
local gotozero w
call StopMusic(true)
call StartSound(gg_snd_theme7)
set w=gotozero.createfrom(0)
set m=branch.createfrom(0)
set m.dis=0.
set s1=spin.createfrom(0)
set s2=spin.createfrom(0)
set m.one=s1
set m.two=s2
set w.speed=300.
set w.x=spawnx
set w.y=spawny
set w.node=m
set s1.radius=50.
set s1.minradius=50.
set s1.maxradius=1200.
set s1.tanspeed=800.
set s1.up=stay.createfrom(cstar)
set s1.right=stay.createfrom(cstar)
set s1.left=stay.createfrom(cstar)
set s1.radiusspeed=100.
//repeat for s2
set s2.radius=50.
set s2.minradius=50.
set s2.maxradius=1200.
set s2.tanspeed=800.
set s2.up=stay.createfrom(cstar)
set s2.left=stay.createfrom(cstar)
//set s2.right=stay.createfrom(cstar)
set s2.down=stay.createfrom(cstar)
set s2.radiusspeed=100.
//this is the trick:
set s2.angle=-45.0
call mobileengine_addmobile(w)
call TimerStart(roundt,44.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 7")
call PolledWait(16.)
call gifts_launch()
call PolledWait(14.)
call gifts_launch()
set s2.radiusspeed=150.
call PolledWait(14.)
call StopSound(gg_snd_theme7,false,true)
call ResumeMusic()
set w.terminate=true
call TimerDialogDisplay(roundd,false)
endfunction
function level7_parasite takes nothing returns nothing
local spin s1=spin.createfrom_c(cstar,PLAYER_COLOR_BLACK)
local spin s2=spin.createfrom_c(cstar,PLAYER_COLOR_BLACK)
local spin s3=spin.createfrom_c(cstar,PLAYER_COLOR_BLACK)
local spin s4=spin.createfrom_c(cstar,PLAYER_COLOR_BLACK)
local branch b1
local branch b2
local branch b3
local branch b4
local wander w
call StopMusic(true)
call StartSound(gg_snd_theme7)
set w=wander.createfrom(0)
set w.speed=100.
set w.node=s1
set w.x=spawnx
set w.y=spawny
set b1=branch.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b1.dis=100.
set b1.one=stay.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b1.two=stay.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b1.three=s2
set s1.up=b1
set s1.tanspeed=50.
set s1.radius=100.
set b2=branch.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b2.dis=100.
set b2.one=stay.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b2.two=stay.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b2.three=s3
set s2.down=b2
set s2.tanspeed=25.
set s2.radius=100.
set b3=branch.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b3.dis=100.
set b3.one=stay.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b3.two=stay.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b3.three=s4
set s3.up=b3
set s3.tanspeed=12.5
set s3.radius=100.
set b4=branch.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b4.dis=100.
set b4.one=stay.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b4.two=stay.createfrom_c(cstar,PLAYER_COLOR_BLUE)
set b4.three=stay.createfrom_c(cstar,PLAYER_COLOR_BLACK)
set s4.down=b4
set s4.tanspeed=6.25
set s4.radius=100.
call mobileengine_addmobile(w)
call TimerStart(roundt,44.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 7")
call PolledWait(16.)
call gifts_launch()
call PolledWait(14.)
call gifts_launch()
//set s.radiusspeed=150.
call PolledWait(14.)
call StopSound(gg_snd_theme7,false,true)
call ResumeMusic()
set w.terminate=true
call TimerDialogDisplay(roundd,false)
endfunction
function level7 takes nothing returns nothing
if (GetRandomInt(0,1)==0) then
call level7_nova()
else
call level7_parasite()
endif
endfunction
//=========================================================
// Level 8 - Arena Stage
// -------
// level 8 is a 'break' from the usual dodge things gameplay
// it gives players a chance to use their killing skills
// this level should allow loser players to rebalance the death
// count if they are skilled enough
//
// It consists of 4 static stars so you could push enemies towards
// them and a lot of gifts fall
function level8 takes nothing returns nothing
local gotozero w=gotozero.createfrom(0)
local spin s=spin.createfrom(0)
call StopMusic(true)
call StartSound(gg_snd_theme8)
set w.speed=300.
set w.x=spawnx
set w.y=spawny
set w.node=s
set s.angle=45.
set s.up=stay.createfrom_c(cstar,PLAYER_COLOR_AQUA)
set s.down=stay.createfrom_c(cstar,PLAYER_COLOR_AQUA)
set s.left=stay.createfrom_c(cstar,PLAYER_COLOR_AQUA)
set s.right=stay.createfrom_c(cstar,PLAYER_COLOR_AQUA)
set s.radius=350.
call mobileengine_addmobile(w)
call TimerStart(roundt,63.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 8")
call PolledWait(13.0)
call gifts_launch()
call PolledWait(8.)
call gifts_launch()
call PolledWait(8.)
call gifts_launch()
call PolledWait(8.)
call gifts_launch()
call PolledWait(11.)
set s.maxradius=10000.
set s.minradius=s.radius
set s.radiusspeed=100.
set s.tanspeed=200.
call gifts_launch()
call PolledWait(15.)
call StopSound(gg_snd_theme8,false,true)
call ResumeMusic()
set w.terminate=true
call TimerDialogDisplay(roundd,false)
endfunction
//============================================================
// level 9 has two modes, it is either the typical rotating thing
// or a missile inferno.
//
struct level9_explode extends bouncylistener
method onUnitInRange takes unit u returns boolean
return false
endmethod
method wantDestroy takes nothing returns boolean
return true
endmethod
method onExplode takes real x, real y returns nothing
local stay s=stay.createfrom(clightningshield)
set s.x=x
set s.y=y
set s.px=0
set s.py=0
set s.duration=17.
call mobileengine_addmobile(s)
endmethod
endstruct
struct level9_launch extends doeraction
method wantDestroy takes nothing returns boolean
return false
endmethod
// create a bouncy that points up
method execute takes real x,real y, real fac returns nothing
local bouncy b=bouncy.createfrom(clightningball,fac)
call b.setPos(x,y,70.)
call b.setXYAngleSpeed(fac,1.)
call b.setZSpeed(1000.)
set b.maxbounces=0
set b.listen=level9_explode.create()
call mobileengine_addmobile(b)
endmethod
endstruct
function level9 takes nothing returns nothing
local wander w=wander.createfrom(0)
local spin s=spin.createfrom(cstar)
local missilelauncher ml1 = missilelauncher.createfrom(cbell)
local missilelauncher ml2 = missilelauncher.createfrom(cbell)
local branch b
local doer d
local level9_launch l9l= level9_launch.create()
local integer i
call StopMusic(true)
call StartSound(gg_snd_theme9)
call SetSoundPlayPosition(gg_snd_theme9,138000)
set ml1.missilegraphicdata= cmissile
set ml2.missilegraphicdata= cmissile
set ml1.missilespeed=900.
set ml2.missilespeed=900.
call ml1.setperiod(1000.)
call ml2.setperiod(1000.)
set s.radius=100.
set s.tanspeed=300.
set b=branch.createfrom(cstar)
set b.dis=100.
set b.facoffset=-45.
set d=doer.createfrom(cstar)
set b.one=d
set d.do=l9l
set d=doer.createfrom(cstar)
set b.two=d
set d.do=l9l
set b.three=ml1
set s.left=b
set b=branch.createfrom(cstar)
set b.dis=100.
set b.facoffset=45.
set d=doer.createfrom(cstar)
set b.one=d
set d.do=l9l
set d=doer.createfrom(cstar)
set b.two=d
set d.do=l9l
set b.three=ml2
set s.right=b
set w.node=s
set w.speed=450.
set w.x=spawnx
set w.y=spawny
call mobileengine_addmobile(w)
call TimerStart(roundt,47.5,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 9")
set i=9
loop
exitwhen i==0
if(i==4) then
call StopSound(gg_snd_theme9,false,true)
call StartSound(gg_snd_theme95)
call SetSoundPlayPosition(gg_snd_theme95,3000)
set s.tanspeed=50.
set w.speed=1.
call doer.doall()
endif
set i=i-1
call PolledWait(3.0)
if (i==0) then
call StopSound(gg_snd_theme95,false,true)
endif
if(i<4) then
set w.speed=100.
set s.tanspeed=50.
call ml1.setperiod(0.15)
call ml2.setperiod(0.15)
call PolledWait(2.0)
call ml1.setperiod(0.9)
call ml2.setperiod(0.9)
set w.speed=450.
set s.tanspeed=300.
else
set w.speed=1.
set s.tanspeed=50.
call ml1.setperiod(0.15)
call ml2.setperiod(0.15)
call PolledWait(2.0)
call ml1.setperiod(1000.)
call ml2.setperiod(1000.)
set w.speed=225.
set s.tanspeed=150.
endif
endloop
set w.terminate=true
call TimerDialogDisplay(roundd,false)
call l9l.destroy()
endfunction
//===========================================================
// Level 10 is another bouncing things levels with 3 variations
// Storm earth and fire.
// We are using the doer object which requires to use the doeraction interface
struct level10_launch1 extends doeraction
method wantDestroy takes nothing returns boolean
return true
endmethod
// create a bouncy that points up
method execute takes real x,real y, real fac returns nothing
local bouncy b=bouncy.createfrom(cball,fac)
call b.setPos(x,y,70.)
call b.setXYAngleSpeed(fac*bj_DEGTORAD,GetRandomReal(100.,800.))
call b.setZSpeed(0.)
call mobileengine_addmobile(b)
endmethod
endstruct
struct level10_fire extends bouncylistener
method onUnitInRange takes unit u returns boolean
return false
endmethod
method wantDestroy takes nothing returns boolean
return true
endmethod
method onExplode takes real x, real y returns nothing
call DestroyEffect(AddSpecialEffect(MODEL_BIG_EXPLOSION,x,y))
//call CasterCastAbilityPoint(Player(12),'A006',"flamestrike",x,y,false)
call DamageUnitsInAOE(Player(12),1000.,x,y,150.0,true)
endmethod
endstruct
struct level10_lightning extends bouncylistener
method onUnitInRange takes unit u returns boolean
return false
endmethod
method wantDestroy takes nothing returns boolean
return true
endmethod
method onExplode takes real x, real y returns nothing
local real fac=GetRandomInt(0,359)
local missile m
local real add
call DestroyEffect(AddSpecialEffect(MODEL_LIGHTNING_1,x,y))
call DestroyEffect(AddSpecialEffect(MODEL_LIGHTNING_2,x,y))
call DamageUnitsInAOE(Player(12),1000.,x,y,100.,false)
set add=0.
loop
exitwhen add>=360.
set m=missile.createfrom(cbiggermissile,(fac+add))
call m.change( (add+fac),600.)
set m.x=x
set m.y=y
call mobileengine_addmobile(m)
set add=add+45.
endloop
endmethod
endstruct
struct level10_launch2 extends doeraction
method wantDestroy takes nothing returns boolean
return true
endmethod
// create a bouncy that points up
method execute takes real x,real y, real fac returns nothing
local bouncy b
if(GetRandomInt(0,3)==0) then
set b=gifts_creategift(x,y,70.,fac*bj_DEGTORAD,GetRandomReal(100.,800.),0.)
else
set b=bouncy.createfrom(credball,fac)
call b.setPos(x,y,70.)
call b.setXYAngleSpeed(fac*bj_DEGTORAD,GetRandomReal(100.,800.))
call b.setZSpeed(0.)
set b.maxbounces=2
set b.listen=level10_fire.create()
call mobileengine_addmobile(b)
endif
endmethod
endstruct
struct level10_launch3 extends doeraction
method wantDestroy takes nothing returns boolean
return true
endmethod
// create a bouncy that points up
method execute takes real x,real y, real fac returns nothing
local bouncy b=bouncy.createfrom(cblueball,fac)
call b.setPos(x+128*CosBJ(fac),y+128*SinBJ(fac),70.)
call b.setXYAngleSpeed(fac*bj_DEGTORAD,GetRandomReal(100.,800.))
call b.setZSpeed(0.)
set b.maxbounces=3
set b.requiredheightforimpact=100.
set b.listen=level10_lightning.create()
call mobileengine_addmobile(b)
endmethod
endstruct
struct level11_stars extends doeraction
method wantDestroy takes nothing returns boolean
return true
endmethod
// create a bouncy that points up
method execute takes real x,real y, real fac returns nothing
local stay s
//return
set s=stay.createfrom(cstar)
set s.x=x
set s.y=y
set s.px=0
set s.py=0
set s.duration=5.
call mobileengine_addmobile(s)
endmethod
endstruct
function level10 takes nothing returns nothing
local level10_launch1 d1=level10_launch1.create()
local level10_launch2 d2=level10_launch2.create()
local level10_launch3 d3=level10_launch3.create()
local elipse w1=elipse.createfrom(0)
local elipse w2=elipse.createfrom(0)
local elipse w3=elipse.createfrom(0)
local doer lau1=doer.createfrom(cbigbell)
local doer lau2=doer.createfrom(cbigbell)
local doer lau3=doer.createfrom(cbigbell)
local doer snake
local wander wn1
local wander wn2
local integer i
//! textmacro level10_stuff takes i
set w$i$.speed=100.
set w$i$.horizontal=1000.
set w$i$.vertical=200.
set w$i$.px=spawnx
set w$i$.py=spawny-900.
set w$i$.y=900.
set w$i$.node=lau$i$
set lau$i$.fac=270.
set lau$i$.do= d$i$
call mobileengine_addmobile(w$i$)
//! endtextmacro
//! runtextmacro level10_stuff("1")
//! runtextmacro level10_stuff("2")
//! runtextmacro level10_stuff("3")
set w2.x=0.
set w1.x=GetRandomReal(-800.,-500.)
set w3.x=GetRandomReal(500.,800.)
set w2.vertical=-200.
call lau1.setperiod(1.2)
call lau2.setperiod(2.6)
call lau3.setperiod(1000000.)//2.8)
call TimerStart(roundt,70.,false,null)
call TimerDialogDisplay(roundd,true)
call TimerDialogSetTitle(roundd,"Level 10")
call StopMusic(true)
call StartSound(gg_snd_theme101)
call PolledWait(15.)
call lau2.setperiod(0.5)
call PolledWait(12.)
call lau2.setperiod(2.6)
call PolledWait(3.)
call gifts_launch()
//loop
// exitwhen n==8
// set w[n]=wander.createfrom(cstar)
// set w[n].x=spawnx
// set w[n].y=-spawny
// set w[n].speed=100.
// call mobileengine_addmobile(w[n])
// set n=n+1
// call PolledWait(5.)
// if (GetRandomReal(0,1)<0.2) then
// call gifts_launch()
// endif
//endloop
//set wn1=wander.createfrom(0)
//set wn1.speed=200.
//set wn1.x=spawnx
//set wn1.y=-spawny
//set snake=doer.createfrom(cstar)
//call snake.setperiod(0.5)
//set snake.do = level11_stars.create()
//set wn1.node=snake
//call mobileengine_addmobile(wn1)
call lau3.setperiod(5.)
call lau2.setperiod(2.)
call PolledWait(20.)
call StopSound(gg_snd_theme101,false,true)
call StartSound(gg_snd_theme102)
call lau3.setperiod(2.)
call lau2.setperiod(1.8)
call lau1.setperiod(1.)
//set wn2=wander.createfrom(0)
//set wn2.speed=200.
//set wn2.x=spawnx
//set wn2.y=-spawny
//set snake=doer.createfrom(cstar)
//call snake.setperiod(0.5)
//set snake.do = level11_stars.create()
//set wn2.node=snake
//call mobileengine_addmobile(wn2)
call PolledWait(20.)
call TimerDialogDisplay(roundd,false)
call StopSound(gg_snd_theme102,false,true)
call ResumeMusic()
set w1.terminate=true
set w2.terminate=true
set w3.terminate=true
//set wn1.terminate=true
//set wn2.terminate=true
endfunction
// for execute func
function setup_levels takes nothing returns nothing
call level1()
call gifts_launch()
call break()
call level2()
call gifts_launch()
call break()
call level3()
call gifts_launch()
call break()
call level4()
call gifts_launch()
call break()
call level5()
call gifts_launch()
call break()
call level6()
call gifts_launch()
call break()
call level7()
call gifts_launch()
call break()
call level8()
call gifts_launch()
call break()
call level9()
call gifts_launch()
call break()
call level10()
call game_end()
endfunction
globals
private timerdialog waitdlg=null
endglobals
private function begin takes nothing returns nothing
call DestroyTimerDialog(waitdlg)
call ReleaseTimer(GetExpiredTimer())
call ExecuteFunc("setup_levels")
endfunction
public function doGame takes nothing returns nothing
local timer t
call TriggerSleepAction(0.)
set t=NewTimer()
call Print("Welcome... The rounds will begin in 10 seconds")
set waitdlg=CreateTimerDialog(t)
call TimerStart(t,10.0, false, function begin)
call TimerDialogDisplay(waitdlg,true)
endfunction
private function dosetup takes nothing returns nothing
set roundt=CreateTimer()
set roundd=CreateTimerDialog(roundt)
call TimerDialogDisplay(roundd,false)
set spawnx=GetRectCenterX(gg_rct_spawn)-GetRectCenterX(gg_rct_game)
set spawny=GetRectCenterY(gg_rct_spawn)-GetRectCenterY(gg_rct_game)
set cmissile=graphicdata.create()
set cmissile.model=MODEL_MISSILE
set cmissile.color=PLAYER_COLOR_RED
set cmissile.scale=2.5
set cmissile.range=30.0
set cbiggermissile=graphicdata.create()
set cbiggermissile.model=MODEL_MISSILE
set cbiggermissile.color=PLAYER_COLOR_BLUE
set cbiggermissile.scale=3.5
set cbiggermissile.range=60.0
set cstar=graphicdata.create()
set cstar.model=MODEL_STAR
set cstar.color=PLAYER_COLOR_BLUE
set cstar.scale=0.6
set cstar.range=50.0
set clightningshield=graphicdata.create()
set clightningshield.model=MODEL_LIGHTNING_SHIELD
set clightningshield.color=PLAYER_COLOR_BLUE
set clightningshield.scale=2.0
set clightningshield.range=100.0
set clightningshield.height=0.0
set cball=graphicdata.create()
set cball.model=MODEL_BALL
set cball.color=PLAYER_COLOR_GREEN
set cball.scale=1.
set cball.radius=64.
set cball.auxiliarid1='h001'
set cball.range=0.0
set cblueball=graphicdata.create()
set cblueball.model=MODEL_BALL
set cblueball.color=PLAYER_COLOR_BLUE
set cblueball.scale=1.5
set cblueball.radius=128.
set cblueball.auxiliarid1='h002'
set cblueball.range=0.0
set credball=graphicdata.create()
set credball.model=MODEL_BALL
set credball.color=PLAYER_COLOR_RED
set credball.scale=0.5
set credball.radius=32.
set credball.auxiliarid1='h006'
set credball.range=0.0
set cball=graphicdata.create()
set cball.model=MODEL_BALL
set cball.color=PLAYER_COLOR_GREEN
set cball.scale=1.
set cball.radius=64.
set cball.auxiliarid1='h001'
set cball.range=0.0
set clightningball=graphicdata.create()
set clightningball.model=MODEL_LIGHTNING_BALL
set clightningball.color=PLAYER_COLOR_GREEN
set clightningball.scale=1.
set clightningball.radius=64.
//set clightningball.auxiliarid1='h001' //lightning, with shadow?
set clightningball.range=0.0
set cbell=graphicdata.create()
set cbell.model=MODEL_BELL
set cbell.color=PLAYER_COLOR_GREEN
set cbell.scale=0.5
set cbell.height=70.
set cbell.range=55.0
set cbigbell=graphicdata.create()
set cbigbell.model=MODEL_BELL
set cbigbell.color=PLAYER_COLOR_GREEN
set cbigbell.scale=1.
set cbigbell.height=70.
set cbigbell.range=70.0
set cbellup=graphicdata.create()
set cbellup.model=MODEL_BELL
set cbellup.color=PLAYER_COLOR_ORANGE
set cbellup.zangle=90
set cbellup.scale=1
set cbellup.height=1.
set cbellup.range=55.0
set cbigball=graphicdata.create()
set cbigball.model=MODEL_BALL
set cbigball.color=PLAYER_COLOR_RED
set cbigball.scale=2.
set cbigball.auxiliarid1='h002'
set cbigball.radius=128.
set cbigball.range=0.0
endfunction
private function init takes nothing returns nothing
call dosetup()
call doGame()
endfunction
endlibrary
//********************************************************************************************************
//* A JESP Spell by Vexorian
//* Codename: RagingCharge
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* Requirements:
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯
//* - The RagingCharge ability
//* - The Caster System ( http://wc3campaigns.net/vexorian ) >=14.0
//* - JASSHelper or other global merger preprocessor ( http://wc3campaigns.net/vexorian/jasshelper/ )
//* - This Trigger (MAKE SURE TO change the rawcodes in the trigger to the correct ones of your map)
//*
//* Object Editor fields
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* - Duration : Duration of the ability determines how much the charge lasts.
//* - Art - Caster : After charge Animation
//* - Art - Special (1) : Hero charge effect
//* - Art - Special (2) : Hero charge effect attachment point
//* - Art - Area Effect (1) : Knockback effect
//* - Art - Area Effect (2) : Knockback effect attachment point
//* - Art - Target (1) : Impact effect
//* - Art - Target (2) : Impact effect attachment point
//*
//********************************************************************************************************
//========================================================================================================
// RagingCharge Spell Configuration:
//
//
////
// SpellId
// ¯¯¯¯¯¯¯
// Make sure to replace A007 with the correct Rawcode in your map.
//
constant function RagingCharge_SpellId takes nothing returns integer
return 'A001'
endfunction
////
// Animation Stuff:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// _AnimationIndex : The sequence index of the animation you want to be played during the charge,
// (Depends on the model used, see next trigger for more info)
// _AnimationDuration: Duration of the animation (Period of time before playing it again)
// _AnimationSpeed : Speed factor for the animation
//
constant function RagingCharge_AnimationIndex takes integer level returns integer
return 5
endfunction
constant function RagingCharge_AnimationDuration takes integer level returns real
return 0.466
endfunction
constant function RagingCharge_AnimationSpeed takes real level returns real
return 1.+level*0
endfunction
constant function RagingCharge_Speed takes real level returns real
return 800.0+level*0
endfunction
////
// Balance Stuff:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
// _Damage : Damage done to units that are hit by RagingCharge
// _DamagePerSecond : Damage per second units get during knockback
// _ImpactRange : How close must a unit be to be hit by RagingCharge?
// _FrontAngle : Angle in Deg, less than 180.0 that determines the front of the hero
//
constant function RagingCharge_Damage takes real level returns real
return 0.0
// return -5 + (85-5*level)*level
endfunction
constant function RagingCharge_DamagePerSecond takes real level returns real
return 0.
endfunction
constant function RagingCharge_ImpactRange takes real level returns real
return 128.0 //256.0
endfunction
constant function RagingCharge_FrontAngle takes real level returns real
return 179.0
endfunction
constant function RagingCharge_MaxKnockbackTargets takes integer level returns integer
return 5+level
// Keep this number small, it is also used for array allocation, so using
//10000 might mean infinite but it would cause a lot of problems, it is not like
// you really need more than 50 for this value.
endfunction
////
// Targetting options:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
function RagingCharge_DamageOptions takes integer level returns integer
//** Damage options for impact damage:
return DamageTypes(ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE) + DamageOnlyEnemies() + DamageException(UNIT_TYPE_FLYING,0)
//
// Will do fire spell damage, won't damage allies, and will only affect ground units.
// other damage options can be used, check caster system readme for more information.
//
// (This is for the Impact damage)
//
endfunction
function RagingCharge_KnockbackOptions takes integer level returns integer
//** Damage options for knockback:
return DamageOnlyEnemies() + DamageException(UNIT_TYPE_FLYING,0)
//
// Will knockback enemy ground units
// other damage options can be used, check caster system readme for more information.
//
// (This is for the Knockback, meaning that only in case these damage options determine an unit is
// immune, it won't be affected by the knockback, this has nothing to do with damage
//
endfunction
function RagingCharge_KillTrees takes integer level returns boolean
//** true == kill trees ; false == don't kill trees
return true
endfunction
////
// Other:
// ¯¯¯¯¯
constant function RagingCharge_Timer takes nothing returns real
//** Timer Period:
return 0.04
//
// This is the timer period, a low value (0.01) will look better but will be worse lag-wise, a high
// value (1.0) would be faster lag-wise but will surelly look bad. I think 0.04 is the perfect value.
endfunction
//========================================================================================================
// RagingCharge code:
//
// Why RagingCharge_ItemCheck instead of IsTerrainPathable?
// IsTerrainPathable doesn't consider pathing blockers, destructables nor buildings
//
struct RagingCharge_data
unit u=null //casting hero
integer g=0 //arrayid of the knockback array
integer l=0 // level of the spell
real f=0. // direction of the charge
trigger ran=null //range eent trigger
trigger endt=null //stop casts event
triggeraction ac=null //action of range event
effect fx=null //charge fx
integer times=0 // number of cycles done
real next=0 //next time to play animation
endstruct
function RagingCharge_GetI takes nothing returns nothing
set bj_rescueChangeColorUnit = bj_rescueChangeColorUnit or (GetEnumItem()!=bj_itemRandomCurrentPick)
endfunction
function RagingCharge_ItemCheck takes item p, real x, real y returns boolean
local integer i=50
local rect r
call SetItemPosition(p,x,y)
if ((Pow(GetItemX(p)-x,2)+Pow(GetItemY(p)-y,2))<=100) then
return true
endif
set r=Rect(x-i,y-i,x+i,y+i)
set bj_itemRandomCurrentPick=p
set bj_rescueChangeColorUnit=false
call EnumItemsInRect(r,null,function RagingCharge_GetI)
call RemoveRect(r)
set r=null
return bj_rescueChangeColorUnit
endfunction
function RagingCharge_CheckPathability takes real x, real y returns boolean
return true
// local item it=CreateItem('ciri',x,y)
// local boolean b =RagingCharge_ItemCheck(it,x,y)
// call SetItemVisible(it,false)
// call RemoveItem(it)
// set it=null
// return b
endfunction
function RagingCharge_OrbMov takes unit m,integer l, timer t, RagingCharge_data k returns boolean
local real x=GetUnitX(m)
local real y=GetUnitY(m)
local real f=k.f
local real d=RagingCharge_Speed(l)*RagingCharge_Timer()
local real nx=x+d*Cos(f*bj_DEGTORAD)
local real ny=y+d*Sin(f*bj_DEGTORAD)
local boolean b
local integer error
local integer n = k.times+1
local real nex
set k.times=n
call SetUnitFacing(m,f)
set nex=k.next
if (n * RagingCharge_Timer() >= nex) then
set k.next=nex+RagingCharge_AnimationDuration(l)
call SetUnitAnimationByIndex(m,RagingCharge_AnimationIndex(l))
endif
if ((RagingCharge_CheckPathability(nx,ny)) and (CS_MoveUnit(m,nx,ny))) then
return true
endif
call SetUnitPosition(m,x,y)
call TriggerEvaluate( k.endt)
return false
endfunction
function RagingCharge_Mov takes nothing returns nothing
local timer t=GetExpiredTimer()
local RagingCharge_data k= GetCSData(t)
local unit m
local unit o
local real f
local real sf=k.f
local real h
local real dir
local real inc
local real x
local real y
local real nx
local real ny
local real px
local real py
local real mina
local real maxa
local integer tms
local integer l= k.l
local trigger tg=k.endt
local integer g=k.g
local integer i
local integer n=GetArrayInt(g,0)
set o=k.u
if (GetTriggerEvalCount(tg)>0) then
set i=1
set x=GetUnitX(o)
set y=GetUnitY(o)
loop
exitwhen (i>n)
// set m=GetArrayUnit(g,i*2)
// set nx=GetUnitX(m)
// set ny=GetUnitY(m)
// set f= Angles_GetMidAngle(Angles_GetMidAngle(Atan2(ny-y,nx-x)*bj_RADTODEG,sf),sf)*bj_DEGTORAD
//
// call buffs_addKnockback(m,RagingCharge_Speed(l),f)
call DestroyEffect(GetArrayEffect(g,i*2-1))
set i=i+1
endloop
call DestroyArray(g)
call DestroyTrigger(tg)
set tg=k.ran
call TriggerRemoveAction(tg, k.ac )
call DestroyTrigger(tg)
call ReleaseTimer(t)
set m=k.u
call DestroyEffect(k.fx)
if (GetWidgetLife(m)>0.405) then
call QueueUnitAnimation(m,GetAbilityEffectById(RagingCharge_SpellId(),EFFECT_TYPE_CASTER,0))
endif
call SetUnitTimeScale(m,1)
call k.destroy()
set o=null
set t=null
set m=null
return
endif
set tg=null
set x=GetUnitX(o)
set y=GetUnitY(o)
set inc=RagingCharge_Speed(l)*RagingCharge_Timer()
if (RagingCharge_KillTrees(l)) then
call DamageTreesInCircle(x,y,RagingCharge_ImpactRange(l))
endif
set h=RagingCharge_DamagePerSecond(l)*RagingCharge_Timer()
set i=1
loop
exitwhen (i>n)
set m=GetArrayUnit(g,i*2)
set nx=GetUnitX(m)
set ny=GetUnitY(m)
if (IsUnitInRange(m,o,RagingCharge_ImpactRange(l))) and (GetWidgetLife(m)>0.405) then
call DamageUnitByOptions(o,m,h,RagingCharge_DamageOptions(l))
//set f= Angles_GetMidAngle(Angles_GetMidAngle(Atan2(ny-y,nx-x)*bj_RADTODEG,sf),sf)*bj_DEGTORAD
//set f= Atan2(ny-y,nx-x)
set f= Angles_GetMidAngle((Atan2(ny-y,nx-x)*bj_RADTODEG),sf)*bj_DEGTORAD
set px=nx+inc*Cos(f)
set py=ny+inc*Sin(f)
call buffs_addKnockback(m,RagingCharge_Speed(l),f)
// call SetUnitPosition(m,px,py)
// call CS_MoveUnit(m,px,py)
call SetUnitFacing(m,GetRandomReal(0,360))
//if (Pow(GetUnitX(m)-px,2)+Pow(GetUnitY(m)-py,2))>400 then
// call SetUnitPosition(m,nx,ny)
//endif
else
// Destroy the effect, remove from array.
call DestroyEffect( GetArrayEffect(g,i*2-1) )
call SetArrayInt(g,i*2,GetArrayInt(g,n*2))
call SetArrayInt(g,i*2-1,GetArrayInt(g,n*2-1))
set n=n-1
call SetArrayInt(g,0,n)
endif
set i=i+1
endloop
call RagingCharge_OrbMov(o,l,t,k)
set t=null
set m=null
endfunction
function RagingCharge_InGArray takes unit u, integer g, integer n returns boolean
local integer i=0
loop
exitwhen i>n
if (GetArrayUnit(g,i*2)==u) then
return true
endif
set i=i+1
endloop
return false
endfunction
function RagingCharge_OrbImpact takes nothing returns nothing
local integer k=GetCSData( GetTriggeringTrigger() )
local unit u
local unit m
local integer g=k.g
local integer l=k.l
local real f
local real dt
local integer s=RagingCharge_SpellId()
local integer i=0
local integer n=GetArrayInt(g,0)
if (n>=RagingCharge_MaxKnockbackTargets(l)) then
return //why even bother?
endif
set u=GetTriggerUnit()
set m=k.u
if not( RagingCharge_InGArray(u,g,n)) and (GetWidgetLife(u)>0) and not(IsUnitType(u,UNIT_TYPE_DEAD)) and not(IsUnitType(u,UNIT_TYPE_STRUCTURE)) then
set f = k.f
set dt=RagingCharge_FrontAngle(l)/2
if (Angles_IsAngleBetweenAngles( Atan2BJ(GetUnitY(u)-GetUnitY(m),GetUnitX(u)-GetUnitX(m)),f-dt,f+dt)) then
if (GetDamageFactorByOptions(m,u,RagingCharge_KnockbackOptions(l))!=0) then
call DestroyEffect( AddSpellEffectTargetById(s,EFFECT_TYPE_TARGET,u,GetAbilityEffectById(s,EFFECT_TYPE_TARGET,1)) )
set n=n+1
call SetArrayObject(g,n*2-1, AddSpellEffectTargetById(s,EFFECT_TYPE_AREA_EFFECT,u,GetAbilityEffectById(s,EFFECT_TYPE_AREA_EFFECT,1)) )
call SetArrayObject(g,n*2, u )
call SetArrayInt(g,0,n)
endif
endif
call DamageUnitByOptions(m,u,RagingCharge_Damage(l),RagingCharge_DamageOptions(l))
endif
set u=null
set m=null
endfunction
function RagingCharge_Actions takes nothing returns nothing
local unit u=GetTriggerUnit()
local integer s=GetSpellAbilityId()
local integer l=GetUnitAbilityLevel(u,s)
local location loc
local real x=GetUnitX(u)
local real y=GetUnitY(u)
local real f
local timer t=NewTimer()
local integer g=NewArray(1+RagingCharge_MaxKnockbackTargets(l)*2,false)
local trigger tg=CreateTrigger()
local RagingCharge_data data= RagingCharge_data.create()
call SetArrayInt(g,0,0) //number of units in the array.
set data.ac=TriggerAddAction(tg,function RagingCharge_OrbImpact)
call SetCSData(t,data)
call SetCSData(tg,data)
if (GetSpellTargetUnit()!=null) then
set loc=GetUnitLoc(GetSpellTargetUnit())
else
set loc=GetSpellTargetLoc()
endif
set f=Atan2(GetLocationY(loc)-y,GetLocationX(loc)-x) * bj_RADTODEG
call RemoveLocation(loc)
set data.l=l
set data.f=f
set data.u=u
set data.g=g
set data.ran=tg
set data.fx=AddSpellEffectTargetById(s,EFFECT_TYPE_SPECIAL,u,GetAbilityEffectById(s,EFFECT_TYPE_SPECIAL,1))
call TriggerRegisterUnitInRange(tg,u,RagingCharge_ImpactRange(l),null)
set tg=CreateTrigger()
call TriggerRegisterUnitEvent(tg,u,EVENT_UNIT_SPELL_ENDCAST)
set data.endt=tg
call TimerStart(t,RagingCharge_Timer(),true,function RagingCharge_Mov)
call SetUnitTimeScale(u,RagingCharge_AnimationSpeed(l))
call SetUnitAnimationByIndex(u,RagingCharge_AnimationIndex(l))
set tg=null
set u=null
set loc=null
set t=null
endfunction
function InitTrig_RagingCharge takes nothing returns nothing
local integer s=RagingCharge_SpellId()
call OnAbilityEffect(s,"RagingCharge_Actions" )
call Preload(GetAbilityEffectById(s,EFFECT_TYPE_SPECIAL,0))
call Preload(GetAbilityEffectById(s,EFFECT_TYPE_TARGET,0))
call Preload(GetAbilityEffectById(s,EFFECT_TYPE_AREA_EFFECT,0))
endfunction
scope Snowball
globals
private constant integer SPELLID='A002'
private constant integer SHADOW='h007'
private constant real INITHEIGHT=40.
private constant real SPEED= 400.
private constant real MISSILESCALE= 1.
private constant real BALLRADIUS= 64.
private constant real ZSPEEDPERDIST=1.0
private constant real MAXZSPEED= 1200.
private constant integer FREEZEID = 'A003'
private constant string FREEZEORDER = "frostnova"
private constant integer HITANIMATION=2
private constant real MINIPAUSEDURATION = 0.5
private graphicdata snow
endglobals
private struct dofreeze extends bouncylistener
unit castingunit=null
method wantDestroy takes nothing returns boolean
return true
endmethod
method onUnitInRange takes unit u returns boolean
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if (u==this.castingunit) or IsUnitType(u,UNIT_TYPE_DEAD) or (GetUnitTypeId(u)==cs_CasterUnitId) then
return false
endif
call CasterCastAbility(GetOwningPlayer(this.castingunit),FREEZEID,FREEZEORDER,u,true)
if not IsUnitType(u,UNIT_TYPE_DEAD) then
call buffs_temPauseUnit(u,MINIPAUSEDURATION)
call SetUnitAnimationByIndex(u,HITANIMATION)
call QueueUnitAnimation(u,"stand")
endif
return true
endmethod
method onExplode takes real x, real y returns nothing
endmethod
endstruct
public function throw takes nothing returns nothing
local unit u=GetTriggerUnit()
local location loc=GetSpellTargetLoc()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
local real tx=GetLocationX(loc)
local real ty=GetLocationY(loc)
local bouncy b
local real f=Atan2(ty-y,tx-x)
local dofreeze freeze=dofreeze.create()
local real zs
set freeze.castingunit=u
call RemoveLocation(loc)
set b=bouncy.createfrom(snow,f)
call b.setPos(x,y,INITHEIGHT)
call b.setXYAngleSpeed(f, SPEED )
set zs=ZSPEEDPERDIST*SquareRoot( (x-tx)*(x-tx)+(y-ty)*(y-ty) )
if (zs>=MAXZSPEED) then
set zs=MAXZSPEED
endif
call b.setZSpeed(zs)
set b.disablekillevent=true
set b.maxbounces=2
set b.listen=freeze
set b.requiredheightforimpact = 10000000.0
set b.watereffect="Objects\\Spawnmodels\\Other\\IllidanFootprint\\IllidanWaterSpawnFootPrint.mdl"
call mobileengine_addmobile(b)
set loc=null
set u=null
endfunction
//===========================================================================
function InitTrig_SnowBall takes nothing returns nothing
set snow=graphicdata.create()
set snow.model=MODEL_SNOW
set snow.color=PLAYER_COLOR_BLACK
set snow.scale=MISSILESCALE
set snow.range=0.0
set snow.radius=BALLRADIUS
set snow.auxiliarid1=SHADOW
call OnAbilityEffect(SPELLID,"Snowball_throw")
endfunction
endscope
scope Swap
public function do takes nothing returns nothing
local unit u =GetTriggerUnit()
local unit t=GetSpellTargetUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
call SetUnitX(u,GetUnitX(t))
call SetUnitY(u,GetUnitY(t))
call SetUnitX(t,x)
call SetUnitY(t,y)
set u=null
set t=null
endfunction
endscope
//===========================================================================
function InitTrig_Swap takes nothing returns nothing
call OnAbilityEffect('A004',"Swap_do")
endfunction
scope InvulnerabilityPotion
public function do takes nothing returns nothing
call buffs_fx2Invulnerability(GetTriggerUnit(),5.)
endfunction
endscope
//===========================================================================
function InitTrig_InvulnerabilityPotion takes nothing returns nothing
call OnAbilityEffect('AIvu',"InvulnerabilityPotion_do")
endfunction
scope BananaBomb
globals
private constant integer SPELLID='A005'
private constant integer BIGBANANASHADOW='h008'
private constant integer SMALLBANANASHADOW='h006'
private constant real INITHEIGHT=40.
private constant real SPEED= 200.
private constant real BIGMISSILESCALE= 2.5
private constant real SMALLMISSILESCALE= 1.5
private constant real SMALL_MINSPEED=200.
private constant real SMALL_MAXSPEED=300.
private constant real SMALL_ZSPEED=800.
private constant real BALLRADIUS= 64.
private constant real ZSPEEDPERDIST=2.0 //0.5
private constant real MAXZSPEED= 1000.
private constant integer FREEZEID = 'A003'
private constant string FREEZEORDER = "frostnova"
private constant integer HITANIMATION=2
private constant real MINIPAUSEDURATION = 0.5
private graphicdata bigbanana
private graphicdata smallbanana
endglobals
private struct smallbananaevents extends bouncylistener
unit castingunit=null
method wantDestroy takes nothing returns boolean
return true
endmethod
method onUnitInRange takes unit u returns boolean
return false
endmethod
method onExplode takes real x, real y returns nothing
call DamageUnitsInAOE(Player(12),1000.,x,y,64.0,true)
call DestroyEffect(AddSpecialEffect(MODEL_SMALL_EXPLOSION,x,y))
endmethod
endstruct
private struct bigbananaevents extends bouncylistener
unit castingunit=null
method wantDestroy takes nothing returns boolean
return true
endmethod
method onUnitInRange takes unit u returns boolean
return false
endmethod
method onExplode takes real x, real y returns nothing
local integer i=3
local bouncy b
local smallbananaevents se
local real f
call DestroyEffect(AddSpecialEffect(MODEL_HUGE_EXPLOSION,x,y))
call DamageUnitsInAOE(Player(12),1000.,x,y,200.0,true)
loop
exitwhen i==0
set f=GetRandomReal(0,bj_PI*2)
set b=bouncy.createfrom(smallbanana,f*bj_RADTODEG)
set se=smallbananaevents.create()
set se.castingunit = this.castingunit
call b.setPos(x,y,10.0)
call b.setXYAngleSpeed( f, GetRandomReal(SMALL_MINSPEED,SMALL_MAXSPEED) )
call b.setZSpeed(SMALL_ZSPEED)
set b.maxbounces=0
set b.requiredheightforimpact = 10000000.0
set b.watereffect=MODEL_SMALL_WATERIMPACT
set b.listen=se
call mobileengine_addmobile(b)
set i=i-1
endloop
endmethod
endstruct
public function throw takes nothing returns nothing
local unit u=GetTriggerUnit()
local location loc=GetSpellTargetLoc()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
local real tx=GetLocationX(loc)
local real ty=GetLocationY(loc)
local bouncy b
local real f=Atan2(ty-y,tx-x)
local real zs
local bigbananaevents be=bigbananaevents.create()
call SetUnitAnimationByIndex(u,ANIMATION_THROW)
set be.castingunit=u
call RemoveLocation(loc)
set b=bouncy.createfrom(bigbanana,f)
call b.setPos(x,y,INITHEIGHT)
call b.setXYAngleSpeed(f, SPEED )
set zs=ZSPEEDPERDIST*SquareRoot( (x-tx)*(x-tx)+(y-ty)*(y-ty) )
if (zs> MAXZSPEED) then
set zs=MAXZSPEED
endif
call b.setZSpeed(zs)
set b.disablekillevent=true
set b.maxbounces=3
set b.listen=be
set b.requiredheightforimpact = 10000000.0
set b.watereffect=MODEL_SMALL_WATERIMPACT
call mobileengine_addmobile(b)
set loc=null
set u=null
endfunction
//===========================================================================
function InitTrig_BananaBomb takes nothing returns nothing
set bigbanana=graphicdata.create()
set bigbanana.model=MODEL_BANANA
set bigbanana.scale=BIGMISSILESCALE
set bigbanana.radius=BALLRADIUS
set bigbanana.range=0.0
set bigbanana.auxiliarid1=BIGBANANASHADOW
set smallbanana=graphicdata.create()
set smallbanana.model=MODEL_BANANA
set smallbanana.scale=SMALLMISSILESCALE
set smallbanana.radius=BALLRADIUS*0.75
set smallbanana.range=0.0
set smallbanana.auxiliarid1=SMALLBANANASHADOW
call OnAbilityEffect(SPELLID,"BananaBomb_throw")
endfunction
endscope