• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Hidden ATTACK_TYPE in the World Editor?

Status
Not open for further replies.
Level 14
Joined
Dec 12, 2012
Messages
1,007
Hello all,

I wounder if there is some "hidden" functionality in the World Editor which isn't specified at all in the libraries, but still accessable.

According to the common.j , there are seven different AttackTypes, namely:

JASS:
ATTACK_TYPE_NORMAL    = ConvertAttackType(0)
ATTACK_TYPE_MELEE     = ConvertAttackType(1)
ATTACK_TYPE_PIERCE    = ConvertAttackType(2)
ATTACK_TYPE_SIEGE     = ConvertAttackType(3)
ATTACK_TYPE_MAGIC     = ConvertAttackType(4)
ATTACK_TYPE_CHAOS     = ConvertAttackType(5)
ATTACK_TYPE_HERO      = ConvertAttackType(6)

This is also what you get in GUI when using the UnitDamageTargetBJ function to deal damage to a target.

BUT if you use ConvertAttackType(7) as an AttackType-Parameter for this function, you will get a "hidden" AttackType. Just like this:

JASS:
call UnitDamageTargetBJ( unitAttacker, unitAttacked , 1.0, ConvertAttackType(7), DAMAGE_TYPE_UNIVERSAL )

This "hidden" AttackType has some interesting behaviour: If you want to deal 1 damage on a unit with it, it deals in reality:

  • 1 Damage to units with armortype MEDIUM
  • 1 Damage to units with armortype FORTIFIED
  • 25 Damage to units with armortype UNARMORED
  • 150 Damage to units with armortype HERO
  • 400 Damage to units with armortype DIVINE
  • 522 Damage to units with armortype HEAVY
  • 522 Damage to units with armortype NORMAL
  • 2048 Damage to units with armortype LIGHT

With this, its quite easy to identify a units armortype. But even more interesting is: Are there more hidden functionalities in the World Editor? A ConvertAttackType(8) doesn't do anything, so after checking all integers up to 10000, this is the only hidden AttackType. There is also a huge amount of DamageTypes (over 1000), but they don't differ in any kind, so they might be uninteressting. But you can convert many other things, like unitevents. So it would be interessting to know if there are more hidden and usefull functions in the WE.

Does anybody know something about this? I googled for several days now and didn't find anything about this...

Greetings,
lfh
 
Last edited:
Level 16
Joined
Mar 3, 2006
Messages
1,564
I was looking for a system that can do the following:

Adds new types of damage which are: fire, cold, electric, acid poison and magic fire and magic cold plus piercing, slashing, crushing damages but I don't know how that could be done. But I wonder what attack type do if you changed to the in-game different types.
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
I was looking for a system that can do the following:

Adds new types of damage which are: fire, cold, electric, acid poison and magic fire and magic cold plus piercing, slashing, crushing damages but I don't know how that could be done. But I wonder what attack type do if you changed to the in-game different types.

Can be done easily with damage detection.

Before dealing damage, specify attack type based on unit/item/abilities of the damage source, and calculate how much should be done based on attack type/defense type.

Save attack/defense ratios using a hashtable or an array.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
Can be done easily with damage detection.

Before dealing damage, specify attack type based on unit/item/abilities of the damage source, and calculate how much should be done based on attack type/defense type.

Save attack/defense ratios using a hashtable or an array.

That's exactly what I have in mind but I never used that system before. Is this system GUI or JASS ?
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
That's exactly what I have in mind but I never used that system before. Is this system GUI or JASS ?

damage detection? gui... just go in spell section and author search "Bribe". its fairly straight forward.

as for getting a units armor to scale the damage,

