HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Simple modHealth System

03-20-2010, 07:05 PM#1
Gorman
Hi guys, I wrote a simple system for modifying health the other day; it uses tomes instead of the add/remove leveled health bug (which I always found to be clunky).
In this way it can only be used on units with a usable inventory, but since it is meant for heroes this is not a problem. And as shown in the test map, you can just add an inventory to non heroes, if you so desire.

Would like some cnc!



Simple modHealth System
The system modifies a unit's
health using a series of tomes
each added in turn to quickly
and easily modify a unit's health.

This system is completely MUI, if you use it in such a manner. As far as I know the system contains no memory leaks (unsure of this, the memory leaks tutorial was less than informative in my opinion). The script requires no additional tools to run. The system contains debug functionality, and is briefly commented.


The system consists of 1 JASS function, 2 GUI triggers, 3 Global variables, and 10 custom tome abilities.

JASS


This function does the actual work of the system.
Collapse JASS:
function modHealth takes integer health, unit target returns nothing

////////////////////////
// Function modHealth is used to modify a unit's health.
// The function can accept positive and negative values.
// The function works using tomes of various sizes, and
// giving them to the target unit, permanatly adding 
// health to the target. Tomes add health in powers of 
// 10. From -10000 health to 10000.
////////////////////////

////////////////////////
// Variables
// integer health      ; the change to make to the health of the unit
// unit    target      ; the unit that will have its health modified
// integer tempInteger ; the size of the max tome being used
// integet j           ; counter for the first loop, used to determine which digit is being modified
// integer k           ; counter for the inside loop, counts how many tomes of a given type are added
// integer isNegative  ; is 0 when false, is 1 when true, tells weather the input health value is negative
////////////////////////

    local integer tempInteger = udg_largestTome
    local integer j = 1
    local integer k
    local integer isNegative = 0

    if ( health < 0 ) then
        // If the health value is negative, it is made positive and noted, such that the function is simpler
        set isNegative = 1
        set health = health * -1
    else
    endif

if ( udg_modHealth_Debug == true ) then
    call DisplayTextToForce( GetPlayersAll(), "")
    call DisplayTextToForce( GetPlayersAll(), "==========[Start of Debug]==========")
    call DisplayTextToForce( GetPlayersAll(), "health = " + I2S(health))
    call DisplayTextToForce( GetPlayersAll(), "isNegative = " + I2S(isNegative))
else
endif

    loop
        exitwhen tempInteger < 1
        if ( health >= tempInteger ) then
            set k = 1
            loop
                exitwhen k > ( health / tempInteger )

if ( udg_modHealth_Debug == true ) then
    call DisplayTextToForce( GetPlayersAll(), "j = " + I2S(j))
    call DisplayTextToForce( GetPlayersAll(), "k = " + I2S(k))
    call DisplayTextToForce( GetPlayersAll(), "tome = " + I2S(6 + ( 5 * isNegative ) - j))
else
endif

                call UnitAddItemByIdSwapped( udg_tomes[( 6 + ( 5 * isNegative) - j )], target )
                call RemoveItem( GetLastCreatedItem() )
                set k = k + 1
            endloop
            set health = ( health - ( ( health / tempInteger ) * tempInteger ) )

if ( udg_modHealth_Debug == true ) then
    call DisplayTextToForce( GetPlayersAll(), "health = " + I2S(health))
else
endif

        else
        endif
        set tempInteger = ( tempInteger / 10 )
        set j = j + 1

if ( udg_modHealth_Debug == true ) then
    call DisplayTextToForce( GetPlayersAll(), "tempInteger = " + I2S(tempInteger))
else
endif

    endloop

if ( udg_modHealth_Debug == true ) then
    call DisplayTextToForce( GetPlayersAll(), "==========[End of Debug]==========")
    call DisplayTextToForce( GetPlayersAll(), "")
else
endif

endfunction

GUI


This function initialises the variables required, and preloads the tomes.
Trigger:
modHealth Initialisation
Collapse Events
Map initialization
Conditions
Collapse Actions
Set modHealth_Debug = False
Set tomes[1] = +1 health
Set tomes[2] = +10 health
Set tomes[3] = +100 health
Set tomes[4] = +1000 health
Set tomes[5] = +10000 health
Set tomes[6] = -1 health
Set tomes[7] = -10 health
Set tomes[8] = -100 health
Set tomes[9] = -1000 health
Set tomes[10] = -10000 health
Set largestTome = 10000
Unit - Create 1 Mage for Neutral Passive at (Center of (Playable map area)) facing Default building facing degrees
Unit - Add Ghost to (Last created unit)
Collapse For each (Integer A) from 1 to 10, do (Actions)
Collapse Loop - Actions
Hero - Create tomes[(Integer A)] and give it to (Last created unit)
Item - Remove (Last created item)
Unit - Remove (Last created unit) from the game
This function toggles the debug messages on/off.
Although not necessary for the the system to work, it is suggested to aid in maintaining and testing.
Trigger:
modHealth Debug
Collapse Events
Player - Player 1 (Red) types a chat message containing -debug as An exact match
Conditions
Collapse Actions
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
modHealth_Debug Equal to True
Collapse Then - Actions
Set modHealth_Debug = False
Game - Display to (All players) the text: modHealth_Debug = F...
Collapse Else - Actions
Set modHealth_Debug = True
Game - Display to (All players) the text: modHealth_Debug = T...

