Wc3C.net Spell Making Course: Part 1: Making a simple stomp spell.
 Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar

06-14-2006, 06:25 PM   #16
CrashLemon
User

Join Date: Jul 2005
Posts: 105

Submissions (2)

Quote:

Here is my code:
JASS:
```function Trig_Stomp_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction

function Stomp_Filter takes nothing returns boolean
return IsPlayerEnemy(GetOwningPlayer(GetTriggerUnit()), GetOwningPlayer(GetFilterUnit())) and GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING)
endfunction

function Stomp_CopyGroup takes group g returns group
endfunction

function Stomp_Move takes nothing returns nothing
local string s = I2S(H2I(GetExpiredTimer()))
local gamecache gc = udg_AbilityCache
local real x = GetStoredReal(gc, s, "x")
local real y = GetStoredReal(gc, s, "y")
local integer i = GetStoredInteger(gc, s, "level")
local group g = Stomp_CopyGroup(I2G(GetStoredInteger(gc, s, "group")))
local real dur = GetStoredReal(gc, s, "dur")+0.05
local real ux
local real uy
local real a
local unit f
if dur < 1+0.5*i then
loop
set f = FirstOfGroup(g)
exitwhen f == null
set ux = GetUnitX(f)
set uy = GetUnitY(f)
set a = Atan2(uy-y, ux-x)
call SetUnitPosition(f, ux+40*Cos(a), uy+40*Sin(a))
call GroupRemoveUnit(g, f)
endloop
call StoreReal(gc, s, "dur", dur)
else
call DestroyGroup(I2G(GetStoredInteger(gc, s, "group")))
call FlushStoredMission(gc, s)
call DestroyTimer(GetExpiredTimer())
endif
set gc = null
call DestroyGroup(g)
set g = null
set f = null
endfunction

function Trig_Stomp_Actions takes nothing returns nothing
local unit c = GetTriggerUnit()
local real x = GetUnitX(c)
local real y = GetUnitY(c)
local integer i = GetUnitAbilityLevel(c, 'A000')
local boolexpr b = Condition(function Stomp_Filter)
local group g = CreateGroup()
local group n
local unit f
local gamecache gc = udg_AbilityCache
local timer t = CreateTimer()
local string s = I2S(H2I(t))
call GroupEnumUnitsInRange(g, x, y, 100+50*i, b)
set n = Stomp_CopyGroup(g)
loop
set f = FirstOfGroup(n)
exitwhen f == null
call UnitDamageTarget(c, f, 25*i, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
call GroupRemoveUnit(n, f)
endloop
call StoreInteger(gc, s, "level", i)
call StoreInteger(gc, s, "group", H2I(g))
call StoreReal(gc, s, "x", x)
call StoreReal(gc, s, "y", y)
call TimerStart(t, 0.05, true, function Stomp_Move)
set c = null
call DestroyBoolExpr(b)
set b = null
set g = null
call DestroyGroup(n)
set n = null
set f = null
set gc = null
set t = null
endfunction

//===========================================================================
function InitTrig_Stomp takes nothing returns nothing
set gg_trg_Stomp = CreateTrigger(  )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Stomp, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Stomp, Condition( function Trig_Stomp_Conditions ) )
call TriggerAddAction( gg_trg_Stomp, function Trig_Stomp_Actions )
endfunction```

Here is the other trigger (the gamecache)
JASS:
```function InitTrig_InitCache takes nothing returns nothing
call FlushGameCache(InitGameCache("abilitycache.w3v"))
set udg_AbilityCache = InitGameCache("abilitycache.w3v")
endfunction```

When I tested it for the first time, it wasn't working... then I copied your code to see if it was mine but your code gave me the same errors...
I have the same Data Code A000 as yours...
__________________
I'm working on Automne RPG (Fall RPG). Its a french RPG and you can take a look at the terrain by cliking here.

Last edited by CrashLemon : 06-14-2006 at 06:26 PM.

 06-14-2006, 06:28 PM #17 Blade.dk .   Respected User   Join Date: May 2005 Posts: 1,990 Submissions (15) Are you sure you have the return bug exploiters? Because that seems to be a good reason as to why it does not work. They are in the tutorial, and it tells you to create them. Make sure that you have them, and that they are above the other code (they should be in the custom script section). __________________ Spell Making Course: Part 1: Making a simple stomp spell. I wonder if I'll ever finish part 2.
