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!
Hey everyone, this is the official thread for spell creation!
Any format is welcome since we will attempt to fix it.
If you can, please make sure that the spells you create are:
(- MUI)
- Leakless (most important)
- Optimized
I've finished Eye of God (Septimus) and Burning Meteor (Amigurumi). (Yeah, I did the easier ones first. )
Just a note for Eye of God, the special effect doesn't seem to work well since there's a small delay before the laser strike is actually shown. Should I add a delay before damage is actually done? (The effect also doesn't have a sound effect.)
I'm working on Volcano Skin (DonDustin).
I'll edit this post with the map of those three spells when I finish.
Edit: Okay I finished those 3 spells.
I used any imported resources the hero creators wanted me to use.
I couldn't download the icon for Volcano Skin since the resource was unavailable.
Used libraries:
ABuff
GroupUtils
SpellEvent
Table
TimerUtils
xe system
Used Buffs: (In case of conflicting)
Cripple
Unholy Frenzy
Hmm we have a DamageEvent & DamageModifiers script defined by Anachron to use.
I suggest using Rising_Dusk's Intuitive Damage Detection System.
Link: http://www.wc3c.net/showthread.php?t=100618
Hell no... you can't even make decent shields with that crap to prevent damage. Besides, ABuff uses ADamage, which is why we decided to use it on the first place. You should NOT have two Damage Detection systems in the same project, as there will be conflicts. Either use one, or use the other, but NOT the two of them. I strongly suggest you toss anything Rising_Dusk may have done to the garbage.
Perhaps you guys could post some code ?
I would like some quick reviews for the simple spells in order to optimize them a little further.
Hell no... you can't even make decent shields with that crap to prevent damage. Besides, ABuff uses ADamage, which is why we decided to use it on the first place. You should NOT have two Damage Detection systems in the same project, as there will be conflicts. Either use one, or use the other, but NOT the two of them. I strongly suggest you toss anything Rising_Dusk may have done to the garbage.
Actually, ABuff uses DamageEvent & DamageModifiers now.
It looks like DamageEvent can support IDDS in that it will interface with IDDS and not create its own damage detection triggers.
Actually, ABuff uses DamageEvent & DamageModifiers now.
It looks like DamageEvent can support IDDS in that it will interface with IDDS and not create its own damage detection triggers.
The problem with IDDS is that it does not allow you to create a shield spell (per example) because it is not meant to reduce damage but only to change it's type and amplify it. I had this problem in the early version of IDDS and that's why Rising_Dusk created a module to create shields (which didn't work properly iirc, dunoo if it is fixed now).
If you want to make shield spells I am quite sure you will be forced to use DamageModifiers because IIDS does not support shields. That's why ABuff is way better with DamageModifiers and not with IDDS.
And let us not forget that DamageEvent interfaces with IDDS and not with the other system of shields, thus not working properly. Correct me if I am wrong.
I strongly recommend you to use DamageEvent with DamageModifiers module. It is not hard and if you are in trouble I am sure I can give you some tips by reading the documentation.
Besides, it has the bonus of interacting shields with ABuff.
As for the preloading system, I suggest using xepreload. watermelon_1234 is already using the xe system, there is no reason to not use the preload module xe already offers.
Btw, may I ask why you need xe watermelon_1234? Because we are using Anachron's projectile system to simulate projectiles. Just making sure
I see your point watermelon_1234.
We have to give one thing in order to gain another. I think that being able to block damage is more important than being able to deal damage differently. Wc3 already has a lot of custom damage types we can use anyway. Magic damage ftw
Anachron allows for AutoIndex in the systems to use. Personally I see it as a waste because you can do everything with Table without ever needing AutoIndex in a project but it is your choice.
I agree with watermelon_1234, I would choose the Table version if I were you.
I am doubting to use so many customization.
Anachron really let me down.
I can lead this project because I have an average (+professional, depending on the resource/field) knowledge of most customizations in the world editor.
My knowledge for using those systems isn't that great. Don't get me wrong, I know how it works and how to use it but I'm afraid everything will fall on my back.
I know that I have these awesome people around me who help, but they can't help me like forever. And not everyone knows how to use a system like that.
In my case, I would like to focus on finishing the hero spells and continue to an alpha version with or without advanced systems. Because, what for are we using it anyway?
Such as the ultimate for M0rbid's hero, which is approved btw. Such as every type of channeling spell as well.
If you fear you don't understand things, I will explain them to you. They are not that hard to understand and you are a pretty smart boy.
Oh, and I forgot: spells that have projectiles will also use the system. Just checking
Everything is needed, otherwise we wouldn't have suggested it.
I finished easy spells again: Heroic Offer (Jaret) and Obliterate Mind (Xerex)
Before I upload these super easy spells, I'm trying to finish Soul Harvest (Xerex). I'm having fun trying to prevent any kind of problems/bugs that can come up. (I'm trying to make it support Tome of Retraining and make it give the correct bonus)
For those that are curious about the code or can help me improve it (There probably is a lot that can be improved) I've put the code here.
I will update this post with a map when I'm done.
Okay, I think I fixed the spell. I won't bother posting the code for the first two spells since they're pretty pathetically easy and I doubt there will be much code optimization.
JASS:
//==========================================================================================
//Soul Harvest (Xerex) by watermelon_1234
//__________________________________________________________________________________________
//Description:
// Corpses within 500 range of Dark Lord will bolster his offensive power.
//******************************************************************************************
//Libraries required:
// - BonusMod
// - GroupUtils
// - TimerUtils
//##########################################################################################
//Importing:
// 1. Copy the ability, Soul Harvest, and its buff.
// 2. Copy this trigger.
// 3. Implement required libraries.
// 4. Configure the spell.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Notes:
// Probably will recode this if we use an Aura system.
// The level check may be inefficient as it always update to that manually. The nice thing
// is that this spell supports Tome of Retraining.
//==========================================================================================
scope SoulHarvest
native UnitAlive takes unit id returns boolean //A better way to check if a unit is alive.
globals
private constant integer SPELL_ID = 'A005' //Raw id of the Soul Harvest ability.
private constant real TIMER_LOOP = 0.15 //How often the timer will loop.
private boolexpr e
endglobals
//The range of the ability which enumerates corpses.
private constant function Range takes integer lvl returns real
return 500. + 0*lvl
endfunction
//The damage bonus gained for each corpse.
private constant function DamageBonus takes integer lvl returns integer
return 2 + 2*lvl
endfunction
//The max damage bonus that one can get from this ability.
private constant function MaxDamageBonus takes integer lvl returns integer
return 70 + 0*lvl
endfunction
private struct Data
unit hero //The hero that learned the ability
integer lvl = 1 //The level of the ability for the hero
integer count //Counts how many corpses there are near the hero
integer oldCount = 0 //Stores the oldCount from the previous count. Used to update the attack damage bonus correctly.
integer totalBonus = 0 //The total attack damage bonus the hero has.
timer t
private static thistype temp
static method create takes unit h returns thistype
local thistype this = thistype.allocate()
set .hero = h
set .t = NewTimer()
call SetTimerData(.t,this)
call TimerStart(.t,TIMER_LOOP,true,function thistype.onLoop)
return this
endmethod
static method countCorpses takes nothing returns boolean
if not UnitAlive(GetFilterUnit()) then
set temp.count = temp.count + 1
endif
return false
endmethod
//Used so many times that I just made a method for this.
method resetBonus takes nothing returns nothing
call AddUnitBonus(.hero,BONUS_DAMAGE,-.totalBonus)
endmethod
static method onLoop takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
local integer add
local integer curLvl = GetUnitAbilityLevel(.hero,SPELL_ID)
if curLvl == 0 then
if .totalBonus > 0 then
call .resetBonus()
endif
call ReleaseTimer(.t)
call .destroy()
elseif UnitAlive(.hero) then
set .count = 0
set temp = this
call GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(.hero),GetUnitY(.hero),Range(.lvl),e)
if .count == 0 and .oldCount != 0 then
call .resetBonus()
set .totalBonus = 0
set .oldCount = 0
elseif .lvl != curLvl then
call .resetBonus()
if .count*DamageBonus(curLvl) > MaxDamageBonus(curLvl) then
set .totalBonus = MaxDamageBonus(curLvl)
else
set .totalBonus = .count*DamageBonus(curLvl)
endif
call AddUnitBonus(.hero,BONUS_DAMAGE,.totalBonus)
set .lvl = curLvl
elseif .count != .oldCount then //The counts aren't the same so change the bonus
if .count*DamageBonus(.lvl) > MaxDamageBonus(.lvl) then
set add = MaxDamageBonus(.lvl) - .totalBonus
else
set add = .count*DamageBonus(.lvl) - .totalBonus
endif
call AddUnitBonus(.hero,BONUS_DAMAGE,add)
set .oldCount = .count
set .totalBonus = .totalBonus + add
endif
endif
endmethod
static method learnSkill takes nothing returns boolean
if GetLearnedSkill() == SPELL_ID and GetUnitAbilityLevel(GetTriggerUnit(),SPELL_ID) == 1 then
call thistype.create(GetTriggerUnit())
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_HERO_SKILL)
call TriggerAddCondition(t,Condition(function thistype.learnSkill))
set e = Filter(function thistype.countCorpses)
endmethod
endstruct
endscope
scope should be private, since it is a spell, we don't want to access it from the rest of the map (avoids naming conflicts and it is a security measure).
Having in mind you are using onloop, perhaps you should replace it by this script made by Vexorian, this way all members of the team will understand your code better.
Since this is an aura, and I find your code quite weird to read, I really think we should use Abuff Aura component of the system (since we are already using ABuff, I see no reason to not use it's aura modules...)
You use BonusMod, but I promised Xarwin I would search for UnitProperties and see which one was best. I am looking for a system that allows us (the team) to expand it's basic components by adding more functionalities. Unfortunately, I cannot find UP and so I can't re-evaluate it :S
Overall it is a good code. I am happy you are on the team.
Please make the changes I requested. This can be done easier with ABuff aura module.
I will add the scripts to the coders page.
Also please, post one of the spells you consider easy. I would like to check them.
As an encouragement for your work, I give you rep++
Sorry, my internet is kind of slow right now which is why I was unable to attach the map to my post. I'll do it after I make the changes though.
I'm pretty sure that scope can't be private...? It shouldn't be too much of a problem though since everything that should be (like global variables and functions) are private.
I'll implement TimedLoop.
I'll see what I can do with ABuffAura.
Sorry for the code being confusing. I'll try to comment more.
I linked UP in my post in the Coders Thread. (It's also in the Jass section of this site) I think Litany removed it from Wc3Campaigns.
Here's the spell code for the easy spells.
JASS:
//==========================================================================================
//Heroic Offer (Jaret) by watermelon_1234
//__________________________________________________________________________________________
//Description:
// When Heroic offer is casted, Jaret loses a certain amount of health, but another player
// gets a certain amount of health healed. This spell has a cooldown of 60 seconds.
//******************************************************************************************
//Libraries required:
// - SpellEvent
//##########################################################################################
//Importing:
// 1. Copy the ability, Heroic Offer.
// 2. Copy this trigger.
// 3. Implement required libraries.
// 4. Configure the spell.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Notes:
// Probably should change the healing done to match a system, if implemented.
// Haven't made a check to make sure the caster cannot kill himself.
//==========================================================================================
scope HeroicOffer initializer Init
globals
//Configurable
private constant integer SPELL_ID = 'A003' //Raw id of the Heroic Offer ability
//Not configurable
private real array Sacrifice //Used for level support
private real array Heal //Used for level support
endglobals
//How much %life the caster will lose. In terms of max life.
private function SetSacrificedLife takes nothing returns nothing
set Sacrifice[1] = .05
set Sacrifice[2] = .1
set Sacrifice[3] = .05
set Sacrifice[4] = .1
set Sacrifice[5] = .05
endfunction
//How much %life the target will gain. In terms of max life.
private function SetHealedLife takes nothing returns nothing
set Heal[1] = .05
set Heal[2] = .1
set Heal[3] = .1
set Heal[4] = .2
set Heal[5] = .2
endfunction
//-------------END OF CONFIGURATION-------------------
private function SpellActions takes nothing returns nothing
local integer lvl = GetUnitAbilityLevel(SpellEvent.CastingUnit,SPELL_ID)
call SetWidgetLife(SpellEvent.CastingUnit,GetWidgetLife(SpellEvent.CastingUnit)-GetUnitState(SpellEvent.CastingUnit,UNIT_STATE_MAX_LIFE)*Sacrifice[lvl])
call SetWidgetLife(SpellEvent.TargetUnit,GetWidgetLife(SpellEvent.TargetUnit)+GetUnitState(SpellEvent.TargetUnit,UNIT_STATE_MAX_LIFE)*Heal[lvl])
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectResponse(SPELL_ID,SpellActions)
call SetSacrificedLife()
call SetHealedLife()
endfunction
endscope
JASS:
//==========================================================================================
//Obliterate Mind (Xerex) by watermelon_1234
//__________________________________________________________________________________________
//Description:
// Deals direct damage to enemy hero and also burns some of its mana.
//******************************************************************************************
//Libraries required:
// - SpellEvent
//##########################################################################################
//Importing:
// 1. Copy the ability, Obliterate Mind.
// 2. Copy this trigger.
// 3. Implement required libraries.
// 4. Configure the spell.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Notes:
// Pretty simple. It was harder to do the tooltip.
//==========================================================================================
scope ObliterateMind initializer Init
globals
//Configurable
private constant integer SPELL_ID = 'A004' //Raw id of the Obliterate Mind ability
private constant attacktype ATK_TYPE = ATTACK_TYPE_NORMAL //Attack type of the spell damage
private constant damagetype DMG_TYPE = DAMAGE_TYPE_UNIVERSAL //Damage type of the spell damage
private constant weapontype WPN_TYPE = null //Weapon type of the spell damage
endglobals
//Damage dealt to enemy hero.
private function Damage takes integer lvl returns real
return 60.*lvl
endfunction
//How much mana the target will lose.
private function ManaLoss takes integer lvl returns real
return 30.*lvl
endfunction
//-------------END OF CONFIGURATION-------------------
private function SpellActions takes nothing returns nothing
local integer lvl = GetUnitAbilityLevel(SpellEvent.CastingUnit,SPELL_ID)
call UnitDamageTarget(SpellEvent.CastingUnit,SpellEvent.TargetUnit,Damage(lvl),false,true,ATK_TYPE,DMG_TYPE,WPN_TYPE)
call SetUnitState(SpellEvent.TargetUnit,UNIT_STATE_MANA,GetUnitState(SpellEvent.TargetUnit,UNIT_STATE_MANA)-ManaLoss(lvl))
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectResponse(SPELL_ID,SpellActions)
endfunction
endscope
Edit:
I feel uncertain about using ABuffAura for this because this spell doesn't really do anything special with buffs. It's also not really an aura because the spell is only counting dead units and not doing anything else with the units; it's focusing more on the hero. Using ABuffAura for this spell feels like it would make it more complicated to do this.
However, I'm probably just not thinking of using the system correctly.
Anyway, I attached a test-map of the three spells.
Here's the updated code:
JASS:
//==========================================================================================
//Soul Harvest (Xerex) by watermelon_1234
//__________________________________________________________________________________________
//Description:
// Corpses within 500 range of Dark Lord will bolster his offensive power.
//******************************************************************************************
//Libraries required:
// - BonusMod
// - GroupUtils
// - TimedLoop
//##########################################################################################
//Importing:
// 1. Copy the ability, Soul Harvest, and its buff.
// 2. Copy this trigger.
// 3. Implement required libraries.
// 4. Configure the spell.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Notes:
// Probably will recode this if we use an Aura system.
// The level check may be inefficient as it always update to that manually. The nice thing
// is that this spell supports Tome of Retraining.
//==========================================================================================
scope SoulHarvest
native UnitAlive takes unit id returns boolean //A better way to check if a unit is alive.
globals
private constant integer SPELL_ID = 'A005' //Raw id of the Soul Harvest ability.
//Not configurable
private boolexpr e //Used for group enumeration
endglobals
//The range of the ability which enumerates corpses.
private constant function Range takes integer lvl returns real
return 500. + 0*lvl
endfunction
//The damage bonus gained for each corpse.
private constant function DamageBonus takes integer lvl returns integer
return 2 + 2*lvl
endfunction
//The max damage bonus that one can get from this ability.
private constant function MaxDamageBonus takes integer lvl returns integer
return 70 + 0*lvl
endfunction
//-------------END OF CONFIGURATION-------------------
private struct Data
unit hero //The hero that learned the ability.
integer lvl = 1 //The level of the ability for the hero. Is updated at the end of every loop as it stores the past level.
integer count //Counts how many corpses there are near the hero.
integer oldCount = 0 //Stores the count from the previous time the loop was run. Used to update the attack damage bonus correctly.
integer totalBonus = 0 //The total attack damage bonus the hero has from this ability.
private static thistype temp //Used for the group filter so that we can set count of a struct instance correctly.
static method create takes unit h returns thistype
local thistype this = thistype.allocate()
set .hero = h
call .startTimedLoop()
return this
endmethod
//Note that this is a filter. Used only to count dead units for the bonus.
static method countCorpses takes nothing returns boolean
if not UnitAlive(GetFilterUnit()) then //Corpses count as units that are dead.
set temp.count = temp.count + 1
endif
return false
endmethod
//Used so many times that I just made a method for this. Basically removes any bonus the hero gained from this spell.
method resetBonus takes nothing returns nothing
call AddUnitBonus(.hero,BONUS_DAMAGE,-.totalBonus)
endmethod
method onTimedLoop takes nothing returns boolean
local integer add //Considers what attack damage bonus the spell needs to add
local integer curLvl = GetUnitAbilityLevel(.hero,SPELL_ID)
//If the level is 0 that means the hero no longer has the ability. That means the spell should stop.
if curLvl == 0 then
//Only reset the bonus if .totalBonus is greater than 0.
if .totalBonus > 0 then
call .resetBonus()
endif
return false
elseif UnitAlive(.hero) then
set .count = 0 //Set to 0 first or else counting the corpses will be messed up.
set temp = this
call GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(.hero),GetUnitY(.hero),Range(.lvl),e)
//No corpses but oldCount has a different number. Remove any bonus given to the hero and correctly set oldCount to 0.
if .count == 0 and .oldCount != 0 then
call .resetBonus()
set .totalBonus = 0
set .oldCount = 0
//Previous level is not updated with the current level.
//In this case, ignore any bonus the hero has received from last loop by resetting it and manually give the correct bonus.
elseif .lvl != curLvl then
call .resetBonus()
//Make sure the bonus will not exceed MaxDamageBonus.
//Remember: The bonus given to the hero is the # of corpses times the damage bonus each corpse gives but the bonus is capped.
if .count*DamageBonus(curLvl) > MaxDamageBonus(curLvl) then
set .totalBonus = MaxDamageBonus(curLvl)
else
set .totalBonus = .count*DamageBonus(curLvl)
endif
call AddUnitBonus(.hero,BONUS_DAMAGE,.totalBonus)
set .lvl = curLvl
elseif .count != .oldCount then //The counts of the corpses aren't the same so change the bonus. Otherwise, don't do anything after this as all is well.
//If the supposed bonus is bigger than MaxDamageBonus, limit it.
//add is the difference between the bonus the hero should have from the spell and the current bonus it has.
if .count*DamageBonus(.lvl) > MaxDamageBonus(.lvl) then
set add = MaxDamageBonus(.lvl) - .totalBonus
else
set add = .count*DamageBonus(.lvl) - .totalBonus
endif
call AddUnitBonus(.hero,BONUS_DAMAGE,add)
//Update some variables to work for the next loop
set .oldCount = .count
set .totalBonus = .totalBonus + add
endif
endif
return true
endmethod
implement TimedLoop
static method learnSkill takes nothing returns boolean
if GetLearnedSkill() == SPELL_ID and GetUnitAbilityLevel(GetTriggerUnit(),SPELL_ID) == 1 then
call thistype.create(GetTriggerUnit())
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_HERO_SKILL)
call TriggerAddCondition(t,Condition(function thistype.learnSkill))
set e = Filter(function thistype.countCorpses)
endmethod
endstruct
endscope
Note: You'll also see my attempt at making a spell with CustomMissile in the test-map. Don't actually use it as it's unfinished and doesn't even work.
private real array Sacrifice[6]
private real array Heal[6]
More efficent than:
JASS:
private real array Sacrifice
private real array Heal
Since you limit the array size to 6 members, thus you spend less memory for it.
Just wondering if it's better since I ain't sure, thus i am asking.
Afaik when you declare a array in WC3 it has a default size of 8191, not all your arrays need that size
I'm pretty sure that scope can't be private...? It shouldn't be too much of a problem though since everything that should be (like global variables and functions) are private.
Last time I checked ABuffAura I found it quite simple to deal with. I am not sure if it has changed since then however. I will give it a look once I install wc3 again.
Heroic Offer
As for the simple spell, it can be improved in some ways:
1 - you should define a clear SETUP section according to the JESP standard. Do NOT mix SETUP globals with system globals. Instead, create another globals block. Check my tutorial to see how I organized globals, it will take you 5 seconds.
I really dislike the use of arrays for the SETUP, it makes no sense and it is hard for the user to change IMO. You should instead do something like:
JASS:
private function SetSacrificedLife takes integer level returns real
return 0.05 * level
endfunction
And the same should apply for SetHealedLife. This approach has many advantages such as:
1 - requires less code
2 - it is easier to understand 3 - it is faster (nothing is faster than arrays, I give you that, but there is no need in using them here, it's not like this is a critical application)
4 - it works for ANY number of levels
Therefore I would really like you to change it.
Finally, you are not preloading the ability, thus there will be first cast lag. We want to avoid that. Please use AbilityPreload.
You should also add a version number to your spells. Per example, this would be version 1.0. It is just to keep track of the different versions a spell can have. When I was coding my project it helped me organize things, so I would like to do it here as well.
Other than that, I would say that code is pretty simple and pretty perfect. Good job. I would give you rep++ but THW fag rep system won't allow me ...
Obliterate Mind
Well, you should preload the ability. Other than that, it is perfect.
Suggestions for spells: Those spells are in deed simple .... so why not make them better? Players love eye candy above all things. I strongly suggest you add some effect to the caster and to the target. It can be a death coil effect, or you can search an imported effect because Xarwin allows for imported effects. If you don't have the time, I can do it.
I can also PM the creators of the hero concepts in order to ask them for effects they would like to see.
Soul Harvest
In method learnSkill you are making multiple accesses to GetTriggerUnit(). I suggest you save that unit into a variable so it it faster (accessing variables is faster than accessing functions).
In your onTimedLoop you are evaluating all dead units every period, which means, you evaluate the dead units around the hero every 0.025 seconds. I don't think it is necessary to do count down of all dead units every 0.025 seconds, perhaps you should make the count down every 0.5 seconds? You only need to add a counter to that method, and it will release the CPU of a significant amount of work.
Other than that, the code is not that bad. I admit it is quite confusing because you use a style of programming that is not my own, but if you say it works, I believe you
Though iirc, there is a native called "corpse" (or something like this) that represents corpses (thus you don't need to check if a unit is alive). This could significantly improve the efficiency of your spell.
One last thing, you should definitely add an effect to the hero when he is bolstered, like an orb arround his weapon or something. It makes him look cooler
EDIT
Bliazzard account is down for maintenence so I can't install wc3 yet :S
As for UP, you forgot to post the link xD
Since you limit the array size to 6 members, thus you spend less memory for it.
Just wondering if it's better since I ain't sure, thus i am asking.
Afaik when you declare a array in WC3 it has a default size of 8191, not all your arrays need that size
If, the default size of an array when declared is 8191, then making" real array[6]" or "real array" gives you no efficiency improvements in time, but allows you to have a significant efficiency improvement in memory. If however, the default size of an array is < 6, (lets say, if it is 1) then each time you add an element, you have to expand the array. Expanding an array is extremely costly because you have to create an array with more memory, and copy the content of the old array to the new one.
The answer lies on the default size of an array when created.
He is using arrays for the setup because the values aren't linear, they rise in exponential way.
JASS:
set Heal[1] = .05
set Heal[2] = .1
set Heal[3] = .1
set Heal[4] = .2
set Heal[5] = .2
See my point?
I think the blizard makes the default size upon defining an array 8191, you can expand it by doing this:
JASS:
integer array Example[40000]
Making it an array with 40000 size, so i think the arrays aren't using the expanding method, but i might be wrong.
Also less memory the map (WC3) takes the better.
And predefining array size is only used when you know you won't be changing it, or you could use a constant integer and simply manipulate array size's by it.
EDIT:
Don't forget to preload dummy abilities if there are any, else it will still cause the 1st time cast lag.
I get it now. But I still dislike using arrays. It is not modular and follows no standard at all. I would prefer he would use the method I suggested with if-then-else.Truth is, we don't know if we are going to add more levels to the heroes in future versions.
I understand the spell is simple, but I would really like other people (like Xarwin and new coders) to be able to change the spell using only the SETUP section without needing to enter the core. It is a principle.
Another thing I really would like to add to Heroic Offer is AbortSpell. It makes no sense to heal a unit that is already full hp right? It is a waste of mana, and a waste of HP.
Therefore watermellon_1234 should make a check to see if the unit is full HP, and if it is full HP, it should abort the spell, show an error message and re-order the unit again. Fortunately for us, someone already made all this for us, thus the perfect library for this job is AbortSpell by Rising_Dusk. All requirements from this library are also allowable and OK to use.
I also noticed that you can heal your enemies this this spell ... it is most certainly a thing we want to avoid (though I suppose that can be changed using the right ability from WE).
This is how you make a simple spell like Heroic Offer something not so simple, but something great: add eye candy and pay attention to details.
I look forward to see how watermellon_1234 is going to change his spells. Notice that if you need any help you only need to ask me.
I would gladly code this spells myself and make the changes myself, but I would be stealing his work, plus I don't have wc3 installed now becayse Bliazzard account website is down ...
I'm hesitant about using ABuffAura because I'm thinking it would be harder to refer to the struct and keep track of how many dead units there are.
I'll separate the non-configurable globals from the configurable globals.
Believe me, I like using functions for level support more than using arrays. However, I think if-then-else would just complicate it since you only need to add another line for each level if you used an array whereas you would need to add about two lines for each level you want to add.
The reason I didn't preload any abilities was that they could be preloaded along with the heroes that had the abilities. No dummy abilities were used so the abilities themselves shouldn't lag.
I'll add version number; does that mean I should have some kind of changelog for each spell?
I added all the special effects the spells used with the ability itself. I didn't add any extra effects if the hero creator didn't specify, except for Soul Harvest as I gave an Aura of Blight effect to the ability. It seems like a good idea to have an effect to show its bonus so I'll add it. (But I'll think I'll only have one sfx representing all the bonus the hero could get.)
I'll add timeCounter to make it loop less.
Instead of importing another library, I could just base Heroic Offer off of Healing Wave which gives an error if the target has full health.
That should also solve the problem of healing enemies which I overlooked.
I did link UP in the post I made in the Coders Thread, but I'll link it again: Unit Properties (Cassiel is basically Litany)
ABuff has an argument of type "int" that can save structures. I believe this solves the problem. Also, please check the corpse type I talked about.
Believe me, I like using functions for level support more than using arrays. However, I think if-then-else would just complicate it since you only need to add another line for each level if you used an array whereas you would need to add about two lines for each level you want to add.
Well, I dislike arrays, but your approach has a point. I will allow you to use arrays, but please separate the globals.
The reason I didn't preload any abilities was that they could be preloaded along with the heroes that had the abilities. No dummy abilities were used so the abilities themselves shouldn't lag.
Yes. Why? Because I plan to make a pack called HB promotional pack and I intend to release it for promotional purposes (with your consent ofc, since you are the creator). This spellpack main idea is to promote the project and make publicity. Thus every spell must be perfect and must have a changelog, like most decent resources have. Ofc, you will be given full credit for your work.
Instead of importing another library, I could just base Heroic Offer off of Healing Wave which gives an error if the target has full health.
That should also solve the problem of healing enemies which I overlooked.
After checking both systems, I do think that BonusMod is easier to use. Therefore I would like to make BonusMod the official system for the project. All agree?
It is also nice because this mod was forged in THW
I'll experiment with ABuffAura more but I don't have the time right now. (I'm going to be gone soon)
I meant that if heroes are preloaded in the map, then the abilities they have will be preloaded with them. If they aren't preloaded, then I'll preload the abilities.
Well with the hero i am making for a THW member who asked me for today and with the Weekend Speed mapping contest i will make the spells for my hero during the 21st.
They are quite easy if you saw, i will make 2 only by using timers and DamageModifiers, and those are the complicated one.
I meant that if heroes are preloaded in the map, then the abilities they have will be preloaded with them. If they aren't preloaded, then I'll preload the abilities.
When you pick a hero you can't preload an ability. How do you know which heroes the players will choose in the loading screen or when the timer clicks 0.0 seconds? You don't know, that is why we always preload all abilities at start. Preloading is simply, basically you choose a dummy unit and give it all the abilities you want to with the time set to zero. This will force the game to load the abilities even before the game starts.
So it lags when you pick a hero, I think that's bad. God created loading screens for a reason, I say use them. We want to avoid all types of lag. I don't care if the players have to wait more 10 seconds than usual, they won't die because of it. Please preload those abilities.
Working atm on the Turret spell for Mortar's hero.
This is how I figured it would work, seeing as I'm not an advanced vJass I'm wondering if anyone has a more efficient method.
The spell to create the turrets could be easily made using a normal Blizz spell.
A trigger using the damage detection library would check everytime a unit is attacked by one of the turrets and set an integer of it (I figured I'd use a hash table to attach the integer to it via the units key) + 1, and when it gets to the maximum value it would kill the unit.
Would this be an appropriate usage of a hash table, or (since some coders dislike hash tables) is there a preferable alternative?
There is a quite easy way without the use of a hash table.
JASS:
private struct damageDetect extends DamageModifier
turret tStruct
method onDamageDealt takes unit u, real damage returns real
local turret t = this.tStruct
set t.count = t.count - 1
if t.count == 0 then
t.destroy()
this.destroy()
endif
return damage
endmethod
endstruct
private struct turret
unit t
integer count
damageDetect dd
method InitExample takes nothing returns nothing
local thistype this = thistype.allocate()
//code...
set .t = *unit*
set .count = *number of attacks*
set .dd = .dd.create(.t,0)
set .dd.tStruct = this
endmethod
endstruct
And i think you get the picture now.
EDIT:
I wrote this in here, not in WC3 so it may have compile errors.
i noticed that you can get to this by making your init function public and then calling the init function when the hero is picked, and taking out the initializer part of the line with the scope declaration. in case someone was not aware of it.
also...where is the link to the system called bonusmod?
i noticed that you can get to this by making your init function public and then calling the init function when the hero is picked, and taking out the initializer part of the line with the scope declaration. in case someone was not aware of it.
Hell no. As far as I am concerned there are easier ways to do that. Methods such as Init are meant to be private and I will not allow inventions like this one.
Preload the damn abilities in the Init method or trigger. I want no excuses, people will not die for waiting 10 seconds.
And if you do not like my decision, we can always ask Xarwin.
also...where is the link to the system called bonusmod?
By preloading heroes, I mean creating them at map init and then removing them. It won't work just to have them in a tavern.
If you wanted to remove any kind of lag, you would want to preload all the heroes since there's a bit of lag when a unit enters the map for the first time. Preloading the heroes would get rid of the need of separately preloading the abilities they would have, except for the dummy abilities that come with the spells.
This thread is starting to get off-topic...
Edit:
Flame_Phoenix was right about using ABuffAura. XD
@Flame_Phoenix:
I don't know what native you're talking about. (The one about corpses?)
Also, I forgot to respond to
In method learnSkill you are making multiple accesses to GetTriggerUnit(). I suggest you save that unit into a variable so it it faster (accessing variables is faster than accessing functions).
I only referred to GetTriggerUnit() twice so there wasn't really a need for a variable. Anyway, that shouldn't even matter anymore since I'm going to use ABuffHeroSkill and ABuffAura.
Edit 2: Or maybe Flame_Phoenix was wrong.
There's a problem with ABuffAura: I can't have ABuffs on dead units, making it impossible to count units with the system. D:
I see your point. However, regular creeps and units will also have special abilities. Thus, in the name of consistency, I want to preload abilities and not units (such as heroes and creeps).
If the team finds it necessary, I can arrange a meeting with Xarwin.
In fact, I think I will have to, because I need to report on progress and I need to decide if we should or should not use xecast and xepreload.
I don't know what native you're talking about. (The one about corpses?)
Yes, I will make a search for it once I have my damn wc3 account online and installed ...
I only referred to GetTriggerUnit() twice so there wasn't really a need for a variable. Anyway, that shouldn't even matter anymore since I'm going to use ABuffHeroSkill and ABuffAura.
I know you only used it twice, but I wanted to make sure that it didn't escape. I understand that a variable is not necessary, a few nano-seconds will not kill our players
i just hope the ability you create was for approve heroes
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.