JASS:
function GetUnitArmor takes unit u returns real
    local real hp = GetUnitState(u, UNIT_STATE_LIFE)
    local real damage
    call UnitDamageTarget( u, u, 10.0, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
    set damage = hp - GetUnitState(u, UNIT_STATE_LIFE)
    call SetUnitState(u, UNIT_STATE_LIFE, hp)
    if damage > 10.0 then
        set damage = 20.0 - damage
        return (damage-10.0)/(damage*0.06)
    endif
    return (10.0-damage)/(damage*0.06)
endfunction

(from Pharoah)
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Hm, I would better do it this way:

JASS:
function Trig_DamageEvent_Actions takes nothing returns nothing
    set udg_damageDealt = GetEventDamage()
endfunction

JASS:
function GetUnitArmor takes unit u returns real
    local real differenceHP
    local real damage

    call UnitDamageTarget( u, u, 0.00000000000001, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, null)

    set damage = udg_damageDealt*100000000000000
    set differenceHP = damage*0.00000000000001

    call SetUnitLifeBJ( u, GetUnitState(u, UNIT_STATE_LIFE) + differenceHP )

    if damage == 0 then
        return -1000000
    elseif damage > 10.0 then
        set damage = 20.0 - damage
        return (damage-10.0)/(damage*0.06)
    else
        return (10.0-damage)/(damage*0.06)
    endif
    
endfunction

As the unit could die if you deal 10 damage. Also it might crash if the unit is invu (division by zero).


But this has quite nothing to do with the topic of this thread, so I would really like to discuss the hidden functionality of the WE in this thread.

Greetings,
lfh
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Hm, I would better do it this way:

JASS:
function Trig_DDS_DamageEvent_Actions takes nothing returns nothing
    set udg_damageDealt = GetEventDamage()
endfunction

JASS:
function GetUnitArmor takes unit u returns real
    local real differenceHP
    local real damage

    call UnitDamageTarget( u, u, 0.00000000000001, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNKNOWN, null)

    set damage = udg_damageDealt*100000000000000
    set differenceHP = damage*0.00000000000001

    call SetUnitLifeBJ( u, GetUnitState(u, UNIT_STATE_LIFE) + differenceHP )

    return damage
endfunction

As the unit could die if you deal 10 damage. Also it might crash if the unit is invu (division by zero).


But this has quite nothing to do with the topic of this thread, so I would really like to discuss the hidden functionality of the WE in this thread.

Greetings,
lfh

reals can only go to 1/32 so your gonna be returning like millions every time
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
reals can only go to 1/32 so your gonna be returning like millions every time

I don't understand?

I made an ArmorType detection system with exactly this code and it works perfect. It also returns the correct value of the damage, so I don't see the problem?

Try:

JASS:
function testReals takes nothing returns nothing
    local real test = 0.00000000000001

    if (0 == test) then
        call BJDebugMsg("test is not zero")
    else
        call BJDebugMsg("test is zero")
    endif

endfunction

It will notice the difference between the both values.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
Well, actually ConvertAttackType(7) is not empty, thats what makes this so interessting.

Maybe there are more invisible functions which one could use and we only have to find out its IDs?

Indeed, they didn't return null when I tested them but what could be there use if you have no way to detect the attack type, I for myself don't know of a function that can do that.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Indeed, they didn't return null when I tested them but what could be there use if you have no way to detect the attack type, I for myself don't know of a function that can do that.

Huh?

With ConvertAttackType you can set an AttackType, so you allready know the AttackType. An application could be a very simple ArmorType Detection, as mentioned.

And maybe there is a hidden function for AttackType Detection, would be awesome.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
Huh?

With ConvertAttackType you can set an AttackType, so you allready know the AttackType. An application could be a very simple ArmorType Detection, as mentioned.

And maybe there is a hidden function for AttackType Detection, would be awesome.

you set the attack type ok, no problem with that, but when a unit takes the attack it will be hard to detect, if it was easy then you could make a resistance system as well.
 
I'm going to necrobump this thread with some possibly useful information that will seem obvious to a lot of you:

JASS:
constant fogstate       FOG_OF_WAR_MASKED               = ConvertFogState(1)
constant fogstate       FOG_OF_WAR_FOGGED               = ConvertFogState(2)
constant fogstate       FOG_OF_WAR_VISIBLE              = ConvertFogState(4)

These are flags.

I'm pretty sure ConvertFogState(5) will give you FOG_OF_WAR_MASKED and FOG_OF_WAR_VISIBLE at the same time.

Care to try experimenting with this?

Try ConvertFogState(7)
It should give you a combination of all of these!

If they're not actually flags, try ConvertFogState(3) to see what happens.

I came to this realization ~8 months ago and I never got to test it, and I can't test it at the moment :V
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
I'm going to necrobump this thread with some possibly useful information that will seem obvious to a lot of you:

JASS:
constant fogstate       FOG_OF_WAR_MASKED               = ConvertFogState(1)
constant fogstate       FOG_OF_WAR_FOGGED               = ConvertFogState(2)
constant fogstate       FOG_OF_WAR_VISIBLE              = ConvertFogState(4)

These are flags.

I'm pretty sure ConvertFogState(5) will give you FOG_OF_WAR_MASKED and FOG_OF_WAR_VISIBLE at the same time.

Care to try experimenting with this?

Try ConvertFogState(7)
It should give you a combination of all of these!

So basically they use integers to create 32-bit boolean arrays?
 
I'm going to necrobump this thread with some possibly useful information that will seem obvious to a lot of you:

JASS:
constant fogstate       FOG_OF_WAR_MASKED               = ConvertFogState(1)
constant fogstate       FOG_OF_WAR_FOGGED               = ConvertFogState(2)
constant fogstate       FOG_OF_WAR_VISIBLE              = ConvertFogState(4)

These are flags.

I'm pretty sure ConvertFogState(5) will give you FOG_OF_WAR_MASKED and FOG_OF_WAR_VISIBLE at the same time.

Care to try experimenting with this?

Try ConvertFogState(7)
It should give you a combination of all of these!

If they're not actually flags, try ConvertFogState(3) to see what happens.

I came to this realization ~8 months ago and I never got to test it, and I can't test it at the moment :V

Papa Meg discovered something, YAY!

Somewhat, It is just like the ids of the flags summed up. like NewFogState = ConvertFogState(GetHandleId(FOG_OF_WAR_MASKED) + GetHandleId(FOG_OF_WAR_VISIBLE))
Hence, a fogstate that shows both visibility and masked states :D

So, if my statement above is true,hence:
FogState[3] = FOG_OF_WAR_MASKED + FOG_OF_WAR_FOGGED
FogState[5] = FOG_OF_WAR_MASKED + FOG_OF_WAR_VISIBLE
FogState[6] = FOG_OF_WAR_FOGGED + FOG_OF_WAR_VISIBLE
FogState[7] = FOG_OF_WAR_MASKED + FOG_OF_WAR_FOGGED + FOG_OF_WAR_MASKED

You can also try the following perhaps : 0, 8, 9, 10, 11, 12+
 
Summing would work, but for the sake of symmetry, we use bitwise operations for all flag adding/removing/checking.

Code:
// add flag
flags = flags | flag; // bitwise OR the flag in

// remove flag
flags = flags & ~flag; // bitwise AND with NOT flag

// check if flag is set
bool b = flags & flag; // bitwise AND

// check if flag is not set
bool b = flags ^ flag; // bitwise XOR

You can also try the following perhaps : 0, 8, 9, 10, 11, 12+

0 and 8 might bring something new to the table.
If 8 fails, anything higher shouldn't really work. (If you're skeptical, try 16, 32 and the rest of the powers of 2)

