Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
You the Blight archer Curse a target with a blight curse causing damge over time also spreading to other units
there will end up being a set of spells for the dark ranger credit to my friend hashjie
he made it for me and hopeful will teach me how to make things like this and to finshi how to finshi the set some day
unforently he has moved on to better coding
1.00 release
1.01 removed some unessery nulling
[jass=vjass]////////////////////////////////////////////////////////////////////
// Blight Curse V1.0 //
// Author: Hashjie //
// //
// //
// Credits: //
// - fireblasts //
// //
// for those of you wondering, I give fireblasts full permission //
// to upload this resource to the hive. he came up with the //
// original concept of the spell. //
// //
// //
// The spell works as followed: //
// Whenever a unit casts Blight Curse, all units within a //
// specified range of the target will get affected by a buff //
// that does damage over time. How much damage is done, how much //
// range it has, how much range it gains, the duration of the //
// spell, the number of units infected and the number of //
// infections gained per level are all configurable. Basically //
// this spell will infect units that come within range of the //
// unit it is casted on or are already in range. //
////////////////////////////////////////////////////////////////////
scope BlightCurse
globals
//--------------------------------------------------------------------------//
// CONFIGURATION //
//--------------------------------------------------------------------------//
// SPELL_ID: //
// The SPELL_ID is the raw code for the spell ability in the object editor. //
// To see rawcodes, press control+d inside the editor. //
//--------------------------------------------------------------------------//
constant integer SPELL_ID = 'A000'
//--------------------------------------------------------------------------//
// DUMMY_UNIT: //
// The DUMMY_UNIT is the raw code for the dumy unit that is used to cast the//
// blight dummy spell that adds the blight buff to the enemies. //
//--------------------------------------------------------------------------//
constant integer DUMMY_UNIT = 'h000'
//--------------------------------------------------------------------------//
// BUFF_ID: //
// The BUFF_ID is the rawcode of the buff that is applied to the infected //
// units. //
//--------------------------------------------------------------------------//
constant integer BUFF_ID = 'B000'
//--------------------------------------------------------------------------//
// EFFECT: //
// The EFFECT is the path to an effect that is created on the position of //
// the units that gets infected. //
//--------------------------------------------------------------------------//
constant string EFFECT = "Abilities\\Spells\\NightElf\\CorrosiveBreath\\ChimaeraAcidTargetArt.mdl"
//--------------------------------------------------------------------------//
// RANGE: //
// The RANGE is the initial range around the target where units can get //
// infected from. //
//--------------------------------------------------------------------------//
constant real RANGE = 300
//--------------------------------------------------------------------------//
// RANGE_PER_LEVEL: //
// The RANGE_PER_LEVEL indicates how much extra range is added each level //
// of the spell. //
//--------------------------------------------------------------------------//
constant real RANGE_PER_LEVEL = 50
//--------------------------------------------------------------------------//
// DAMAGE: //
// The DAMAGE is the amount of damage per second against the infected units.//
//--------------------------------------------------------------------------//
constant real DAMAGE = 20
//--------------------------------------------------------------------------//
// DURATION: //
// The DURATION is how long the spell lasts/untill the buff wears off. //
//--------------------------------------------------------------------------//
constant real DURATION = 10
//--------------------------------------------------------------------------//
// INFECTIONS: //
// The INFECTIONS is the inital amount of maximum infections the spell must //
// have. //
//--------------------------------------------------------------------------//
constant integer INFECTIONS = 5
//--------------------------------------------------------------------------//
// INFECTIONS_PER_LEVEL: //
// The INFECTIONS_PER_LEVEL is the amount of extra infections it can have //
// per level of the spell. //
//--------------------------------------------------------------------------//
constant integer INFECTIONS_PER_LEVEL = 1
//--------------------------------------------------------------------------//
// TIMEOUT: (WARNING) //
// Please leave this value as is and don't touch it. If you mess with this //
// value you will mess with the duration and interval of the spell. //
//--------------------------------------------------------------------------//
constant real TIMEOUT = 0.03125
endglobals
struct BlightCurse
private thistype next
private thistype prev
private static timer time = CreateTimer()
private integer tick1
private integer tick2
private integer level
private integer infections
private player owner
private unit caster
private unit target
private group targets
private group temp
private group swap
private boolean infected
private method destroy takes nothing returns nothing
local unit u
call this.deallocate()
set this.next.prev = this.prev
set this.prev.next = this.next
if this.next == 1 then
call PauseTimer(time)
endif
set this.caster = null
set this.target = null
set this.owner = null
loop
set u = FirstOfGroup(this.targets)
exitwhen u == null
call UnitRemoveAbility(u, BUFF_ID)
call GroupRemoveUnit(this.targets, u)
endloop
call DestroyGroup(this.targets)
call DestroyGroup(this.temp)
call DestroyGroup(this.swap)
endmethod
private static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
local unit u
local unit dummy
local real unitX
local real unitY
loop
exitwhen this == 0
if this.tick2 == DURATION then
call this.destroy()
endif
set this.tick1 = this.tick1 + 1
if this.tick1 == 4 then
if not this.infected then
set unitX = GetUnitX(this.target)
set unitY = GetUnitY(this.target)
call GroupEnumUnitsInRange(this.temp, unitX, unitY, RANGE + (this.level * RANGE_PER_LEVEL), null)
loop
set u = FirstOfGroup(this.temp)
exitwhen u == null
if GetUnitTypeId(u) != DUMMY_UNIT and GetWidgetLife(u) > 0 and IsUnitEnemy(u, this.owner) then
if this.infections < (INFECTIONS + (this.level * INFECTIONS_PER_LEVEL)) then
if GetUnitAbilityLevel(u, BUFF_ID) == 0 then
set unitX = GetUnitX(u)
set unitY = GetUnitY(u)
call DestroyEffect(AddSpecialEffect(EFFECT, unitX, unitY))
set dummy = CreateUnit(this.owner, DUMMY_UNIT, unitX, unitY, 0)
call UnitApplyTimedLife(dummy, 'BTLF', 1)
call IssueTargetOrder(dummy, "soulburn", u)
call GroupAddUnit(this.targets, u)
set this.infections = this.infections + 1
endif
elseif this.infections == (INFECTIONS + (this.level * INFECTIONS_PER_LEVEL)) then
set this.infected = true
endif
endif
call GroupRemoveUnit(this.temp, u)
endloop
endif
endif
if this.tick1 == 32 then
loop
set u = FirstOfGroup(this.targets)
exitwhen u == null
if GetUnitAbilityLevel(u, BUFF_ID) > 0 then
call UnitDamageTarget(this.caster, u, DAMAGE, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
call GroupAddUnit(this.temp, u)
call GroupRemoveUnit(this.targets, u)
endloop
set this.swap = this.targets
set this.targets = this.temp
set this.temp = this.swap
set this.tick2 = this.tick2 + 1
set this.tick1 = 0
endif
set this = this.next
endloop
set u = null
set dummy = null
endmethod
private static method run takes nothing returns boolean
local thistype this
local unit u
local unit dummy
local real unitX
local real unitY
if GetSpellAbilityId() == SPELL_ID then
set this = thistype.allocate()
set this.next = 0
set this.prev = thistype(0).prev
set thistype(0).prev.next = this
set thistype(0).prev = this
if this.next == 0 then
call TimerStart(time, TIMEOUT, true, function thistype.periodic)
endif
set this.caster = GetTriggerUnit()
set this.target = GetSpellTargetUnit()
set this.owner = GetTriggerPlayer()
set this.level = GetUnitAbilityLevel(this.caster, SPELL_ID)
set this.tick1 = 0
set this.tick2 = 0
set this.temp = CreateGroup()
set this.targets = CreateGroup()
set this.infections = 0
set this.infected = false
set unitX = GetUnitX(this.target)
set unitY = GetUnitY(this.target)
call DestroyEffect(AddSpecialEffect(EFFECT, unitX, unitY))
set dummy = CreateUnit(this.owner, DUMMY_UNIT, unitX, unitY, 0)
call UnitApplyTimedLife(dummy, 'BTLF', 1)
call IssueTargetOrder(dummy, "soulburn", this.target)
call GroupAddUnit(this.targets, this.target)
set this.infections = this.infections + 1
call GroupEnumUnitsInRange(this.temp, unitX, unitY, RANGE + (this.level * RANGE_PER_LEVEL), null)
loop
set u = FirstOfGroup(this.temp)
exitwhen u == null
if GetUnitTypeId(u) != DUMMY_UNIT and GetWidgetLife(u) > 0 and IsUnitEnemy(u, this.owner) then
if this.infections < (INFECTIONS + (this.level * INFECTIONS_PER_LEVEL)) then
if GetUnitAbilityLevel(u, BUFF_ID) == 0 then
set unitX = GetUnitX(u)
set unitY = GetUnitY(u)
call DestroyEffect(AddSpecialEffect(EFFECT, unitX, unitY))
set dummy = CreateUnit(this.owner, DUMMY_UNIT, unitX, unitY, 0)
call UnitApplyTimedLife(dummy, 'BTLF', 1)
call IssueTargetOrder(dummy, "soulburn", u)
call GroupAddUnit(this.targets, u)
set this.infections = this.infections + 1
endif
elseif this.infections == (INFECTIONS + (this.level * INFECTIONS_PER_LEVEL)) then
set this.infected = true
endif
endif
call GroupRemoveUnit(this.temp, u)
endloop
endif
set u = null
set dummy = null
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.run))
set t = null
endmethod
endstruct
endscope[/code]
BPower: The way you shift groups is not working ( You can test it by displaying the handle id of each group. You will realise you destroy 1 handle twice )
Your spell does not provide any tooltip, which is really unprofessional.
Cleanup your code...
BPower: The way you shift groups is not working ( You can test it by displaying the handle id of each group. You will realise you destroy 1 handle twice )
Your spell does not provide any tooltip, which is really unprofessional.
Cleanup your code, make a proper demo, then you can upload the new version.
If you need help with your code feel free to make a post in Triggers&Scripts
Hey, please provide a decent description of your spell.
Also you should add basic documentation. Especially when it comes
to configuration for the user, documentation becomes very important.
Sometimes it's better to use constant functions over constant values,
when it comes to certain aspects in configuration, for example for damage:
private static constant real DAMAGE = 20
->
JASS:
private constant function Damage takes integer level returns real
return 20. //*level for example can be used.
endfunction
x, and y coordinates of unit can stored into locals onCast.
In your enum you don't filter out for examle dead units.
You also might want filter for enemy units.
JASS:
private group targets
private group temp
private group swap
^Three groups for an instance can be avoided here.
Basicly:
Temporary enums only, then: private static group myGroup
-> is completly enough. No need to destroy/re-create it over and over again.
Need to keep track of certain units for each instance, then: private group myGroup
-> Now each instance has it's own group, that can be used for damage only once for example.
Your case is a bit special now, because you use the fresh swapping method
in combination with FoG loops. But here also static help groups can be used.
Read last chapter here: http://www.hiveworkshop.com/forums/...on-using-first-group-loop-enumeration-223140/
When it comes to checks if an expression is true or false, you don't
need to compare it with true or false explicitly.
Just let the expression for true, and for false use not before it.
You also don't say "it is rainy == true" -> "it is rainy"
You also don't say "it is rainy == false" -> "it is not rainy"
The extra comparison becomes redundant.
this.tick1 == 32
-> I guess you want to wait 1 second. But as the timeout is configurable,
the value in comparison also should depend on it, and should not be a hardcoded constant.
private static timer iterator = CreateTimer()
^Nothing serious, but I personaly think "iterator" is a strange name for a timer variable.
I personaly would go with just something like "tim", or "clock".
Agents, and only agents need to be nulled when they fall out of scope.
You don't null groups onDeindex, but instead following operations are not needed:
JASS:
set this.infected = FALSE
set this.tick1 = 0
set this.tick2 = 0
set this.level = 0
set this.infections = 0
An instance should probably be deindex if this.caster is not in game/not alive anymore. (?)
I see you are new on hive, so welcome on THW!
Please read the post carefuly before next update.
1.) Please put your code in a scope/library. Spells normally are scopes.
Encapsulation is very important to avoid code conflicts.
2.) You could add a small description above the configuration, explaining what the spell does.
The configuration part could be in a global block, to be better seperated from the rest of the code.
Furthermore the comments for the configuration part are poor made. i.e:
JASS:
private static constant real RANGE = 300
/// range///
3.) Using static integer count is repeated unnecessarily.
Instead make use of your linked list data structure if this.next == 0 then
2.) Store GetUnitX/Y into a local variable to reduce computation time.
( function calls are more expensive than variable look-ups )
3.) this.infected == false --> not this.infected
4.) Due to shifting groups back and forth you have a lot of group handle leaks.
Find a better solution. I quickly demonstrate the current problem
JASS:
group temp
group swap
group targets
--->
set swap = targets// ok
set targets = temp// ok
set temp = swap// means temp becomes original targets. Leak original swap handle.
-->
call DestroyGroup(targets)// Destroys temp
call DestroyGroup(temp)// Destroys targets
call DestroyGroup(swap)// Destroys targets
--> swap is never destroyed.
First off let me state that I give fireblasts full permission to upload this resource, I'm the one that coded it.
IcemanBo said:
^Three groups for an instance can be avoided here.
Basicly:
Temporary enums only, then: private static group myGroup
-> is completly enough. No need to destroy/re-create it over and over again.
Need to keep track of certain units for each instance, then: private group myGroup
-> Now each instance has it's own group, that can be used for damage only once for example.
Your case is a bit special now, because you use the fresh swapping method
in combination with FoG loops. But here also static help groups can be used.
Read last chapter here: http://www.hiveworkshop.com/forums/spells-569/blight-curse-1-01-a-266978/j...ration-223140/
Does this mean that this tutorial http://www.hiveworkshop.com/forums/...on-using-first-group-loop-enumeration-223140/ would have the same group leak?
I basically copied what was done there. I would like some clearance on how this can be avoided in the future. Perhaps what IcemanBo suggested can help but I still need some guidance on what exactly is meant with the static help group. I can't wrap my head around it.
IcemanBo said:
An instance should probably be deindex if this.caster is not in game/not alive anymore. (?)
The difference is in his tutorial he is using always the same global variables.
You are not using globals, but member of instances, so array. (global == static)
In here, each instance own 3 groups for it's own, which is not neeed for swap.
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.