Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Vector
//*****************************************************************
//* VECTOR LIBRARY
//*
//* written by: Anitarf
//*
//* The library contains a struct named vector, which represents a
//* point in 3D space. As such, it has three real members, one for
//* each coordinate: x, y, z. It also has the following methods:
//*
//* static method create takes real x, real y, real z returns vector
//* Creates a new vector with the given coordinates.
//*
//* method getLength takes nothing returns real
//* Returns the length of the vector it is called on.
//*
//* static method sum takes vector augend, vector addend returns vector
//* Returns the sum of two vectors as a new vector.
//*
//* method add takes vector addend returns nothing
//* Similar to sum, except that it doesn't create a new vector for the result,
//* but changes the vector it is called on by adding the "added" to it.
//*
//* static method difference takes vector minuend, vector subtrahend returns vector
//* Returns the difference between two vectors as a new vector.
//*
//* method subtract takes vector subtrahend returns nothing
//* Similar to difference, except that it doesn't create a new vector for the result,
//* but changes the vector it is called on by subtracting the "subtrahend" from it.
//*
//* method scale takes real factor returns nothing
//* Scales the vector it is called on by the given factor.
//*
//* method setLength takes real length returns nothing
//* Sets the length of the vector it is called on to the given value, maintaining its orientation.
//*
//* static method dotProduct takes vector a, vector b returns real
//* Calculates the dot product (also called scalar product) of two vectors.
//*
//* static method crossProduct takes vector a, vector b returns vector
//* Calculates the cross product (also called vector product) of two vectors
//* and returns it as a new vector.
//*
//* static method tripleProductScalar takes vector a, vector b, vector c returns real
//* Calculates the triple scalar product of three vectors.
//*
//* static method tripleProductVector takes vector a, vector b, vector c returns vector
//* Calculates the triple vector product of three vectors and returns it as a new vector.
//*
//*
//* static method projectionVector takes vector projected, vector direction returns vector
//* Calculates the projection of the vector "projected" onto the vector "direction"
//* and returns it as a new vector.
//* Returns null if the vector "direction" has a length of 0.
//*
//* method projectVector takes vector direction returns nothing
//* Projects the vector it is called on onto the vector "direction".
//* Does nothing if the vector "direction" has a length of 0.
//*
//* static method projectionPlane takes vector projected, vector normal returns vector
//* Calculates the projection of the vector "projected" onto a plane defined by
//* its normal vector and returns it as a new vector.
//* Returns null if the vector "normal" has a length of 0.
//*
//* method projectPlane takes vector normal returns nothing
//* Projects the vector it is called on onto a plane defined by its normal vector.
//* Does nothing if the vector "normal" has a length of 0.
//*
//* static method getAngle takes vector a, vector b returns real
//* Returns the angle between two vectors, in radians, returns a value between 0 and pi.
//* Returns 0.0 if any of the vectors are 0 units long.
//*
//* method rotate takes vector axis, real angle returns nothing
//* Rotates the vector it is called on around the axis defined by the vector "axis"
//* by the given angle, which should be input in radians.
//* Does nothing if axis is 0 units long.
//*
//*
//* static method createTerrainPoint takes real x, real y returns vector
//* Creates a vector to the given terrain coordinate, taking its z height into account.
//*
//* method getTerrainPoint takes real x, real y returns nothing
//* Sets the vector it is called on to the given terrain coordinate, taking its z height into account.
//*
//* static method createTerrainNormal takes real x, real y, real sampleRadius returns vector
//* Creates the normal vector of the terrain at given coordinates. "sampleRadius" defines
//* how far apart the reference points will be, if they are further apart, the result will
//* be an impression of smoother terrain; normaly the value should be between 0 and 128.
//*
//* method getTerrainNormal takes real x, real y, real sampleRadius returns nothing
//* Sets the vector it is called on to the normal of the terrain at given coordinates.
//*
//*
//* method isInCylinder takes vector cylinderOrigin, vector cylinderHeight, real cylinderRadius returns boolean
//* Determines if a point is within a given cylinder. The cylinder's origin vector points
//* to the center of one of the two paralel circular sides, and the height vector points
//* from the origin point to the center of the other of the two paralel circular sides.
//* Returns false if the point is not in the cylinder or if the vector cylinderHeight is 0 units long.
//*
//* method isInCone takes vector coneOrigin, vector coneHeight, real coneRadius returns boolean
//* Determines if a point is within a given cone. The cone's origin vector points to the
//* center of the circular side, and the height vector points from the origin point to
//* the tip of the cone.
//* Returns false if the point is not in the cylinder or if the vector coneHeight is 0 units long.
//*
//* method isInSphere takes vector sphereOrigin, real sphereRadius returns boolean
//* Determines if a point is within a give sphere. The sphere's origin vector points to the
//* center of the sphere.
//* Returns false if the point is not in the sphere.
//*****************************************************************
struct vector
real x
real y
real z
static method create takes real x, real y, real z returns vector
local vector v = vector.allocate()
set v.x=x
set v.y=y
set v.z=z
return v
endmethod
method getLength takes nothing returns real
return SquareRoot(.x*.x + .y*.y + .z*.z)
endmethod
static method sum takes vector augend, vector addend returns vector
local vector v = vector.allocate()
set v.x = augend.x+addend.x
set v.y = augend.y+addend.y
set v.z = augend.z+addend.z
return v
endmethod
method add takes vector addend returns nothing
set this.x=this.x+addend.x
set this.y=this.y+addend.y
set this.z=this.z+addend.z
endmethod
static method difference takes vector minuend, vector subtrahend returns vector
local vector v = vector.allocate()
set v.x = minuend.x-subtrahend.x
set v.y = minuend.y-subtrahend.y
set v.z = minuend.z-subtrahend.z
return v
endmethod
method subtract takes vector subtrahend returns nothing
set this.x=this.x-subtrahend.x
set this.y=this.y-subtrahend.y
set this.z=this.z-subtrahend.z
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
method setLength takes real length returns nothing
local real l = SquareRoot(.x*.x + .y*.y + .z*.z)
if l == 0.0 then
debug call BJDebugMsg("vector.setLength error: The length of the vector is 0.0!")
return
endif
set l = length/l
set this.x = this.x*l
set this.y = this.y*l
set this.z = this.z*l
endmethod
static method dotProduct takes vector a, vector b returns real
return (a.x*b.x+a.y*b.y+a.z*b.z)
endmethod
static method crossProduct takes vector a, vector b returns vector
local vector v = vector.allocate()
set v.x = a.y*b.z - a.z*b.y
set v.y = a.z*b.x - a.x*b.z
set v.z = a.x*b.y - a.y*b.x
return v
endmethod
static method tripleProductScalar takes vector a, vector b, vector c returns real
return ((a.y*b.z - a.z*b.y)*c.x+(a.z*b.x - a.x*b.z)*c.y+(a.x*b.y - a.y*b.x)*c.z)
endmethod
static method tripleProductVector takes vector a, vector b, vector c returns vector
local vector v = vector.allocate()
local real n = a.x*c.x+a.y*c.y+a.z*c.z
local real m = a.x*b.x+a.y*b.y+a.z*b.z
set v.x = b.x*n-c.x*m
set v.y = b.y*n-c.y*m
set v.z = b.z*n-c.z*m
return v
endmethod
// ================================================================
static method projectionVector takes vector projected, vector direction returns vector
local vector v = vector.allocate()
local real l = direction.x*direction.x+direction.y*direction.y+direction.z*direction.z
if l == 0.0 then
call v.destroy()
debug call BJDebugMsg("vector.projectionVector error: The length of the direction vector is 0.0!")
return 0
endif
set l = (projected.x*direction.x+projected.y*direction.y+projected.z*direction.z) / l
set v.x = direction.x*l
set v.y = direction.y*l
set v.z = direction.z*l
return v
endmethod
method projectVector takes vector direction returns nothing
local real l = direction.x*direction.x+direction.y*direction.y+direction.z*direction.z
if l == 0.0 then
debug call BJDebugMsg("vector.projectVector error: The length of the direction vector is 0.0!")
return
endif
set l = (this.x*direction.x+this.y*direction.y+this.z*direction.z) / l
set this.x = direction.x*l
set this.y = direction.y*l
set this.z = direction.z*l
endmethod
static method projectionPlane takes vector projected, vector normal returns vector
local vector v = vector.allocate()
local real l = normal.x*normal.x+normal.y*normal.y+normal.z*normal.z
if l == 0.0 then
call v.destroy()
debug call BJDebugMsg("vector.projectionPlane error: The length of the normal vector is 0.0!")
return 0
endif
set l = (projected.x*normal.x+projected.y*normal.y+projected.z*normal.z) / l
set v.x = projected.x - normal.x*l
set v.y = projected.y - normal.y*l
set v.z = projected.z - normal.z*l
return v
endmethod
method projectPlane takes vector normal returns nothing
local real l = normal.x*normal.x+normal.y*normal.y+normal.z*normal.z
if l == 0.0 then
debug call BJDebugMsg("vector.projectPlane error: The length of the normal vector is 0.0!")
return
endif
set l = (this.x*normal.x+this.y*normal.y+this.z*normal.z) / l
set this.x = this.x - normal.x*l
set this.y = this.y - normal.y*l
set this.z = this.z - normal.z*l
endmethod
static method getAngle takes vector a, vector b returns real
local real l = SquareRoot(a.x*a.x + a.y*a.y + a.z*a.z)*SquareRoot(b.x*b.x + b.y*b.y + b.z*b.z)
if l == 0 then
debug call BJDebugMsg("vector.getAngle error: The length of at least one of the vectors is 0.0!")
return 0.0
endif
return Acos((a.x*b.x+a.y*b.y+a.z*b.z)/l) //angle is returned in radians
endmethod
method rotate takes vector axis, real angle returns nothing //angle is taken in radians
local real xx
local real xy
local real xz
local real yx
local real yy
local real yz
local real zx
local real zy
local real zz
local real al = axis.x*axis.x+axis.y*axis.y+axis.z*axis.z //axis length^2
local real f
local real c = Cos(angle)
local real s = Sin(angle)
if al == 0.0 then
debug call BJDebugMsg("vector.rotate error: The length of the axis vector is 0.0!")
return
endif
set f = (this.x*axis.x+this.y*axis.y+this.z*axis.z) / al
set zx = axis.x*f
set zy = axis.y*f
set zz = axis.z*f //axis component of rotated vector
set xx = this.x-zx
set xy = this.y-zy
set xz = this.z-zz //component of vector perpendicular to axis
set al = SquareRoot(al)
set yx = (axis.y*xz - axis.z*xy)/al
set yy = (axis.z*xx - axis.x*xz)/al //y same length as x by using cross product and dividing with axis length
set yz = (axis.x*xy - axis.y*xx)/al //x,y - coordinate system in which we rotate
set this.x=xx*c+yx*s+zx
set this.y=xy*c+yy*s+zy
set this.z=xz*c+yz*s+zz
endmethod
// ================================================================
private static location loc = Location(0.0,0.0)
static method createTerrainPoint takes real x, real y returns vector
local vector v = vector.allocate()
call MoveLocation(vector.loc,x,y)
set v.x=x
set v.y=y
set v.z=GetLocationZ(loc)
return v
endmethod
method getTerrainPoint takes real x, real y returns nothing
call MoveLocation(vector.loc,x,y)
set this.x=x
set this.y=y
set this.z=GetLocationZ(loc)
endmethod
static method createTerrainNormal takes real x, real y, real sampleRadius returns vector
local vector v = vector.allocate()
local real zx
local real zy
call MoveLocation(vector.loc, x-sampleRadius, y)
set zx=GetLocationZ(vector.loc)
call MoveLocation(vector.loc, x+sampleRadius, y)
set zx=zx-GetLocationZ(vector.loc)
call MoveLocation(vector.loc, x, y-sampleRadius)
set zy=GetLocationZ(vector.loc)
call MoveLocation(vector.loc, x, y+sampleRadius)
set zy=zy-GetLocationZ(vector.loc)
set sampleRadius=2*sampleRadius
set v.x = zx*sampleRadius
set v.y = zy*sampleRadius
set v.z = sampleRadius*sampleRadius
return v
endmethod
method getTerrainNormal takes real x, real y, real sampleRadius returns nothing
local real zx
local real zy
call MoveLocation(vector.loc, x-sampleRadius, y)
set zx=GetLocationZ(vector.loc)
call MoveLocation(vector.loc, x+sampleRadius, y)
set zx=zx-GetLocationZ(vector.loc)
call MoveLocation(vector.loc, x, y-sampleRadius)
set zy=GetLocationZ(vector.loc)
call MoveLocation(vector.loc, x, y+sampleRadius)
set zy=zy-GetLocationZ(vector.loc)
set sampleRadius=2*sampleRadius
set this.x = zx*sampleRadius
set this.y = zy*sampleRadius
set this.z = sampleRadius*sampleRadius
endmethod
// ================================================================
method isInCylinder takes vector cylinderOrigin, vector cylinderHeight, real cylinderRadius returns boolean
local real l
local real x = this.x-cylinderOrigin.x
local real y = this.y-cylinderOrigin.y
local real z = this.z-cylinderOrigin.z
if x*cylinderHeight.x+y*cylinderHeight.y+z*cylinderHeight.z < 0.0 then //point below cylinder
return false
endif
set x = x-cylinderHeight.x
set y = y-cylinderHeight.y
set z = z-cylinderHeight.z
if x*cylinderHeight.x+y*cylinderHeight.y+z*cylinderHeight.z > 0.0 then //point above cylinder
return false
endif
set l = cylinderHeight.x*cylinderHeight.x+cylinderHeight.y*cylinderHeight.y+cylinderHeight.z*cylinderHeight.z
if l == 0.0 then
debug call BJDebugMsg("vector.isInCylinder error: The length of the cylinderHeight vector is 0.0!")
return false
endif
set l = (x*cylinderHeight.x+y*cylinderHeight.y+z*cylinderHeight.z) / l
set x = x - cylinderHeight.x*l
set y = y - cylinderHeight.y*l
set z = z - cylinderHeight.z*l
if x*x+y*y+z*z > cylinderRadius*cylinderRadius then //point outside cylinder
return false
endif
return true
endmethod
method isInCone takes vector coneOrigin, vector coneHeight, real coneRadius returns boolean
local real l
local real x = this.x-coneOrigin.x
local real y = this.y-coneOrigin.y
local real z = this.z-coneOrigin.z
if x*coneHeight.x+y*coneHeight.y+z*coneHeight.z < 0.0 then //point below cone
return false
endif
set l = coneHeight.x*coneHeight.x+coneHeight.y*coneHeight.y+coneHeight.z*coneHeight.z
if l == 0.0 then
debug call BJDebugMsg("vector.isInCone error: The length of the coneHeight vector is 0.0!")
return false
endif
set l = (x*coneHeight.x+y*coneHeight.y+z*coneHeight.z) / l
set x = x - coneHeight.x*l
set y = y - coneHeight.y*l
set z = z - coneHeight.z*l
if SquareRoot(x*x+y*y+z*z) > coneRadius*(1.0-l) then //point outside cone
return false
endif
return true
endmethod
method isInSphere takes vector sphereOrigin, real sphereRadius returns boolean
if sphereRadius*sphereRadius < ((this.x-sphereOrigin.x)*(this.x-sphereOrigin.x)+(this.y-sphereOrigin.y)*(this.y-sphereOrigin.y)+(this.z-sphereOrigin.z)*(this.z-sphereOrigin.z)) then
return false
endif
return true
endmethod
endstruct
endlibrary
library VectorLib requires Vector // For backwards compatibility.
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library BoundSentinel initializer init
//*************************************************
//* BoundSentinel
//* -------------
//* Don't leave your units unsupervised, naughty
//* them may try to get out of the map bounds and
//* crash your game.
//*
//* To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//*************************************************
//==================================================
//=========================================================================================
globals
private constant boolean ALLOW_OUTSIDE_PLAYABLE_MAP_AREA = false
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns boolean
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if(x>maxx) then
set x=maxx
elseif(x<minx) then
set x=minx
endif
if(y>maxy) then
set y=maxy
elseif(y<miny) then
set y=miny
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
set u=null
return false
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
local region r = CreateRegion()
local rect map
local rect rc
if ALLOW_OUTSIDE_PLAYABLE_MAP_AREA then
set map = GetWorldBounds()
else
set map = bj_mapInitialPlayableArea
endif
set minx = GetRectMinX(map)
set miny = GetRectMinY(map)
set maxx = GetRectMaxX(map)
set maxy = GetRectMaxY(map)
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
if ALLOW_OUTSIDE_PLAYABLE_MAP_AREA then
call RemoveRect(map)
endif
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddCondition(t, Condition(function dis))
set rc=null
set map = null
endfunction
endlibrary
//TESH.scrollpos=141
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
set tT[0]=CreateTimer()
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DestructableLib initializer Initialization
//* ============================================================================ *
//* Made by PitzerMike *
//* *
//* I made this to detect if a destructable is a tree or not. It works not only *
//* for the standard trees but also for custom destructables created with the *
//* object editor. It uses a footie as a dummy with the goul's harvest ability. *
//* The dummy ids can be changed though. I also added the IsDestructableDead *
//* function for completeness. *
//* ============================================================================ *
globals
private constant integer DUMMY_UNIT_ID = 'hfoo' // footman
private constant integer HARVEST_ID = 'Ahrl' // ghouls harvest
private constant player OWNING_PLAYER = Player(15)
private unit dummy = null
endglobals
function IsDestructableDead takes destructable dest returns boolean
return GetDestructableLife(dest) <= 0.405
endfunction
function IsDestructableTree takes destructable dest returns boolean
local boolean result = false
if (dest != null) then
call PauseUnit(dummy, false)
set result = IssueTargetOrder(dummy, "harvest", dest)
call PauseUnit(dummy, true) // stops order
endif
return result
endfunction
private function Initialization takes nothing returns nothing
set dummy = CreateUnit(OWNING_PLAYER, DUMMY_UNIT_ID, 0.0, 0.0, 0.0)
call ShowUnit(dummy, false) // cannot enumerate
call UnitAddAbility(dummy, HARVEST_ID)
call UnitAddAbility(dummy, 'Aloc') // unselectable, invulnerable
call PauseUnit(dummy, true)
endfunction
endlibrary
//TESH.scrollpos=59
//TESH.alwaysfold=0
/*
==========Bouncing Bombs 1.4
==========Made by: Mckill2009
REQUIRES:
- Jass New Gen Pack (JNGP) by Vexorian
- BoundSentinel by Vexorian
- TimerUtils by Vexorian
- Vector by Anitarf
- DestructableLib by PitzerMike
HOW TO INSTALL:
- Copy ALL the triggers in the folder at the left of this screen that says "All these MUST be copied to your map".
- If you already have the "Required Libraries" in your map, then no need to copy the said library.
- Change the raw codes if needed.
FEATURES:
- You can configure how many bombs you want to create
- Much of the features are configurables, please see below
CREDITS:
- Bribe for the tip
*/
library BouncingBombs uses Vector, TimerUtils, DestructableLib, BoundSentinel
globals
//These are the raw codes, change it if necessary
private constant integer SPELL_ID = 'A000' //flame strike
private constant integer BOMB_ID = 'h000'
//Never touch these!
private vector xV
private vector yV
private vector zV
private rect REC
endglobals
globals
//Configurables
private constant integer MAX_BOMBS = 5 //maximum bombs created
private constant real AOE = 200 //aoe of the bomb when explodes
private constant real MAX_DIST = 300 //used for bombs to be at random point in SpellTargetXY
private constant real PERIODIC = 0.03125
private constant real SPEED = 15 //recommended
private constant attacktype ATK = ATTACK_TYPE_CHAOS
private constant damagetype DMG = DAMAGE_TYPE_NORMAL
private constant string SFX = "Objects\\Spawnmodels\\Human\\FragmentationShards\\FragBoomSpawn.mdl"
private constant boolean DAMAGE_ONLY_TREE = true
endglobals
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction
private function GetDamage takes integer i returns real
return 25 + i * 25.
endfunction
private function ParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)
endfunction
struct VectorLib
vector position
vector velocity
method bounce takes unit u, real x, real y returns nothing
local vector v
set .position.x = x
set .position.y = y
call .velocity.add(yV)
call .position.add(.velocity)
call .velocity.add(yV)
call zV.getTerrainPoint(.position.x, .position.y)
call SetUnitPosition(u, .position.x, .position.y)
call SetUnitFlyHeight(u, .position.z, 0.0)
if zV.z >= .position.z then
call zV.getTerrainNormal(zV.x, zV.y,4.0)
set v = vector.projectionVector(.velocity, zV)
call v.scale(-2.0)
call .velocity.add(v)
call v.destroy()
endif
endmethod
method vcreate takes unit u, real velocityX, real velocityY, real bounceheight returns nothing
set .position = vector.create(GetUnitX(u),GetUnitY(u),bounceheight)
set .velocity = vector.create(velocityX,velocityY,10)
endmethod
endstruct
private struct BB extends VectorLib
unit caster
unit missile
real duration
real damage
real angle
real distance
real distx
real height
static constant real FIXED_CREATION_HEIGHT = 100
static method getDestructables takes nothing returns boolean
local destructable d = GetFilterDestructable()
if DAMAGE_ONLY_TREE and IsDestructableTree(d) then
call KillDestructable(d)
elseif not DAMAGE_ONLY_TREE then
if GetDestructableLife(d) >= 0.405 then
call KillDestructable(d)
endif
endif
set d = null
return false
endmethod
method dest takes real x, real y returns nothing
call MoveRectTo(REC, x, y)
call EnumDestructablesInRect(REC,null,function thistype.getDestructables)
endmethod
private static method bombmovements takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local unit first
local unit dummy
local real x = GetUnitX(.missile)
local real y = GetUnitY(.missile)
local real x1
local real y1
if .duration > 0 then
set .duration = .duration - PERIODIC
if .distx > 0 then
set .distx = .distx - SPEED
call SetUnitPosition(.missile, x + SPEED * Cos(.angle), y + SPEED * Sin(.angle))
call SetUnitFlyHeight(.missile, ParabolaZ(.height, .distance, .distx), 0)
else
call bounce(.missile,x,y)
if GetUnitFlyHeight(.missile) <= 10 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE, null)
loop
set first = FirstOfGroup(bj_lastCreatedGroup)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, GetOwningPlayer(.missile)) then
call UnitDamageTarget(.missile, first, .damage, false, false, ATK, DMG, null)
call KillUnit(.missile)
call DestroyEffect(AddSpecialEffectTarget(SFX, .missile, "chest"))
call .dest(x,y)
endif
call GroupRemoveUnit(bj_lastCreatedGroup, first)
endloop
endif
endif
else
if UnitAlive(.missile) then
call KillUnit(.missile)
call DestroyEffect(AddSpecialEffectTarget(SFX, .missile, "chest"))
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE, null)
call .dest(x,y)
loop
set first = FirstOfGroup(bj_lastCreatedGroup)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, GetOwningPlayer(.missile)) then
call UnitDamageTarget(.missile, first, .damage, false, false, ATK, DMG, null)
endif
call GroupRemoveUnit(bj_lastCreatedGroup, first)
endloop
endif
call ReleaseTimer(t)
call .destroy()
endif
set t = null
endmethod
private static method create takes unit u, unit missile, real distance, real angle, integer level returns thistype
local thistype this = thistype.allocate()
local timer t = NewTimer()
call vcreate(u,GetRandomReal(-3,3),GetRandomReal(-3,3),100)
set .caster = u
set .missile = missile
set .distance = distance
set .distx = distance
set .angle = angle
set .height = FIXED_CREATION_HEIGHT
set .damage = GetDamage(level)
set .duration = GetRandomReal(5, 10)
call SetTimerData(t, this)
call TimerStart(t, PERIODIC, true, function thistype.bombmovements)
return this
endmethod
private static method creation takes unit u returns nothing
local integer i = 0
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real x1
local real y1
local real dx
local real dy
local unit missile
loop
set x1 = GetSpellTargetX()+GetRandomReal(50, MAX_DIST)*(GetRandomReal(-1,1))
set y1 = GetSpellTargetY()+GetRandomReal(50, MAX_DIST)*(GetRandomReal(-1,1))
set dx = x1-x
set dy = y1-y
set missile = CreateUnit(GetTriggerPlayer(), BOMB_ID, x, y, 0)
call BB.create(u, missile, SquareRoot(dx*dx+dy*dy), Atan2(y1-y, x1-x), GetUnitAbilityLevel(u, SPELL_ID))
set i = i + 1
exitwhen i==MAX_BOMBS
endloop
set missile = null
endmethod
static method go takes nothing returns boolean
if GetSpellAbilityId()==SPELL_ID then
call creation(GetTriggerUnit())
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, function thistype.go)
set xV = vector.create(1,0,30)
set yV = vector.create(0,0,-0.5)
set zV = vector.create(0,0,-0.035)
set REC = Rect(-AOE,-AOE,AOE,AOE)
set t = null
endmethod
endstruct
endlibrary