Also, I didn't discover anything. Pipedream, Pitzermike, Daeod, Vexorian or some other wc3c.net relics probably tried this many years ago.
A lot of the things we're "discovering" today are usually already known somewhere :p
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
539
I don't know. This kind of thing should be common knowledge.
Not sure why nobody talks about it.

When a programmer looks at such numbers, the first thing that should come to his mind is flags :V

Because it isn't of any significance (is there?). Everyone who sees those numbers gets it.
Same things applies to ConvertMapFlag, ConvertGameType and some more.

What could be of interest are different damagetypes.
common.j jumps over some numbers.
http://jass.sf.net/doc/api/common_j-source.shtml#217

e: or not, op says he tested over 1000 damagetypes…
 
Because it isn't of any significance (is there?)

No idea at all if anything significant could be done with these
Fogstate might allow someone to pull off some crazy visual shit, but this is just a hypothesis and it will require some testing :p

What could be of interest are different damagetype s.
common.j jumps over some numbers.

Yeah, I noticed those. Never got a chance to see what they might be :eek:
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
Level 5
Joined
May 6, 2013
Messages
125
To Come back to the op (though i'm aware of it being quite old and that he wont read this):
I took a quick look into the UnitDamageTarget native:
- every AttackType > 7 is discarded. No hidden attack types there.
- every WeaponType > 0x18 (#24) is discarded. i think common.j's WeaponTypes go till 23, but i dont remember that weaponTypes do anything at all anyways
- I dont get what they do to the DamageType, its doesnt seem to have such a clear border
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,188
The damage type seems to have an "off by one" error in it. Thus the hidden entry is all garbage as it is probably reading values from memory directly after where the damage tables are stored.

Have you tried negative values? It might go backwards and start to read memory before the start of the table.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
interesting stuff, but you cant make an armor detection system of any kind with this because the damage amount for each armor type is not unique

Yes, unfortunatly they are not unique... which is really annoying :D
At least we can use the attacktype to deal armor table independent damage.

To Come back to the op (though i'm aware of it being quite old and that he wont read this):

Hi, I'm still active and reading all this stuff here ;)


The damage type seems to have an "off by one" error in it. Thus the hidden entry is all garbage as it is probably reading values from memory directly after where the damage tables are stored.

Hm I doubt this somehow, as you can use the damagetypes with bigger values without any problems. If they would be just random garbage memory they shouldn't work I think.

I also remember when I tested this that there is some periodicity in the damagetypes: After some values they started again with the first damagetype, so it might just look like there would be thausands of different damagetypes, while in reality some safty mechanism might reduce the user parameter to a valid value.

Good luck testing those :p

edit
Actually, there is one way to test those. Register the ~200 events to 1 trigger.
Whenever it fires, output the return value of GetTriggerEventId() and see if you can find anything interesting :p

Yes, new events would be really awesome^^
But until now I found nothing.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
Yes, unfortunatly they are not unique... which is really annoying :D
Can't you make them unique via gameplay constants?

Regarding the attack types: attack type 7 is reading memory that it isn't supposed to read.
In fact, I just confirmed that:
- the value in UNARMORED is the minimum movement speed for buildings
- the value in HERO and DIVINE is the minimum movement speed for units (maybe it's here twice because there's a different movement speed for units & heroes)
- the value in HEAVY and NORMAL seems to be the hardcoded maximum movement speed (522)
- the value in LIGHT, if I'd take a guess, is the hardcoded maximum sight range?

I also remember when I tested this that there is some periodicity in the damagetypes
I don't know how you tested this, but I just looped through 1 million damage types, and none of them return the same damagetype value
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
Can't you make them unique via gameplay constants?

Regarding the attack types: attack type 7 is reading memory that it isn't supposed to read.
In fact, I just confirmed that:
- the value in UNARMORED is the minimum movement speed for buildings
- the value in HERO and DIVINE is the minimum movement speed for units (maybe it's here twice because there's a different movement speed for units & heroes)
- the value in HEAVY and NORMAL seems to be the hardcoded maximum movement speed (522)
- the value in LIGHT, if I'd take a guess, is the hardcoded maximum sight range?


I don't know how you tested this, but I just looped through 1 million damage types, and none of them return the same damagetype value

150 is the default minimum for units, 400 is default maximum(speed).
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Can't you make them unique via gameplay constants?

1.) No of course not. There is no field in the gameplay constants for this attacktype, thats why its "hidden".

2.) Even if one could it would be completly senseless because you could do that with every other attacktype too.

Regarding the attack types: attack type 7 is reading memory that it isn't supposed to read.
In fact, I just confirmed that:
- the value in UNARMORED is the minimum movement speed for buildings
- the value in HERO and DIVINE is the minimum movement speed for units (maybe it's here twice because there's a different movement speed for units & heroes)
- the value in HEAVY and NORMAL seems to be the hardcoded maximum movement speed (522)
- the value in LIGHT, if I'd take a guess, is the hardcoded maximum sight range?

Hm, interesting.

I don't know how you tested this, but I just looped through 1 million damage types, and none of them return the same damagetype value

Some damagetypes are affected by the armor value (depending on the attacktype too). When you loop through all damagetypes and use them to deal damage you will notice that the offset between those armor value affected damagetypes is constantly repeated. The handle id is of course unique.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
150 is the default minimum for units, 400 is default maximum(speed).

Yes, I made a mistake by setting max movement speed below min movement speed, which is why I got the same value for HERO and DIVINE.

UNARMORED = Minimum Building Movement Speed
HERO = Minimum Unit Movement Speed
DIVINE = Maximum Unit Movement Speed
HEAVY / NORMAL = Absolute maximum unit/building movement speed (522)
LIGHT = unknown, possibly maximum sight range.

1.) No of course not. There is no field in the gameplay constants for this attacktype, thats why its "hidden".