06-14-2006, 06:32 PM   #18
CrashLemon
User

Join Date: Jul 2005
Posts: 105

Submissions (2)

Quote:
 Originally Posted by Blade.dk Are you sure you have the return bug exploiters? Because that seems to be a good reason as to why it does not work. They are in the tutorial, and it tells you to create them. Make sure that you have them, and that they are above the other code (they should be in the custom script section).

Awww.. this was the error. Thank you to be patient with me tough. Next time I think i'll need to reread some parts of the Tutorial.
__________________
I'm working on Automne RPG (Fall RPG). Its a french RPG and you can take a look at the terrain by cliking here.

 06-14-2006, 06:44 PM #19 Blade.dk .   Respected User   Join Date: May 2005 Posts: 1,990 Submissions (15) No problem :). Glad if it works. __________________ Spell Making Course: Part 1: Making a simple stomp spell. I wonder if I'll ever finish part 2.
06-25-2006, 10:17 PM   #20
Themerion
Brahms-fan

Join Date: Jan 2006
Posts: 642

Submissions (2)

How would the performance of this spell be affected if we altered it; so that the trigonometric functions was only used in the initialization of the loop?

Right now, for each time the loop runs, the knockback recalculates the angle. It also recalculates the x-pos update and the y-pos update. This means that for each unit every time the loop is run, three trigonometric functions are executed: Atan2, Cos and Sin. Usually, solving trigonometric equations require algorithms which might be quite heavy to use (compared to more simple math, such as addition and division).

However, the angle, doesn't need to be recalculated as it is constant, because units are moving in a straight line from the casting point. Therefore, the update in x and y for each loop doesn't need to be recalculated either (but for speed in the enhanched version), as it is the same. So what if we added the update in x and y to each unit with GC-variables, instead of recalculating everything all the time?

Unfortunately, I've read that Game Cache calls like:
JASS:
`I2S(H2I(GetAnyHandle()))`
are not too quick either.

So, how would it affect the prestanda of the spell?

Something like this:
JASS:
```function Stomp_Move takes nothing returns nothing
local string as = I2S(Stom_SpellId())
local string us
// Cut
local real p = GetStoredReal(gc, s, "speed")-0.5/(1+0.5*i)

loop
// f is the "EnumUnit"
set ux = GetUnitX(f)
set uy = GetUnitY(f)
set us = I2S(H2I(f))
set dx = GetStoredInteger(gc, us, as + "_dx")
set dy = GetStoredInteger(gc, us, as + "_dy")
call SetUnitPosition(f, ux+p*dx, uy+p*dy)
// Cut :P
endloop
call StoreReal(gc, s, "speed", p)
// Cut more... :D
endfunction

function Trig_Stomp_Actions takes nothing returns nothing
local string as = I2S(Stom_SpellId())
local string us
local real dx
local real dy
// Cut...
loop
// f is the "EnumUnit"
set us = I2S(H2I(f))
call StoreReal(gc, us, as + "_dx",dx)
call StoreReal(gc, us, as + "_dy",dy)
endloop
// Cut... =)
endfunction```
__________________
Submissions::
 (v)JASS Tutorial Covers how to make fast and safe coding for common tasks in vJASS/JASS. Creep Respawn System It has never been easier to respawn creep groups...

Last edited by Themerion : 06-25-2006 at 10:19 PM.

 06-26-2006, 01:31 AM #21 PipeDream Moderator   Code Moderator   Join Date: Feb 2006 Posts: 1,405 Submissions (6) The trig functions are really quite fast. On x86 they're even a CPU instruction, although I can't show whether blizzard uses that hardware. Work wise a hash table access is pretty much equal. We can ignore the I2S(HtoI()) cost since we have to do that anyway, but it still has to hash some strings. Most of the work in executing warcraft code is the parser. The less characters it chomps through, the better. __________________
06-26-2006, 02:11 AM   #22
Themerion
Brahms-fan

Join Date: Jan 2006
Posts: 642

Submissions (2)

Quote:
 Originally Posted by PipeDream The trig functions are really quite fast. On x86 they're even a CPU instruction, although I can't show whether blizzard uses that hardware. Work wise a hash table access is pretty much equal. We can ignore the I2S(HtoI()) cost since we have to do that anyway, but it still has to hash some strings. Most of the work in executing warcraft code is the parser. The less characters it chomps through, the better.

