So, recently I have started a thread regarding an issue with a spell I was making. Since then, I have essentially broken it beyond repair and decided to try to re-write it. So far, it's looking promising (I still have a LOT of optimization to do, but I like to get it to work before sweating the small stuff, something I didn't do before as I had no set path in mind for it).
The idea of the spell is simple. I lob a javelin which goes across the map and speeds up, increasing damage as it travels until it contacts a unit.
It's a little messy right now, but I will be improving it over time and hopefully get enough experience from this adventure to be able to create some truly interesting things and submit them to this website and hopefully get more involved in the community.
Here is the spell:
So there is the spell in all of its glory. Written in about 10-20 minutes as I had a path set in my mind. My current issues are these:
Functionality error: 2 dummies are created. One is on the caster, the other travels perfectly fine.
-So the spell works, but for some reason it creates a second dummy. I am 100% certain that it's not another trigger, so the problem lies here. From what I have seen it's because the function "Actions" is also the same function I use for its condition.
I believe I can fix this by simply moving the if/then statement away from all the actions and just storing a return there, but I'm not sure if that would actually work or just result in the spell not working at all. What is the standard for that? Removing the "TriggerAddAction" so that the trigger runs through the condition, or by doing what I said in the former.
Efficiency problem: Indexes are not recycled, but are destroyed.
-This problem is simply due to the fact that I don't know the best way to recycle indexes. Normally, this would be easy if a spell had a fixed amount of time it ran, but with a spell like this, if you cast it once, then one second later, the first one is not guaranteed to finish first, thus creating an issue. As such, it runs through ALL of the indexes ever used each time it is cast, even though previous ones had been destroyed.
I have started working around this issue by adding a minimum index (although I haven't fully implemented that yet), just so that it only runs through the index range I know is currently in-use. The problem I have then is just recycling the old indexes without breaking anything, seeing how it would be detrimental of the function of the ability if it was in the process of being cast and I reduced "Total" to re-use those older indexes. I am unsure on how to proceed with that.
Efficiency problem: Locations, polar projections, X & Ys.
-I have heard in the past that locations are inefficient. I would like to work around them if that is the case with X & Y locations. This is less of an issue as I have a general idea of how this would go, but I can't ever seem to get it right. This is something I feel I can research by myself, however, but any advice that may not be so obvious would be appreciated if any exist.
-------------
There are also lots of small issues (I pause the timer after one of the javelins finish, rather than after all of them. A problem I feel requires knowledge on recycling the indexes.) but I think I had highlighted the major ones I have ran into that I can't seem to find anything that elaborates on why it works. I hate copying if I can't understand it. I don't learn anything that way.
I would also like to apologize if I am a nuisance beforehand. 80% of the reason for this thread is to get some help and to understand these things better, and the other 20% is to understand my mistakes by trying to figure out what I may have done wrong.
Thanks ahead of time for any help.
The idea of the spell is simple. I lob a javelin which goes across the map and speeds up, increasing damage as it travels until it contacts a unit.
It's a little messy right now, but I will be improving it over time and hopefully get enough experience from this adventure to be able to create some truly interesting things and submit them to this website and hopefully get more involved in the community.
Here is the spell:
JASS:
scope MagicJavelin2 initializer Init
private struct Data
integer Ticks = 0
unit Caster
unit Dummy
real Angle
location CasterLoc
static method create takes nothing returns thistype
local thistype this = Data.allocate()
local location CastLoc = GetSpellTargetLoc()
set this.Caster = GetSpellAbilityUnit()
set this.CasterLoc = GetUnitLoc(this.Caster)
set this.Angle = AngleBetweenPoints(this.CasterLoc, CastLoc)
call RemoveLocation(CastLoc)
return this
endmethod
method destroy takes nothing returns nothing
set .Caster = null
set .Dummy = null
call RemoveLocation(.CasterLoc)
endmethod
endstruct
globals
private Data array D
private integer Total = 0
private timer ticker = CreateTimer()
private integer i
private integer min_index = 0
endglobals
private function Finish takes nothing returns nothing
if(i == min_index) then
set min_index = min_index + 1
endif
call D[i].destroy()
call PauseTimer(ticker)
endfunction
private function GroupActions takes nothing returns nothing
call UnitDamageTargetBJ( D[i].Caster, GetEnumUnit(), ( ( 50.00 + ( 75.00 * ( I2R(GetUnitAbilityLevel(D[i].Caster, 'A002')) - 1 ) ) ) + ( ( ( 100.00 + ( 150.00 * ( I2R(GetUnitAbilityLevel(D[i].Caster, 'A002')) - 1 ) ) ) * 0.03 ) * D[i].Ticks ) ), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
call RemoveUnit( D[i].Dummy )
call Finish()
endfunction
private function GroupConds takes nothing returns boolean
return (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false) and (IsUnitAliveBJ(GetFilterUnit()) == true) and (GetFilterUnit() != D[i].Dummy)
endfunction
private function Tick takes nothing returns nothing
local location DummyLoc
local location Offset
local group g
set i = 0
loop
set DummyLoc = GetUnitLoc(D[i].Dummy)
set Offset = PolarProjectionBJ(DummyLoc, ( 20.00 + ( 0.10 * D[i].Ticks ) ), D[i].Angle)
call SetUnitPositionLoc( D[i].Dummy, Offset )
set g = GetUnitsInRangeOfLocMatching(60.00, Offset, Condition(function GroupConds))
call RemoveLocation(DummyLoc)
call RemoveLocation(Offset)
call ForGroupBJ( g, function GroupActions )
call DestroyGroup(g)
set D[i].Ticks = D[i].Ticks + 1
exitwhen i >= Total
set i = i + 1
endloop
endfunction
private function Actions takes nothing returns boolean
local location Offset
if(GetSpellAbilityId() == 'A002') then
set D[Total] = Data.create()
set Offset = PolarProjectionBJ(D[Total].CasterLoc, 100.00, D[Total].Angle)
call CreateNUnitsAtLoc( 1, 'h001', GetOwningPlayer(D[Total].Caster), Offset, D[Total].Angle )
set D[Total].Dummy = GetLastCreatedUnit()
call RemoveLocation(Offset)
if(Total == 0) then
call TimerStart(ticker, 0.03, true, function Tick)
endif
return true
endif
return false
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Actions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
So there is the spell in all of its glory. Written in about 10-20 minutes as I had a path set in my mind. My current issues are these:
Functionality error: 2 dummies are created. One is on the caster, the other travels perfectly fine.
-So the spell works, but for some reason it creates a second dummy. I am 100% certain that it's not another trigger, so the problem lies here. From what I have seen it's because the function "Actions" is also the same function I use for its condition.
I believe I can fix this by simply moving the if/then statement away from all the actions and just storing a return there, but I'm not sure if that would actually work or just result in the spell not working at all. What is the standard for that? Removing the "TriggerAddAction" so that the trigger runs through the condition, or by doing what I said in the former.
Efficiency problem: Indexes are not recycled, but are destroyed.
-This problem is simply due to the fact that I don't know the best way to recycle indexes. Normally, this would be easy if a spell had a fixed amount of time it ran, but with a spell like this, if you cast it once, then one second later, the first one is not guaranteed to finish first, thus creating an issue. As such, it runs through ALL of the indexes ever used each time it is cast, even though previous ones had been destroyed.
I have started working around this issue by adding a minimum index (although I haven't fully implemented that yet), just so that it only runs through the index range I know is currently in-use. The problem I have then is just recycling the old indexes without breaking anything, seeing how it would be detrimental of the function of the ability if it was in the process of being cast and I reduced "Total" to re-use those older indexes. I am unsure on how to proceed with that.
Efficiency problem: Locations, polar projections, X & Ys.
-I have heard in the past that locations are inefficient. I would like to work around them if that is the case with X & Y locations. This is less of an issue as I have a general idea of how this would go, but I can't ever seem to get it right. This is something I feel I can research by myself, however, but any advice that may not be so obvious would be appreciated if any exist.
-------------
There are also lots of small issues (I pause the timer after one of the javelins finish, rather than after all of them. A problem I feel requires knowledge on recycling the indexes.) but I think I had highlighted the major ones I have ran into that I can't seem to find anything that elaborates on why it works. I hate copying if I can't understand it. I don't learn anything that way.
I would also like to apologize if I am a nuisance beforehand. 80% of the reason for this thread is to get some help and to understand these things better, and the other 20% is to understand my mistakes by trying to figure out what I may have done wrong.
Thanks ahead of time for any help.