I was talking about the non-hidden attack types. If you change those gameplay constants, you can detect the defense type of a unit by calling UnitDamageTarget() and seeing how much damage you actually did.

Also, small nitpick, but it's not really a handle id, it's just the number you passed. ConvertAttackType(3) == ConvertDamageType(3)
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Yes, I made a mistake by setting max movement speed below min movement speed, which is why I got the same value for HERO and DIVINE.

UNARMORED = Minimum Building Movement Speed
HERO = Minimum Unit Movement Speed
DIVINE = Maximum Unit Movement Speed
HEAVY / NORMAL = Absolute maximum unit/building movement speed (522)
LIGHT = unknown, possibly maximum sight range.

I could just verify this. If you change the corresponding values in the gamplay constants, the dealt damage from the hidden attacktype is also changed.

The hidden attacktype deals for example 400 damage on divine armor (which is the default value for maximum unit movement speed as you said). If I change this value to 200, the attacktype deals 200 damage. So it is really reading from those memory fields.

Good job spotting this!

I was talking about the non-hidden attack types. If you change those gameplay constants, you can detect the defense type of a unit by calling UnitDamageTarget() and seeing how much damage you actually did.

Yes, but then it would not be armor table independent. But this doesn't work anyway with the new discoveries.

Also, small nitpick, but it's not really a handle id, it's just the number you passed. ConvertAttackType(3) == ConvertDamageType(3)

