| 10-30-2007, 10:24 PM | #1 |
This spell is supposed to make the caster dash towards the target and hurt units that get in the way. It uses local handle variables. Now, I'm wondering if this spell could be more efficient if I used something like Vexorian's Caster System or vJass? I'll learn vJass if it's that much better... JASS:function dashMove takes nothing returns nothing local timer t=GetExpiredTimer() local real Velocity=40 local real DamageRadius=100 local unit cast=GetHandleUnit(t,"cast") local unit targ=GetHandleUnit(t,"targ") local group g=CreateGroup() local group done=GetHandleGroup(t,"done") local real angle=GetHandleReal(t,"angle") local real damage=100 local real distance=GetHandleReal(t,"distance")+Velocity local real maxdistance=GetHandleReal(t,"maxdistance") local unit u call SetHandleReal(t,"distance",distance) call SetUnitX(cast,GetUnitX(cast)+Cos(bj_DEGTORAD*angle)*Velocity) call SetUnitY(cast,GetUnitY(cast)+Sin(bj_DEGTORAD*angle)*Velocity) call SetUnitFacing(cast,angle) call GroupEnumUnitsInRange(g,GetUnitX(cast),GetUnitY(cast),DamageRadius,null) set g=grouper(cast,g) loop set u=FirstOfGroup(g) exitwhen u==null call GroupRemoveUnit(g,u) if IsUnitInGroup(u,done)==false then call GroupAddUnit(done,u) call UnitDamageTargetBJ(cast,u,damage,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL) endif endloop call SetHandleHandle(t,"done",done) if distance>=maxdistance then call PauseTimer(t) call FlushHandleLocals(t) call DestroyTimer(t) call DestroyGroup(done) endif set t=null set cast=null set targ=null call DestroyGroup(g) set g=null set done=null set u=null endfunction function Trig_dash_Conditions takes nothing returns boolean return GetSpellAbilityId() == 'A03G' endfunction function Trig_dash_Actions takes nothing returns nothing local timer t=CreateTimer() local unit cast=GetTriggerUnit() local unit targ=GetSpellTargetUnit() local real angle=GetAngleBetweenPoints(GetUnitX(cast),GetUnitY(cast),GetUnitX(targ),GetUnitY(targ)) local group done=CreateGroup() call SetHandleHandle(t,"cast",cast) call SetHandleHandle(t,"targ",targ) call SetHandleHandle(t,"done",done) call SetHandleReal(t,"angle",angle) call SetHandleReal(t,"maxdistance",600) call SetHandleReal(t,"distance",0) call TimerStart(t,.03,true,function dashMove) call TriggerSleepAction(0) set t=null set cast=null set targ=null set done=null endfunction //=========================================================================== function InitTrig_dash takes nothing returns nothing set gg_trg_dash = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( gg_trg_dash, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( gg_trg_dash, Condition( function Trig_dash_Conditions ) ) call TriggerAddAction( gg_trg_dash, function Trig_dash_Actions ) endfunction |
| 10-31-2007, 12:02 AM | #2 |
Well you could make the Trig_dash_Conditions "return CONDITION" instead of the whole messy if. Otherwise it is fine or you could try to learn vJass because I've heard it is so much better (and it probably is but I don't know). P.S. For your first function you might also want to destroy "done" unit group, not just the "g" one. |
| 10-31-2007, 12:47 AM | #3 |
vJass would remove all those ugly SetHandleReal() and SetHandleHandle with 1 sexy SetHandleInteger(YourStruct). You can then save everything to your struct and get it all back later, increasing speed (since GameCache is slow). You could then create a stack out of those structs and not even need gamecache. Just make the structs into a stack and loop through the stack. This would also benefit as it would make the spell run off a single timer, for all instances (big kodos in today's day of jass). |
| 10-31-2007, 02:29 AM | #4 |
Sounds good. So SetHandleInteger(YourStruct) doesn't involve gamecache? |
| 10-31-2007, 03:51 AM | #5 |
That specifically would use gamecache, but there are struct attachment systems out there that use global arrays and otherwise to avoid the gamecache. |
| 10-31-2007, 04:29 AM | #6 |
or include a next and previous value in your struct and then create a global struct variable that would hold the first struct in a stack. I also created a simple stack feature which creates another struct which can be used as a simple stack. JASS://! textmacro STACK takes TYPE, NAME globals $NAME$Stack First$NAME$Stack endglobals struct $NAME$Stack $NAME$Stack next $NAME$Stack prev $TYPE$ current static method create takes $TYPE$ cur returns $NAME$Stack local $NAME$Stack s = $NAME$Stack.allocate() set s.current = cur set s.next = First$NAME$Stack set First$NAME$Stack.prev = s return s endmethod method onDestroy takes nothing returns nothing if .prev == null then // first of stack set First$NAME$Stack = .next set .next.prev = 0 else // middle or at end of stack set .next.prev = .prev set .prev.next = .next endif set .next = 0 set .prev = 0 endmethod endstruct //! endtextmacro so, to create a stack for a unit, you would do //! runtextmacro Stack(unit, Casters) and then you could do local CastersStack cs = CastersStack.create(SomeUnit) and it would add it to the stack. The same with structs. JASS:struct spelldata unit caster unit target integer level effect e // methods and what not endstruct //! call runtextmacro Stack(spelldata, Spell) function loop takes nothing returns nothing local SpellStack ss = FirstSpellStack local spelldata sd loop exitwhen ss == null set sd = ss.current // do stuff with your spell struct sd set ss = ss.next endloop endfunction And you get a stack to loop all your spells though. Of course it would be more efficent to include the stack in the struct, but you should get the idea. |
| 11-01-2007, 02:41 AM | #7 |
Ok, thanks for the help. How should I start making this spell in vJass? Do I create the spelldata struct in the actions of this trigger? And then start a timer that executes the loop function you provided? Should I recycle timers using CSSafety? I also put some other questions in if you don't mind answering them. JASS:struct spelldata unit caster unit target integer level effect e //I don't know exactly what to put here, basically everything I was attaching to the timer before? endstruct //! call runtextmacro Stack(spelldata, Spell) function loop takes nothing returns nothing local SpellStack ss = FirstSpellStack local spelldata sd loop exitwhen ss == null set sd = ss.current // do stuff with your spell struct sd // Do I put the stuff that dashMove does in here? set ss = ss.next endloop endfunction function Trig_dashstart_Conditions takes nothing returns boolean return GetSpellAbilityId() == 'A03G' endfunction function Trig_dashstart_Actions takes nothing returns nothing //create struct here? //start timer here? CSSafety? endfunction =========================================================================== function InitTrig_dashstart takes nothing returns nothing set gg_trg_dashstart = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( gg_trg_dashstart, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( gg_trg_dashstart, Condition( function Trig_dashstart_Conditions ) ) call TriggerAddAction( gg_trg_dashstart, function Trig_dashstart_Actions ) endfunction |
| 11-01-2007, 05:09 AM | #8 |
A struct is basically a group of variables. The variables declared after the header "struct spelldata" would be them. After that, you would put methods. Example: JASS:struct whatever unit caster static method create takes unit u returns whatever //will replace the normal create function local whatever w = whatever.allocate() // use allocate within a create method set w.caster = u return u endmethod method ChangeCaster takes unit u returns nothing // normal methods also take the struct as an arguemen (expressed with a . in front of the variables). set .caster = u endmethod method onDestroy takes nothing returns nothing set .caster = null endmethod endstruct function test takes nothing returns nothing local whatever w = whatever.create(GetTriggeringUnit()) call w.ChangeCaster(SomeOtherUnit) call w.destroy() endfunction Methods are used to modify values within the struct, or perform struct specific actions. You can also modify struct data directly by using set w.caster = SomeOtherUnit instead of the method. The the loop function, it is setup to use the struct variable sd for the actions. There you would manipulate all your struct data and perform your movements. So basically yes. The last comment, you would create the struct there and thats it. Since the spell is automatically added to the stack with the stack struct, it will be run off a global varaible. You may want to pause the timer when there are no spells to run, but its personal preference. If you are using a stack, it is not required to use CSSafety or CSCache since it only requires 1 timer and all the data is in a global stack (but local to each struct). I personally would recommend learning to code in vJass. It makes life a lot easier and your codes simpler, yet complex at the same time (more freedoms and more stream-lined/organized). You can read the JassNewGen manual either in the NewGen Folder or online here. Once you have converted your spell to vJass, post it here and I shall help you clean it up. If you have any questions before then, ask; although I don't want to make the code for you. Read the manual and even other guides in the tutorial section first. |
| 11-01-2007, 10:58 AM | #9 | |
Quote:
Hahaha! ![]() Uhmm, what is SetHandleInteger? Shouldn't it be SetHandleInt? |
| 11-01-2007, 02:33 PM | #10 |
I guess it should be. Just shows how much CSCache I really use since stacks are superior. |
| 11-01-2007, 08:18 PM | #11 |
Am I supposed to create a stack? Where should I do that? And should I start one global timer executing the loop function at map initialization? |
| 11-01-2007, 10:25 PM | #12 |
The stack should be created after the struct it is being used for. For the timer, you can do that for now. Once the spell is working, you can make it pause when the stack has no spells in it. |
| 11-02-2007, 12:54 AM | #13 |
I mean where should I put set FirstSpellStack=SpellStack.Create(sd)? In Trig_dash_Actions? |
| 11-02-2007, 02:09 AM | #14 |
First off, do not set the FirstSpellStack variable to anything since it is already being manipulated within the stack struct. You can set a variable to it though. Do not do:set FirstSpellStack = somestruct This is okaysomestruct = FirstSpellStack You should create a struct every time the spell is casted. JASS:struct spell unit caster real x real y real face method create takes unit u returns spell local spell s = spell.allocate() set s.caster = u endmethod endstruct //! runtextmacro Stack(spell, Spell) function Spell_cast_actions takes nothing returns nothing local unit u = GetSpellAbilityUnit() local spell s = spell.create(u) // our spell struct (not the stack struct) (also sets the caster when created) set spell.x = GetUnitX(u) set spell.y = GetUnitY(u) set spell.face = GetUnitFacing(u) call SpellStack.create(s) // creates the stack struct and adds the spell to the stack. endfunction Again, I don't mind helping you, but please try to completely create your code in vJass and then post it here. It will be easier for me to address all problems at once than one at a time. Also, it will give you a chance to figure it out yourself, since trial and error is one of the best methods of learning new things, besides guides* and manuals. *Guides: - vJass for Spell Makers - How to Create a New Object Type (vJass) - How to Properly Inline Text Macros - Text Macros in vJass |
| 11-02-2007, 02:35 AM | #15 |
Alright, this is my attempt. I get an error "Unitialized variable "FirstSpellStack" used in function "s__SpellStack_create" " when I cast the spell. JASS://! textmacro STACK takes TYPE, NAME globals $NAME$Stack First$NAME$Stack endglobals struct $NAME$Stack $NAME$Stack next $NAME$Stack prev $TYPE$ current static method create takes $TYPE$ cur returns $NAME$Stack local $NAME$Stack s = $NAME$Stack.allocate() set s.current = cur set s.next = First$NAME$Stack set First$NAME$Stack.prev = s return s endmethod method onDestroy takes nothing returns nothing if .prev == null then // first of stack set First$NAME$Stack = .next set .next.prev = 0 else // middle or at end of stack set .next.prev = .prev set .prev.next = .next endif set .next = 0 set .prev = 0 endmethod endstruct //! endtextmacro globals timer dashTimer=CreateTimer() endglobals struct spelldata unit cast real distance real maxdistance real velocity real angle group done group g real damageradius=100 real damage static method create takes unit cast, unit targ, real maxdistance, real velocity returns spelldata local spelldata w=spelldata.allocate() set w.cast=cast set w.distance=0 set w.maxdistance=maxdistance set w.velocity=velocity set w.angle=GetAngleBetweenPoints(GetUnitX(cast),GetUnitY(cast),GetUnitX(targ),GetUnitY(targ)) set w.done=CreateGroup() set w.g=CreateGroup() call BJDebugMsg("created spelldata") return w endmethod method onDestroy takes nothing returns nothing set .cast=null call DestroyGroup(.done) call DestroyGroup(.g) call BJDebugMsg("destroyed spelldata") endmethod endstruct //! runtextmacro STACK("spelldata", "Spell") function dashloop takes nothing returns nothing local SpellStack ss = FirstSpellStack local spelldata sd local unit u local real x local real y call BJDebugMsg("dashloop") loop exitwhen ss == null call BJDebugMsg("stack loop") set sd = ss.current set sd.distance=sd.distance+sd.velocity set x=GetUnitX(sd.cast)+Cos(bj_DEGTORAD*sd.angle)*sd.velocity set y=GetUnitY(sd.cast)+Sin(bj_DEGTORAD*sd.angle)*sd.velocity call SetUnitX(sd.cast,x) call SetUnitY(sd.cast,y) call SetUnitFacing(sd.cast,sd.angle) call GroupEnumUnitsInRange(sd.g,x,y,sd.damageradius,null) set sd.g=grouper(sd.cast,sd.g) loop set u=FirstOfGroup(sd.g) exitwhen u==null call GroupRemoveUnit(sd.g,u) call UnitDamageTargetBJ(sd.cast,u,sd.damage,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL) endloop if sd.distance>=sd.maxdistance then call sd.destroy() endif set u=null set ss = ss.next endloop endfunction function Trig_dashstart_Conditions takes nothing returns boolean return GetSpellAbilityId() == 'A000' endfunction function Trig_dashstart_Actions takes nothing returns nothing local unit cast=GetTriggerUnit() local unit targ=GetSpellTargetUnit() local spelldata sd=spelldata.create(cast,targ,600,40) call BJDebugMsg("start") set sd.damage=100 call SpellStack.create(sd) //call TimerStart(dashTimer,.03,true,function dashloop) set cast=null set targ=null endfunction function InitTrig_dashstart takes nothing returns nothing set gg_trg_dashstart = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( gg_trg_dashstart, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( gg_trg_dashstart, Condition( function Trig_dashstart_Conditions ) ) call TriggerAddAction( gg_trg_dashstart, function Trig_dashstart_Actions ) endfunction |