Globals


Table:
TypeNameFunction
IntegerlargestTomeThe amount of health added/removed by the largest tome
Item Type [10]tomesAn array of all the tomes, tomes after the 5th tome are negative.
BooleanmodHealth_DebugIf true the debug messages will be displayed



In addition, 2 example spells have been constructed in the test map, which show how to use the system.
Health Buff, which doubles a unit's health for a short duration, and;
Touch of Death, which permanently decreases a unit's health by 25%.

Known limitations of the system;
  • Only units with an inventory that allows an item to be used can make use of this system.
  • The system is built to handle health up to 100000 without trouble. If you wish to have it manipulate more health than this then I suggest scaling up the system by adding larger tomes and modifying the largestTome constant, and modify the line; call UnitAddItemByIdSwapped( udg_tomes[( 6 + ( 5 * isNegative) - j )], target ) to fit your needs.
  • The performance shift is negligable as the amount of health set to modify increases, however if the health is given in less round numbers (for example 874495 as apposed to 900500) then the system will be marginally slower (not a true limitation, but something to be aware of).



Please give detailed feedback, and be aware that I am not high skilled or knowledgeable about JASS, so try not to use too much jargon ;)
03-20-2010, 08:14 PM#2
TheKid
So this is only accurate to 10? Also it doesn't allow for negative values.

Quote:
Originally Posted by Gorman
Only units with an inventory that allows an item to be used can make use of this system.

I would consider this a pretty major limitation, considering the "clunky" option which you don't want to use (using abilities) allows for this, and handles values that are not multiples of 10.

I would assume the fact that you are creating an item automatically makes this system's overhead greater than the alternative option (abilities) --but I don't know much about that kind of thing.
03-20-2010, 11:07 PM#3
Ammorth
I would look at using binary values to add the tomes in (1, 2, 4, 8, 16, etc...) This will reduce the number of loops/tomes required for the majority of values.

TheKid does have a point though, I think abilities would be faster than tomes as there is less overhead (abilities don't require handle creation/destruction). Although someone would need to stopwatch it.
03-21-2010, 12:36 AM#4
Anitarf
A bigger problem than handle creation is that this does not work on units without an inventory.
03-21-2010, 02:07 AM#5
Earth-Fury
The ability-based variety will always be much faster, and not prone to the requirement of an inventory. Even if the bug is eventually fixed at some time in the future (which I highly doubt), one can just use BonusMod to apply somewhat limited health changes. The ability variant also has the advantage of handling mana, too.

Also, my vJASS implementations of UnitMaxState (and BonusMod) are lightning fast while also being trivial to use, and they even use Mike's ObjectMerger to generate the needed abilities with little to no configuration required by the end user. (Links in my signature, if you're curious.) I really don't see any advantages to this method over the method I used. I especially don't see how my implementations could be called "clunky" :( They literally Just Work™.

(Yes, this post is a bit of a shameless plug. I blame Space Hitler and his nazi moon base.)
03-21-2010, 07:48 AM#6
Gorman
Quote:
Originally Posted by TheKid
So this is only accurate to 10? Also it doesn't allow for negative values.

I would assume the fact that you are creating an item automatically makes this system's overhead greater than the alternative option (abilities) --but I don't know much about that kind of thing.
Uh what? Its accurate to 1, and can do negative values. I guess you didnt read/try it? :3

The only downside is as you said the items, but as I said I dont really know too much advanced stuff. I would assume that adding/removing 10 items wouldn't be too bad.

Quote:
Originally Posted by Ammorth
I would look at using binary values to add the tomes in (1, 2, 4, 8, 16, etc...) This will reduce the number of loops/tomes required for the majority of values.
I think its faster like this already, most people have round values (eg 1500, 3400, 120 etc), so multiples of 10 is generally better. I did a little bit of quick maths, and basically came to this conclusion.
If you have funky health values in your map, then you should modify the system (which is easy anyway) to do what you want.

Quote:
Originally Posted by Ammorth
Although someone would need to stopwatch it.
This would be highly appreciated.

Quote:
Originally Posted by Earth-Fury
The ability-based variety will always be much faster, and not prone to the requirement of an inventory. Even if the bug is eventually fixed at some time in the future (which I highly doubt), one can just use BonusMod to apply somewhat limited health changes. The ability variant also has the advantage of handling mana, too.
The system is made to do one thing only ;)