How should an attacktype be equal to a damagetype?
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
I could just verify this. If you change the corresponding values in the gamplay constants, the dealt damage from the hidden attacktype is also changed.
That's basically how I verified it.

How should an attacktype be equal to a damagetype?
It IS equal. ConvertAttackType(0) is also equal to "null". I assume Convert<anything> just returns the int parameter.
 
You know, a mouse can be represented by a singleton class or any static set of data. If Blizzard software engineers actually used a static singleton to represent the mouse internally (they could be avoiding this completely by just using the data Win32 API provides o.o), we might be able to use these ConvertXXX functions to navigate to the memory addresses of these coordinates :D

ConvertPlayerColor(16+) take you into the textures in the MPQ. It's undefined behavior really, but one of the possible scenarios is getting MPQ textures as my testing in the past showed :p
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,188
Hm I doubt this somehow, as you can use the damagetypes with bigger values without any problems. If they would be just random garbage memory they shouldn't work I think.
That is what bound checking is for. It also is why I say it is an "off by one" error as instead of using <7 for maximum bound check they used <=7 which is, well, off by one.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
Might be that it references something that isn't usually used. Not constants then, though.

Has anyone tried negative attack types?

I tried negative attack types, I also tried positive attack types up to 10000. With each attack type having at least 8 floats, that's 80Kb of memory that would all be zero? No, like DSG said, it's just a bounds checking mistake.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,188
It could also be a bounds checking error caused by the removal of an attack type. During early development of WC3 there may have been an extra attack type. This attack type was removed before release and the data entry for it eradicated. Thus the native still thinks that the game has this attack type (why the value is valid) but in reality it is pointing to garbage (as mentioned above, they are other constants that are stored directly after the damage type tables in memory).
 
Level 18
Joined
Oct 20, 2007
Messages
353
You know, a mouse can be represented by a singleton class or any static set of data. If Blizzard software engineers actually used a static singleton to represent the mouse internally (they could be avoiding this completely by just using the data Win32 API provides o.o), we might be able to use these ConvertXXX functions to navigate to the memory addresses of these coordinates :D

ConvertPlayerColor(16+) take you into the textures in the MPQ. It's undefined behavior really, but one of the possible scenarios is getting MPQ textures as my testing in the past showed :p

I had similar idea in the past - change texture by changing player color to 16+ and importing that textures with appropriate name. But this did't worked, game crashed when I was setting 16+ color to unit(

Interesting, what result you had?
 
JASS:
struct Test extends array

    private static method onInit takes nothing returns nothing
        // Choose any number you want here.
        // If you continue to retry this code, at one point, you'll get nice textures <:
        local playercolor undefinedBehaviorFactory = ConvertPlayerColor(22)
        local unit u = CreateUnit(Player(0), 'hpea', 0, 0, 0)

        call SetUnitColor(u, undefinedBehaviorFactory)

        set u = null
    endmethod
endstruct

Run that a few times. When it doesn't crash, it'll give you weird effects or no effects at all.
 
Level 18
Joined
Oct 20, 2007
Messages
353
JASS:
struct Test extends array

    private static method onInit takes nothing returns nothing
        // Choose any number you want here.
        // If you continue to retry this code, at one point, you'll get nice textures <:
        local playercolor undefinedBehaviorFactory = ConvertPlayerColor(22)
        local unit u = CreateUnit(Player(0), 'hpea', 0, 0, 0)

        call SetUnitColor(u, undefinedBehaviorFactory)

        set u = null
    endmethod
endstruct

Run that a few times. When it doesn't crash, it'll give you weird effects or no effects at all.

Haha, this is pretty much the same as I did, only the difference was that I have tried only 17th color - game crashed and I thought that the same will be for other values))

This is a lesson for me now - never give up!)

Thanks for pointing out that there is some effects for greater values)
 
Status
Not open for further replies.
Top