library EntityCore initializer Init uses VectorSystem
globals
private constant timer t = CreateTimer()
private constant real interval = 0.04
private real slowmo = 1
private constant real m = 64. //How many wc3 units there are in one meter
private constant real grav = ((9.80665*m)/((1/interval)*(1/interval)))
private constant integer dummyID = 'h000'
private constant real THRESHOLDS = 40.
private constant real COLL_ALGO_SPD = 400.
private real maxx
private real maxy
private real minx
private real miny
private entity array Entity
private integer Total = 0
endglobals
struct entity
unit u
effect model
real mass
real coll
real restitution
real friction
vector v
boolean wantDestroy
boolean canBounce
boolean resting
static method create takes player p, string mdl, real mass, real coll, real x, real y, real z, real a, real restitution, real friction, boolean canBounce returns entity
local entity e = entity.allocate()
local location l = Location(x, y)
set e.u = CreateUnit(p, dummyID, x, y, a * bj_RADTODEG)
set e.model = AddSpecialEffectTarget(mdl, e.u, "origin")
set e.mass = mass
set e.coll = coll
set e.v = vector.create(x, y, z + GetLocationZ(l))
set e.restitution = restitution
set e.friction = friction
set e.wantDestroy = false
set e.canBounce = canBounce
set e.resting = false
call SetUnitAnimationByIndex(e.u, 1)
call SetUnitLookAt(e.u, "bone_Head", e.u, 0., 20., 0.)
call UnitAddAbility(e.u, 'Amrf')
call UnitRemoveAbility(e.u, 'Amrf')
call SetUnitFlyHeight(e.u, z, 0.)
call RemoveLocation(l)
set Total = Total + 1
set Entity[Total] = e
if Total == 1 then
call TimerStart(t, interval, true, function entity.Loop)
endif
set l = null
return e
endmethod
static method Loop takes nothing returns nothing
local integer i = 1
local entity e
local location l = Location(0., 0.)
local real lz
local real s
local vector v
local integer i2
local entity e2
local group g
local real vx
local real vy
local real vz
local real px
local real py
local real pz
local real s2
local real r
local real r2
if Total == 0 then
call PauseTimer(t)
return
endif
loop
exitwhen i > Total
set e = Entity[i]
//Updates the entity's position and it's z velocity and moves the entity based on it's speed
set e.v.x = e.v.x + (e.v.xvel/slowmo)
set e.v.y = e.v.y + (e.v.yvel/slowmo)
set e.v.z = e.v.z + (e.v.zvel/slowmo)
set e.v.zvel = e.v.zvel - ((e.mass * grav)/slowmo)
call MoveLocation(l, e.v.x, e.v.y)
set lz = GetLocationZ(l)
set e.v.z = e.v.z - lz
call SetUnitX(e.u, e.v.x)
call SetUnitY(e.u, e.v.y)
call SetUnitFlyHeight(e.u, e.v.z, 0.)
call SetUnitAnimationByIndex(e.u, 1)
//call SetUnitLookAt(e.u, "bone_Head", e.u, e.v.xvel, e.v.yvel, e.v.zvel)
call SetUnitLookAt(e.u, "bone_Head", e.u, 0., 20., 0.)
set e.v.z = e.v.z + lz
set s = SquareRoot(e.v.xvel*e.v.xvel + e.v.yvel*e.v.yvel + e.v.zvel*e.v.zvel)
//Checks if the entity is within map bounds
if e.v.x > maxx or e.v.x < minx or e.v.y > maxy or e.v.y < miny then
//set e.wantDestroy = true
if e.v.x > maxx or e.v.x < minx then
set e.v.xvel = e.v.xvel*-1
elseif e.v.y > maxy or e.v.y < miny then
set e.v.yvel = e.v.yvel*-1
endif
endif
//Checking for collision with the ground
if e.v.z - e.coll > lz then
//Entity did not touch the surface
else
//Entity is touching the surface. Make it bounce
set v = vector.GetBounceVector(e.v.x, e.v.y, e.v.xvel, e.v.yvel, e.v.zvel, e.restitution)
set e.v.xvel = v.xvel
set e.v.yvel = v.yvel
set e.v.zvel = v.zvel
set e.v.z = lz + e.coll
if (e.v.zvel*e.v.zvel)/2. <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
set e.v.xvel = e.v.xvel*(1-(e.friction/slowmo))
set e.v.yvel = e.v.yvel*(1-(e.friction/slowmo))
set e.v.zvel = 0.
endif
if e.v.xvel*e.v.xvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
set e.v.xvel = 0.
elseif e.v.yvel*e.v.yvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
set e.v.yvel = 0.
endif
call v.destroy()
endif
//Checking for collision between entities
set i2 = 1
loop
exitwhen i2 > Total
set e2 = Entity[i2]
if e2 != e then
set vx = e.v.xvel - e2.v.xvel
set vy = e.v.yvel - e2.v.yvel
set vz = e.v.zvel - e2.v.zvel
set r2 = vx*vx + vy*vy + vz*vz
if r2 >= (COLL_ALGO_SPD*COLL_ALGO_SPD)/((1/interval)*(1/interval)) then
// If the relative velocity is larger than the collision separator, advanced collision detection is executed
// The following collision detection was established using the equation: |deltaP + t*deltaV| <= r1 + r2
// Note that at this point, variable names most likely have nothing to do with what they hold
set px = e.v.x - e2.v.x
set py = e.v.y - e2.v.y
set pz = e.v.z - e2.v.z
set s = px*vx + py*vy + pz*vz
set r = px*px + py*py + pz*pz
set vx = e.coll + e2.coll
set vy = s*s - r2*(r - vx*vx)
if vy >= 0. then
set vy = (-s - SquareRoot(vy))/r2
if vy > 0. and vy <= 1. then
// --
// The following prepares collision resolution while moving entities to their touching position
set e2.v.x = e2.v.x + e2.v.xvel*vy
set e2.v.y = e2.v.y + e2.v.yvel*vy
set e2.v.z = e2.v.z + e2.v.zvel*vy
set e.v.x = e.v.x + e.v.xvel*vy
set e.v.y = e.v.y + e.v.yvel*vy
set e.v.z = e.v.z + e.v.zvel*vy
// --
// --
// The following is code for collision resolution
set s = s*(1. + e2.restitution*e.restitution)/(r*(e2.mass + e.mass) + 0.001)
if e2.canBounce then
set vx = s*e.mass
set e2.v.xvel = e2.v.xvel + px*vx
set e2.v.yvel = e2.v.yvel + py*vx
set e2.v.zvel = e2.v.zvel + pz*vx
if e2.v.xvel*e2.v.xvel + e2.v.yvel*e2.v.yvel + e2.v.zvel*e2.v.zvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
// If the entity moves slower than the threshold velocity, set the velocity to 0
set e2.v.xvel = 0.
set e2.v.yvel = 0.
set e2.v.zvel = 0.
else
//set e2.resting = false
endif
endif
if e.canBounce then
set vx = s*e2.mass
set e.v.xvel = e.v.xvel - px*vx
set e.v.yvel = e.v.yvel - py*vx
set e.v.zvel = e.v.zvel - pz*vx
if e.v.xvel*e.v.xvel + e.v.yvel*e.v.yvel + e.v.zvel*e.v.zvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
// If the entity moves slower than the threshold velocity, set the velocity to 0
set e.v.xvel = 0.
set e.v.yvel = 0.
set e.v.zvel = 0.
else
//set e.resting = false
endif
endif
elseif vy < 0.0 and r < vx*vx then
set vz = (vx/(SquareRoot(r) + 0.001) - 1.0)/(e2.mass + e.mass + 0.001)
set vy = e.mass*vz
if r*vy*vy > 0.01/((1/interval)*(1/interval)) then
set e2.v.x = e2.v.x - vy*px
set e2.v.x = e2.v.x - vy*py
set e2.v.x = e2.v.x - vy*pz
//set e2.resting = false
endif
set vy = e2.mass*vz
if r*vy*vy > 0.01/((1/interval)*(1/interval)) then
set e.v.x = e.v.x + vy*px
set e.v.x = e.v.x + vy*py
set e.v.x = e.v.x + vy*pz
//set e.resting = false
endif
endif
endif
else
set px = e.v.x - e2.v.x
set py = e.v.y - e2.v.y
set pz = e.v.z - e2.v.z
set r = px*px + py*py + pz*pz
set r2 = e.coll + e2.coll
if r < r2*r2 then
// If the relative velocity is smaller than the collision separator;
// and if two entities are currently colliding, simple collision script is executed
// --
// The following code moves entities apart from eachother based on their mass and the distance between them
set s2 = (px*vx + py*vy + pz*vz)*(1. + e2.restitution*e.restitution)/(r*(e2.mass + e.mass) + 0.001)
set vz = (r2/(SquareRoot(r) + 0.001) - 1.)/(e2.mass + e.mass + 0.001)
set vy = e2.mass*vz
if r*vy*vy > 0.01/((1/interval)*(1/interval)) then
set e.v.x = e.v.x + vy*px
set e.v.y = e.v.y + vy*py
set e.v.z = e.v.z + vy*pz
//set e.resting = false
endif
set vy = e.mass*vz
if r*vy*vy > 0.01/((1/interval)*(1/interval)) then
set e2.v.x = e2.v.x - vy*px
set e2.v.y = e2.v.y - vy*py
set e2.v.z = e2.v.z - vy*pz
//set e2.resting = false
endif
// --
// The following is code for collision resolution
if e2.canBounce then
set vx = s*e.mass
set e2.v.xvel = e2.v.xvel + px*vx
set e2.v.yvel = e2.v.yvel + py*vx
set e2.v.zvel = e2.v.zvel + pz*vx
if e2.v.xvel*e2.v.xvel + e2.v.yvel*e2.v.yvel + e2.v.zvel*e2.v.zvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
// If the entity moves slower than the threshold velocity, set the velocity to 0
set e2.v.xvel = 0.
set e2.v.yvel = 0.
set e2.v.zvel = 0.
else
//set e2.resting = false
endif
endif
if e.canBounce then
set vx = s*e2.mass
set e.v.xvel = e.v.xvel - px*vx
set e.v.yvel = e.v.yvel - py*vx
set e.v.zvel = e.v.zvel - pz*vx
if e.v.xvel*e.v.xvel + e.v.yvel*e.v.yvel + e.v.zvel*e.v.zvel <= THRESHOLDS*THRESHOLDS/((1/interval)*(1/interval)) then
// If the entity moves slower than the threshold velocity, set the velocity to 0
set e.v.xvel = 0.
set e.v.yvel = 0.
set e.v.zvel = 0.
else
//set e.resting = false
endif
endif
endif
endif
endif
set i2 = i2 + 1
endloop
//Destroying entities marked for destruction
if e.wantDestroy then
set Entity[i] = Entity[Total]
set Total = Total - 1
set i = i - 1
call e.destroy()
endif
set i = i + 1
endloop
call RemoveLocation(l)
endmethod
method onDestroy takes nothing returns nothing
call RemoveUnit(.u)
call DestroyEffect(.model)
call .v.destroy()
set .u = null
set .model = null
endmethod
endstruct
private function Init takes nothing returns nothing
call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 0., 0., 500., 0., 0.4, 0.3, true)
call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., -100., 0., 500., 0., 0.4, 0.3, true)
call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 0., -100., 500., 0., 0.4, 0.3, true)
call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 100., 0., 500., 0., 0.4, 0.3, true)
call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 0., 100., 500., 0., 0.4, 0.3, true)
call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., -100., 100., 500., 0., 0.4, 0.3, true)
call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 100., 100., 500., 0., 0.4, 0.3, true)
call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., 100., -100., 500., 0., 0.4, 0.3, true)
call entity.create(Player(0), "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 2, 40., -100., -100., 500., 0., 0.4, 0.3, true)
set maxx = GetRectMaxX(bj_mapInitialPlayableArea)
set maxy = GetRectMaxY(bj_mapInitialPlayableArea)
set minx = GetRectMinX(bj_mapInitialPlayableArea)
set miny = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
endlibrary