-
Are you planning to upload your awesome spell or system to Hive? Please review the rules here.Dismiss Notice
-
Find your way through the deepest dungeon in the 18th Mini Mapping Contest Poll.Dismiss Notice
-
A brave new world lies beyond the seven seas. Join the 34th Modeling Contest today!Dismiss Notice
-
Check out the Staff job openings thread.Dismiss Notice
Dismiss Notice
Hive 3 Remoosed BETA - NOW LIVE. Go check it out at BETA Hive Workshop! Post your feedback in this new forum BETA Feedback.
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.
Spiraling Trails
Submitted by
Aniki
Spiraling Trails - casts magical stars that leave spiraling trails
scope SpiralingTrails initializer init
globals
private constant integer ABILITY_ID = 'A000'
private constant integer DUMMY_ID = 'e000'
private constant string DUMMY_MODEL = "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdx"
private constant real DT = 1.0 / 32.0
private constant real Z_OFFSET = 80.0
// the target point is considered reached if we are this many units away from it
private constant real TARGET_DISTANCE_THRESHOLD = 16.0
// if we are this many or less units from the terrain we stop
private constant real TERRAIN_DISTANCE_THRESHOLD = 16.0
// UnitDamageTarget arguments
private constant boolean MELEE_ATTACK = false
private constant boolean RANGE_ATTACK = true
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL // spell
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_UNIVERSAL // ignore armor value
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
endglobals
private function unit_filter takes unit u returns boolean
// e.g: return false if the unit is invulnerable
return true
endfunction
private function linear_speed takes integer level returns real
return 500.0
endfunction
private function distance takes integer level returns real
return 900.0
endfunction
private function dummy_scale takes integer level returns real
return 0.5 + 0.5 * level
endfunction
private function spiral_radius takes integer level returns real
return 64.0
endfunction
private function damage takes integer level returns real
return 100.0 * level
endfunction
// NOTE: you can rewrite these functions to use your dummy recycling scripts!
globals
private unit created_dummy
endglobals
private function dummy_create takes player p returns unit
set created_dummy = CreateUnit(p, DUMMY_ID, 0.0, 0.0, 270.0)
call UnitAddAbility(created_dummy, 'Amrf')
call UnitRemoveAbility(created_dummy, 'Amrf')
call UnitAddAbility(created_dummy, 'Aloc')
call UnitRemoveAbility(created_dummy, 'Aloc')
return created_dummy
endfunction
private function dummy_destroy takes unit u returns nothing
call RemoveUnit(u)
endfunction
globals
private location loc = Location(0.0, 0.0)
endglobals
private function GetTerrainZ takes real x, real y returns real
call MoveLocation(loc, x, y)
return GetLocationZ(loc)
endfunction
private function GetUnitZ takes unit u returns real
call MoveLocation(loc, GetUnitX(u), GetUnitY(u))
return GetLocationZ(loc) + GetUnitFlyHeight(u)
endfunction
private function SetUnitZ takes unit u, real z returns nothing
call MoveLocation(loc, GetUnitX(u), GetUnitY(u))
call SetUnitFlyHeight(u, z - GetLocationZ(loc), 0.0)
endfunction
native UnitAlive takes unit u returns boolean
globals
private constant real TADT_POW_2 = TARGET_DISTANCE_THRESHOLD * TARGET_DISTANCE_THRESHOLD
private constant real TEDT = TERRAIN_DISTANCE_THRESHOLD
private real dx
private real dy
private real dz
private real v_len
private real ax
private real ay
private real az
private group G = CreateGroup()
private unit U
endglobals
private struct SpiralingTrail
static timer tmr = CreateTimer()
static thistype array update_list
static integer update_count = 0
player caster_owner
unit caster
unit dummy
effect dummy_model
real dummy_scale
real damage
// current position
real px
real py
real pz
// linear velocity
real dpx
real dpy
real dpz
// target point
real tx
real ty
real tz
real bvx_x
real bvx_y
real bvx_z
real bvy_x
real bvy_y
real bvy_z
real bvz_x
real bvz_y
real bvz_z
real spiral_radius
real ang_xy
real ang_xz
real ang_xz_inc
real x
real y
real z
static method create takes unit caster, string dummy_model, real px, real py, real pz, real tx, real ty, real tz, real ang_xz_initial, integer inc_sign, real speed, real scale, real p_spiral_radius, real p_damage returns thistype
local thistype this = allocate()
local real ang
local real y_axis_deg
local real bvz_ang_xy
local real bvz_ang_xz
set this.caster_owner = GetOwningPlayer(caster)
set this.caster = caster
set this.dummy = dummy_create(this.caster_owner)
set this.dummy_model = AddSpecialEffectTarget(dummy_model, this.dummy, "origin")
set this.dummy_scale = scale
call SetUnitScale(this.dummy, scale, scale, scale)
set this.damage = p_damage
set this.px = px
set this.py = py
set this.pz = pz
set this.tx = tx
set this.ty = ty
set this.tz = tz
set dx = this.tx - this.px
set dy = this.ty - this.py
set dz = this.tz - this.pz
set v_len = SquareRoot(dx * dx + dy * dy + dz * dz)
set dx = dx / v_len
set dy = dy / v_len
set dz = dz / v_len
set this.dpx = dx * speed * DT
set this.dpy = dy * speed * DT
set this.dpz = dz * speed * DT
set ang = 2.0 * bj_PI - Atan2(dy, dx)
set bvx_x = Cos(ang - bj_PI / 2.0)
set bvx_y = Sin(ang - bj_PI / 2.0)
set bvx_z = 0.0
set bvy_x = Cos(ang)
set bvy_y = Sin(ang)
set bvy_z = 0.0
set bvz_x = 0.0
set bvz_y = 0.0
set bvz_z = 1.0
set this.ang_xy = 0.0
set this.ang_xz = ang_xz_initial
set this.spiral_radius = p_spiral_radius
set this.ang_xz_inc = inc_sign * 2.0 * bj_PI / 15.0
call SetUnitX(this.dummy, this.px)
call SetUnitY(this.dummy, this.py)
call SetUnitZ(this.dummy, this.pz)
call SetUnitFacing(this.dummy, Atan2(dy, dx) * bj_RADTODEG)
call SetUnitAnimationByIndex(this.dummy, R2I(Atan2(dz, SquareRoot(dx * dx + dy * dy)) * bj_RADTODEG + 90.0))
return this
endmethod
method destroy2 takes integer i returns nothing
set update_list[i] = update_list[update_count]
set update_count = update_count - 1
call DestroyEffect(this.dummy_model)
call dummy_destroy(this.dummy)
set this.caster = null
set this.dummy = null
call this.destroy()
endmethod
static method move takes nothing returns nothing
local integer i
local thistype this
local real terrain_z
local boolean hit_unit
set i = 1
loop
exitwhen i > update_count
set this = update_list[i]
set dx = this.tx - this.px
set dy = this.ty - this.py
set dz = this.tz - this.pz
if dx * dx + dy * dy + dz * dz <= TADT_POW_2 then
// we reached the target point
//
set this.px = this.tx
set this.py = this.ty
set this.pz = this.tz
call SetUnitX(this.dummy, this.px)
call SetUnitY(this.dummy, this.py)
call SetUnitZ(this.dummy, this.pz)
call this.destroy2(i)
set i = i - 1
else
set this.px = this.px + this.dpx
set this.py = this.py + this.dpy
set this.pz = this.pz + this.dpz
set ax = this.spiral_radius * Sin(this.ang_xz) * Cos(this.ang_xy)
set ay = this.spiral_radius * Sin(this.ang_xz) * Sin(this.ang_xy)
set az = this.spiral_radius * Cos(this.ang_xz)
set this.x = this.px + this.bvx_x * ax + this.bvx_y * ay + this.bvx_z * az
set this.y = this.py + this.bvy_x * ax + this.bvy_y * ay + this.bvy_z * az
set this.z = this.pz + this.bvz_x * ax + this.bvz_y * ay + this.bvz_z * az
call SetUnitX(this.dummy, this.x)
call SetUnitY(this.dummy, this.y)
call SetUnitZ(this.dummy, this.z)
set this.ang_xz = this.ang_xz + this.ang_xz_inc
// check for enemy units
set hit_unit = false
call GroupEnumUnitsInRange(G, this.x, this.y, this.dummy_scale * 64.0, null)
loop
set U = FirstOfGroup(G)
exitwhen U == null
call GroupRemoveUnit(G, U)
if UnitAlive(U) and IsUnitEnemy(U, this.caster_owner) and not hit_unit and unit_filter(U) then
set hit_unit = true
if GetWidgetLife(U) - this.damage <= 0.405 then
call SetUnitExploded(U, true)
call UnitDamageTarget(this.caster, U, this.damage, MELEE_ATTACK, RANGE_ATTACK, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
else
call UnitDamageTarget(this.caster, U, this.damage, MELEE_ATTACK, RANGE_ATTACK, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
endif
call this.destroy2(i)
set i = i - 1
exitwhen true
endif
endloop
if not hit_unit then
// check for terrain/cliffs
call MoveLocation(loc, this.x, this.y)
set terrain_z = GetLocationZ(loc)
if this.pz - terrain_z <= TEDT then
call this.destroy2(i)
set i = i - 1
endif
endif
endif
set i = i + 1
endloop
endmethod
method start_moving takes nothing returns nothing
set update_count = update_count + 1
set update_list[update_count] = this
if update_count == 1 then
call TimerStart(tmr, DT, true, function thistype.move)
endif
endmethod
endstruct
private struct SpiralingTrails extends array
static method cast takes nothing returns nothing
local SpiralingTrail st
local unit caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(caster, ABILITY_ID)
local real dist = distance(level)
local real speed = linear_speed(level)
local real scale = dummy_scale(level)
local real p_spiral_radius = spiral_radius(level)
local real p_damage = damage(level)
local real cx = GetUnitX(caster)
local real cy = GetUnitY(caster)
local real cz = GetUnitZ(caster) + Z_OFFSET
local real tx = GetSpellTargetX()
local real ty = GetSpellTargetY()
local real tz = cz // GetTerrainZ(tx, ty)
// call MoveLocation(loc, tx, ty)
// set tz = GetLocationZ(loc)
set dx = tx - cx
set dy = ty - cy
set dz = tz - cz
set v_len = SquareRoot(dx * dx + dy * dy + dz * dz)
set dx = dx / v_len
set dy = dy / v_len
set dz = dz / v_len
set tx = cx + dx * dist
set ty = cy + dy * dist
set tz = cz + dz * dist
set st = SpiralingTrail.create(caster, DUMMY_MODEL, cx, cy, cz, tx, ty, tz, 0.0, 1, speed, scale, p_spiral_radius, p_damage)
call st.start_moving()
set st = SpiralingTrail.create(caster, DUMMY_MODEL, cx, cy, cz, tx, ty, tz, bj_PI / 4.0, -1, speed, scale, p_spiral_radius, p_damage)
call st.start_moving()
set caster = null
endmethod
endstruct
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddAction(t, function SpiralingTrails.cast)
endfunction
endscope
Code (vJASS):
scope SpiralingTrails initializer init
globals
private constant integer ABILITY_ID = 'A000'
private constant integer DUMMY_ID = 'e000'
private constant string DUMMY_MODEL = "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdx"
private constant real DT = 1.0 / 32.0
private constant real Z_OFFSET = 80.0
// the target point is considered reached if we are this many units away from it
private constant real TARGET_DISTANCE_THRESHOLD = 16.0
// if we are this many or less units from the terrain we stop
private constant real TERRAIN_DISTANCE_THRESHOLD = 16.0
// UnitDamageTarget arguments
private constant boolean MELEE_ATTACK = false
private constant boolean RANGE_ATTACK = true
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL // spell
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_UNIVERSAL // ignore armor value
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
endglobals
private function unit_filter takes unit u returns boolean
// e.g: return false if the unit is invulnerable
return true
endfunction
private function linear_speed takes integer level returns real
return 500.0
endfunction
private function distance takes integer level returns real
return 900.0
endfunction
private function dummy_scale takes integer level returns real
return 0.5 + 0.5 * level
endfunction
private function spiral_radius takes integer level returns real
return 64.0
endfunction
private function damage takes integer level returns real
return 100.0 * level
endfunction
// NOTE: you can rewrite these functions to use your dummy recycling scripts!
globals
private unit created_dummy
endglobals
private function dummy_create takes player p returns unit
set created_dummy = CreateUnit(p, DUMMY_ID, 0.0, 0.0, 270.0)
call UnitAddAbility(created_dummy, 'Amrf')
call UnitRemoveAbility(created_dummy, 'Amrf')
call UnitAddAbility(created_dummy, 'Aloc')
call UnitRemoveAbility(created_dummy, 'Aloc')
return created_dummy
endfunction
private function dummy_destroy takes unit u returns nothing
call RemoveUnit(u)
endfunction
globals
private location loc = Location(0.0, 0.0)
endglobals
private function GetTerrainZ takes real x, real y returns real
call MoveLocation(loc, x, y)
return GetLocationZ(loc)
endfunction
private function GetUnitZ takes unit u returns real
call MoveLocation(loc, GetUnitX(u), GetUnitY(u))
return GetLocationZ(loc) + GetUnitFlyHeight(u)
endfunction
private function SetUnitZ takes unit u, real z returns nothing
call MoveLocation(loc, GetUnitX(u), GetUnitY(u))
call SetUnitFlyHeight(u, z - GetLocationZ(loc), 0.0)
endfunction
native UnitAlive takes unit u returns boolean
globals
private constant real TADT_POW_2 = TARGET_DISTANCE_THRESHOLD * TARGET_DISTANCE_THRESHOLD
private constant real TEDT = TERRAIN_DISTANCE_THRESHOLD
private real dx
private real dy
private real dz
private real v_len
private real ax
private real ay
private real az
private group G = CreateGroup()
private unit U
endglobals
private struct SpiralingTrail
static timer tmr = CreateTimer()
static thistype array update_list
static integer update_count = 0
player caster_owner
unit caster
unit dummy
effect dummy_model
real dummy_scale
real damage
// current position
real px
real py
real pz
// linear velocity
real dpx
real dpy
real dpz
// target point
real tx
real ty
real tz
real bvx_x
real bvx_y
real bvx_z
real bvy_x
real bvy_y
real bvy_z
real bvz_x
real bvz_y
real bvz_z
real spiral_radius
real ang_xy
real ang_xz
real ang_xz_inc
real x
real y
real z
static method create takes unit caster, string dummy_model, real px, real py, real pz, real tx, real ty, real tz, real ang_xz_initial, integer inc_sign, real speed, real scale, real p_spiral_radius, real p_damage returns thistype
local thistype this = allocate()
local real ang
local real y_axis_deg
local real bvz_ang_xy
local real bvz_ang_xz
set this.caster_owner = GetOwningPlayer(caster)
set this.caster = caster
set this.dummy = dummy_create(this.caster_owner)
set this.dummy_model = AddSpecialEffectTarget(dummy_model, this.dummy, "origin")
set this.dummy_scale = scale
call SetUnitScale(this.dummy, scale, scale, scale)
set this.damage = p_damage
set this.px = px
set this.py = py
set this.pz = pz
set this.tx = tx
set this.ty = ty
set this.tz = tz
set dx = this.tx - this.px
set dy = this.ty - this.py
set dz = this.tz - this.pz
set v_len = SquareRoot(dx * dx + dy * dy + dz * dz)
set dx = dx / v_len
set dy = dy / v_len
set dz = dz / v_len
set this.dpx = dx * speed * DT
set this.dpy = dy * speed * DT
set this.dpz = dz * speed * DT
set ang = 2.0 * bj_PI - Atan2(dy, dx)
set bvx_x = Cos(ang - bj_PI / 2.0)
set bvx_y = Sin(ang - bj_PI / 2.0)
set bvx_z = 0.0
set bvy_x = Cos(ang)
set bvy_y = Sin(ang)
set bvy_z = 0.0
set bvz_x = 0.0
set bvz_y = 0.0
set bvz_z = 1.0
set this.ang_xy = 0.0
set this.ang_xz = ang_xz_initial
set this.spiral_radius = p_spiral_radius
set this.ang_xz_inc = inc_sign * 2.0 * bj_PI / 15.0
call SetUnitX(this.dummy, this.px)
call SetUnitY(this.dummy, this.py)
call SetUnitZ(this.dummy, this.pz)
call SetUnitFacing(this.dummy, Atan2(dy, dx) * bj_RADTODEG)
call SetUnitAnimationByIndex(this.dummy, R2I(Atan2(dz, SquareRoot(dx * dx + dy * dy)) * bj_RADTODEG + 90.0))
return this
endmethod
method destroy2 takes integer i returns nothing
set update_list[i] = update_list[update_count]
set update_count = update_count - 1
call DestroyEffect(this.dummy_model)
call dummy_destroy(this.dummy)
set this.caster = null
set this.dummy = null
call this.destroy()
endmethod
static method move takes nothing returns nothing
local integer i
local thistype this
local real terrain_z
local boolean hit_unit
set i = 1
loop
exitwhen i > update_count
set this = update_list[i]
set dx = this.tx - this.px
set dy = this.ty - this.py
set dz = this.tz - this.pz
if dx * dx + dy * dy + dz * dz <= TADT_POW_2 then
// we reached the target point
//
set this.px = this.tx
set this.py = this.ty
set this.pz = this.tz
call SetUnitX(this.dummy, this.px)
call SetUnitY(this.dummy, this.py)
call SetUnitZ(this.dummy, this.pz)
call this.destroy2(i)
set i = i - 1
else
set this.px = this.px + this.dpx
set this.py = this.py + this.dpy
set this.pz = this.pz + this.dpz
set ax = this.spiral_radius * Sin(this.ang_xz) * Cos(this.ang_xy)
set ay = this.spiral_radius * Sin(this.ang_xz) * Sin(this.ang_xy)
set az = this.spiral_radius * Cos(this.ang_xz)
set this.x = this.px + this.bvx_x * ax + this.bvx_y * ay + this.bvx_z * az
set this.y = this.py + this.bvy_x * ax + this.bvy_y * ay + this.bvy_z * az
set this.z = this.pz + this.bvz_x * ax + this.bvz_y * ay + this.bvz_z * az
call SetUnitX(this.dummy, this.x)
call SetUnitY(this.dummy, this.y)
call SetUnitZ(this.dummy, this.z)
set this.ang_xz = this.ang_xz + this.ang_xz_inc
// check for enemy units
set hit_unit = false
call GroupEnumUnitsInRange(G, this.x, this.y, this.dummy_scale * 64.0, null)
loop
set U = FirstOfGroup(G)
exitwhen U == null
call GroupRemoveUnit(G, U)
if UnitAlive(U) and IsUnitEnemy(U, this.caster_owner) and not hit_unit and unit_filter(U) then
set hit_unit = true
if GetWidgetLife(U) - this.damage <= 0.405 then
call SetUnitExploded(U, true)
call UnitDamageTarget(this.caster, U, this.damage, MELEE_ATTACK, RANGE_ATTACK, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
else
call UnitDamageTarget(this.caster, U, this.damage, MELEE_ATTACK, RANGE_ATTACK, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
endif
call this.destroy2(i)
set i = i - 1
exitwhen true
endif
endloop
if not hit_unit then
// check for terrain/cliffs
call MoveLocation(loc, this.x, this.y)
set terrain_z = GetLocationZ(loc)
if this.pz - terrain_z <= TEDT then
call this.destroy2(i)
set i = i - 1
endif
endif
endif
set i = i + 1
endloop
endmethod
method start_moving takes nothing returns nothing
set update_count = update_count + 1
set update_list[update_count] = this
if update_count == 1 then
call TimerStart(tmr, DT, true, function thistype.move)
endif
endmethod
endstruct
private struct SpiralingTrails extends array
static method cast takes nothing returns nothing
local SpiralingTrail st
local unit caster = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(caster, ABILITY_ID)
local real dist = distance(level)
local real speed = linear_speed(level)
local real scale = dummy_scale(level)
local real p_spiral_radius = spiral_radius(level)
local real p_damage = damage(level)
local real cx = GetUnitX(caster)
local real cy = GetUnitY(caster)
local real cz = GetUnitZ(caster) + Z_OFFSET
local real tx = GetSpellTargetX()
local real ty = GetSpellTargetY()
local real tz = cz // GetTerrainZ(tx, ty)
// call MoveLocation(loc, tx, ty)
// set tz = GetLocationZ(loc)
set dx = tx - cx
set dy = ty - cy
set dz = tz - cz
set v_len = SquareRoot(dx * dx + dy * dy + dz * dz)
set dx = dx / v_len
set dy = dy / v_len
set dz = dz / v_len
set tx = cx + dx * dist
set ty = cy + dy * dist
set tz = cz + dz * dist
set st = SpiralingTrail.create(caster, DUMMY_MODEL, cx, cy, cz, tx, ty, tz, 0.0, 1, speed, scale, p_spiral_radius, p_damage)
call st.start_moving()
set st = SpiralingTrail.create(caster, DUMMY_MODEL, cx, cy, cz, tx, ty, tz, bj_PI / 4.0, -1, speed, scale, p_spiral_radius, p_damage)
call st.start_moving()
set caster = null
endmethod
endstruct
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddAction(t, function SpiralingTrails.cast)
endfunction
endscope
Contents