Okay, thanks. Then I can feel free to use whichever method I like best

This really is a good tutorial btw. It covers lots of useful things
__________________
Submissions::
 (v)JASS Tutorial Covers how to make fast and safe coding for common tasks in vJASS/JASS. Creep Respawn System It has never been easier to respawn creep groups...

 08-27-2006, 04:57 AM #23 taste User     Join Date: Aug 2006 Posts: 12 hi..thanks for the great tutorial even though to be honest.. it was in no way a 'simple' stomp spell for a beginner like me. there's something i'm wondering though, is using gamecache the only way to make a spell multi-instancible? i thought you could just stick to using local variables to ensure that your trigger executes for that particular instance only.. or did i think wrong?
 10-17-2006, 07:18 PM #24 aidan_124 User   Join Date: Oct 2006 Posts: 47 I'm trying to do this...but get a major error on the Game Cache. Here is the trigger: JASS:```function InitTrig_InitCache takes nothing returns nothing call FlushGameCache(InitGameCache("abilitycache.w3v")) set udg_AbilityCache = InitGameCache("abilitycache.w3v") endfunction ``` I'm using WEU and it is moaning about there not being a variable name on the first line, and then moans in the other trigger when i try to use my game cache...am i missing something?
01-10-2007, 02:04 AM   #25
Joker
User

Join Date: Sep 2006
Posts: 687

Quote:
 Originally Posted by taste hi..thanks for the great tutorial even though to be honest.. it was in no way a 'simple' stomp spell for a beginner like me. there's something i'm wondering though, is using gamecache the only way to make a spell multi-instancible? i thought you could just stick to using local variables to ensure that your trigger executes for that particular instance only.. or did i think wrong?
