//TESH.scrollpos=-1
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
//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=0
//TESH.alwaysfold=0
library RT initializer Init
globals
private trigger Trig = CreateTrigger()
private constant real RegrowTime = 20
endglobals
function RegrowTrees takes nothing returns nothing
local destructable d = GetTriggerDestructable()
call TriggerSleepAction(RegrowTime)
call DestructableRestoreLife( d, GetDestructableMaxLife(d), true )
set d=null
endfunction
function Revival takes nothing returns nothing
if IsDestructableTree(GetEnumDestructable())==true then
call TriggerRegisterDeathEvent( Trig, GetEnumDestructable() )
endif
endfunction
function Init takes nothing returns nothing
call EnumDestructablesInRect(bj_mapInitialPlayableArea,null,function Revival )
call TriggerAddAction(Trig,function RegrowTrees)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Init initializer Set
globals
private real MAP_MIN_X
private real MAP_MAX_X
private real MAP_MIN_Y
private real MAP_MAX_Y
endglobals
function IsInMapXY takes real x , real y returns boolean
return x > MAP_MIN_X and x < MAP_MAX_X and y > MAP_MIN_Y and y < MAP_MAX_Y
endfunction
private function Set takes nothing returns nothing
set MAP_MIN_X = GetRectMinX(bj_mapInitialPlayableArea)
set MAP_MAX_X = GetRectMaxX(bj_mapInitialPlayableArea)
set MAP_MIN_Y = GetRectMinY(bj_mapInitialPlayableArea)
set MAP_MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea)
endfunction
endlibrary
//***************************************************************************
//*
//* SetUnitZ - By TriggerHappy187
//*
//***************************************************************************
//*
//* Installation
//* * All you need to do is copy this script into your map and you can use
//* the provided functions.
//*
//***************************************************************************
//*
//* Requirements
//* * This requires no external systems, all it requires is JassHelper.
//*
//***************************************************************************
//
// Precautions
// * If this function is used on a point with a terarin deformation
// A desync may occur.
//
//***************************************************************************
library SetUnitZ
globals
private location heightFixer = Location(0,0)
endglobals
function GetCoordZ takes real x, real y returns real
call MoveLocation(heightFixer, x, y)
return GetLocationZ(heightFixer)
endfunction
function SetUnitZ takes unit u, real h returns nothing
local location loc = GetUnitLoc(u)
local real z = GetLocationZ(loc)
call RemoveLocation(loc)
set loc = null
call SetUnitFlyHeight(u,h-z,0.)
endfunction
//function SetUnitZ takes unit whichUnit, real height, real rate returns nothing
// if GetUnitFlyHeight(whichUnit) == 0 then
// if UnitAddAbility(whichUnit, 'Arav') then
// call UnitRemoveAbility(whichUnit, 'Arav')
// endif
// endif
// //call MoveLocation(heightFixer, GetUnitX(whichUnit), GetUnitY(whichUnit))
// call SetUnitFlyHeight(whichUnit, height-GetCoordZ(GetUnitX(whichUnit), GetUnitY(whichUnit)), rate)
//endfunction
function GetUnitZ takes unit whichUnit returns real
call MoveLocation(heightFixer, GetUnitX(whichUnit), GetUnitY(whichUnit))
return GetUnitFlyHeight(whichUnit)+GetLocationZ(heightFixer)
endfunction
endlibrary
library GetTerrainZ
// How to Implement:
//
// by D.V.D
//
// Copy this code
// Create a trigger in your map
// Change the trigger to custom script
// Paste the code into the trigger
globals
location GL = Location(0,0)
endglobals
function GetTerrainZ takes real x, real y returns real
call MoveLocation(GL, x, y)
return GetLocationZ(GL)
endfunction
function GetTerrainZLoc takes location loc returns real
call MoveLocation(GL, GetLocationX(loc), GetLocationY(loc))
return GetLocationZ(GL)
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
scope Grenade initializer Init
private keyword Data
globals
// Editable Globals
private constant integer GRENADE_ID = 'gdum' // Grenade unit
private constant integer GRENADE_SFX1 = 'xdum' // SFX 1
private constant integer GRENADE_SFX2 = 'xsfx' // SFX 2
private constant integer SPELL_ID = 'GAId' // Ability ID
private constant real MAX_RANGE = 1000
private constant real MIN_RANGE = 400
private constant real MAX_HEIGHT = 400
private constant attacktype AT = ATTACK_TYPE_NORMAL
private constant damagetype DT = DAMAGE_TYPE_NORMAL
private constant weapontype WT = WEAPON_TYPE_WHOKNOWS
private constant boolean DAMAGE_SELF = false// Can it hurt player units ?
private constant boolean DAMAGE_ALLY = false// Can it hurt ally units ?
// Editable Globals
// Don't change...
private constant real PERIOD = 0.04 // Depends on what period you like ... don't moan at me if your .0001 period lags though...
private constant real SPEED = 700 * PERIOD// How fast the grenade travels per second
private Data DATA //Temp Globals
private real X //Temp Globals
private real Y //Temp Globals
private real DIST //Temp Globals
private integer COUNT = 0
private Data array GData
private timer TIMER = CreateTimer()
private location LOC = Location(0,0)
//Don't change
endglobals
private constant function AOE_Range takes integer lvl returns real
return 150 + lvl*50 *1.0
endfunction
private function MinMax takes real val,real min,real max returns real
if(min>val) then
return min
elseif(val>max) then
return max
else
return val
endif
endfunction
private function GetParabolaZ takes real x,real d,real h returns real
return 4 * h * x * (d - x) / (d * d)
endfunction // By AceHart
private function GetDamage takes integer level returns real
return GetRandomReal (10,20) + 15 * (level-1)
endfunction// I guess Flare @ TH.net helped me with this O_o...
private struct Data
unit Grenade
unit caster
player p
real x
real y
real DistCur
real DistMax
real baseH
real aoe
integer level
real cos
real sin
static group GROUP = CreateGroup()
static method Damage takes nothing returns boolean
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(u)
local Data d = DATA
local real damage = GetDamage(d.level)
local boolean dmg = false
if(DAMAGE_SELF and p==d.p)then
set dmg = true
elseif(DAMAGE_ALLY and IsPlayerAlly(p,d.p))then
set dmg = true
elseif(IsPlayerEnemy(p,d.p))then
set dmg = true
endif
if(dmg) then
call UnitDamageTarget(d.caster,u,damage,true,true,AT,DT,WT)
endif
set u = null
return false
endmethod
static method InCircle takes nothing returns boolean
local destructable d = GetFilterDestructable()
local real x = DATA.x - GetDestructableX(d)
local real y = DATA.y - GetDestructableY(d)
local real dist = x*x+y*y
set d = null
if(dist>DATA.aoe*DATA.aoe)then// or SquareRoot(dist) > AOE_RANGE either workz...
return false
else
return true
endif
endmethod
static method TreeDestroy takes nothing returns nothing
local destructable d = GetEnumDestructable()
if IsDestructableTree(d) then
call KillDestructable(d)
endif
set d = null
endmethod
method KillTrees takes real x,real y returns nothing
local rect r = Rect(x-.aoe,y-.aoe,x+.aoe,y+.aoe)
call EnumDestructablesInRect(r,Filter(function Data.InCircle),function Data.TreeDestroy)
call RemoveRect(r)
set r = null
endmethod
method Explode takes nothing returns nothing
call UnitApplyTimedLife(CreateUnit(.p,GRENADE_SFX1,.x,.y,0),0,1)
call UnitApplyTimedLife(CreateUnit(.p,GRENADE_SFX2,.x,.y,0),0,1)
set DATA = this
call GroupEnumUnitsInRange(.GROUP,.x,.y,this.aoe,Filter(function Data.Damage))
call .KillTrees(.x,.y)
call .destroy()
endmethod
method onDestroy takes nothing returns nothing
call ShowUnit(.Grenade,false)// Don't know wether this is neccesary ?
call RemoveUnit(.Grenade)
endmethod
endstruct
private function Execute takes nothing returns nothing
local integer i = 0
local Data d
local unit u
local boolean zhit
loop
exitwhen i == COUNT
set zhit = false
set d = GData[i]
set u = d.Grenade
set d.DistCur = d.DistCur + SPEED
set d.x = d.x + SPEED * d.cos
set d.y = d.y + SPEED * d.sin
if IsInMapXY(d.x,d.y) == true then
call SetUnitX(u,d.x)
call SetUnitY(u,d.y)
call SetUnitZ(u,d.baseH+GetParabolaZ(d.DistCur,d.DistMax,MAX_HEIGHT))
call MoveLocation(LOC,d.x,d.y)
if(R2I(GetUnitZ(u))==R2I(GetLocationZ(LOC)))then
// R2I because it gives me '0.001' and stuff ... so it isn't 'equal' unit height
set zhit=true
endif
if zhit==true then
set COUNT = COUNT - 1
set GData[i] = GData[COUNT]
call d.Explode()
else
set i = i + 1
endif
else
set COUNT = COUNT - 1
set GData[i] = GData[COUNT]
call d.destroy()
endif
endloop
set u = null
if COUNT == 0 then
call PauseTimer(TIMER)
endif
endfunction
private function Run takes nothing returns nothing
local Data d = Data.create()
local location l = GetSpellTargetLoc()
local real x = GetLocationX(l)
local real y = GetLocationY(l)
local real dist = 0
local real facing
call RemoveLocation(l)// do I need to 'set l = null' ?
set d.caster = GetTriggerUnit()
set l = GetUnitLoc(d.caster)
set d.baseH = GetLocationZ(l)
call RemoveLocation(l)
set l = null
set d.p = GetOwningPlayer(d.caster)
set d.x = GetUnitX(d.caster)
set d.y = GetUnitY(d.caster)
set d.level = GetUnitAbilityLevel(d.caster,SPELL_ID)
set d.aoe = AOE_Range(d.level)
set x = x - d.x
set y = y - d.y
set facing = Atan2(y,x)
set d.cos = Cos(facing)
set d.sin = Sin(facing)
set d.Grenade = CreateUnit(d.p,GRENADE_ID,d.x,d.y,facing)
call UnitAddAbility(d.Grenade,'Amrf')// I have to do this or else it goes buggy over raised terrain
call UnitRemoveAbility(d.Grenade,'Amrf')
set d.DistMax = MinMax(SquareRoot(x*x+y*y),MIN_RANGE,MAX_RANGE)
set d.DistCur = 0
set GData[COUNT] = d
set COUNT = COUNT + 1
if COUNT == 1 then
call TimerStart(TIMER,PERIOD,true,function Execute)
endif
endfunction
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call Run()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t,Condition(function Cond))
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
//
//
// To Implement the spell
//
//
// Copy the following : UNITS
//
// Explosion -> 'xdum'
// Explosion SFX -> 'xsfx''
// Grenade -> ' gdum''
//
//
//
// Copy the following : ABILITy
//
// Grenade -> 'GAId'
//
//
// Copy the following : Triggers
//
// Regrow Trees
// IsDestructableTree
// InitLibrary
//
//
//
// You can change many of the grenades features, such as :
//
// max height , max/min range , aoe range
// damage , wether it can hurt allied or player units
//
//TESH.scrollpos=-1
//TESH.alwaysfold=0
scope BouncyGrenade initializer Init
private keyword Data
globals
// Editable Globals
private constant integer GRENADE_ID = 'gdum'
private constant integer GRENADE_SFX1 = 'xdum'
private constant integer GRENADE_SFX2 = 'xsfx'
private constant integer SPELL_ID = 'BGid'
private constant integer MAX_BOUNCES = 2// How many bounces ?
private constant real BOUNCE_DECREASE = 1.5// How much the range divises by per bounce
private constant real MAX_RANGE = 1200// max range of grenade
private constant real MIN_RANGE = 400// min range of grenade
private constant real MAX_HEIGHT = 400// maximum height reachable
private constant attacktype AT = ATTACK_TYPE_NORMAL // attack type..
private constant damagetype DT = DAMAGE_TYPE_NORMAL// damage type..
private constant weapontype WT = WEAPON_TYPE_WHOKNOWS// Weapon type..
private constant boolean DAMAGE_SELF = false// Can it hurt player units ?
private constant boolean DAMAGE_ALLY = false// Can it hurt ally units ?
//
// Don't change...
private constant real PERIOD = 0.04 // Depends on what period you like ... don't moan at me if your .0001 period lags though...
private constant real SPEED = 700 *PERIOD // How fast the grenade travels per second
private Data DATA// Temp Globals
private real X //Temp Globals
private real Y //Temp Globals
private real DIST //Temp Globals
private integer COUNT = 0
private Data array GData
private timer TIMER = CreateTimer()
//You can now continue to the rest of the code...
endglobals
private constant function AOE_Range takes integer lvl returns real
return 150 + lvl*50 *1.0// Find AoE for Grenade explosion
endfunction
private function MinMax takes real val,real min,real max returns real
if(min>val) then
return min
elseif(val>max) then
return max
else
return val
endif
endfunction
private function GetRange takes real range returns real
return range/BOUNCE_DECREASE// devise the range
endfunction
private function GetSpeed takes real range returns real
return (range/MAX_RANGE)*SPEED*2// find speed with this 'formula'
endfunction
private function GetHeight takes real range returns real// find the max height for that bounce
return MinMax((range/MAX_RANGE)*MAX_HEIGHT*3,0,MAX_HEIGHT)
endfunction
private function GetParabolaZ takes real x,real d,real h returns real
return 4 * h * x * (d - x) / (d * d)
endfunction // By AceHart
private function GetDamage takes integer level returns real
return GetRandomReal (10,20) + 15 * (level-1)
endfunction// I guess Flare @ TH.net helped me with this O_o...
private struct Data
unit Grenade
unit caster
player p
real x
real y
real DistCur
real DistMax
real HeightMax
real heightBase
real baseH
real aoe
real facing
integer level
real speed
real cos
real sin
integer bounce
boolean justBounced
static group GROUP = CreateGroup()
static method Damage takes nothing returns boolean// To damage the targets near grenade
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(u)
local Data d = DATA
local real damage = GetDamage(d.level)
local boolean dmg = false
if(DAMAGE_SELF and p==d.p)then// damage the caster's and player units ... if possible ?
set dmg = true
elseif(DAMAGE_ALLY and IsPlayerAlly(p,d.p))then// hurt allies ?
set dmg = true
elseif(IsPlayerEnemy(p,d.p))then// or just enemies...
set dmg = true
endif
if(dmg) then
call UnitDamageTarget(d.caster,u,damage,true,true,AT,DT,WT)// the damage..
endif
set u = null
return false// return false to not add to global group..
endmethod
static method InCircle takes nothing returns boolean
local destructable d = GetFilterDestructable()
local real x = DATA.x - GetDestructableX(d)
local real y = DATA.y - GetDestructableY(d)
local real dist = x*x+y*y
// Check if the destructable is in range of the grenade AoE
set d = null
if(dist>DATA.aoe*DATA.aoe)then// or SquareRoot(dist) > AOE_RANGE either workz...
return false
else
return true
endif
endmethod
static method TreeDestroy takes nothing returns nothing
local destructable d = GetEnumDestructable()
if IsDestructableTree(d) then
call KillDestructable(d)// Destroy the tree if its a tree...
endif
set d = null//nulls...
endmethod
method KillTrees takes real x,real y returns nothing
local rect r = Rect(x-.aoe,y-.aoe,x+.aoe,y+.aoe)
// find trees within a rect then find within a circle...
call EnumDestructablesInRect(r,Filter(function Data.InCircle),function Data.TreeDestroy)
call RemoveRect(r)// nulls...
set r = null
endmethod
method Explode takes nothing returns nothing
call UnitApplyTimedLife(CreateUnit(.p,GRENADE_SFX1,.x,.y,0),0,1)
call UnitApplyTimedLife(CreateUnit(.p,GRENADE_SFX2,.x,.y,0),0,1)// Add each SFX for a second
set DATA = this
// global data for enums ...
call GroupEnumUnitsInRange(.GROUP,.x,.y,this.aoe,Filter(function Data.Damage))
call .KillTrees(.x,.y)
call .destroy()// kill trees then destroy self..
endmethod
method onDestroy takes nothing returns nothing
call ShowUnit(.Grenade,false)// Don't know wether this is neccesary ?
call RemoveUnit(.Grenade)
endmethod
method NewBounce takes nothing returns nothing// set new data for that bounce
local location l = GetUnitLoc(.Grenade)
set .bounce = .bounce + 1// increase bounce
set .DistMax = .DistCur/BOUNCE_DECREASE// find the distmax from the distance traveled / decrement
set .DistCur = 0// reset dist traveled
set .HeightMax = GetHeight(.DistMax)// formula for height
set .speed = GetSpeed(.DistMax)// find the speed for new bounce
set .baseH = GetLocationZ(l)//find 'this' bounce height again..
call RemoveLocation(l)// leaks
set l = null
endmethod
endstruct
private function Execute takes nothing returns nothing
local integer i = 0
local Data d
local unit u
local boolean zhit // Z - Hit if anyone has a weird font like me which looks like an s ...
local location l = Location(0,0)
loop
exitwhen i == COUNT
set zhit = false
set d = GData[i]
set u = d.Grenade
set d.DistCur = d.DistCur + d.speed
set d.x = d.x + d.speed * d.cos// moving data...
set d.y = d.y + d.speed * d.sin
if IsInMapXY(d.x,d.y) == true then// grenade in map
call SetUnitX(u,d.x)
call SetUnitY(u,d.y)// move the grenade
call SetUnitZ(u,d.baseH+GetParabolaZ(d.DistCur,d.DistMax,d.HeightMax))
// set unit Z
call MoveLocation(l,d.x,d.y)
if(R2I(GetUnitZ(u))==R2I(GetLocationZ(l)))then
// R2I because it gives me '0.001' and stuff ... so it isn't 'equal' unit height
set zhit=true
endif
// I dont think the dist current can go higher than the max... but just in case
if zhit==true then
if d.bounce==2 then
set COUNT = COUNT - 1
set GData[i] = GData[COUNT]// next instance
call d.Explode()
else
call d.NewBounce()// new bounce because of zhit
endif
else
set i = i + 1// just increase the value to the next instance
endif
else
set COUNT = COUNT - 1// change to next instance
set GData[i] = GData[COUNT]
call d.destroy()
endif
endloop
call RemoveLocation(l)
set u = null// leaks
set l = null
if COUNT == 0 then
call PauseTimer(TIMER)// pause
endif
endfunction
private function Run takes nothing returns nothing
local Data d = Data.create()
local location l = GetSpellTargetLoc()
local real x = GetLocationX(l)
local real y = GetLocationY(l)
local real dist = 0// locals for data
local real facing
call RemoveLocation(l)// do I need to 'set l = null' ?
set d.caster = GetTriggerUnit()
set l = GetUnitLoc(d.caster)
set d.baseH = GetLocationZ(l)
call RemoveLocation(l)
set l = null// leaks
set d.caster = GetTriggerUnit()
set d.p = GetOwningPlayer(d.caster)
set d.x = GetUnitX(d.caster)// caster data
set d.y = GetUnitY(d.caster)
set d.level = GetUnitAbilityLevel(d.caster,SPELL_ID)
set d.aoe = AOE_Range(d.level)
set d.bounce = 0
set x = x - d.x
set y = y - d.y
set facing = Atan2(y,x)
set d.cos = Cos(facing)
set d.sin = Sin(facing)// facing,,,
set d.Grenade = CreateUnit(d.p,GRENADE_ID,d.x,d.y,facing)
call UnitAddAbility(d.Grenade,'Amrf')// I have to do this or else it goes buggy over raised terrain
call UnitRemoveAbility(d.Grenade,'Amrf')
set d.DistMax = MinMax(SquareRoot(x*x+y*y)/Pow(BOUNCE_DECREASE,MAX_BOUNCES),0,MAX_RANGE)
set d.HeightMax = GetHeight(d.DistMax)// height, dist , speed data
set d.speed = GetSpeed(d.DistMax)
//MinMax(SquareRoot(x*x+y*y),MIN_RANGE,MAX_RANGE)
set d.DistCur = 0
set GData[COUNT] = d
set COUNT = COUNT + 1
if COUNT == 1 then
call TimerStart(TIMER,PERIOD,true,function Execute)
endif
endfunction
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call Run()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t,Condition(function Cond))
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
//
//
// To Implement the spell
//
//
// Copy the following : UNITS
//
// Explosion -> 'xdum'
// Explosion SFX -> 'xsfx''
// Grenade -> ' gdum''
//
//
//
// Copy the following : ABILITy
//
// Grenade -> 'BGid'
//
//
// Copy the following : Triggers
//
// Regrow Trees
// IsDestructableTree
// InitLibrary
//
//
// You can change many of the grenades features, such as :
//
// max height , max/min range , aoe range
// damage , wether it can hurt allied or player units
// max bounces , how far each bounce ... bounces
//
// I tried to make the formulas even as if they were a real grenade...
// slowing down , not bouncing as high , and traveling less distance