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!
For those of you who play dota, the question is simple: How do I produce Ursa Warrior's Ulti? Or Barathrum's Empowering Haste's atk increment effect?
For those of you who don't, it means: How do I, via triggers, increase a unit's Attack stat? As of current, I do not see some kind of trigger that increases a unit's attack and displays it on the status bar.
You will need to create a few abilities. Firstly, copy the attack damage bonus ability from items section, make its object ID = 'DM+a', and set the damage bonus to +1. Now copy this item, set the object ID to 'DM+b', and set the damage bonus to +2. For the third time, you will copy the ability again, set the object ID to 'DM+c', and set the damage bonus to +4. I'm hoping that by now you've started to notice a patern, basically keep creating those abilities, progressing in the alphabet, and doubling the damage bonus. So the next few abilities ID's would be DM+d, DM+e, and damages +8, +16. Keep creating those abilities up to damage bonus of 256. This will let you set your units damage to anything from 0 up to 511.
This was the easy object editor part, time for some code.
Firstly, you will need to make a new trigger, after that convert it into text, and remove anything that's in there.
Now we'll type in "library DamageBonus", press enter, and type in "endlibrary."
We're finished with the library! Well not quite, it still needs a couple of things inside of it.
What your trigger should look like right now is:
JASS:
library DamageBonus
endlibrary
Next part to do is create a struct, which is simple. Firstly create the struct, the struct declaration is "struct" followed by a name (ex. struct DamageBonus), and ended with "endstruct"
Now declare a unit with a name of "obj", and an integer with a name of "dmg" inside of the struct.
Your code should look like this:
JASS:
library DamageBonus
struct DamageBonus
integer dmg
unit obj
endstruct
endlibrary
Basically, now we have something to hold the units damage information in. You'll need to declare two new variables inside of your struct. Both of them are integer, name one pow, and the other cdmg. Make both of those last created variables into static variables. You do this by declaring the word "static" in front of them. Make the cdmg values equal to 'DM+a', and make pow equal to 8.
What you want to do right now is make all of those variables private, you do so by placing the keyword "private" in front of them.
After you have made it private, create a static method called create, make it take a unit, and return DamageBonus.
Create a local DamageBonus, create it using allocate method, and let obj variable equal to the unit given, after you have done that, return the DamageBonus struct.
Right now your code should look like this:
JASS:
library DamageBonus
struct DamageBonus
private integer dmg = 0
private unit obj = null
private static integer pow = 8
private static integer cdmg = 'DM+a'
static method create takes unit u returns DamageBonus
local DamageBonus this = DamageBonus.allocate()
set this.obj = u
return this
endmethod
endstruct
endlibrary
What you are going to do now, is creating a few method operators. You create them just like a regular method, but after the method keyword you place the word operator (ex. method operator damage takes nothing returns integer). You place the symbol "=" after the method name if you are adjusting a value, not receiving it (ex. method operator damage= takes integer s returns nothing).
Create a get method operator, call it object, and make it return the obj value. Create a duplicate set method, and instead of return the obj value, set obj value to the receiving value. Create two similar methods for dmg variable aswell.
Right now your code should look like this:
JASS:
library DamageBonus
struct DamageBonus
private integer dmg = 0
private unit obj = null
private static integer pow = 8
private static integer cdmg = 'DM+a'
static method create takes unit u returns DamageBonus
local DamageBonus this = DamageBonus.allocate()
set this.obj = u
return this
endmethod
method operator object takes nothing returns unit
return .obj
endmethod
method operator object= takes unit s returns nothing
set .obj = s
endmethod
method operator damage takes nothing returns integer
return .dmg
endmethod
method operator damage= takes integer s returns nothing
set .dmg = s
endmethod
endstruct
endlibrary
We're almost done! All we need now is a method that will actually give the abilities to the units.
Create a method called update_dmg above all the method operator, but below the create method.
Make the last created method have 2 local integers, call one i, and the other num. Set i = .pow, and num = .dmg.
Now create an if statement, make sure that the num value is less than 512. If that's true, than return, and no else statement.
Create a loop, and for the exit statement place i < 0. Inside of the loop check if Pow( 2, i) is less then or equal to num. If so, add an ability to the .obj, for the ability ID use .cdmg + i. After the add function call, set num = num - R2I(Pow(2,i)). Now for the else statement, remove an ability from the object, for the ability id use .cdmg + i. After the if statement, set i to itself minus one. End the loop.
Right now your code should look like this:
JASS:
library DamageBonus
struct DamageBonus
private integer dmg = 0
private unit obj = null
private static integer pow = 8
private static integer cdmg = 'DM+a'
static method create takes unit u returns DamageBonus
local DamageBonus this = DamageBonus.allocate()
set this.obj = u
return this
endmethod
private method update_dmg takes nothing returns nothing
local integer i = .pow
local integer num = .dmg
if num > 511 then
return
endif
loop
exitwhen i < 0
if Pow(2,i) <= num then
call UnitAddAbility( .obj, .cdmg + i )
set num = num - R2I(Pow(2,i))
else
call UnitRemoveAbility( .obj, .cdmg + i )
endif
set i = i - 1
endloop
endmethod
method operator object takes nothing returns unit
return .obj
endmethod
method operator object= takes unit s returns nothing
set .obj = s
endmethod
method operator damage takes nothing returns integer
return .dmg
endmethod
method operator damage= takes integer s returns nothing
set .dmg = s
endmethod
endstruct
endlibrary
Now what you're gonna have to do, is go back to the method operator where you adjusted the damage value, and after the value is adjusted, call .update_dmg().
Only thing left to do, is create an onDestroy method. Inside the method, create a local integer, with the name of i, and set it's value to .pow.
Than create a loop, exitwhen i is less than 0. Inside of the loop remove each of the abilities on the unit. Set i to equal itself minus one. After the loop, set .obj to null.
Now our code should look like this:
JASS:
library DamageBonus
struct DamageBonus
private integer dmg = 0
private unit obj = null
private static integer pow = 8
private static integer cdmg = 'DM+a'
static method create takes unit u returns DamageBonus
local DamageBonus this = DamageBonus.allocate()
set this.obj = u
return this
endmethod
private method update_dmg takes nothing returns nothing
local integer i = .pow
local integer num = .dmg
if num > 511 then
return
endif
loop
exitwhen i < 0
if Pow(2,i) <= num then
call UnitAddAbility( .obj, .cdmg + i )
set num = num - R2I(Pow(2,i))
else
call UnitRemoveAbility( .obj, .cdmg + i )
endif
set i = i - 1
endloop
endmethod
method operator object takes nothing returns unit
return .obj
endmethod
method operator object= takes unit s returns nothing
set .obj = s
endmethod
method operator damage takes nothing returns integer
return .dmg
endmethod
method operator damage= takes integer s returns nothing
set .dmg = s
call .update_dmg()
endmethod
private method onDestroy takes nothing returns nothing
local integer i = .pow
loop
exitwhen i < 0
call UnitRemoveAbility(.obj, .cdmg + i)
set i = i - 1
endloop
set .obj = null
endmethod
endstruct
endlibrary
The system is finished!
Now what we have to do to use it, is create a DamageBonus struct, and set the struct damage to whatever you want. You can even do so in a GUI trigger.
Untitled Trigger 001
Events
Map initialization
Conditions
Actions
Custom script: local DamageBonus this = DamageBonus.create(some_unit)
Custom script: set this.damage=200
Now, there is one issue with this code, it will leak when the units die, so what we will have to do, is attach the structs to the units user data, create a group, and when a unit with the struct attached dies his struct will be destroyed.
Here is the final code with self clean-up type of thing enabled:
JASS:
library DamageBonus initializer init
globals
unit some_unit
endglobals
struct DamageBonus
private integer dmg = 0
private unit obj = null
private static integer pow = 8
private static integer cdmg = 'DM+a'
static group grp = null
static method create takes unit u returns DamageBonus
local DamageBonus this = DamageBonus.allocate()
if IsUnitInGroup(u, .grp) then
debug call BJDebugMsg("Trying to create multiple damage bonuses for unit " + GetUnitName(.obj))
return null
endif
call GroupAddUnit( .grp, u)
set this.obj = u
return this
endmethod
private method update_dmg takes nothing returns nothing
local integer i = .pow
local integer num = .dmg
if num > 511 then
return
endif
loop
exitwhen i < 0
if Pow(2,i) <= num then
call UnitAddAbility( .obj, .cdmg + i )
set num = num - R2I(Pow(2,i))
else
call UnitRemoveAbility( .obj, .cdmg + i )
endif
set i = i - 1
endloop
endmethod
method operator object takes nothing returns unit
return .obj
endmethod
method operator object= takes unit s returns nothing
set .obj = s
endmethod
method operator damage takes nothing returns integer
return .dmg
endmethod
method operator damage= takes integer s returns nothing
set .dmg = s
call .update_dmg()
endmethod
private method onDestroy takes nothing returns nothing
local integer i = .pow
if .obj == null then
debug call BJDebugMsg("Trying to double release a struct attached to unit " + GetUnitName(.obj))
return
endif
loop
exitwhen i < 0
call UnitRemoveAbility(.obj, .cdmg + i)
set i = i - 1
endloop
call GroupRemoveUnit(.grp, .obj)
set .obj = null
endmethod
static method onInit takes nothing returns nothing
set .grp = CreateGroup()
endmethod
endstruct
private function condition takes nothing returns boolean
local DamageBonus d = GetUnitUserData(GetTriggerUnit())
if IsUnitInGroup(d.object, d.grp) then
return true
endif
return false
endfunction
private function action takes nothing returns nothing
local DamageBonus d = GetUnitUserData(GetTriggerUnit())
call d.destroy()
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t,Condition(function condition))
call TriggerAddAction(t, function action)
endfunction
endlibrary
To use the system above you would have to add one more line to your GUI trigger, here is how it would look.
Untitled Trigger 001
Events
Map initialization
Conditions
Actions
Custom script: local DamageBonus this = DamageBonus.create(some_unit)
Tried to make it a tutorial, so you learn as you make it, but if you're just a person who just wants to use the code, I guess you can just copy+paste the last example code given. What you WILL have to do is create those abilities tho.
EDIT: If anyone wants me to explain any part of the code, you can post and ask.
Tried to make it a tutorial, so you learn as you make it, but if you're just a person who just wants to use the code, I guess you can just copy+paste the last example code given. What you WILL have to do is create those abilities tho.
EDIT: If anyone wants me to explain any part of the code, you can post and ask.
to be honest, I pretty much don't understand the overall method of handling Jass/vJASS.
But with this, I guess I'll use it as a benchmark if I were to finally take that leap into JASS (but I haven't even mastered GUI to a degree...oh well)
to be honest, I pretty much don't understand the overall method of handling Jass/vJASS.
But with this, I guess I'll use it as a benchmark if I were to finally take that leap into JASS (but I haven't even mastered GUI to a degree...oh well)
Read the last function first, which is almost always an initializer. If you want to know how to do something in jass, convert a gui function and then look at the BJ's used for info on how the natives work.
I'd recommend looking at some proper tutorials for beginners though, as we could spend weeks explaining stuff to you if you learn in an improper order.
Read the last function first, which is almost always an initializer. If you want to know how to do something in jass, convert a gui function and then look at the BJ's used for info on how the natives work.
I'd recommend looking at some proper tutorials for beginners though, as we could spend weeks explaining stuff to you if you learn in an improper order.
BJ stands for blizzard.j function, which are all the functions blizzard made to make programming "easier," they simply perform actions using the natives. It's generally considered to avoid them, but some have a use at certain times over straight natives.
init refers to the function, trigger is usually created in the initializer function.
You will remove the global block, the some_unit variable was there to make sure code compiled, and you will have to create 8 or 9 abilities (i forgot) with the pattern that i showed you in the very start of the mini tutorial, you will start with ability id o DM+a, than go down into DM+b, DM+c etc... Base the ability off the weapon damage bonus ability from items.
EDIT: Toward "Cokemonkey11," I tend to place initialization functions at end of code for personal reasons .
You will remove the global block, the some_unit variable was there to make sure code compiled, and you will have to create 8 or 9 abilities (i forgot) with the pattern that i showed you in the very start of the mini tutorial, you will start with ability id o DM+a, than go down into DM+b, DM+c etc... Base the ability off the weapon damage bonus ability from items.
EDIT: Toward "Cokemonkey11," I tend to place initialization functions at end of code for personal reasons .
another question: the event trigger for the system u posted is Map initialization, can i change it to "unit begins the effect of an ability" so it happens when I use a skill? (provided I can find the part where I can modify it to % of my hp/mp etc....)
and I just have to say this out: my first time ever typing a JASS code (thx to Feroc1ty), and it feels...awesome. Lol
EDIT: oh wait, the part where I can modify it to % of my hp/mp is the damage struct in the GUI trigger right?
another question: the event trigger for the system u posted is Map initialization, can i change it to "unit begins the effect of an ability" so it happens when I use a skill? (provided I can find the part where I can modify it to % of my hp/mp etc....)
and I just have to say this out: my first time ever typing a JASS code (thx to Feroc1ty), and it feels...awesome. Lol
EDIT: oh wait, the part where I can modify it to % of my hp/mp is the damage struct in the GUI trigger right?
I don't think you comprehend how this system works... Look at the trigger example, you type in 3 custom lines of code per unit you want to have custom damage. Any unit can have it.
I honestly don't see why people use a system of "damage +2, +4, +8, etc."
I created my own little "damage bonus" system, using +1, +10, +100, +1000, +10000. Each with 9 lvls. So, With 5 abilities, I can have any number between 1-99,999. With another ability, I'd have 999,999.
Can anyone tell me why people use the binary way instead of the decimal way?
I don't think you comprehend how this system works... Look at the trigger example, you type in 3 custom lines of code per unit you want to have custom damage. Any unit can have it.
Because it was for the test trigger, you set the system up by doing "Custom script: local DamageBonus this = DamageBonus.create(some_unit)", and replacing some_unit with the unit which you want it to be.
I honestly don't see why people use a system of "damage +2, +4, +8, etc."
I created my own little "damage bonus" system, using +1, +10, +100, +1000, +10000. Each with 9 lvls. So, With 5 abilities, I can have any number between 1-99,999. With another ability, I'd have 999,999.
Can anyone tell me why people use the binary way instead of the decimal way?
Each one of those abilities will add around +1 second of loading time, and you have five of them, so you're looking at at least 5 extra seconds of loading time for a simple damage system (whilst level one abilities will get widgetized into an slk and turn the loading time into around 0.05 seconds). Another reason this system is better, is because I have one macro that does the binary, so in one line of code (and a few object editor abilities) I can add a completely new stat, such as strength, agility, intelligence, etc...
Because it was for the test trigger, you set the system up by doing "Custom script: local DamageBonus this = DamageBonus.create(some_unit)", and replacing some_unit with the unit which you want it to be.
Each one of those abilities will add around +1 second of loading time, and you have five of them, so you're looking at at least 5 extra seconds of loading time for a simple damage system (whilst level one abilities will get widgetized into an slk and turn the loading time into around 0.05 seconds). Another reason this system is better, is because I have one macro that does the binary, so in one line of code (and a few object editor abilities) I can add a completely new stat, such as strength, agility, intelligence, etc...
I see. I've used optimisers before, but I don't know how they work. What is the deal with SLKs? I understand that optimising the SLK reduces the loading time, but how? And, why won't it work on abilities with more than 1 level?
I see. I've used optimisers before, but I don't know how they work. What is the deal with SLKs? I understand that optimising the SLK reduces the loading time, but how? And, why won't it work on abilities with more than 1 level?
Object editor crap is placed in a shitty way, what slk does is display the information better, so warcraft gets all of the information quicker. It works on abilities that are level 3 at most.
Well, you could still cut the number of abilities down then, right? You use single level abilities, you could be using triple level, and have 1/3 the number of required abilities.
Tell me if I'm wrong here.
Well, you could still cut the number of abilities down then, right? You use single level abilities, you could be using triple level, and have 1/3 the number of required abilities.
Tell me if I'm wrong here.
since I've never understood what exactly those <gen> things were for, I tend to get dumbfounded when people use them.
correct me if I'm wrong, but the <gen> thing is only created when that unit is in a map initially, right?
So, if, per se, I include this skill for a hero in an AoS style map, which means I have to purchase that hero, I would I know what is its "name: #### <gen>"?
EDIT: a variable to the unit means...? Setting a unit-type variable or something in the GUI trigger that equals to "my unit"?
since I've never understood what exactly those <gen> things were for, I tend to get dumbfounded when people use them.
correct me if I'm wrong, but the <gen> thing is only created when that unit is in a map initially, right?
So, if, per se, I include this skill for a hero in an AoS style map, which means I have to purchase that hero, I would I know what is its "name: #### <gen>"?
EDIT: a variable to the unit means...? Setting a unit-type variable or something in the GUI trigger that equals to "my unit"?
As it was stated to me above, using abilities with 3 or less levels means that they can be optimised for loading doing it my original way increases map loading time (by approximately 50x to 100x faster). But, if you really don't care about loading times, then feel free to use decimal instead of binary
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.