-
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.
Demongo
Submitted by
Aniki
Demongo The Soul Collector
Demongo is a character in the SJ universe.
Soul model and movement code from Rift Stalker's Soul Conjure ability from TcX AoS by Toadcop.
library Demongo requires Ht, DummyUnit, TimedEffect, v3
private function dd takes string s returns nothing
call BJDebugMsg(s)
endfunction
globals
private constant string SOUL_MODEL = "models\\soul-conjure-missile.mdx"
private constant string SOUL_SUMMONED_MODEL = "Abilities\\Spells\\Orc\\Disenchant\\DisenchantSpecialArt.mdl"
private constant real SOUL_DT = 1.0 / 32.0
private constant integer DEMONGO_SOUL_COLLECTION_ID = 'A003'
//! textmacro DEMONGO_IDS
// odd: unit-type-id, even: ability-id
set ids[1] = 'hfoo'
set ids[2] = 'A001'
set ids[3] = 'ogru'
set ids[4] = 'A002'
set ids[5] = 'n001'
set ids[6] = 'A004'
set ids[7] = 'n002'
set ids[8] = 'A005'
set ids[9] = 'n003'
set ids[10] = 'A006'
set ids[11] = 'n004'
set ids[12] = 'A007'
set ids[13] = 'n005'
set ids[14] = 'A008'
set ids[15] = 'n006'
set ids[16] = 'A009'
set ids[17] = 'n007'
set ids[18] = 'A00A'
set ids[19] = 'n008'
set ids[20] = 'A00B'
set ids[21] = 'n009'
set ids[22] = 'A00C'
set ids[23] = 'n00A'
set ids[24] = 'A00D'
set ids_count = 24
//! endtextmacro
endglobals
private keyword Demongo
private function targets_allowed takes Demongo dem, unit dying_unit returns boolean
// we already check for the above unit-type-ids
// return IsUnitEnemy(dying_unit, GetOwningPlayer(dem.d_u))
return true
endfunction
globals
private constant real tau = 2.0 * (355.0 / 113.0)
private integer array abis
private integer abis_count = 0
private real map_min_x
private real map_max_x
private real map_min_y
private real map_max_y
endglobals
private struct Demongo
static Ht abi_from_uid
static Ht uid_from_abi
static Ht dem_from_unit
static Ht souls_count_of_type
// all Demongos (if one decides to clone him for example) are in this list
static thistype dems
// d_ = Demongo
thistype d_prev
thistype d_next
unit d_u
// Demongo can have a list of souls that follow him around
// s_ = Soul
static timer s_tmr = CreateTimer()
static boolean s_tmr_ticking = false
thistype s_prev
thistype s_next
v3 s_p
v3 s_dp
v3 s_ddp
real s_accel
real s_accelmult
v3 s_a
v3 s_b
real s_dist_xy
real s_dist_xyz
real s_t
real s_t_inc
thistype s_dem
DummyUnit s_du
effect s_ef_a // because the soul model is a bit dim
effect s_ef_b // we use 2 at the same time
static constant integer Soul_State_Follow_Demongo = 1
static constant integer Soul_State_Summoned = 2
static constant integer Soul_State_Goto_Heaven = 3
integer s_state
unit s_tar
integer s_summon_uid
static code on_unit_death_handler
static code soul_update_handler
static code on_spell_effect_handler
private static method onInit takes nothing returns nothing
local integer array ids
local integer ids_count
local trigger t
local integer p
local integer i
local rect r
call ExecuteFunc("s__" + "thistype" + "_set_handlers")
set r = GetWorldBounds()
set map_min_x = GetRectMinX(r)
set map_max_x = GetRectMaxX(r)
set map_min_y = GetRectMinY(r)
set map_max_y = GetRectMaxY(r)
call RemoveRect(r)
set r = null
set abi_from_uid = Ht.create()
set uid_from_abi = Ht.create()
set dem_from_unit = Ht.create()
set souls_count_of_type = Ht.create()
set dems = allocate()
set dems.d_prev = dems
set dems.d_next = dems
//! runtextmacro DEMONGO_IDS()
set i = 1
loop
exitwhen i > ids_count
set abi_from_uid.select()[ids[i]].int = ids[i + 1]
set uid_from_abi.select()[ids[i + 1]].int = ids[i]
set abis_count = abis_count + 1
set abis[abis_count] = ids[i + 1]
set p = 0
loop
exitwhen p >= bj_MAX_PLAYER_SLOTS
call SetPlayerAbilityAvailable(Player(p), ids[i + 1], false)
set p = p + 1
endloop
set i = i + 2
endloop
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddAction(t, on_unit_death_handler)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(t, on_spell_effect_handler)
endmethod
static method modify_souls_count_of_type_for takes thistype dem, integer uid, integer value returns integer
local integer new_count
call souls_count_of_type.select()
set new_count = souls_count_of_type[integer(dem) * 8190 + uid].int + value
set souls_count_of_type[integer(dem) * 8190 + uid].int = new_count
return new_count
endmethod
static method reset_souls_count_of_type_for takes thistype dem, integer uid returns nothing
call souls_count_of_type.select()
set souls_count_of_type[integer(dem) * 8190 + uid].int = 0
endmethod
static method Demongo_create takes unit u_dem returns thistype
local thistype dem = allocate()
set dem.d_prev = dems.d_prev
set dem.d_next = dems
set dem.d_prev.d_next = dem
set dem.d_next.d_prev = dem
set dem.s_prev = dem
set dem.s_next = dem
set dem.d_u = u_dem
return dem
endmethod
static method Soul_create takes thistype dem, unit u_dem, unit dying_unit returns thistype
local thistype s = allocate()
local unit u
set s.s_prev = dem.s_prev
set s.s_next = dem
set s.s_prev.s_next = s
set s.s_next.s_prev = s
set s.s_p = v3_from_unit(dying_unit).to_owned()
set s.s_dp = v3c(0.0, 0.0, 0.0).to_owned()
set s.s_ddp = v3c(0.0, 0.0, 0.0).to_owned()
set s.s_ddp.z = GetRandomReal(600.0, 900.0)
set s.s_accel = GetRandomReal(1300.0, 1800.0)
set s.s_accelmult = GetRandomReal(0.125,0.16)
set s.s_a = v3c(0.0, 0.0, 0.0).to_owned()
set s.s_b = v3c(0.0, 0.0, 0.0).to_owned()
set s.s_dem = dem
set s.s_du = DummyUnit.get().with_owner(GetPlayerId(GetOwningPlayer(u_dem)))
set u = s.s_du.u
set s.s_ef_a = AddSpecialEffectTarget(SOUL_MODEL, u, "origin")
set s.s_ef_b = AddSpecialEffectTarget(SOUL_MODEL, u, "origin")
call SetUnitScale(u, 1.1, 1.1, 1.1)
set s.s_state = Soul_State_Follow_Demongo
set s.s_tar = u_dem
set s.s_summon_uid = 0
if not s_tmr_ticking then
set s_tmr_ticking = true
call TimerStart(s_tmr, SOUL_DT, true, soul_update_handler)
endif
set u = null
return s
endmethod
static method Soul_destroy takes thistype s returns nothing
set s.s_prev.s_next = s.s_next
set s.s_next.s_prev = s.s_prev
call s.s_p.destroy()
call s.s_dp.destroy()
call s.s_ddp.destroy()
call s.s_a.destroy()
call s.s_b.destroy()
call s.s_du.return_instantly()
call DestroyEffect(s.s_ef_a)
set s.s_ef_a = null
call DestroyEffect(s.s_ef_b)
set s.s_ef_b = null
set s.s_tar = null
call s.destroy()
endmethod
static method on_unit_death takes nothing returns nothing
local unit killing_unit = GetKillingUnit()
local unit dying_unit = GetTriggerUnit() // GetDyingUnit()
local integer abi
local integer uid
local thistype dem
local thistype s // soul
local v3 v
local player pp
local integer i
local boolean killing_unit_is_demongo
local boolean dying_unit_is_demongo
set killing_unit_is_demongo = GetUnitAbilityLevel(killing_unit, DEMONGO_SOUL_COLLECTION_ID) > 0
if killing_unit_is_demongo then
set dem = dem_from_unit.select()[Ht.h2i(killing_unit)].int
if dem == 0 then
set dem = Demongo_create(killing_unit)
set dem_from_unit[Ht.h2i(killing_unit)].int = dem
endif
set uid = GetUnitTypeId(dying_unit)
set abi = abi_from_uid.select()[uid].int
if abi != 0 and targets_allowed(dem, dying_unit) then
call SetPlayerAbilityAvailable(GetOwningPlayer(killing_unit), abi, true)
set s = Soul_create(dem, killing_unit, dying_unit)
call modify_souls_count_of_type_for(dem, uid, 1)
endif
endif
set dying_unit_is_demongo = GetUnitAbilityLevel(dying_unit, DEMONGO_SOUL_COLLECTION_ID) > 0
if dying_unit_is_demongo then
set dem = dem_from_unit.select()[Ht.h2i(dying_unit)].int
if dem == 0 then
set dem = Demongo_create(dying_unit)
set dem_from_unit[Ht.h2i(dying_unit)].int = dem
endif
set s = dem.s_next
loop
exitwhen s == dem
set s.s_state = Soul_State_Goto_Heaven
set s.s_tar = DummyUnit.get().u
// heaven is 2048.0 units above =)
set v = v3c(GetRandomReal(-600.0, 600.0), GetRandomReal(-600.0, 600.0), 2048.0)
set v = v3a(v, v3_from_unit(s.s_dem.d_u))
call SetUnitX(s.s_tar, v.x)
call SetUnitY(s.s_tar, v.y)
call MoveLocation(v3_loc, v.x, v.y)
call SetUnitFlyHeight(s.s_tar, v.z - GetLocationZ(v3_loc), 0.0)
call s.s_ddp.set_eq_to(v3c(0.0, 0.0, 0.0))
set s.s_accel = s.s_accel / 12.0
set s = s.s_next
endloop
set pp = GetOwningPlayer(dying_unit)
set i = 1
loop
exitwhen i > abis_count
call SetPlayerAbilityAvailable(pp, abis[i], false)
call reset_souls_count_of_type_for(dem, uid_from_abi.select()[abis[i]])
set i = i + 1
endloop
endif
set killing_unit = null
set dying_unit = null
endmethod
static method on_spell_effect takes nothing returns nothing
local integer abi
local integer uid
local thistype dem
local thistype s // soul
local v3 a
local v3 b
local v3 ab
local v3 c
set abi = GetSpellAbilityId()
set uid = uid_from_abi.select()[abi].int
if uid == 0 then
return
endif
set dem = dem_from_unit.select()[Ht.h2i(GetTriggerUnit())].int
if modify_souls_count_of_type_for(dem, uid, -1) == 0 then
call SetPlayerAbilityAvailable(GetOwningPlayer(dem.d_u), abi, false)
endif
// find the first soul that is not being summoned
// there should always be at least one such soul
set s = dem.s_next
loop
debug exitwhen s == dem
if s.s_summon_uid == 0 then
exitwhen true
endif
set s = s.s_next
endloop
// assert that there really is an available soul
static if DEBUG_MODE then
if s == dem then
call dd("soul bug!")
if 1 / 0 == 1 then
endif
endif
endif
set s.s_state = Soul_State_Summoned
set a = v3_from_unit(s.s_dem.d_u)
set b = v3_from_spell_target()
set ab = v3s(b, a)
set c = v3_from_polar(ab.ang_rot(), 24.0)
set c.z = c.z + 48.0
call s.s_a.set_eq_to(v3a(c, a))
call s.s_b.set_eq_to(ab)
set s.s_dist_xy = s.s_b.len_xy()
set s.s_dist_xyz = s.s_b.len()
set s.s_t = 0.0
set s.s_t_inc = (900.0 / s.s_dist_xy) * SOUL_DT
set s.s_summon_uid = uid
endmethod
static method soul_update takes nothing returns nothing
local thistype dem
local thistype s // soul
local thistype next_soul
local v3 vn
local v3 v
local unit u
local real z_offset = 0.0
local real d
local boolean done
set dem = dems.d_next
loop
exitwhen dem == dems
set s = dem.s_next
loop
exitwhen s == dem
set next_soul = s.s_next
set done = false
if s.s_state == Soul_State_Follow_Demongo or s.s_state == Soul_State_Goto_Heaven then
set vn = v3n(v3s(v3_from_unit(s.s_tar), s.s_p))
call s.s_ddp.set_eq_to(v3a(s.s_ddp, v3sc(s.s_accel * SOUL_DT, vn)))
set v = v3a(v3sc(s.s_accel * s.s_accelmult, vn), s.s_ddp)
call s.s_dp.set_eq_to(v3sc(SOUL_DT, v))
call s.s_p.set_eq_to(v3a(s.s_p, s.s_dp))
// Demongo scaled to 0.60 is about 90.0 units high and his torso is
// somewhere around 60.0
set z_offset = 60.0
if s.s_state == Soul_State_Goto_Heaven then
set z_offset = 0.0
if s.s_p.z > 2048.0 then
set done = true
call DummyUnit.from(s.s_tar).return_instantly()
endif
endif
elseif s.s_state == Soul_State_Summoned then
if s.s_t >= 1.0 then
set done = true
set s.s_t = 1.0
endif
call s.s_p.set_eq_to(v3a(s.s_a, v3sc(s.s_t, s.s_b)))
set d = s.s_t * s.s_dist_xyz
set s.s_p.z = s.s_p.z + ((4.0 * s.s_dist_xy * 0.5 * d * (s.s_dist_xyz - d)) / (s.s_dist_xyz * s.s_dist_xyz))
if done then
call CreateUnit(GetOwningPlayer(s.s_dem.d_u), s.s_summon_uid, s.s_p.x, s.s_p.y, bj_RADTODEG * GetRandomReal(0.0, tau))
call TimedEffect/*
*/.create(SOUL_SUMMONED_MODEL, 1.0)/*
*/.set_xyz(s.s_p.x, s.s_p.y, 0.0)/*
*/.show()
call TimedEffect/*
*/.create("Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl", 1.0)/*
*/.set_xyz(s.s_p.x, s.s_p.y, 0.0)/*
*/.scale(0.2)/*
*/.show()
else
set s.s_t = s.s_t + s.s_t_inc
endif
set z_offset = 0.0
endif
if s.s_p.x < map_min_x then
set s.s_p.x = map_min_x
elseif s.s_p.x > map_max_x then
set s.s_p.x = map_max_x
elseif s.s_p.y < map_min_y then
set s.s_p.y = map_min_y
elseif s.s_p.y > map_max_y then
set s.s_p.y = map_max_y
endif
set u = s.s_du.u
call SetUnitX(u, s.s_p.x)
call SetUnitY(u, s.s_p.y)
call MoveLocation(v3_loc, s.s_p.x, s.s_p.y)
call SetUnitFlyHeight(u, s.s_p.z - GetLocationZ(v3_loc) + z_offset, 0.0)
if done then
call Soul_destroy(s)
endif
set s = next_soul
endloop
set dem = dem.d_next
endloop
set u = null
endmethod
static method set_handlers takes nothing returns nothing
set on_unit_death_handler = function thistype.on_unit_death
set soul_update_handler = function thistype.soul_update
set on_spell_effect_handler = function thistype.on_spell_effect
endmethod
endstruct
endlibrary
Demongo is a character in the SJ universe.
Soul model and movement code from Rift Stalker's Soul Conjure ability from TcX AoS by Toadcop.
Code (vJASS):
library Demongo requires Ht, DummyUnit, TimedEffect, v3
private function dd takes string s returns nothing
call BJDebugMsg(s)
endfunction
globals
private constant string SOUL_MODEL = "models\\soul-conjure-missile.mdx"
private constant string SOUL_SUMMONED_MODEL = "Abilities\\Spells\\Orc\\Disenchant\\DisenchantSpecialArt.mdl"
private constant real SOUL_DT = 1.0 / 32.0
private constant integer DEMONGO_SOUL_COLLECTION_ID = 'A003'
//! textmacro DEMONGO_IDS
// odd: unit-type-id, even: ability-id
set ids[1] = 'hfoo'
set ids[2] = 'A001'
set ids[3] = 'ogru'
set ids[4] = 'A002'
set ids[5] = 'n001'
set ids[6] = 'A004'
set ids[7] = 'n002'
set ids[8] = 'A005'
set ids[9] = 'n003'
set ids[10] = 'A006'
set ids[11] = 'n004'
set ids[12] = 'A007'
set ids[13] = 'n005'
set ids[14] = 'A008'
set ids[15] = 'n006'
set ids[16] = 'A009'
set ids[17] = 'n007'
set ids[18] = 'A00A'
set ids[19] = 'n008'
set ids[20] = 'A00B'
set ids[21] = 'n009'
set ids[22] = 'A00C'
set ids[23] = 'n00A'
set ids[24] = 'A00D'
set ids_count = 24
//! endtextmacro
endglobals
private keyword Demongo
private function targets_allowed takes Demongo dem, unit dying_unit returns boolean
// we already check for the above unit-type-ids
// return IsUnitEnemy(dying_unit, GetOwningPlayer(dem.d_u))
return true
endfunction
globals
private constant real tau = 2.0 * (355.0 / 113.0)
private integer array abis
private integer abis_count = 0
private real map_min_x
private real map_max_x
private real map_min_y
private real map_max_y
endglobals
private struct Demongo
static Ht abi_from_uid
static Ht uid_from_abi
static Ht dem_from_unit
static Ht souls_count_of_type
// all Demongos (if one decides to clone him for example) are in this list
static thistype dems
// d_ = Demongo
thistype d_prev
thistype d_next
unit d_u
// Demongo can have a list of souls that follow him around
// s_ = Soul
static timer s_tmr = CreateTimer()
static boolean s_tmr_ticking = false
thistype s_prev
thistype s_next
v3 s_p
v3 s_dp
v3 s_ddp
real s_accel
real s_accelmult
v3 s_a
v3 s_b
real s_dist_xy
real s_dist_xyz
real s_t
real s_t_inc
thistype s_dem
DummyUnit s_du
effect s_ef_a // because the soul model is a bit dim
effect s_ef_b // we use 2 at the same time
static constant integer Soul_State_Follow_Demongo = 1
static constant integer Soul_State_Summoned = 2
static constant integer Soul_State_Goto_Heaven = 3
integer s_state
unit s_tar
integer s_summon_uid
static code on_unit_death_handler
static code soul_update_handler
static code on_spell_effect_handler
private static method onInit takes nothing returns nothing
local integer array ids
local integer ids_count
local trigger t
local integer p
local integer i
local rect r
call ExecuteFunc("s__" + "thistype" + "_set_handlers")
set r = GetWorldBounds()
set map_min_x = GetRectMinX(r)
set map_max_x = GetRectMaxX(r)
set map_min_y = GetRectMinY(r)
set map_max_y = GetRectMaxY(r)
call RemoveRect(r)
set r = null
set abi_from_uid = Ht.create()
set uid_from_abi = Ht.create()
set dem_from_unit = Ht.create()
set souls_count_of_type = Ht.create()
set dems = allocate()
set dems.d_prev = dems
set dems.d_next = dems
//! runtextmacro DEMONGO_IDS()
set i = 1
loop
exitwhen i > ids_count
set abi_from_uid.select()[ids[i]].int = ids[i + 1]
set uid_from_abi.select()[ids[i + 1]].int = ids[i]
set abis_count = abis_count + 1
set abis[abis_count] = ids[i + 1]
set p = 0
loop
exitwhen p >= bj_MAX_PLAYER_SLOTS
call SetPlayerAbilityAvailable(Player(p), ids[i + 1], false)
set p = p + 1
endloop
set i = i + 2
endloop
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddAction(t, on_unit_death_handler)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(t, on_spell_effect_handler)
endmethod
static method modify_souls_count_of_type_for takes thistype dem, integer uid, integer value returns integer
local integer new_count
call souls_count_of_type.select()
set new_count = souls_count_of_type[integer(dem) * 8190 + uid].int + value
set souls_count_of_type[integer(dem) * 8190 + uid].int = new_count
return new_count
endmethod
static method reset_souls_count_of_type_for takes thistype dem, integer uid returns nothing
call souls_count_of_type.select()
set souls_count_of_type[integer(dem) * 8190 + uid].int = 0
endmethod
static method Demongo_create takes unit u_dem returns thistype
local thistype dem = allocate()
set dem.d_prev = dems.d_prev
set dem.d_next = dems
set dem.d_prev.d_next = dem
set dem.d_next.d_prev = dem
set dem.s_prev = dem
set dem.s_next = dem
set dem.d_u = u_dem
return dem
endmethod
static method Soul_create takes thistype dem, unit u_dem, unit dying_unit returns thistype
local thistype s = allocate()
local unit u
set s.s_prev = dem.s_prev
set s.s_next = dem
set s.s_prev.s_next = s
set s.s_next.s_prev = s
set s.s_p = v3_from_unit(dying_unit).to_owned()
set s.s_dp = v3c(0.0, 0.0, 0.0).to_owned()
set s.s_ddp = v3c(0.0, 0.0, 0.0).to_owned()
set s.s_ddp.z = GetRandomReal(600.0, 900.0)
set s.s_accel = GetRandomReal(1300.0, 1800.0)
set s.s_accelmult = GetRandomReal(0.125,0.16)
set s.s_a = v3c(0.0, 0.0, 0.0).to_owned()
set s.s_b = v3c(0.0, 0.0, 0.0).to_owned()
set s.s_dem = dem
set s.s_du = DummyUnit.get().with_owner(GetPlayerId(GetOwningPlayer(u_dem)))
set u = s.s_du.u
set s.s_ef_a = AddSpecialEffectTarget(SOUL_MODEL, u, "origin")
set s.s_ef_b = AddSpecialEffectTarget(SOUL_MODEL, u, "origin")
call SetUnitScale(u, 1.1, 1.1, 1.1)
set s.s_state = Soul_State_Follow_Demongo
set s.s_tar = u_dem
set s.s_summon_uid = 0
if not s_tmr_ticking then
set s_tmr_ticking = true
call TimerStart(s_tmr, SOUL_DT, true, soul_update_handler)
endif
set u = null
return s
endmethod
static method Soul_destroy takes thistype s returns nothing
set s.s_prev.s_next = s.s_next
set s.s_next.s_prev = s.s_prev
call s.s_p.destroy()
call s.s_dp.destroy()
call s.s_ddp.destroy()
call s.s_a.destroy()
call s.s_b.destroy()
call s.s_du.return_instantly()
call DestroyEffect(s.s_ef_a)
set s.s_ef_a = null
call DestroyEffect(s.s_ef_b)
set s.s_ef_b = null
set s.s_tar = null
call s.destroy()
endmethod
static method on_unit_death takes nothing returns nothing
local unit killing_unit = GetKillingUnit()
local unit dying_unit = GetTriggerUnit() // GetDyingUnit()
local integer abi
local integer uid
local thistype dem
local thistype s // soul
local v3 v
local player pp
local integer i
local boolean killing_unit_is_demongo
local boolean dying_unit_is_demongo
set killing_unit_is_demongo = GetUnitAbilityLevel(killing_unit, DEMONGO_SOUL_COLLECTION_ID) > 0
if killing_unit_is_demongo then
set dem = dem_from_unit.select()[Ht.h2i(killing_unit)].int
if dem == 0 then
set dem = Demongo_create(killing_unit)
set dem_from_unit[Ht.h2i(killing_unit)].int = dem
endif
set uid = GetUnitTypeId(dying_unit)
set abi = abi_from_uid.select()[uid].int
if abi != 0 and targets_allowed(dem, dying_unit) then
call SetPlayerAbilityAvailable(GetOwningPlayer(killing_unit), abi, true)
set s = Soul_create(dem, killing_unit, dying_unit)
call modify_souls_count_of_type_for(dem, uid, 1)
endif
endif
set dying_unit_is_demongo = GetUnitAbilityLevel(dying_unit, DEMONGO_SOUL_COLLECTION_ID) > 0
if dying_unit_is_demongo then
set dem = dem_from_unit.select()[Ht.h2i(dying_unit)].int
if dem == 0 then
set dem = Demongo_create(dying_unit)
set dem_from_unit[Ht.h2i(dying_unit)].int = dem
endif
set s = dem.s_next
loop
exitwhen s == dem
set s.s_state = Soul_State_Goto_Heaven
set s.s_tar = DummyUnit.get().u
// heaven is 2048.0 units above =)
set v = v3c(GetRandomReal(-600.0, 600.0), GetRandomReal(-600.0, 600.0), 2048.0)
set v = v3a(v, v3_from_unit(s.s_dem.d_u))
call SetUnitX(s.s_tar, v.x)
call SetUnitY(s.s_tar, v.y)
call MoveLocation(v3_loc, v.x, v.y)
call SetUnitFlyHeight(s.s_tar, v.z - GetLocationZ(v3_loc), 0.0)
call s.s_ddp.set_eq_to(v3c(0.0, 0.0, 0.0))
set s.s_accel = s.s_accel / 12.0
set s = s.s_next
endloop
set pp = GetOwningPlayer(dying_unit)
set i = 1
loop
exitwhen i > abis_count
call SetPlayerAbilityAvailable(pp, abis[i], false)
call reset_souls_count_of_type_for(dem, uid_from_abi.select()[abis[i]])
set i = i + 1
endloop
endif
set killing_unit = null
set dying_unit = null
endmethod
static method on_spell_effect takes nothing returns nothing
local integer abi
local integer uid
local thistype dem
local thistype s // soul
local v3 a
local v3 b
local v3 ab
local v3 c
set abi = GetSpellAbilityId()
set uid = uid_from_abi.select()[abi].int
if uid == 0 then
return
endif
set dem = dem_from_unit.select()[Ht.h2i(GetTriggerUnit())].int
if modify_souls_count_of_type_for(dem, uid, -1) == 0 then
call SetPlayerAbilityAvailable(GetOwningPlayer(dem.d_u), abi, false)
endif
// find the first soul that is not being summoned
// there should always be at least one such soul
set s = dem.s_next
loop
debug exitwhen s == dem
if s.s_summon_uid == 0 then
exitwhen true
endif
set s = s.s_next
endloop
// assert that there really is an available soul
static if DEBUG_MODE then
if s == dem then
call dd("soul bug!")
if 1 / 0 == 1 then
endif
endif
endif
set s.s_state = Soul_State_Summoned
set a = v3_from_unit(s.s_dem.d_u)
set b = v3_from_spell_target()
set ab = v3s(b, a)
set c = v3_from_polar(ab.ang_rot(), 24.0)
set c.z = c.z + 48.0
call s.s_a.set_eq_to(v3a(c, a))
call s.s_b.set_eq_to(ab)
set s.s_dist_xy = s.s_b.len_xy()
set s.s_dist_xyz = s.s_b.len()
set s.s_t = 0.0
set s.s_t_inc = (900.0 / s.s_dist_xy) * SOUL_DT
set s.s_summon_uid = uid
endmethod
static method soul_update takes nothing returns nothing
local thistype dem
local thistype s // soul
local thistype next_soul
local v3 vn
local v3 v
local unit u
local real z_offset = 0.0
local real d
local boolean done
set dem = dems.d_next
loop
exitwhen dem == dems
set s = dem.s_next
loop
exitwhen s == dem
set next_soul = s.s_next
set done = false
if s.s_state == Soul_State_Follow_Demongo or s.s_state == Soul_State_Goto_Heaven then
set vn = v3n(v3s(v3_from_unit(s.s_tar), s.s_p))
call s.s_ddp.set_eq_to(v3a(s.s_ddp, v3sc(s.s_accel * SOUL_DT, vn)))
set v = v3a(v3sc(s.s_accel * s.s_accelmult, vn), s.s_ddp)
call s.s_dp.set_eq_to(v3sc(SOUL_DT, v))
call s.s_p.set_eq_to(v3a(s.s_p, s.s_dp))
// Demongo scaled to 0.60 is about 90.0 units high and his torso is
// somewhere around 60.0
set z_offset = 60.0
if s.s_state == Soul_State_Goto_Heaven then
set z_offset = 0.0
if s.s_p.z > 2048.0 then
set done = true
call DummyUnit.from(s.s_tar).return_instantly()
endif
endif
elseif s.s_state == Soul_State_Summoned then
if s.s_t >= 1.0 then
set done = true
set s.s_t = 1.0
endif
call s.s_p.set_eq_to(v3a(s.s_a, v3sc(s.s_t, s.s_b)))
set d = s.s_t * s.s_dist_xyz
set s.s_p.z = s.s_p.z + ((4.0 * s.s_dist_xy * 0.5 * d * (s.s_dist_xyz - d)) / (s.s_dist_xyz * s.s_dist_xyz))
if done then
call CreateUnit(GetOwningPlayer(s.s_dem.d_u), s.s_summon_uid, s.s_p.x, s.s_p.y, bj_RADTODEG * GetRandomReal(0.0, tau))
call TimedEffect/*
*/.create(SOUL_SUMMONED_MODEL, 1.0)/*
*/.set_xyz(s.s_p.x, s.s_p.y, 0.0)/*
*/.show()
call TimedEffect/*
*/.create("Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl", 1.0)/*
*/.set_xyz(s.s_p.x, s.s_p.y, 0.0)/*
*/.scale(0.2)/*
*/.show()
else
set s.s_t = s.s_t + s.s_t_inc
endif
set z_offset = 0.0
endif
if s.s_p.x < map_min_x then
set s.s_p.x = map_min_x
elseif s.s_p.x > map_max_x then
set s.s_p.x = map_max_x
elseif s.s_p.y < map_min_y then
set s.s_p.y = map_min_y
elseif s.s_p.y > map_max_y then
set s.s_p.y = map_max_y
endif
set u = s.s_du.u
call SetUnitX(u, s.s_p.x)
call SetUnitY(u, s.s_p.y)
call MoveLocation(v3_loc, s.s_p.x, s.s_p.y)
call SetUnitFlyHeight(u, s.s_p.z - GetLocationZ(v3_loc) + z_offset, 0.0)
if done then
call Soul_destroy(s)
endif
set s = next_soul
endloop
set dem = dem.d_next
endloop
set u = null
endmethod
static method set_handlers takes nothing returns nothing
set on_unit_death_handler = function thistype.on_unit_death
set soul_update_handler = function thistype.soul_update
set on_spell_effect_handler = function thistype.on_spell_effect
endmethod
endstruct
endlibrary
Contents