- Joined
- Sep 29, 2006
- Messages
- 447
Grenade Type Spells
Okay I’m going to show you guys how to make a grenade type spell. This is not an introduction to dummy units or dummy spells, I’m assuming you know how to make them. You also need basic triggering knowledge for this.
What do I mean by this? Well, a grenade type spell (as far as I’m concerned) is a spell in which a unit throws a projectile to a target location, and then the projectile explodes, damaging everything in an area.
1. Setting Everything Up
Now, to do this we’re going to need to make three abilities, and 2 dummy units. Here’s the spells we’ll need:
The caster’s dummy ability (based off of channel)
A projectile ability for one dummy (based off of acid bomb)
An ability to deal the damage for the other dummy (based off of thunderclap)
Then we need two dummies:
A traditional dummy with the locust ability
A copy of that dummy, except without locust (I’ll explain why later)
Now at this point you may be asking yourself, “why not just trigger the damage?”
Well, here’s my answer. It’s much easier just to create a separate ability with all of the levels and damage amounts you want, and then order a dummy unit to cast it. Otherwise, we’d have to come up with some type of formula and use if/then/else statements to trigger the damage. I think that having a dummy use and ability is much easier. The only drawback to this is that there is spell damage reduction. However, since we’re making a spell that should happen anyway. Also, if you’re a fan of using raw data in tooltips, it makes it easier to change the tooltips. We also avoid using unit groups which is a plus.
Okay now on to the good stuff.
I’m assuming you know how to make dummy casters. So make them, give one locust and keep the other one without locust but all the same properties. You need one without locust because we’re going to have dummy 1 “acidbomb” dummy two; therefore, dummy 2 needs to be vulnerable.
So for the custom acid bomb spell, make it so that it deals no damage, has no duration, no AoE (very important), no negative effects, etc. the only thing we need is the projectile art. Set it to what you want. I prefer the Human Battleship projectile. Make sure the spell can target friends (VERY important). Make sure the mana cost and cooldown are 0 and such.
Now we need to make our thunderclap spell.
Q: Why are we using thunderclap and not warstomp?
A: Well, this is a matter of preference but, Thunderclap will not break channeling spells so if you set the duration to .01 the side effects will not take place. Also you can set the debuffs to 0.
So for thunderclap, set the targets to what you want (I have it set so that it can target ALL ground units). Set the debuffs to 0 (unless you want a disorienting grenade) and set the damage to what you want. Make sure the mana cost and cooldown are 0 and such.
Now we want to make our dummy ability for the caster, complete with mana, cooldown, and tooltips. I suggest using channel with a targeting image. Make sure the AoE of your dummy ability and thunderclap are the same!
Okay so our abilities and dummy units are all set, now its time to start triggering!
2. The Triggering
First we need to set up our basic spell trigger (I’ve titled my spell, Grenade Launch):
-
Grenade Launch
-
Events
- Unit - A unit Starts the effect of an ability
-
Conditions
- (Ability being cast) Equal to Grenade Launch (Heavy Machine Gunner)
-
Events
So here’s what our actions are going to look like for now
-
Actions
- Set TempPoint = (Position of (Triggering unit))
- Set TempPoint2 = (Target point of ability being cast)
- Unit - Create 1 dummy unit for (Owner of (Triggering unit)) at TempPoint facing Default building facing degrees
- Set TempUnit = (Last created unit)
- Unit - Add grenade projectile to TempUnit
- Unit - Add a 6.00 second Generic expiration timer to TempUnit
- Unit - Create 1 dummy unit (vulnerable) for (Owner of (Triggering unit)) at TempPoint2 facing Default building facing degrees
- Set TempUnit2 = (Last created unit)
- Unit - Add grenade explosion to TempUnit2
- Unit - Set level of grenade explosion for TempUnit2 to (Level of Grenade Launch (Heavy Machine Gunner) for (Triggering unit))
- Unit - Add a 6.00 second Generic expiration timer to TempUnit2
The next part of this trigger will be creating the projectile and dealing the damage. Now, what we’re going to do is order TempUnit to “acidbomb” TempUnit2. This will give us our projectile. Then we’re going to wait the distance between TempPoint and TempPoint2 divided by the projectile speed of the acid bomb projectile. Then we just order TempUnit2 to “thunderclap” and add some nifty special effects. Not too hard right. So lets take a look at the actions now:
-
Actions
- Set TempPoint = (Position of (Triggering unit))
- Set TempPoint2 = (Target point of ability being cast)
- Unit - Create 1 dummy unit for (Owner of (Triggering unit)) at TempPoint facing Default building facing degrees
- Set TempUnit = (Last created unit)
- Unit - Add grenade projectile to TempUnit
- Unit - Add a 6.00 second Generic expiration timer to TempUnit
- Unit - Create 1 dummy unit (vulnerable) for (Owner of (Triggering unit)) at TempPoint2 facing Default building facing degrees
- Set TempUnit2 = (Last created unit)
- Unit - Add grenade explosion to TempUnit2
- Unit - Set level of grenade explosion for TempUnit2 to (Level of Grenade Launch (Heavy Machine Gunner) for (Triggering unit))
- Unit - Add a 6.00 second Generic expiration timer to TempUnit2
- Unit - Order TempUnit to Neutral Alchemist - Acid Bomb TempUnit2
- Wait ((Distance between TempPoint and TempPoint2) / 700.00) seconds
- Unit - Order TempUnit2 to Human Mountain King - Thunder Clap
- Special Effect - Create a special effect at TempPoint2 using war3mapImported\ShrapnelShards.mdx
- Special Effect - Destroy (Last created special effect)
- Special Effect - Create a special effect at TempPoint2 using Abilities\Spells\Other\Incinerate\FireLordDeathExplode.mdl
- Special Effect - Destroy (Last created special effect)
- Special Effect - Create a special effect at TempPoint2 using war3mapImported\ShrapnelShards.mdx
Now just for one more thing. We need to remove all of those nasty leaks. So we add this to the end of the code:
- Custom script: call RemoveLocation(udg_TempPoint)
- Custom script: call RemoveLocation(udg_TempPoint2)
-
Grenade Launch
-
Events
- Unit - A unit Starts the effect of an ability
-
Conditions
- (Ability being cast) Equal to Grenade Launch (Heavy Machine Gunner)
-
Actions
- Set TempPoint = (Position of (Triggering unit))
- Set TempPoint2 = (Target point of ability being cast)
- Unit - Create 1 dummy unit for (Owner of (Triggering unit)) at TempPoint facing Default building facing degrees
- Set TempUnit = (Last created unit)
- Unit - Add grenade projectile to TempUnit
- Unit - Add a 6.00 second Generic expiration timer to TempUnit
- Unit - Create 1 dummy unit (vulnerable) for (Owner of (Triggering unit)) at TempPoint2 facing Default building facing degrees
- Set TempUnit2 = (Last created unit)
- Unit - Add grenade explosion to TempUnit2
- Unit - Set level of grenade explosion for TempUnit2 to (Level of Grenade Launch (Heavy Machine Gunner) for (Triggering unit))
- Unit - Add a 6.00 second Generic expiration timer to TempUnit2
- Unit - Order TempUnit to Neutral Alchemist - Acid Bomb TempUnit2
- Wait ((Distance between TempPoint and TempPoint2) / 700.00) seconds
- Unit - Order TempUnit2 to Human Mountain King - Thunder Clap
- Special Effect - Create a special effect at TempPoint2 using war3mapImported\ShrapnelShards.mdx
- Special Effect - Destroy (Last created special effect)
- Special Effect - Create a special effect at TempPoint2 using Abilities\Spells\Other\Incinerate\FireLordDeathExplode.mdl
- Special Effect - Destroy (Last created special effect)
- Custom script: call RemoveLocation(udg_TempPoint)
- Custom script: call RemoveLocation(udg_TempPoint2)
-
Events
3. Making it MUI
Don’t be frightened. This is extremely basic JASS and does not require any third party editor stuff like newgen or vJASS. THIS IS NOT AN INTRODUCTION TO JASS. So if that’s what you’re looking for please don’t read on, although I strongly believe that even those with no knowledge of JASS may be able to do this,
Okay, first things first, lets go to edit and convert out trigger to custom text (be sure to save a GUI copy). We should get something like this:
JASS:
function Trig_Grenade_Launch_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A00J' ) ) then
return false
endif
return true
endfunction
function Trig_Grenade_Launch_Actions takes nothing returns nothing
set udg_TempPoint = GetUnitLoc(GetTriggerUnit())
set udg_TempPoint2 = GetSpellTargetLoc()
call CreateNUnitsAtLoc( 1, 'h005', GetOwningPlayer(GetTriggerUnit()), udg_TempPoint, bj_UNIT_FACING )
set udg_TempUnit = GetLastCreatedUnit()
call UnitAddAbilityBJ( 'A00K', udg_TempUnit )
call UnitApplyTimedLifeBJ( 6.00, 'BTLF', udg_TempUnit )
call CreateNUnitsAtLoc( 1, 'h006', GetOwningPlayer(GetTriggerUnit()), udg_TempPoint2, bj_UNIT_FACING )
set udg_TempUnit2 = GetLastCreatedUnit()
call UnitAddAbilityBJ( 'A00L', udg_TempUnit2 )
call SetUnitAbilityLevelSwapped( 'A00L', udg_TempUnit2, GetUnitAbilityLevelSwapped('A00J', GetTriggerUnit()) )
call UnitApplyTimedLifeBJ( 6.00, 'BTLF', udg_TempUnit2 )
call IssueTargetOrderBJ( udg_TempUnit, "acidbomb", udg_TempUnit2 )
call TriggerSleepAction( ( DistanceBetweenPoints(udg_TempPoint, udg_TempPoint2) / 700.00 ) )
call IssueImmediateOrderBJ( udg_TempUnit2, "thunderclap" )
call AddSpecialEffectLocBJ( udg_TempPoint2, "war3mapImported\\ShrapnelShards.mdx" )
call DestroyEffectBJ( GetLastCreatedEffectBJ() )
call AddSpecialEffectLocBJ( udg_TempPoint2, "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl" )
call DestroyEffectBJ( GetLastCreatedEffectBJ() )
call RemoveLocation(udg_TempPoint)
call RemoveLocation(udg_TempPoint2)
endfunction
//===========================================================================
function InitTrig_Grenade_Launch takes nothing returns nothing
set gg_trg_Grenade_Launch = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Grenade_Launch, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Grenade_Launch, Condition( function Trig_Grenade_Launch_Conditions ) )
call TriggerAddAction( gg_trg_Grenade_Launch, function Trig_Grenade_Launch_Actions )
endfunction
Before we start, I feel I should mention raw codes in this tutorial. A raw code is a series of letters and numbers (kind of like a serial number) that refers to a unit, ability, doodad, etc. Raw codes, when dealing with custom units and abilities, are generated in order. for instance, your first custom unit will be named 'h000'. So if you look at the raw code for my dummy unit (which is 'h005'), you can see that it is the sixth custom unit I've created in my map. I'll list all of the raw codes I"M using. YOURS WILL BE DIFFERENT, so don't fret when you see that. Just swap my raw codes with yours. You can find the raw codes for your units and abilities by going to the object editor and hitting ctrl+D. Everything will convert to its raw code.
‘h005’ = the locust dummy unit
‘h006’ = the dummy unit that is vulnerable
'A00J' = the caster's channel ability
'A00K' = the acid bomb ability
'A00L' = the thunderclap spell
You'll notice that these seem to be in order. The units are by number, and the abilities by alphabet. Clearly, i created channel first, then acid bomb, then thunderclap. For hard-coded (already existing) spells, the raw codes will look different and will not be ordered like this. If you create a GUI trigger first and then convert it, the raw codes should all be in place and there will be no need to change them.
Now we may continue.
The first step to making this MUI (and really the only one) is to add in the local variables. So take a look at the section of the trigger that says:
JASS:
function Trig_Grenade_Launch_Actions takes nothing returns nothing
JASS:
local unit caster = GetTriggerUnit()
local unit TempUnit
local unit TempUnit2
local location TempPoint = GetUnitLoc(caster)
local location TempPoint2 = GetSpellTargetLoc()
For setting the TempUnits, you would have to set them immediately after they are created like so:
JASS:
call CreateNUnitsAtLoc( 1, 'h005', GetOwningPlayer(GetTriggerUnit()), udg_TempPoint, bj_UNIT_FACING )
set TempUnit = GetLastCreatedUnit()
So after replacing everything, your trigger should look like this:
JASS:
function Trig_Grenade_Launch_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A00J' ) ) then
return false
endif
return true
endfunction
function Trig_Grenade_Launch_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit TempUnit
local unit TempUnit2
local location TempPoint = GetUnitLoc(caster)
local location TempPoint2 = GetSpellTargetLoc()
call CreateNUnitsAtLoc( 1, 'h005', GetOwningPlayer(caster), TempPoint, bj_UNIT_FACING )
set TempUnit = GetLastCreatedUnit()
call UnitAddAbilityBJ( 'A00K', TempUnit )
call UnitApplyTimedLifeBJ( 6.00, 'BTLF', TempUnit )
call CreateNUnitsAtLoc( 1, 'h006', GetOwningPlayer(caster), TempPoint2, bj_UNIT_FACING )
set TempUnit2 = GetLastCreatedUnit()
call UnitAddAbilityBJ( 'A00L', TempUnit2 )
call SetUnitAbilityLevelSwapped( 'A00L', TempUnit2, GetUnitAbilityLevelSwapped('A00J', caster) )
call UnitApplyTimedLifeBJ( 6.00, 'BTLF', TempUnit2 )
call IssueTargetOrderBJ( TempUnit, "acidbomb", TempUnit2 )
call TriggerSleepAction( ( DistanceBetweenPoints(TempPoint, TempPoint2) / 700.00 ) )
call IssueImmediateOrderBJ( TempUnit2, "thunderclap" )
call AddSpecialEffectLocBJ( TempPoint2, "war3mapImported\\ShrapnelShards.mdx" )
call DestroyEffectBJ( GetLastCreatedEffectBJ() )
call AddSpecialEffectLocBJ( TempPoint2, "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl" )
call DestroyEffectBJ( GetLastCreatedEffectBJ() )
call RemoveLocation(TempPoint)
call RemoveLocation(TempPoint2)
set caster = null
set TempUnit = null
set TempUnit2 = null
endfunction
//===========================================================================
function InitTrig_Grenade_Launch takes nothing returns nothing
set gg_trg_Grenade_Launch = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Grenade_Launch, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Grenade_Launch, Condition( function Trig_Grenade_Launch_Conditions ) )
call TriggerAddAction( gg_trg_Grenade_Launch, function Trig_Grenade_Launch_Actions )
endfunction
Some of you may have noticed that I’ve added those three null lines at the end of the trigger. This is done to prevent them from leaking, it’s not mandatory, but it’s definitely good for your map and something you should do.
Okay so you’re done. Or are you? We’re going to take this a step further and make the code much more efficient. This section is for those slightly more experienced JASSers so if you feel uneasy, do not read on. Once again, I am not giving a full JASS tutorial, it is assumed that some of these things are already known to the reader.
4. Efficiency
All I’m going to do is swap some native functions for the BJ functions, and reduce that miserable conditions line.
Lets take a look at that condition function:
JASS:
function Trig_Grenade_Launch_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A00J' ) ) then
return false
endif
return true
endfunction
JASS:
function Trig_Grenade_Launch_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00J'
endfunction
Now I’m going to show you how to make setting the TempUnits more effective and how to more effectively destroy special effects. They have the same concepts, we’re going to be combining two lines into one.
So let’s take a look at these two lines:
JASS:
call CreateNUnitsAtLoc( 1, 'h005', GetOwningPlayer(caster), TempPoint, bj_UNIT_FACING )
set TempUnit = GetLastCreatedUnit()
JASS:
set TempUnit = CreateNUnitsAtLoc( 1, 'h005', GetOwningPlayer(caster), TempPoint, bj_UNIT_FACING )
JASS:
call DestroyEffectBJ( AddSpecialEffectLocBJ( TempPoint2, "war3mapImported\\ShrapnelShards.mdx" ) )
Now to swap for BJs with natives. You may have noticed that some functions have a BJ after, such as:
JASS:
call UnitAddAbilityBJ( 'A00K', TempUnit )
So the native function that UnitAddAbilityBJ calls is:
JASS:
call UnitAddAbility( TempUnit, 'A00K' )
JASS:
function Trig_Grenade_Launch_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00J'
endfunction
function Trig_Grenade_Launch_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit TempUnit
local unit TempUnit2
local location TempPoint = GetUnitLoc(caster)
local location TempPoint2 = GetSpellTargetLoc()
set TempUnit = CreateUnitAtLoc( GetOwningPlayer(caster), 'h005', TempPoint, 270.00 )
call UnitAddAbility( TempUnit, 'A00K' )
call UnitApplyTimedLife( TempUnit, 'BTLF', 6.00 )
set TempUnit2 = CreateUnitAtLoc( GetOwningPlayer(caster), 'h006', TempPoint2, 270.00 )
call UnitAddAbility( TempUnit2, 'A00L' )
call SetUnitAbilityLevel( TempUnit2, 'A00L', GetUnitAbilityLevel(caster, 'A00J') )
call UnitApplyTimedLife( TempUnit2, 'BTLF', 6.00 )
call IssueTargetOrder( TempUnit, "acidbomb", TempUnit2 )
call TriggerSleepAction( ( DistanceBetweenPoints(TempPoint, TempPoint2) / 650.00 ) )
call IssueImmediateOrder( TempUnit2, "thunderclap" )
call DestroyEffect( AddSpecialEffectLoc( "war3mapImported\\ShrapnelShards.mdx", TempPoint2 ) )
call DestroyEffect( AddSpecialEffectLoc( "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl", TempPoint2 ) )
call Rem oveLocation(TempPoint)
call RemoveLocation(TempPoint2)
set caster = null
set TempUnit = null
set TempUnit2 = null
endfunction
//===========================================================================
function InitTrig_Grenade_Launch takes nothing returns nothing
set gg_trg_Grenade_Launch = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Grenade_Launch, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Grenade_Launch, Condition( function Trig_Grenade_Launch_Conditions ) )
call TriggerAddAction( gg_trg_Grenade_Launch, function Trig_Grenade_Launch_Actions )
endfunction
The specific grenade ability we made in this tutorial is an ability for a hero of mine in my map Space Orcs!, an AoS style map which will be out for Beta testing very soon so keep a look out. This code can be imported straight into any map, just make sure you have the custom abilities, and dummies set in. The two things that you have to look for if you copy and paste are:
1) Change the raw codes of dummy units and abilities
2) Make sure you replace my imported custom effect with something else otherwise you WILL get an error!
Hope someone found this useful!
I've attached a test map for those of you who want to try out the ability. The raw codes and special effects in this map are different because i added it after I did the tutorial, but the fundamentals are exactly the same.
Credit for the Tauren Marine model in the screenshots goes to General_Frank
Credit for the Shrapnel Explosion model in the screenshots goes to Will_the_Almighty
Attachments
Last edited by a moderator: