GoGo-Boy
You can change this now in User CP
- Reaction score
- 40
GoGo-Boy aka Na_Dann_Ma_GoGo presents: MOLTEN MATTER
JASS: Yes.
vJASS: Yes.
MUI: Yes.
Laggless: Yes.
Leakless: Yes.
JESP: Hopefully, you got to tell me
Requires: NewGen Editor, ABCT Credits to Cohadar
The really nice testmap was made by Tinki3 and then edited by me to suit this certain spell testing.
Description:
This is a spell which can be used for dummy spells that are based of stuff that targets a location. A projectile will fly towards the targeted location and deals damage in a radius. While flying the projectile checks units in its range and little projectiles will spread out and target the checked units' location. This however only happens once to each unit. The little projectiles deal a minor damage in a minor radius. If the big projectile is in a certain range to it's impact location it will NOT release any further little balls, since that doesn't make any sense and I had to re-script quite a lot stuff to let the little projectiles fly on while the main one is already exploded.
Tooltip:
The caster throws a chunk of molten matter towards a targeted location. Whenever a units comes within 400 AOE of that liquid mass parts of the matter split and float to the units location (neither the big chunk nor the little chops FOLLOW a unit). On impact the little parts deal 15 * level damage while the big one can cause up to 75 * level damage in a certain radius. The more matter has been split the less damage the greater impact deals. A maximum of 15 matter chops can spread out before the main matter explodes without dealing any damage.
Level 1 - A chunk of molten matter that flies towards the targeted position and loses some matter, that target units. On impact the little chops deal 15 and the big matter ball up to 75 damage.
Level 2 - A chunk of molten matter that flies towards the targeted position and loses some matter, that target units. On impact the little chops deal 30 and the big matter ball up to 150 damage.
Level 3 - A chunk of molten matter that flies towards the targeted position and loses some matter, that target units. On impact the little chops deal 45 and the big matter ball up to 225 damage.
Screenshot:
Implantation can be read in an explanation above the trigger.
Here comes the code:
Changelog: Replaced GetUnitState(...) > 0 with GetWidgetLife(..) > 0
Remove an unnecessary timer and a global group is now used for all the loop stuff I do
Have fun testing it and please comment and critique me!! Probable this spell can be improved and yet does leak!
Give Credits!
PS: My first spell I submitted and in case my English isn't very well excuse me ^^
JASS: Yes.
vJASS: Yes.
MUI: Yes.
Laggless: Yes.
Leakless: Yes.
JESP: Hopefully, you got to tell me
Requires: NewGen Editor, ABCT Credits to Cohadar
The really nice testmap was made by Tinki3 and then edited by me to suit this certain spell testing.
Description:
This is a spell which can be used for dummy spells that are based of stuff that targets a location. A projectile will fly towards the targeted location and deals damage in a radius. While flying the projectile checks units in its range and little projectiles will spread out and target the checked units' location. This however only happens once to each unit. The little projectiles deal a minor damage in a minor radius. If the big projectile is in a certain range to it's impact location it will NOT release any further little balls, since that doesn't make any sense and I had to re-script quite a lot stuff to let the little projectiles fly on while the main one is already exploded.
Tooltip:
The caster throws a chunk of molten matter towards a targeted location. Whenever a units comes within 400 AOE of that liquid mass parts of the matter split and float to the units location (neither the big chunk nor the little chops FOLLOW a unit). On impact the little parts deal 15 * level damage while the big one can cause up to 75 * level damage in a certain radius. The more matter has been split the less damage the greater impact deals. A maximum of 15 matter chops can spread out before the main matter explodes without dealing any damage.
Level 1 - A chunk of molten matter that flies towards the targeted position and loses some matter, that target units. On impact the little chops deal 15 and the big matter ball up to 75 damage.
Level 2 - A chunk of molten matter that flies towards the targeted position and loses some matter, that target units. On impact the little chops deal 30 and the big matter ball up to 150 damage.
Level 3 - A chunk of molten matter that flies towards the targeted position and loses some matter, that target units. On impact the little chops deal 45 and the big matter ball up to 225 damage.
Screenshot:
Implantation can be read in an explanation above the trigger.
Here comes the code:
JASS:
scope MoltenMatter
globals
private constant integer FIREBALL_DUMMY = 039;u001039; // this dummy model must have the dummy.mdx model to work. It is included in the import manager+
private constant integer DUMMY_SPELL_ID = 039;A000039; // enter the correct ability ID of the ability you use
private constant string EXPLODE_PATH = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl" // model path for the impact effect of the main lavaball
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_UNIVERSAL // the damage type
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_CHAOS // the attack type
private constant real BIG_BALL_SIZE = 2.1 // the size of the main lavaball
private constant real SIZE_LOSS = 0.04 // this determinates the size loss of the main ball whenever little ones spread out
private constant real LITTLE_BALL_SIZE = 0.85 // the size of the spreeding lavaball
private constant real SPEED = 20 // distance amount the fireballs move per interval
private constant real LITTLE_SPEED = 20
private constant integer MAX_BALLS = 15 // determinates the amount of balls that can spread out of the big one, should NOT be set too high because the struct limit might struggle then
private constant real RADIUS = 400 // this is the radius in which little balls spread out of the main one and fly forwards enemy units
// better do NOT combine a low LITTLE_SPEED with a hugh RADIUS and high MAX_BALLS because that could end up laggy, since a lot units might be moved in some situations
private constant real BIG_DAMAGE_RADIUS = 300 // the damage radius for the main-impact
private constant real LITTLE_DAMAGE_RADIUS = 150 // same for the one of the little lavaballs
private constant real BIG_DAMAGE = 75 // AOE damage dealt on impact by the big lavaball
private constant real LITTLE_DAMAGE = 15 // the amount of AOE damage dealt by little lavaballs for each ability level (level 3 will deal 45...)
private constant real FIREBALL_FLIGHT_HEIGHT = 60 // fly high for all lavaballs, looks very well with 60 in my opinion
// please do NOT touch these globals because they're not variables that are made for being configurable rather for improving the performance or provide savety!!
private constant real SLIDE_PERIOD = 0.035 // interval in which the fireball moves [better don't change because 0.035 is smooth enough]
private player PLAYER // global player to filter out enemy units because you can't use GetTriggerPlayer/Unit() in filterfunctions that are called in a callback function
private group CHECK_GROUP // global group that is set in each callback function to ensure an easy filtering of units that are already hit --- similar to PLAYER above
private group GROUP = CreateGroup() // a global group to improve performance and perhaps even readability
private real MaxX // this x-value will prevent the fireball from leaving the map and thus crashing the game [set at MapInit as well]
private real MinX // " "
private real MaxY // " same with y "
private real MinY // " "
endglobals
// function to determinate the damage caused by the impact of the hugh lavaball added this to
// the top because some guys wanna might deal in damage in a certain way [e.g. with attributes]
private function Damage takes integer level, real RaiseTo returns real
return level * BIG_DAMAGE * Pow(0.95,R2I(RaiseTo))
endfunction
private function LittleDamage takes integer level returns real
return level * LITTLE_DAMAGE
endfunction
// filterfunction to filter units around the big lavaball that shall be targeted by little lavaballs
// simply add an extra "if ..... then " and for sure an "endif" afterwards, if you would like to add something
private function filt takes nothing returns boolean
local unit u = GetFilterUnit()
if IsUnitType(u,UNIT_TYPE_STRUCTURE) != true then
if GetWidgetLife(u) > 0 then
if IsUnitInGroup(u,CHECK_GROUP) != true then
if IsUnitEnemy(u,PLAYER) then
set u = null
return true
endif
endif
endif
endif
set u = null
return false
endfunction
// this function filters out the units that shall be damaged on little and big lava ball impacts
// again add an extra "if ..... then " and for sure an "endif" afterwards...
private function filtdamager 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
// ------------> STOP ADAPTING THINGS TO YOUR WISHES FROM HERE ON IF YOU ARE NOT EXPERIENCED ENOUGH!!! <---------
// functin to take care about SetUnitX/Y
private function InMap takes real x, real y returns boolean
return x >= MinX and x <= MaxX and y >= MinY and y <= MaxY
endfunction
private struct Fireball
real x
real y
real array l_x[MAX_BALLS] // arrays are used for the little lavaballs the "l_" - prefix means that these arrays are used for the little lavaballs
real array l_y[MAX_BALLS]
unit fireball
unit array ball[MAX_BALLS]
player owner
unit caster
real big_size = BIG_BALL_SIZE
integer level
integer ticks
integer no_more = R2I(BIG_DAMAGE_RADIUS / SPEED) // this is used to prevent little lavaballs from spreading out shortly before the impact, because they were destroyed then anyway...
integer array l_ticks[MAX_BALLS]
integer current_balls = 0
real facing
real array l_facing[MAX_BALLS]
group already_hit = CreateGroup()
static method create takes nothing returns Fireball
local Fireball data = Fireball.allocate()
local real x
local real y
local location l = GetSpellTargetLoc()
local real x2 = GetLocationX(l)
local real y2 = GetLocationY(l)
set data.caster = GetTriggerUnit()
set data.x = GetUnitX(data.caster)
set data.y = GetUnitY(data.caster)
set x = x2 - data.x
set y = y2 - data.y
set data.owner = GetTriggerPlayer()
set data.level = GetUnitAbilityLevel(data.caster,GetSpellAbilityId())
set data.facing = Atan2(y,x)
set data.fireball = CreateUnit(data.owner,FIREBALL_DUMMY,data.x,data.y,GetUnitFacing(data.caster))
set data.ticks = R2I(SquareRoot(x * x + y * y) / SPEED)
call SetUnitFlyHeight(data.fireball,FIREBALL_FLIGHT_HEIGHT,0)
call SetUnitScale(data.fireball,BIG_BALL_SIZE,BIG_BALL_SIZE,BIG_BALL_SIZE)
call RemoveLocation(l)
set l = null
return data
endmethod
method onDestroy takes nothing returns nothing
local integer index = 1
call DestroyGroup(.already_hit)
call KillUnit(.fireball)
set .fireball = null
set .caster = null
loop
call KillUnit(.ball[index])
set .ball[index] = null
set index = index + 1
exitwhen index == MAX_BALLS
endloop
endmethod
endstruct
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == DUMMY_SPELL_ID
endfunction
private function Callback takes nothing returns boolean
local Fireball data = ABCT_GetData()
local unit victim
local real x = data.x + SPEED * Cos(data.facing)
local real y = data.y + SPEED * Sin(data.facing)
local real l_x
local real l_y
local integer index = 0
local unit ball
set PLAYER = data.owner
set CHECK_GROUP = data.already_hit
if data.current_balls <= MAX_BALLS then
if data.ticks >= data.no_more then
call GroupEnumUnitsInRange(GROUP,data.x,data.y,RADIUS,Filter(function filt))
loop
set victim = FirstOfGroup(GROUP)
set index = data.current_balls
exitwhen victim == null // exitwhen victim == null means that the group is empty. That's why I don't use GroupClear()... but does it work without leaking that way??
set data.current_balls = data.current_balls + 1
set index = index + 1
set data.ball[index] = CreateUnit(data.owner,FIREBALL_DUMMY,data.x,data.y,bj_UNIT_FACING)
set data.big_size = data.big_size - SIZE_LOSS
set l_x = GetUnitX(victim) - data.x
set l_y = GetUnitY(victim) - data.y
set data.l_x[index] = data.x
set data.l_y[index] = data.y
set data.l_facing[index] = Atan2(l_y,l_x)
set data.l_ticks[index] = R2I(SquareRoot(l_x *l_x + l_y * l_y) / LITTLE_SPEED)
call GroupRemoveUnit(GROUP,victim) // unit removing
call GroupAddUnit(data.already_hit,victim)
call SetUnitFlyHeight(data.ball[index],FIREBALL_FLIGHT_HEIGHT,0)
call SetUnitScale(data.ball[index],LITTLE_BALL_SIZE,LITTLE_BALL_SIZE,LITTLE_BALL_SIZE)
endloop
endif
set index = 1
loop
exitwhen index > data.current_balls
if GetWidgetLife(data.ball[index]) >= 0.406 then
if data.l_ticks[index] >= 1 then
set data.l_x[index] = data.l_x[index] + LITTLE_SPEED * Cos(data.l_facing[index])
set data.l_y[index] = data.l_y[index] + LITTLE_SPEED * Sin(data.l_facing[index])
if InMap(data.l_x[index],data.l_y[index]) then
call SetUnitX(data.ball[index],data.l_x[index])
call SetUnitY(data.ball[index],data.l_y[index])
endif
set data.l_ticks[index] = data.l_ticks[index] - 1
else
call GroupEnumUnitsInRange(GROUP,data.l_x[index],data.l_y[index],LITTLE_DAMAGE_RADIUS,Filter(function filtdamager))
loop
set victim = FirstOfGroup(GROUP)
exitwhen victim == null
call GroupRemoveUnit(GROUP,victim)
call UnitDamageTarget(data.caster,victim,LittleDamage(data.level),false,false,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE_WHOKNOWS)
endloop
call KillUnit(data.ball[index])
endif
endif
set index = index + 1
endloop
if InMap(x,y) then
call SetUnitX(data.fireball,x)
call SetUnitY(data.fireball,y)
endif
call SetUnitScale(data.fireball,data.big_size,data.big_size,data.big_size)
set data.x = x
set data.y = y
set data.ticks = data.ticks - 1
if data.ticks <= 0 then
call GroupEnumUnitsInRange(GROUP,data.x,data.y,BIG_DAMAGE_RADIUS,Filter(function filtdamager))
loop
set victim = FirstOfGroup(GROUP)
exitwhen victim == null
call GroupRemoveUnit(GROUP,victim)
call UnitDamageTarget(data.caster,victim,Damage(data.level,R2I(data.current_balls)),false,false,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE_WHOKNOWS)
endloop
call DestroyEffect(AddSpecialEffect(EXPLODE_PATH,GetUnitX(data.fireball),GetUnitY(data.fireball)))
set ball = null
call data.destroy()
return true
endif
set ball = null
return false
endif
call data.destroy()
return true
endfunction
private function Actions takes nothing returns nothing
local Fireball data = Fireball.create()
call ABCT_Start(function Callback, data, SLIDE_PERIOD)
endfunction
public function InitTrig takes nothing returns nothing
local trigger trig = CreateTrigger()
set MinX = GetRectMinX(bj_mapInitialPlayableArea) + 100
set MaxX = GetRectMaxX(bj_mapInitialPlayableArea) - 100
set MinY = GetRectMinY(bj_mapInitialPlayableArea) + 100
set MaxY = GetRectMaxY(bj_mapInitialPlayableArea) - 100
call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trig, Condition(function Conditions))
call TriggerAddAction(trig, function Actions)
endfunction
endscope
Changelog: Replaced GetUnitState(...) > 0 with GetWidgetLife(..) > 0
Remove an unnecessary timer and a global group is now used for all the loop stuff I do
Have fun testing it and please comment and critique me!! Probable this spell can be improved and yet does leak!
Give Credits!
PS: My first spell I submitted and in case my English isn't very well excuse me ^^