GoGo-Boy
You can change this now in User CP
- Reaction score
- 40
GoGo-Boy aka Na_Dann_Ma_GoGo presents: Fusion Orbs
JASS / GUI: JASS.
vJASS: Yes.
MUI: Yes.
Laggless: Yes.
Leakless: Think so.
Requires: NewGen Editor, HSAS Credits to PandaMine
The really nice testmap was made by Tinki3 and then a little bit edited by me to suit this certain spell testing.
I use the special dummy model which is made by Vexorian. This is to avoid the unnecessary use of multiple dummy units.
Purpose of it? Having a spell with a very, very cool movement which is totally configurable! Don't believe me? Test it!
Tooltip:
The hero launches one fire and one ice orb that fly towards the targeted location. The orbs rotate around each other until they have reached a certain distance from which on they'll start to slow down and gain fly height to afterwards smash down with full power and explode on impact. The enemy units take damage duo to the heat and are frozen because of the cold provided by the ice. If the distance between the caster and the targeted location isn't sufficent, the orbs will explode with minor effects.
Range - 1500
Level 1 - 130 damage and 3 sec freeze
Level 2 - 190 damage and 4.5 sec freeze
Level 3 - 250 damage and 6 sec freeze
Screenshots:
Fly Around (doesn't show it's real coolness ):
Explosion (that screenshot was kinda good I would say :O) :
Wanna see the code.. don't you?:
Notes:
I updated the spell code but not the map itself yet. Will re-upload it after some other changes.
The reason I use a second dummy ability (entangle) to freeze the units is that it greatly reduces the amount of code AND provides a buff (hence making it disspellable) + making it really MUI in such a way, that the new freeze duration will override the old... as it is with entangle.
You better don't base the main dummy ability (something with a target location) of something, that can be cast anywhere, and hence outside the map because I did not add a function that checks whether everything is in playable map area. But I based my dummy ability on shockwave which can't target areas outside the map AND I've read on campaigns.net, that the next patch fixes the crashes through "SetUnitX()/Y()".
Implantation instructions can be read above the trigger in the map.
Changelog:
Give Credits to either GoGo-Boy or Na_Dann_Ma_GoGo if you use this spell in your map.
Have fun with testing and please give feedback!
JASS / GUI: JASS.
vJASS: Yes.
MUI: Yes.
Laggless: Yes.
Leakless: Think so.
Requires: NewGen Editor, HSAS Credits to PandaMine
The really nice testmap was made by Tinki3 and then a little bit edited by me to suit this certain spell testing.
I use the special dummy model which is made by Vexorian. This is to avoid the unnecessary use of multiple dummy units.
Purpose of it? Having a spell with a very, very cool movement which is totally configurable! Don't believe me? Test it!
Tooltip:
The hero launches one fire and one ice orb that fly towards the targeted location. The orbs rotate around each other until they have reached a certain distance from which on they'll start to slow down and gain fly height to afterwards smash down with full power and explode on impact. The enemy units take damage duo to the heat and are frozen because of the cold provided by the ice. If the distance between the caster and the targeted location isn't sufficent, the orbs will explode with minor effects.
Range - 1500
Level 1 - 130 damage and 3 sec freeze
Level 2 - 190 damage and 4.5 sec freeze
Level 3 - 250 damage and 6 sec freeze
Screenshots:
Fly Around (doesn't show it's real coolness ):
Wanna see the code.. don't you?:
JASS:
// Fusion Orbs by GoGo-Boy aka Na_Dann_Ma_GoGo ------- Credits to tinki3 for testmap, PandaMine for his HSAS and Anitarf for some help considering the orbs rotation
// this is necessary for the use of HSAS
library HSASintroduction
//! runtextmacro HSAS_Static("Fusion","32760","")
endlibrary
scope Fusionorbs initializer InitTrig
globals
//======================== RAW DATAS =========================================\\
private constant integer DUMMY_ID = 039;u001039; // the Raw Id of the dummy unit (must have the dummy.mdl model file!!!![look at import manager])
private constant integer SPELL_ID = 039;A000039; // the Raw Id of the dummy spell
private constant integer ROOT_ID = 039;A002039; // the Raw Id of the entangle spell (to "freeze" the units)
//========================= MODEL / EFFECT PATHS =================================================\\
private constant string ICE_PATH = "Abilities\\Spells\\Other\\FrostBolt\\FrostBoltMissile.mdl" // model path for the icy orb model
private constant string FIRE_PATH = "Abilities\\Weapons\\LordofFlameMissile\\LordofFlameMissile.mdl" // model path of the fireorb model
private constant string ICE_EXPLODE = "Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl" // explosion effect
private constant string FIRE_EXPLODE = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl" // "" ""
private constant string FIRE_EXPLODE2 = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl" // "" ""
//=========================== SIZE OF BOTH ORBS + EXPLOSION SIZE + FLY HEIGHT OF BOTH ORBS =========================================================\\
private constant real CYCLES_PER_SEC = 1 // the time in seconds a orbs need to fullify a rotation
private constant real FIRE_ORB_SIZE = 1.2 // size of the fire orb
private constant real ICE_ORB_SIZE = 1.5 // size of the ice orb
private constant real EXPLODE_SIZE = 3.5 // size for the explosion effects
private constant real FLY_HEIGHT = 70 // fly height of both orbs
//============================== Damage Configurations ===========================
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_CHAOS
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
//============================== DIFFERENT SPEED VALUES ==========================================\\
private constant real SLIDE_PERIOD = 0.03 // timer movement period [do not choose values below 0.025 (because it'll make no difference but is more intensive) or over 0.04 (won't be smooth enough anymore)
private constant real DISTANCE = 60 // distance between both orbs (here 80... the " /2 " has other purposes :
private constant real VELOCITY = 700 // amount of distance moved each second!
//================================== DAMAGE AND FREEZE AOE ON IMPACT =======================================\\
private constant real EXPLODE_AOE = 300 // AOE in which enemy units get frozen and damaged
private constant real BASE_FIRE_DAMAGE = 130 // base damage
private constant real LEVEL_FIRE_DAMAGE = 60 // damage per level [total of 190 at level 2 for example]
//===================================DISTANCES OF THE FINAL MOVEMENT===================\\
private constant real SLOW_DOWN_DIST = 150 // amount of distance during which the orbs slow down [setting it to zero or less looks so cool <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite2" alt=";)" title="Wink ;)" loading="lazy" data-shortname=";)" /> ]
private constant real SPEED_UP_DIST = 250 // amount of distance during which the orbs speed up
// warning --- the sum of SLOW_DOWN_DIST and SPEED_UP_DIST must be unequal to zero!!
private constant real MAX_RISE_UP_HEIGHT = 200 // amount of height difference the orbs reach during the slow down phase
private constant real MAX_SIDE_DISTANCE = 150 // amount of distance the orbs slide to the sides on slow down phase
private constant real MODEL_ADJUSTMENT = 35 // this is to get both models on the correct position... in that case the fire orb would be a bit behind without that adjustment
//============================== GLOBAL PLAYER VARIABLE FOR FILTERING ===========================
private player PLAYER
//=================================== MOSTLY PHYSICAL MOVEMENT CALCULATIONS - DO NOT TOUCH! ElSE YOU MIGHT DIE ==================\\
private constant real PI_HALF = 1.5708
private constant real PI_DOUBLE = 2 * bj_PI
private constant real FINAL_DISTANCE = SLOW_DOWN_DIST + SPEED_UP_DIST
private constant real FINAL_TIME = FINAL_DISTANCE / VELOCITY
private constant real SLOW_DOWN_TIME = FINAL_TIME * 1.5 / 3
private constant real SPEED_UP_TIME = FINAL_TIME * 1.5 / 3
private constant real NEG_ACCELERATION = (SLOW_DOWN_DIST - VELOCITY * SLOW_DOWN_TIME) / (SLOW_DOWN_TIME * SLOW_DOWN_TIME)
private constant real SPEED_UP_SPEED = (NEG_ACCELERATION * 2 * SLOW_DOWN_TIME + VELOCITY)
private constant real POS_ACCELERATION = (SPEED_UP_DIST - SPEED_UP_SPEED * SPEED_UP_TIME) / (SPEED_UP_TIME * SPEED_UP_TIME)
private constant real RISE_UP_ACCELERATION = MAX_RISE_UP_HEIGHT / ( SLOW_DOWN_TIME * SLOW_DOWN_TIME)
private constant real FALL_DOWN_ACCELERATION = -((MAX_RISE_UP_HEIGHT + FLY_HEIGHT - 10) / (SPEED_UP_TIME * SPEED_UP_TIME))
private constant real SIDE_ACCELERATION = MAX_SIDE_DISTANCE / ( SLOW_DOWN_TIME * SLOW_DOWN_TIME)
private constant real NEG_SIDE_ACCELERATION = -((MAX_SIDE_DISTANCE + DISTANCE) / (SPEED_UP_TIME * SPEED_UP_TIME))
endglobals
// filterfunction to filter out the units that will take damage and get frozen
// add an extra "if ..... then " and for sure an "endif" afterwards...
private function FilterVictims takes nothing returns boolean
local unit u = GetFilterUnit()
if IsUnitType(u,UNIT_TYPE_STRUCTURE) != true then
if IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE) != true then
if GetWidgetLife(u) > 0 then
if IsUnitEnemy(u,PLAYER) then
set u = null
return true
endif
endif
endif
endif
set u = null
return false
endfunction
private struct Fusion
real level
unit caster
real caster_x
real caster_y
unit ice
real ice_x
real ice_y
unit fire
real fire_x
real fire_y
real ice_height
real fire_height
player owner
effect fire_model
effect ice_model
real facing
real time =SLIDE_PERIOD
real max_time = 0
real rotation_adjustment
real speed_up_time = SLIDE_PERIOD
real slow_down_time = SLIDE_PERIOD
boolean enough_range = false
boolean checked = false
boolean fall = false
static method create takes nothing returns Fusion
local Fusion f = Fusion.allocate()
local location loc = GetSpellTargetLoc()
local real loc_x
local real loc_y
local real move
local unit caster = GetTriggerUnit()
local real cast_x = GetUnitX(caster)
local real cast_y = GetUnitY(caster)
set f.caster = caster
set loc_x = GetLocationX(loc) - cast_x
set loc_y = GetLocationY(loc) - cast_y
set f.owner = GetTriggerPlayer()
set f.level = I2R(GetUnitAbilityLevel(f.caster,SPELL_ID))
set f.facing = Atan2(loc_y,loc_x)
set f.caster_x = cast_x + 40 * Cos(f.facing)
set f.caster_y = cast_y + 40 * Sin(f.facing)
set f.max_time = SquareRoot(loc_y * loc_y + loc_x * loc_x) / VELOCITY
if f.max_time > FINAL_TIME then
set f.enough_range = true
set f.rotation_adjustment = (1-((f.max_time - FINAL_TIME) - R2I(f.max_time - FINAL_TIME))) * PI_DOUBLE
set f.max_time = f.max_time - FINAL_TIME
endif
set f.ice = CreateUnit(f.owner,DUMMY_ID,f.caster_x,f.caster_y, bj_RADTODEG * f.facing)
set f.ice_model = AddSpecialEffectTarget(ICE_PATH,f.ice,"origin")
call SetUnitScale(f.ice,ICE_ORB_SIZE,ICE_ORB_SIZE,ICE_ORB_SIZE)
set f.fire = CreateUnit(f.owner,DUMMY_ID,f.caster_x,f.caster_y, bj_RADTODEG * f.facing)
set f.fire_model = AddSpecialEffectTarget(FIRE_PATH,f.fire,"origin")
call SetUnitScale(f.fire,FIRE_ORB_SIZE,FIRE_ORB_SIZE,FIRE_ORB_SIZE)
call RemoveLocation(loc)
set caster = null
set loc = null
return f
endmethod
method onDestroy takes nothing returns nothing
local real x = GetUnitX(.ice)
local real y = GetUnitY(.ice)
local unit u = CreateUnit(.owner,DUMMY_ID,x,y,0)
local unit u2 = CreateUnit(.owner,DUMMY_ID,x,y,0)
local unit victim
local unit dummy
local real damage
local integer rootlevel
local group g = CreateGroup()
call SetUnitScale(u,EXPLODE_SIZE,EXPLODE_SIZE,EXPLODE_SIZE)
call SetUnitScale(u2,EXPLODE_SIZE / 2,EXPLODE_SIZE / 2,EXPLODE_SIZE / 2)
call KillUnit(.fire)
call KillUnit(.ice)
call KillUnit(u)
call KillUnit(u2)
call DestroyEffect(AddSpecialEffectTarget(ICE_EXPLODE,u2,"origin"))
call DestroyEffect(AddSpecialEffectTarget(FIRE_EXPLODE,u,"origin"))
call DestroyEffect(.fire_model)
call DestroyEffect(.ice_model)
if .enough_range == true then
call DestroyEffect(AddSpecialEffectTarget(FIRE_EXPLODE2,u2,"origin"))
call DestroyEffect(AddSpecialEffectTarget(ICE_EXPLODE,u,"origin"))
set damage = BASE_FIRE_DAMAGE + LEVEL_FIRE_DAMAGE * (.level - 1)
set rootlevel = R2I(.level)
else
call DestroyEffect(AddSpecialEffectTarget(ICE_EXPLODE,u2,"origin"))
set damage = (BASE_FIRE_DAMAGE + LEVEL_FIRE_DAMAGE * (.level -1 )) / 2
set rootlevel = 1
endif
set PLAYER = .owner
call GroupEnumUnitsInRange(g,x,y,EXPLODE_AOE,Filter(function FilterVictims))
loop
set victim = FirstOfGroup(g)
exitwhen victim == null
call GroupRemoveUnit(g,victim)
set dummy = CreateUnit(.owner,DUMMY_ID,x,y,0)
call UnitApplyTimedLife(dummy,039;BTLF039;,1)
call UnitAddAbility(dummy,ROOT_ID)
call SetUnitAbilityLevel(dummy,ROOT_ID,rootlevel)
call IssueTargetOrder(dummy,"entanglingroots",victim)
call UnitDamageTarget(.caster,victim,damage,false,false,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE)
endloop
call DestroyGroup(g)
set g = null
set dummy = null
set u = null
set u2 = null
set .caster = null
set .fire = null
set .ice = null
set .fire_model = null
set .ice_model = null
set .owner = null
endmethod
endstruct
private function Callback takes nothing returns nothing
local timer t = GetExpiredTimer()
local Fusion f = GetAttachedStructFusion(t)
local real dx
local real dy
local real dz
if f.time <= f.max_time then
// for the following I thank Anitarf for his help
set dz = DISTANCE * Sin(PI_DOUBLE * f.time * CYCLES_PER_SEC + f.rotation_adjustment)
set dy = DISTANCE * Cos(PI_DOUBLE * f.time * CYCLES_PER_SEC + f.rotation_adjustment)
set dx = dy * Cos(f.facing + PI_HALF)
set dy = dy * Sin(f.facing + PI_HALF)
call SetUnitFlyHeight(f.ice,FLY_HEIGHT + DISTANCE + dz,0)
call SetUnitX(f.ice, f.caster_x + VELOCITY * f.time * Cos(f.facing) + dx)
call SetUnitY(f.ice, f.caster_y + VELOCITY * f.time * Sin(f.facing) + dy)
call SetUnitFlyHeight(f.fire, FLY_HEIGHT + DISTANCE - dz,0)
call SetUnitX(f.fire, f.caster_x + MODEL_ADJUSTMENT * Cos(f.facing) + VELOCITY * f.time * Cos(f.facing) - dx)
call SetUnitY(f.fire, f.caster_y + MODEL_ADJUSTMENT * Sin(f.facing) + VELOCITY * f.time * Sin(f.facing) - dy)
set f.time = f.time + SLIDE_PERIOD
set t = null
elseif f.slow_down_time <= FINAL_TIME and f.enough_range == true then
if f.checked == false then
set f.ice_x = GetUnitX(f.ice)
set f.ice_y = GetUnitY(f.ice)
set f.fire_x = GetUnitX(f.fire)
set f.fire_y = GetUnitY(f.fire)
set f.ice_height = GetUnitFlyHeight(f.ice)
set f.fire_height = GetUnitFlyHeight(f.fire)
set f.checked = true
endif
if f.slow_down_time <= SLOW_DOWN_TIME then
call SetUnitX(f.ice,f.ice_x + ((VELOCITY * f.slow_down_time + NEG_ACCELERATION * (f.slow_down_time * f.slow_down_time)) * Cos(f.facing)) + SIDE_ACCELERATION * (f.slow_down_time*f.slow_down_time) * Cos(f.facing + PI_HALF))
call SetUnitY(f.ice,f.ice_y + ((VELOCITY * f.slow_down_time + NEG_ACCELERATION * (f.slow_down_time * f.slow_down_time)) * Sin(f.facing)) + SIDE_ACCELERATION * (f.slow_down_time*f.slow_down_time) * Sin(f.facing + PI_HALF))
call SetUnitX(f.fire,f.fire_x + ((VELOCITY * f.slow_down_time + NEG_ACCELERATION * (f.slow_down_time * f.slow_down_time)) * Cos(f.facing)) + SIDE_ACCELERATION * (f.slow_down_time*f.slow_down_time) * Cos(f.facing - PI_HALF))
call SetUnitY(f.fire,f.fire_y + ((VELOCITY * f.slow_down_time + NEG_ACCELERATION * (f.slow_down_time * f.slow_down_time)) * Sin(f.facing)) + SIDE_ACCELERATION * (f.slow_down_time*f.slow_down_time) * Sin(f.facing - PI_HALF))
call SetUnitFlyHeight(f.ice,f.ice_height + RISE_UP_ACCELERATION * (f.slow_down_time * f.slow_down_time),0)
call SetUnitFlyHeight(f.fire,f.fire_height + RISE_UP_ACCELERATION * (f.slow_down_time * f.slow_down_time),0)
set f.slow_down_time = f.slow_down_time + SLIDE_PERIOD
elseif f.speed_up_time <= SPEED_UP_TIME then
if f.fall == false then
set f.ice_x = GetUnitX(f.ice)
set f.ice_y = GetUnitY(f.ice)
set f.fire_x = GetUnitX(f.fire)
set f.fire_y = GetUnitY(f.fire)
set f.ice_height = GetUnitFlyHeight(f.ice)
set f.fire_height = GetUnitFlyHeight(f.fire)
set f.fall = true
endif
call SetUnitX(f.ice,f.ice_x + ((SPEED_UP_SPEED * f.speed_up_time + POS_ACCELERATION * (f.speed_up_time * f.speed_up_time)) * Cos(f.facing)) + NEG_SIDE_ACCELERATION * (f.speed_up_time*f.speed_up_time) * Cos(f.facing + PI_HALF))
call SetUnitY(f.ice,f.ice_y + ((SPEED_UP_SPEED * f.speed_up_time + POS_ACCELERATION * (f.speed_up_time * f.speed_up_time)) * Sin(f.facing)) + NEG_SIDE_ACCELERATION * (f.speed_up_time*f.speed_up_time) * Sin(f.facing + PI_HALF))
call SetUnitX(f.fire,f.fire_x + ((SPEED_UP_SPEED * f.speed_up_time + POS_ACCELERATION * (f.speed_up_time * f.speed_up_time)) * Cos(f.facing)) + NEG_SIDE_ACCELERATION * (f.speed_up_time*f.speed_up_time) * Cos(f.facing - PI_HALF))
call SetUnitY(f.fire,f.fire_y + ((SPEED_UP_SPEED * f.speed_up_time + POS_ACCELERATION * (f.speed_up_time * f.speed_up_time)) * Sin(f.facing)) + NEG_SIDE_ACCELERATION * (f.speed_up_time*f.speed_up_time) * Sin(f.facing - PI_HALF))
call SetUnitFlyHeight(f.ice, f.ice_height + FALL_DOWN_ACCELERATION * (f.speed_up_time * f.speed_up_time),0)
call SetUnitFlyHeight(f.fire,f.fire_height + FALL_DOWN_ACCELERATION * (f.speed_up_time * f.speed_up_time),0)
set f.speed_up_time = f.speed_up_time + SLIDE_PERIOD
set t = null
else
call PauseTimer(t)
call DestroyTimer(t)
call f.destroy()
set t = null
endif
else
call PauseTimer(t)
call DestroyTimer(t)
call f.destroy()
set t = null
endif
endfunction
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == SPELL_ID
endfunction
private function Actions takes nothing returns nothing
local Fusion f = Fusion.create()
local timer t = CreateTimer()
call AttachStructFusion(t,f)
call TimerStart(t,SLIDE_PERIOD,true,function Callback)
set t = null
endfunction
private function InitTrig takes nothing returns nothing
local trigger trig = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trig,Condition(function Conditions))
call TriggerAddAction(trig,function Actions)
endfunction
endscope
Notes:
I updated the spell code but not the map itself yet. Will re-upload it after some other changes.
The reason I use a second dummy ability (entangle) to freeze the units is that it greatly reduces the amount of code AND provides a buff (hence making it disspellable) + making it really MUI in such a way, that the new freeze duration will override the old... as it is with entangle.
You better don't base the main dummy ability (something with a target location) of something, that can be cast anywhere, and hence outside the map because I did not add a function that checks whether everything is in playable map area. But I based my dummy ability on shockwave which can't target areas outside the map AND I've read on campaigns.net, that the next patch fixes the crashes through "SetUnitX()/Y()".
Implantation instructions can be read above the trigger in the map.
Changelog:
Code:
Mai 12 - Release
Aug 13 - Update
Give Credits to either GoGo-Boy or Na_Dann_Ma_GoGo if you use this spell in your map.
Have fun with testing and please give feedback!