MasterOfRa
New Member
- Reaction score
- 10
I'm working on a projectile system for a game, and it works fine, but it is too laggy. I don't know what to do to optimize it.
edit: did minor updates,
The projectile Library handles the projectile dummies, and the collisions
(CJass used)
The Unit Library handles units, the collision part is important.
The Shield Library handles shields, bubbles that absorb projectiles that hit the outside.
The UnitDatabase Library handles unit types.
edit: did minor updates,
The projectile Library handles the projectile dummies, and the collisions
(CJass used)
JASS:
library Projectile initializer init uses Recycler
// uses Cjass
private group dummyPool // Used for recycling
private function NewDummy takes real x, real y returns unit
unit u = FirstOfGroup(dummyPool) // Get first of group
if u == null then
// if group was empty, create a new one
u = CreateUnit(Player(15), UID_DUMMY,x,y,0)
UnitAddAbility(u,AID_FLY) // Enable HeightChange
UnitRemoveAbility(u,AID_FLY)
UnitAddAbility(u,AID_LOCUST)
else
// otherwise, set location, and remove unit from group
SetUnitX(u,x)
SetUnitY(u,y)
GroupRemoveUnit(dummyPool, u)
ShowUnit(u,true)
UnitAddAbility(u,AID_LOCUST)
endif
return u
endfunction
private function ReleaseDummy takes unit u returns nothing
GroupAddUnit(dummyPool,u)
ShowUnit(u,false)
UnitRemoveAbility(u,AID_LOCUST)
// Add Dummy to Group
endfunction
struct Projectile
implement PAM_Property
//instance list
readonly static integer num = 0
readonly static Projectile array list
readonly integer listIndex
//unit
readonly unit u = null // The Dummy
readonly unit owner = null // The Dummy
readonly effect sfx = null // The Effect
readonly real dx = 0 // MomentumX
readonly real dy = 0 // MomentumY
readonly real dz = 0 // MomentumX
readonly real x = 0 // CurrentX
readonly real y = 0 // CurrentY
readonly real z = 0 // CurrentZ
readonly real radius= 0 // CollisionRadius
readonly real damage // Damage
readonly real aoe // area of effect
readonly Shield shieldHit
///Updates all Projectiles by one second
public static method CatchTick takes nothing returns nothing
integer i
Projectile t
//Apply Momentum
loopForIntBelow(i, Projectile.num)
t = Projectile.list<i>
t.ApplyMomentum()
if Projectile.list<i> != t then
i--
endif
endloop
integer z = Projectile.num
//Check Collision
loopForIntBelow(i, Projectile.num)
t = Projectile.list<i>
t.CheckCollision()
z--
if Projectile.list<i> != t then
i--
endif
endloop
endmethod
method CheckCollision takes nothing returns nothing
MoveLocation(TempLoc,.x,.y)
if .z - GetLocationZ(TempLoc) <= 0 then // Check for ground hit.
DestroyEffect(AddSpecialEffect(FID_lightninghit,.x,.y))
.destroy()
return
endif
unit u
Unit unitData
Shield shieldData = Shield.ProjectileCollision(this)
if shieldData != 0 then
.shieldHit = shieldData
DestroyEffect(AddSpecialEffect(FID_shieldhit,.x,.y))
.destroy()
return
endif
GroupEnumUnitsInRange(g,.x,.y,UnitEnumRange + ProjectileEnumRange,Filter_AliveUnit())
loop
u = FirstOfGroup(g)
exitwhen u == null
GroupRemoveUnit(g,u)
unitData = Unit<u>
if u != .owner then
if unitData != 0 then
if unitData.IsSphereIntersecting(.x,.y,.z,.radius)
DestroyEffect(AddSpecialEffect(FID_lightninghitkill,.x,.y))
.destroy()
return
endif
endif
endif
endloop
endmethod
method ApplyMomentum takes nothing returns nothing
.x+= .dx * PERIOD// offset Location
.y+= .dy * PERIOD//
.z+= .dz * PERIOD//
SetUnitX(.u,.x)// Move the unit
SetUnitY(.u,.y)
MoveLocation(TempLoc,.x,.y)
SetUnitFlyHeight(.u,.z - GetLocationZ(TempLoc),0) // Set Height
SetUnitFacing(.u,Atan2(.dy,.dx)*bj_RADTODEG) // Set facing
real dxy = SquareRoot(.dx*.dx+.dy*.dy)
integer angle = R2I(Atan2(dxy,.dz)*bj_RADTODEG)
if angle < 0 then
angle *= -1
endif
angle = 180 - angle
SetUnitAnimationByIndex(.u,angle+1) // Set AngleV
.dz -= GRAVITY*PERIOD
endmethod
///Creates a Projectile structure for a given unit
public static method create takes string SFX ,\ // Attached Effect
real scale ,\ // Size
real radius,\
real x ,\ // StartLocation
real y ,\
real z ,\
real dx ,\ // StartMomentum
real dy ,\
real dz ,\
real damage,\
real aoe ,\
unit owner \
returns thistype
Projectile this
macro_AllocCheck(this, Projectile)
.u = NewDummy(x,y) // Get a new dummy unit
SetUnitScale(.u,scale,scale,scale) // Set Size
.sfx = AddSpecialEffectTarget(SFX,.u,"origin") // Attach the Effect
.x = x // Set Stored Location
.y = y
.z = z
.dx = dx // Set Momentum
.dy = dy
.dz = dz
.radius = radius
.damage = damage
.aoe = aoe
.shieldHit = 0
.owner = owner
real offset = RMaxBJ(radius,aoe)
ProjectileEnumRange = RMaxBJ(ProjectileEnumRange,offset)
MoveLocation(TempLoc,x,y)
SetUnitFlyHeight(.u,z-GetLocationZ(TempLoc),0) // Set Height
SetUnitFacing(.u,Atan2(.dy,.dx)*bj_RADTODEG)
real dxy = SquareRoot(dx*dx+dy*dy)
integer angle = R2I(Atan2(dxy,dz)*bj_RADTODEG)
if angle < 0 then
angle *= -1
endif
SetUnitAnimationByIndex(.u,angle+1) // Set AngleV
.listIndex = Projectile.num
Projectile.list[Projectile.num] = this
Projectile.num += 1
Projectile[.u] = this
return this
endmethod
///Cleans up properly
private method onDestroy takes nothing returns nothing
assert(this != 0)
//Explode
unit u
Unit data
integer z
Shield s
ShieldArray shieldArray = shieldArray.create()
loopForIntBelow(z, Shield.num)
s = Shield.list[z]
SphereSphereInterection(s.x,s.y,s.z,s.size,.x,.y,.z,.aoe)
if TempBool_C and (s != .shieldHit) then
shieldArray.AddShield(s)
endif
if TempBool_B and TempBool_C and s != .shieldHit then
s.TakeDamage(.damage)
endif
endloop
if .shieldHit != 0 then
.shieldHit.TakeDamage(.damage)
endif
GroupEnumUnitsInRange(g,.x,.y,UnitEnumRange + ProjectileEnumRange,Filter_AliveUnit())
loop
u = FirstOfGroup(g)
exitwhen u == null
GroupRemoveUnit(g,u)
data = 0
data = Unit<u>
if data != 0 then
if u != .owner then
if data.IsSphereIntersecting(.x,\
.y,\
.z,\
.aoe)
data.UpdateShields()
data.shieldArray.Compair(shieldArray)
if TempInt_A == 0 then
data.TakeDamage(.u,.damage)
endif
endif
endif
endif
endloop
//remove from global array
Projectile.num -= 1
Projectile.list[Projectile.num].listIndex = .listIndex
Projectile.list[.listIndex] = Projectile.list[Projectile.num]
Projectile.list[Projectile.num] = 0
//destroy other stuff
Projectile.RemoveKey(.u)
DestroyEffect(.sfx)
schedule_unit(Action_unit.ReleaseDummy, 5, .u)
.sfx = null
.u = null
shieldArray.destroy()
endmethod
endstruct
private function init takes nothing returns nothing
TempLoc = Location(0.0,0.0) // Create the Temp Location
dummyPool = NewGroup() // Create the dummyPool
integer z = 0
loop
unit u = CreateUnit(Player(15), UID_DUMMY,0,0,0)
UnitAddAbility(u,AID_FLY) // Enable HeightChange
UnitRemoveAbility(u,AID_FLY)
UnitAddAbility(u,AID_LOCUST)
ReleaseDummy(u)
z++
exitwhen z > 35
endloop
u = null
TriggerSleepAction(.01)
timer t = CreateTimer()
TimerStart(t,PERIOD,true,function Projectile.CatchTick)
t = null
endfunction
endlibrary
</u></u></i></i></i></i>
The Unit Library handles units, the collision part is important.
JASS:
library Unit initializer init uses Recycler, Special, Constants
constant integer MAX_PROTECTING_SHIELDS = 25 // per array
constant integer MAX_ATTACKS = 5 // per unit
struct Unit
implement PAM_Property
//instance list
readonly static integer num = 0
readonly static Unit array list
readonly integer listIndex
//Collision
readonly integer CollisionType = 0
readonly real Radius = 0
readonly real SizeX = 0
readonly real SizeY = 0
readonly real SizeZ = 0
readonly real CollisionXOffset = 0
readonly real CollisionYOffset = 0
readonly real CollisionZOffset = 0
//Attacks
readonly real LanchAngleXY
readonly real LanchXY
readonly real LanchZ
readonly integer AttackNum
readonly Attack array Attacks[MAX_ATTACKS]
readonly real array LastAttack[MAX_ATTACKS]
//Shielding
readonly ShieldArray shieldArray
//unit
readonly unit u = null // The Unit
readonly UnitData data
readonly boolean air
readonly real lifeGenDelay = 0
readonly real baseLifeGen = 0
readonly real lastDamage = 0
readonly real manaGenDelay = 0
readonly real baseManaGen = 0
readonly real lastManaUsed = 0
method AddAttack takes Attack attack returns nothing
.Attacks[.AttackNum] = attack
.LastAttack[.AttackNum] = 0
.AttackNum++
endmethod
method RemoveAttack takes Attack attack returns nothing
integer z
loopForIntBelow(z, .AttackNum)
if .Attacks[z] == attack then
.Attacks[z] = .Attacks[.AttackNum]
.Attacks[.AttackNum] = 0
.AttackNum--
endif
endloop
endmethod
method InShield takes Shield s returns boolean
if s.active then
real x = GetUnitX(.u) + .CollisionXOffset
real y = GetUnitY(.u) + .CollisionYOffset
MoveLocation(TempLoc,x,y)
real dx = s.x - x
real dy = s.y - y
real dz = s.z - (GetLocationZ(TempLoc)+.CollisionZOffset)
real dxyz = ((dx*dx)+(dy*dy)+(dz*dz))
if (dxyz < (s.size * s.size)) then
return true
endif
endif
return false
endmethod
method TakeDamage takes unit u, real amount returns nothing
SetUnitState(.u,UNIT_STATE_LIFE, GetWidgetLife(.u) - amount)
set .lastDamage = TimerGetElapsed(GameTimer)
endmethod
method IsSphereIntersecting takes \
real x, \ // Xcoord of the projectiles sphere
real y, \ // Ycoord of the projectiles sphere
real z, \ // Zcoord of the projectiles sphere
real radius\ // Radius of the projectiles sphere
returns boolean // True if the objects overlap
// Get current angle of the unit
// Get current x,y,z of the unit.
real unitXCoord = GetUnitX(.u)
real unitYCoord = GetUnitY(.u)
MoveLocation(TempLoc,unitXCoord,unitYCoord)
real unitZCoord = GetLocationZ(TempLoc) + .CollisionZOffset
// Get distance between the two centers
real deltaX = x - unitXCoord
real deltaY = y - unitYCoord
real deltaZ = z - unitZCoord
real angle = Atan2(deltaY,deltaX)
unitXCoord += (.CollisionXOffset * Cos(angle))
unitYCoord += (.CollisionYOffset * Sin(angle))
deltaX = x - unitXCoord
deltaY = y - unitYCoord
real distanceBetweenPoints = 0.0
real maxDistanceBetweenPoints = 0.0
real deltaXy = 0.0
real ax = 0.0
real ay = 0.0
real az = 0.0
if .CollisionType == COLLISION_TYPE_SPHERE then
return SphereSphereInterection(x,y,z,radius,unitXCoord,unitYCoord,unitZCoord,.Radius)
elseif .CollisionType == COLLISION_TYPE_CYLINDER then
deltaXy = (deltaX * deltaX) + (deltaY * deltaY)
boolean inCircle = deltaXy <= (.Radius * .Radius)
if z > (unitZCoord + .SizeZ) then
az = unitZCoord + .SizeZ
elseif z < unitZCoord then
az = unitZCoord
else
az = z
endif
if inCircle then
ax = x
ay = y
else
ax = unitXCoord + (x * ((radius * radius) / deltaXy))
ay = unitYCoord + (y * ((radius * radius) / deltaXy))
endif
deltaX = x - ax
deltaY = y - ay
deltaZ = z - az
distanceBetweenPoints = ((deltaX * deltaX) + \
(deltaY * deltaY) + \
(deltaZ * deltaZ))
maxDistanceBetweenPoints = radius * radius
if distanceBetweenPoints <= (maxDistanceBetweenPoints) then
return true
else
return false
endif
elseif .CollisionType == COLLISION_TYPE_CUBE
deltaXy = SquareRoot((deltaX * deltaX) + (deltaY * deltaY))
x = unitXCoord + deltaXy * Cos(angle - GetUnitFacing(.u))
y = unitYCoord + deltaXy * Sin(angle - GetUnitFacing(.u))
if x > (unitXCoord + (.SizeX / 2)) then
ax = unitXCoord + (.SizeX / 2)
elseif x < (unitXCoord - (.SizeX / 2)) then
ax = unitXCoord - (.SizeX / 2)
else
ax = x
endif
if y > (unitYCoord + (.SizeY / 2)) then
ay = unitYCoord + (.SizeY / 2)
elseif y < (unitYCoord - (.SizeY / 2)) then
ay = unitYCoord - (.SizeY / 2)
else
ay = y
endif
if z > (unitZCoord + .SizeZ) then
az = unitZCoord + .SizeZ
elseif z < (unitZCoord) then
az = unitZCoord
else
az = z
endif
deltaX = x - ax
deltaY = y - ay
deltaZ = z - az
distanceBetweenPoints = ((deltaX * deltaX) + \
(deltaY * deltaY) + \
(deltaZ * deltaZ))
maxDistanceBetweenPoints = radius * radius
if distanceBetweenPoints <= (maxDistanceBetweenPoints) then
return true
else
return false
endif
endif
return false
endmethod
///Updates all Units by one second
public static method CatchTick takes nothing returns nothing
integer i
Unit t
loopForIntBelow(i, Unit.num)
t = Unit.list<i>
t.ApplyPeriodic()
endloop
loopForIntBelow(i, Unit.num)
t = Unit.list<i>
t.UpdateShields()
endloop
loopForIntBelow(i, Unit.num)
t = Unit.list<i>
t.Attack()
endloop
endmethod
method Attack takes nothing returns nothing
integer z
Attack a
Unit target = 0
loopForIntBelow(z, .AttackNum)
a = .Attacks[z]
if (.LastAttack[z] + a.cooldown) <= TimerGetElapsed(GameTimer) then
GroupEnumUnitsInSector(g,GetUnitX(.u),GetUnitY(.u),GetUnitFacing(.u)*bj_DEGTORAD,a.range,30*bj_DEGTORAD,Filter_AliveEnemyUnit(GetOwningPlayer(.u)))
target = Unit[FirstOfGroup(g)]
GroupClear(g)
if target != 0 then
if GetUnitState(.u,UNIT_STATE_MANA) >= a.manaCost then
SetUnitState(.u,UNIT_STATE_MANA,GetUnitState(.u,UNIT_STATE_MANA) - a.manaCost)
if a.manaCost > .5 then
.lastManaUsed = TimerGetElapsed(GameTimer)
endif
SetUnitAnimation(.u,"attack")
a.Attack(this,target)
.LastAttack[z] = TimerGetElapsed(GameTimer)
endif
endif
endif
endloop
endmethod
method UpdateShields takes nothing returns nothing
integer z
Shield s
loopForIntBelow(z, Shield.num)
s = Shield.list[z]
if .shieldArray.ContainsShield(s) then
if not .InShield(s) then
.shieldArray.RemoveShield(s)
endif
else
if .InShield(s) then
.shieldArray.AddShield(s)
endif
endif
endloop
endmethod
method ApplyPeriodic takes nothing returns nothing
real life
if (.lastDamage + .lifeGenDelay) <= TimerGetElapsed(GameTimer) then
life = GetWidgetLife(.u)
life += .baseLifeGen
SetUnitState(.u,UNIT_STATE_LIFE,life)
endif
if (.lastManaUsed + .manaGenDelay) <= TimerGetElapsed(GameTimer) then
life = GetUnitState(.u,UNIT_STATE_MANA)
life += .baseManaGen
SetUnitState(.u,UNIT_STATE_MANA,life)
endif
endmethod
///Creates a Unit structure for a given unit
public static method create takes unit u\
returns thistype
Unit this
macro_AllocCheck(this, Unit)
.shieldArray = ShieldArray.create()
.u = u
.data = UnitData[GetUnitTypeId(u)]
setUnitMaxLife(u,.data.life)
setUnitMaxMana(u,.data.mana)
.lifeGenDelay = .data.lifeGenDelay
.baseLifeGen = .data.lifeGen * PERIOD
.manaGenDelay = .data.manaGenDelay
.baseManaGen = .data.manaGen * PERIOD
.CollisionType = .data.CollisionType
.Radius = .data.Radius
.SizeX = .data.SizeX
.SizeY = .data.SizeY
.SizeZ = .data.SizeZ
.CollisionXOffset = .data.CollisionXOffset
.CollisionYOffset = .data.CollisionYOffset
.CollisionZOffset = .data.CollisionZOffset
.LanchAngleXY = .data.LanchAngleXY
.LanchXY = .data.LanchXY
.LanchZ = .data.LanchZ
loopForIntBelow(.AttackNum, .data.AttackNum)
.Attacks[.AttackNum] = .data.Attacks[.AttackNum]
.LastAttack[.AttackNum] = 0
endloop
.listIndex = Unit.num
Unit.list[Unit.num] = this
Unit.num += 1
Unit[.u] = this
return this
endmethod
///Cleans up properly
private method onDestroy takes nothing returns nothing
assert(this != 0)
.shieldArray.destroy()
//remove from global array
Unit.num -= 1
Unit.list[Unit.num].listIndex = .listIndex
Unit.list[.listIndex] = Unit.list[Unit.num]
Unit.list[Unit.num] = 0
//destroy other stuff
Unit.RemoveKey(.u)
.u = null
endmethod
endstruct
private function CatchDeath takes nothing returns nothing
Unit t = Unit[GetTriggerUnit()]
if t != 0 then; t.destroy(); endif
endfunction
private function init takes nothing returns nothing
TriggerSleepAction(.01)
timer t = CreateTimer()
TimerStart(t,PERIOD,true,function Unit.CatchTick)
macro_AddUnitEventHandler(EVENT_PLAYER_UNIT_DEATH, function CatchDeath)
TriggerSleepAction(2)
unit u
Unit.create(CreateUnit(Player(0),UID_RIFLEMAN , -350, 175,90))
Unit.create(CreateUnit(Player(0),UID_SIEGE_ENGINE, -175, 350,90))
Unit.create(CreateUnit(Player(0),UID_SORCERESS , -350, 350,90))
Unit.create(CreateUnit(Player(1),UID_RIFLEMAN , -350, -175,90))
Unit.create(CreateUnit(Player(1),UID_SIEGE_ENGINE, -175, -350,90))
Unit.create(CreateUnit(Player(1),UID_SORCERESS , -350, -350,90))
Unit.create(CreateUnit(Player(2),UID_RIFLEMAN , 350, 175,90))
Unit.create(CreateUnit(Player(2),UID_SIEGE_ENGINE, 175, 350,90))
Unit.create(CreateUnit(Player(2),UID_SORCERESS , 350, 350,90))
Unit.create(CreateUnit(Player(3),UID_RIFLEMAN , 350, -175,90))
Unit.create(CreateUnit(Player(3),UID_SIEGE_ENGINE, 175, -350,90))
Unit.create(CreateUnit(Player(3),UID_SORCERESS , 350, -350,90))
Unit.create(CreateUnit(Player(4),UID_SORCERESS, -1024,-1024,90))
Unit.create(CreateUnit(Player(4),UID_SORCERESS, -1024, 1024,90))
Unit.create(CreateUnit(Player(4),UID_SORCERESS, 1024,-1024,90))
Unit.create(CreateUnit(Player(4),UID_SORCERESS, 1024, 1024,90))
u = CreateUnit(Player(4),UID_SORCERESS, -1536, 0,90)
Unit.create(u)
u = CreateUnit(Player(4),UID_SORCERESS, -1536, 128,90)
Unit.create(u)
u = CreateUnit(Player(4),UID_SORCERESS, -1536, -128,90)
Unit.create(u)
//Shield.create(Player(4),u,-1536,0,GetLocationZ(TempLoc) + 0,100,100,0,2,25)
u = CreateUnit(Player(4),UID_SORCERESS, 1536, 0,90)
Unit.create(u)
u = CreateUnit(Player(4),UID_SORCERESS, 1536, 128,90)
Unit.create(u)
u = CreateUnit(Player(4),UID_SORCERESS, 1536, -128,90)
Unit.create(u)
//Shield.create(Player(4),u, 1536,0,GetLocationZ(TempLoc) + 0,100,100,0,2,25)
u = CreateUnit(Player(4),UID_SORCERESS, 0,-1536,90)
Unit.create(u)
u = CreateUnit(Player(4),UID_SORCERESS, 128,-1536,90)
Unit.create(u)
u = CreateUnit(Player(4),UID_SORCERESS, -128,-1536,90)
Unit.create(u)
//Shield.create(Player(4),u,0,-1536,GetLocationZ(TempLoc) + 0,100,100,0,2,25)
u = CreateUnit(Player(4),UID_SORCERESS, 0, 1536,90)
Unit.create(u)
u = CreateUnit(Player(4),UID_SORCERESS, 128, 1536,90)
Unit.create(u)
u = CreateUnit(Player(4),UID_SORCERESS, -128, 1536,90)
Unit.create(u)
//Shield.create(Player(4),u,0, 1536,GetLocationZ(TempLoc) + 0,100,100,0,2,25)
u = null
endfunction
endlibrary
</i></i></i>
The Shield Library handles shields, bubbles that absorb projectiles that hit the outside.
JASS:
library Shields initializer init uses Recycler
private group dummyPool // Used for recycling
private function NewDummy takes real x, real y, real z, real size, player owner returns unit
local unit u = FirstOfGroup(dummyPool) // Get first of group
if u == null then
// if group was empty, create a new one
u = CreateUnit(owner, UID_SHIELD,x,y,0)
SetUnitX(u,x)
SetUnitY(u,y)
call UnitAddAbility(u,AID_FLY) // Enable HeightChange
call UnitRemoveAbility(u,AID_FLY)
else
// otherwise, set location, and remove unit from group
SetUnitOwner(u,owner,true)
SetUnitX(u,x)
SetUnitY(u,y)
GroupRemoveUnit(dummyPool, u)
ShowUnit(u,true)
endif
UnitAddAbility(u,AID_LOCUST)
MoveLocation(TempLoc,x,y)
SetUnitFlyHeight(u,z-GetLocationZ(TempLoc),0)
SetUnitScale(u,size,size,size)
UnitAddAbility(u,AID_LOCUST)
return u
endfunction
private function ReleaseDummy takes unit u returns nothing
GroupAddUnit(dummyPool,u)
ShowUnit(u,false)
UnitRemoveAbility(u,AID_LOCUST)
// Add Dummy to Group
endfunction
struct Shield
implement PAM_Property
//instance list
readonly static integer num = 0
readonly static Shield array list
readonly integer listIndex
readonly unit Dummy = null // The shield
readonly unit Generator = null // The shield Generator
readonly boolean active = false
readonly real lifeGenDelay = 0
readonly real lifeGen = 0
readonly real lastDamage = 0
readonly real life = 0
readonly real lifeMax = 0
readonly real size = 0 // The Shields radius
readonly real x = 0 // Where the shield is
readonly real y = 0 //
readonly real z = 0 //
readonly real xOffset = 0 // from the Generator
readonly real yOffset = 0 //
readonly real zOffset = 0 //
readonly real sizeThreshhold = 0 // A factor in Operating Costs
readonly real sizeMult = 0 // A factor in Operating Costs
readonly real regenCost = 0 // The cost of regenerating life from 0 to max
method TakeDamage takes real amount returns nothing
.life -= amount
set .lastDamage = TimerGetElapsed(GameTimer)
if .life <= 0 then
.Deactivate()
endif
SetUnitVertexColor(.Dummy,255,255,255,R2I(.life/.lifeMax * 255))
endmethod
method Deactivate takes nothing returns nothing
.active = false
ShowUnit(.Dummy,false)
UnitRemoveAbility(.Dummy,AID_LOCUST)
endmethod
method Activate takes nothing returns nothing
.active = true
ShowUnit(.Dummy,true)
UnitAddAbility(.Dummy,AID_LOCUST)
endmethod
public static method CatchTick takes nothing returns nothing
integer i
Shield t
loopForIntBelow(i, Shield.num)
t = Shield.list<i>
t.ApplyPeriodic()
endloop
endmethod
method ApplyPeriodic takes nothing returns nothing
if .Generator != null then
if GetWidgetLife(.Generator) <= 4.05 then
.life -= (.lifeMax * PERIOD / 10)
if .life <= 0 then
.destroy()
endif
endif
.x = GetUnitX(.Generator) + .xOffset
.y = GetUnitY(.Generator) + .yOffset
MoveLocation(TempLoc,GetUnitX(.Generator),GetUnitY(.Generator))
.z = GetLocationZ(TempLoc) + .zOffset
SetUnitX(.Dummy,.x)
SetUnitY(.Dummy,.y)
SetUnitFlyHeight(.Dummy,.z,2)
Projectile t
integer x
integer z = Projectile.num
//Check Collision
loopForIntBelow(x, Projectile.num)
t = Projectile.list[x]
t.CheckCollision()
z--
if Projectile.list[x] != t then
x--
endif
endloop
endif
if (.lastDamage + .lifeGenDelay) <= TimerGetElapsed(GameTimer) then
if .active then
.life += (.lifeGen * PERIOD)
else
.life += (.lifeGen * PERIOD * 10)
endif
endif
.life = RMinBJ(.life,.lifeMax)
if not .active and .life == .lifeMax then
.Activate()
endif
SetUnitVertexColor(.Dummy,255,255,255,R2I(.life/.lifeMax * 255))
// This regen is free, but later charge .sizeMult * life / 1000 energy or somthing like that
endmethod
private method ProjectileCollisionChild takes Projectile data returns boolean
boolean intersects = SphereSphereInterection(.x,.y,.z,.size,data.x,data.y,data.z,data.radius)
boolean touchesShell = TempBool_A
boolean willIntersect = SphereSphereInterection(.x,.y,.z,.size,data.x + (data.dx * PERIOD),\
data.y + (data.dy * PERIOD),\
data.z + (data.dz * PERIOD),\
data.radius)
boolean willTouchShell = TempBool_A
if willIntersect and not intersects then
return true
endif
return false
endmethod
static method ProjectileCollision takes Projectile data returns Projectile
integer i
Shield t
loopForIntBelow(i, Shield.num)
t = Shield.list<i>
if t.active then
if t.ProjectileCollisionChild(data) then
return t
endif
endif
endloop
return 0
endmethod
///Creates a Projectile structure for a given unit
public static method create takes player owner ,\
unit generator ,\
real x ,\
real y ,\
real z ,\
real sizeThreshhold,\
real size ,\
real lifeGenDelay ,\
real lifeGen ,\
real life \
returns thistype
Shield this
macro_AllocCheck(this, Shield)
.Dummy = NewDummy(x,y,z,size/SHIELD_SIZE,owner)
.Generator = generator
.active = true
.x = x
.y = y
.z = z
if generator != null then
.xOffset = x - GetUnitX(generator)
.yOffset = y - GetUnitY(generator)
MoveLocation(TempLoc,GetUnitX(generator),GetUnitX(generator))
.zOffset = z - GetLocationZ(TempLoc)
else
.xOffset = 0
.yOffset = 0
.zOffset = 0
endif
.size = size
.lifeGenDelay = lifeGenDelay
.lifeGen = lifeGen
.lifeMax = life
.life = life
.sizeThreshhold = sizeThreshhold
.sizeMult = size/sizeThreshhold
ShieldEnumRange = RMaxBJ(ShieldEnumRange,size)
if .sizeMult > 1 then
.sizeMult *= .sizeMult
endif
.regenCost = .sizeMult * life / 10
.listIndex = Shield.num
Shield.list[Shield.num] = this
Shield.num += 1
Shield[.Dummy] = this
return this
endmethod
///Cleans up properly
private method onDestroy takes nothing returns nothing
assert(this != 0)
//remove from global array
Shield.num -= 1
Shield.list[Shield.num].listIndex = .listIndex
Shield.list[.listIndex] = Shield.list[Shield.num]
Shield.list[Shield.num] = 0
//destroy other stuff
Shield.RemoveKey(.Dummy)
endmethod
endstruct
struct ShieldArray
readonly integer ShieldCount = 0
readonly Shield array Shields[MAX_PROTECTING_SHIELDS]
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
method onDestroy takes nothing returns nothing
loop
exitwhen .ShieldCount == 0
.Shields[.ShieldCount] = 0
.ShieldCount--
endloop
endmethod
method AddShield takes Shield s returns nothing
.Shields[.ShieldCount] = s
.ShieldCount++
endmethod
method RemoveShield takes Shield s returns nothing
integer z = 0
loop
if .Shields[z] == s then
.ShieldCount--
.Shields[z] = .Shields[.ShieldCount]
.Shields[.ShieldCount] = 0
endif
exitwhen z >= .ShieldCount
z++
endloop
endmethod
method ContainsShield takes Shield s returns boolean
integer z = 0
loop
if .Shields[z] == s then
return true
endif
exitwhen z >= .ShieldCount
z++
endloop
return false
endmethod
method Compair takes ShieldArray that returns nothing
integer x = 0
integer y = 0
boolean array thisMatched
boolean array thatMatched
loop
exitwhen x >= .ShieldCount
thisMatched[x] = false
x++
endloop
loop
exitwhen y >= that.ShieldCount
thatMatched[y] = false
y++
endloop
x = 0
y = 0
loop
exitwhen x >= .ShieldCount
y = 0
loop
exitwhen y >= that.ShieldCount
if .Shields[x] == that.Shields[y] then
thisMatched[x] = true
thatMatched[y] = true
endif
y++
endloop
x++
endloop
x = 0
TempInt_A = 0 // how many of this's shields had no match
y = 0
TempInt_B = 0 // how many of that's shields had no match
loop
exitwhen x >= .ShieldCount
if not thisMatched[x] then
TempInt_A++
endif
x++
endloop
loop
exitwhen y >= that.ShieldCount
if not thatMatched[y] then
TempInt_B++
endif
y++
endloop
endmethod
endstruct
private function init takes nothing returns nothing
dummyPool = CreateGroup()
TriggerSleepAction(.01)
timer t = CreateTimer()
TimerStart(t,PERIOD,true, function Shield.CatchTick)
MoveLocation(TempLoc,0,0)
unit u = CreateUnit(Player(0),UID_SHIELD_GENERATOR , 0, 0,270)
Unit.create(u)
Shield.create(Player(0),u,0,0,GetLocationZ(TempLoc) + 0,500,400,5,2,100)
u = null
endfunction
endlibrary
</i></i>
The UnitDatabase Library handles unit types.
JASS:
library UnitDatabase uses General, PAM
struct UnitData
implement PAM_RawProperty
integer tintRed = 255
integer tintBlue = 255
integer tintGreen = 255
// Unit
readonly integer unitId
readonly integer life
readonly integer mana
readonly real lifeGenDelay
readonly real lifeGen
readonly real manaGenDelay
readonly real manaGen
// Collision
readonly integer CollisionType
readonly real Radius
readonly real SizeX
readonly real SizeY
readonly real SizeZ
readonly real CollisionXOffset
readonly real CollisionYOffset
readonly real CollisionZOffset
// Attack
readonly real LanchAngleXY
readonly real LanchXY
readonly real LanchZ
readonly integer AttackNum = 0
readonly Attack array Attacks[MAX_ATTACKS]
method AddAttack takes Attack attack returns nothing
.Attacks[.AttackNum] = attack
.AttackNum++
endmethod
public static method create takes integer unitId ,\
integer life ,\
integer mana ,\
real lifeGenDelay ,\
real lifeGen ,\
real manaGenDelay ,\
real manaGen ,\
integer CollisionType,\
real Radius ,\
real SizeX ,\
real SizeY ,\
real SizeZ ,\
real CollisionXOffset,\
real CollisionYOffset,\
real CollisionZOffset,\
real LanchX ,\
real LanchY ,\
real LanchZ \
returns thistype
assert(unitId != 0)
UnitData this
macro_AllocCheck(this, UnitData)
.unitId = unitId
.life = life
.mana = mana
.lifeGenDelay = lifeGenDelay
.lifeGen = lifeGen
.manaGenDelay = manaGenDelay
.manaGen = manaGen
.CollisionType = CollisionType
.Radius = Radius
.SizeX = SizeX
.SizeY = SizeY
.SizeZ = SizeZ
.CollisionXOffset = CollisionXOffset
.CollisionYOffset = CollisionYOffset
.CollisionZOffset = CollisionZOffset
.LanchAngleXY = Atan2(LanchY,LanchX)
.LanchXY = SquareRoot((LanchX * LanchX) + (LanchY * LanchY))
.LanchZ = LanchZ
real offset
if Radius > 0 then
offset = Radius
offset += SquareRoot((CollisionXOffset * CollisionXOffset) + (CollisionYOffset * CollisionYOffset))
UnitEnumRange = RMaxBJ(UnitEnumRange,offset)
endif
if SizeX > 0 or SizeY > 0 then
real dx = SizeX + CollisionXOffset
real dy = SizeY + CollisionYOffset
offset = SquareRoot((dx + dx) + (dy + dy))
UnitEnumRange = RMaxBJ(UnitEnumRange,offset)
endif
UnitData[unitId] = this
return this
endmethod
private method onDestroy takes nothing returns nothing
assert(this != 0)
UnitData[.unitId] = 0
endmethod
endstruct
endlibrary