The 'requirement of an inventory' could be seen as a part of the system, also stops it from accidently being used on non inventory units, a sort of failsafe.

Quote:
Originally Posted by Earth-Fury
Also, my vJASS implementations of UnitMaxState (and BonusMod) are lightning fast while also being trivial to use, and they even use Mike's ObjectMerger to generate the needed abilities with little to no configuration required by the end user. (Links in my signature, if you're curious.) I really don't see any advantages to this method over the method I used. I especially don't see how my implementations could be called "clunky" :( They literally Just Work™.
I just don't like abusing bugs to make systems, that is the clunky bit, even if the bug is unlikely to ever be fixed.

I also don't like having all these other things required to do just a simple task. Its great for you guys who love your JASS and love all your fancy interwoven systems, but I'm not really into that :P
(inb4 flame; its personal preference)

Quote:
Originally Posted by Earth-Fury
(Yes, this post is a bit of a shameless plug. I blame Space Hitler and his nazi moon base.)
Blast, damn that space hitler!
03-21-2010, 02:05 PM#7
Anitarf
Quote:
Originally Posted by Gorman
I also don't like having all these other things required to do just a simple task. Its great for you guys who love your JASS and love all your fancy interwoven systems, but I'm not really into that :P
What other things? UnitMaxState is a stand-alone library and has no mandatory requirements. There's only the optional requirement of AbilityPreload which itself has no other requirements. As far as vJass libraries go, this is rather non-interwoven.
03-21-2010, 02:56 PM#8
Gorman
He said a bunch of names and whatnot, I assumed they were needed.
I'm not really down with the JASS scene etc.
03-21-2010, 04:35 PM#9
Earth-Fury
Quote:
Originally Posted by Gorman
I think its faster like this already, most people have round values (eg 1500, 3400, 120 etc), so multiples of 10 is generally better. I did a little bit of quick maths, and basically came to this conclusion.

1500:
1000
100
100
100
100
100

1500:
1024
256
128
64
16
2

Equal iterations.

9:
1
1
1
1
1
1
1
1
1

9:
8
1

Not so equal.

Powers of 2 are much better, speed-wise.

Quote:
Originally Posted by Gorman
If you have funky health values in your map, then you should modify the system (which is easy anyway) to do what you want.

The point of libraries is that users don't have to modify them. They are black boxes which do exactly what they say they do, saving the user from having to write it themselves. One shouldn't ever have to understand how a library does something to use it.

Quote:
Originally Posted by Gorman
This would be highly appreciated.
Handle creation is slower than ability adding. (Unless you fail to preload the abilities, in which case the first time you add the ability it may be slower.) Powers of 10 are slower than or equal to powers of 2 in speed, depending on the test case. And of course my UnitMaxState code is highly optimized JASS, while yours is using Blizzard.j functions ;) I 100% guarantee almost any benchmark would be in favour of UnitMaxState.

Quote:
Originally Posted by Gorman
The system is made to do one thing only ;)
How does that make it superior when it does the one thing it's meant to do not as well..?

Quote:
Originally Posted by Gorman
The 'requirement of an inventory' could be seen as a part of the system, also stops it from accidently being used on non inventory units, a sort of failsafe.
Or you could check for the inventory abilities when you semantically need to as the end-user, which you should be doing already. You're a really bad programmer if you're relying on a limitation of a library to do checks for you.

Quote:
Originally Posted by Gorman
I just don't like abusing bugs to make systems, that is the clunky bit, even if the bug is unlikely to ever be fixed.
A nondescript dislike is less powerful than a proven method.

------------------------------

Just to be clear, I'm not trying to insult you or discourage you or anything of the sort. I am simply being honest with my years of experience.
03-21-2010, 09:19 PM#10
TheKid
Quote:
Originally Posted by Gorman
also stops it from accidently being used on non inventory units,

Its not like you slip, fall, and irreversibly add unintended life to a unit.
03-23-2010, 08:08 AM#11
Gorman
It's much appreciated Earth :)

Fixing up system now!

Where can I find Mike's ObjectMerger?


Quote:
Originally Posted by TheKid
Its not like you slip, fall, and irreversibly add unintended life to a unit.
Yup, bugs are a myth invented by micro$oft so they can makez more cash amirite?!
03-23-2010, 05:31 PM#12
Ammorth
Its part of the JNGP. You can find examples of how to use it in the Grimex Manual (check the Grimex folder in the JNGP folder). As for using LUA (which I recommend for more than 1 object) you can checkout http://www.wc3c.net/showpost.php?p=1120806&postcount=2 and http://www.wc3c.net/showthread.php?t=107940 (the bonus mod main library).