Yes, gamecaches are the only way to make it MUI

 02-04-2007, 03:42 AM #26 deathreaper945 User   Join Date: Feb 2006 Posts: 11 I've been going through this several times...no damages, no movements or anything..I had errors for first few times, but once I got it, no damage. >< Stomp Trigger: JASS:```function Trig_Stomp_Conditions takes nothing returns boolean return GetSpellAbilityId() == 'A0ws' endfunction function Stomp_Filter takes nothing returns boolean return IsPlayerEnemy(GetOwningPlayer(GetTriggerUnit()), GetOwningPlayer(GetFilterUnit())) and GetWidgetLife(GetFilterUnit()) > 0.405 and not IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING) endfunction function Stomp_CopyGroup takes group g returns group set bj_groupAddGroupDest = CreateGroup() call ForGroup(g, function GroupAddGroupEnum) return bj_groupAddGroupDest endfunction function Stomp_Move takes nothing returns nothing local string s = I2S(H2I(GetExpiredTimer())) local gamecache gc = udg_AbilityCache local real x = GetStoredReal(gc, s, "x") local real y = GetStoredReal(gc, s, "y") local integer i = GetStoredInteger(gc, s, "level") local group g = Stomp_CopyGroup(I2G(GetStoredInteger(gc, s, "group"))) local real dur = GetStoredReal(gc, s, "dur")+0.05 local real ux local real uy local real a local unit f local real p = GetStoredReal(gc, s, "speed")-0.5/(1+0.5*i) local real fx = GetStoredReal(gc, s, "fx")+0.05 if dur < 1+0.5*i then loop set f = FirstOfGroup(g) exitwhen f == null set ux = GetUnitX(f) set uy = GetUnitY(f) set a = Atan2(uy-y, ux-x) call SetUnitPosition(f, ux+p*Cos(a), uy+p*Sin(a)) if fx >= 1 then call DestroyEffect(AddSpecialEffectTarget(GetAbilityEffectById('A0ws', EFFECT_TYPE_MISSILE, 1), f, GetAbilityEffectById('A0ws', EFFECT_TYPE_MISSILE, 2))) endif call GroupRemoveUnit(g, f) endloop call StoreReal(gc, s, "dur", dur) call StoreReal(gc, s, "speed", p) call StoreReal(gc, s, "fx", fx) if fx >= 1 then call StoreReal(gc, s, "fx", 0) endif else call DestroyGroup(I2G(GetStoredInteger(gc, s, "group"))) call FlushStoredMission(gc, s) call DestroyTimer(GetExpiredTimer()) endif set gc = null call DestroyGroup(g) set g = null set f = null endfunction function Trig_Stomp_Actions takes nothing returns nothing local unit c = GetTriggerUnit() local real x = GetUnitX(c) local real y = GetUnitY(c) local integer i = GetUnitAbilityLevel(c, 'A0ws') local boolexpr b = Condition(function Stomp_Filter) local group g = CreateGroup() local group n local unit f local gamecache gc = udg_AbilityCache local timer t = CreateTimer() local string s = I2S(H2I(t)) call DestroyEffect(AddSpecialEffect(GetAbilityEffectById('A0ws', EFFECT_TYPE_MISSILE, 0), x, y)) call GroupEnumUnitsInRange(g, x, y, 100+50*i, b) set n = Stomp_CopyGroup(g) loop set f = FirstOfGroup(n) exitwhen f == null call UnitDamageTarget(c, f, 25*i, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null) call GroupRemoveUnit(n, f) endloop call StoreInteger(gc, s, "level", i) call StoreInteger(gc, s, "group", H2I(g)) call StoreReal(gc, s, "x", x) call StoreReal(gc, s, "y", y) call TimerStart(t, 0.05, true, function Stomp_Move) set c = null call DestroyBoolExpr(b) set b = null set g = null call DestroyGroup(n) set n = null set f = null set gc = null set t = null endfunction //=========================================================================== function InitTrig_Stomp takes nothing returns nothing set gg_trg_Stomp = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( gg_trg_Stomp, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( gg_trg_Stomp, Condition( function Trig_Stomp_Conditions ) ) call TriggerAddAction( gg_trg_Stomp, function Trig_Stomp_Actions ) call Preload(GetAbilityEffectById('A0ws', EFFECT_TYPE_MISSILE, 0)) call Preload(GetAbilityEffectById('A0ws', EFFECT_TYPE_MISSILE, 1)) endfunction``` InitCache Trigger: JASS:```function InitTrig_InitCache takes nothing returns nothing call FlushGameCache(InitGameCache("abilitycache.w3v")) set udg_AbilityCache = InitGameCache("abilitycache.w3v") endfunction ``` And last, Custom Script: JASS:```function H2I takes handle h returns integer return h return 0 endfunction function I2G takes integer i returns group return i return null endfunction``` P.S. I used JassCraft also. Sorry for bump. Last edited by deathreaper945 : 02-04-2007 at 03:45 AM.
 02-13-2007, 02:18 PM #27 kixer User     Join Date: Jan 2007 Posts: 4 Thanks for the great tut.... kinda helped me understand gamecaches but it didnt actualy work... No knockback for some reason... __________________ This is what i have every morning
 08-26-2007, 10:26 AM #28 frozenthrone2000 User   Join Date: Apr 2007 Posts: 14 Hey, nice tutorial you've got here! The explanations are easy to understand, but when I actually tried to follow the instructions, I encountered 40+ errors. Most are expected somethings (endloops, etc.) BTW, in the function where it returns the ability code, i.e. 'A000', is the return value really an integer?
08-26-2007, 10:31 PM   #29
Pyrogasm

Respected User

Join Date: Sep 2006
Posts: 4,523

Submissions (9)

Yes, it's just very, very large.
__________________
Quote:
 Originally posted by Rising_Dusk Your spells are mostly ignored because they are not very cool so we aren't very excited to review/approve them, but you are incredibly persistent and won't give us an excuse to graveyard it. That is generally what results in a resource being ignored for a long time.

The Spell Request ThreadDone for, unless someone else wants to revive it...
It lasted a damn long time.

Quote:
 Originally posted by Kyrbi0 Huh. Almost makes me wish I had a girlfriend, to take advantage of today (wait, no, that's not what I meant... I mean, take advantage of the fact that it is international women's day... gah, never mind).
Quote:
 Originally posted by Pyrogasm Rome may not have been built in a day, but the Romans sure as hell didn't say "look at this great city we built guys!" when they had nothing more than a bit of stone and some cottages.

 08-28-2007, 01:33 AM #30 frozenthrone2000 User   Join Date: Apr 2007 Posts: 14 Oh, thanks for enlightening me on that. BTW, I also had another problem regarding the UnitDamageTarget(...)... If it's really a function, why is it not highlighted when I used the JASS Highlighter for Notepad++ and in JASSCraft? I also tried this in the WE, but no dice. It tells me 'bout "expecting a function" or something. What's wrong?