J4L's "Damage" breaking the thread ?!

Komaqtion

You can change this now in User CP.
Reaction score
469
Hello :D

I just saw a post in some thread here about someone wanting to block "damage giving", meaning that nearby heroes shouldn't get experience when the unit dies.

So, I thought I'd use Damage for this, in combination with AIDS (And maybe Event somehow :S XD) so this is what I came up with (So far ;)):
JASS:
library BlockExpGive requires AIDS, Damage, Event

    struct ExpData extends array
        //! runtextmacro AIDS()
        
        static if DEBUG_MODE then
            private static group ENUM
        endif
        
        boolean BlockingExp
        
        method AIDS_onCreate takes nothing returns nothing
            set BlockingExp = false
        endmethod
        
        static method Actions takes nothing returns boolean
            local unit u = GetTriggerUnit()
            local thistype this = thistype[ u ]
            
            call BJDebugMsg( "Blocked !" )
            
            if BlockingExp and GetEventDamage() >= GetWidgetLife( u ) then
                call Damage_Block( GetEventDamage() - GetWidgetLife( u ) - .415 )
                
                call BJDebugMsg( "Blocked !" )
                
                call RemoveUnit( u )
            endif
            
            set u = null
            
            return false
        endmethod
        
        static if DEBUG_MODE then
        
            private static method Filters takes nothing returns boolean
                local unit u = GetFilterUnit()
                
                set thistype( GetUnitIndex( u ) ).BlockingExp = true
                
                call BJDebugMsg( GetUnitName( u ) )
                
                return false
            endmethod
            
        endif
        
        private static method AIDS_onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            
            call BJDebugMsg( "Init !" )
            
            call Damage_RegisterEvent( t )
            call TriggerAddCondition( t, Condition( function thistype.Actions ) )
            
            call BJDebugMsg( "Registered !" )
            
            static if DEBUG_MODE then
                set thistype.ENUM = CreateGroup()
                
                call GroupEnumUnitsInRect( ENUM, bj_mapInitialPlayableArea, Filter( function thistype.Filters ) )
            endif
            
        endmethod
        
    endstruct
    
endlibrary


The there's only one tiny problem here, and that is that any line after [ljass]call Damage_RegisterEvent( t )[/ljass] doesn't run, meaning that that line somehow broke the thread...

So, I haven't actually used J4L's system Damage before (If I remember correctly XD) so I'm not quite sure how to use it, but I thought I got it right :(

Anyways, anyone can help me fix this little issue I'm having ? :eek:

(Also, if I remove that line (The Damage_RegisterEvent one) then there are a ton of AIDS errors in-game when I test it...
 

13lade619

is now a game developer :)
Reaction score
399
did you let AIDS and Damage create their required object data (from objectmerger)

JASS:
//!external ObjectMerger w3a Adef AIDS anam "State Detection" ansf "(AIDS)" aart "" arac 0

//! external ObjectMerger w3a AIlz dprv anam "Life Bonus" ansf "(Damage System)" Ilif 1 500000 aite 0


what errors in AIDS exactly?
 

Komaqtion

You can change this now in User CP.
Reaction score
469
AIDS has one of those ?! :S

Might not have updated them then XD
Will check :D

Thank you ;)

EDIT: Ok, so now it seems to be registering ok since both the "Init !" and "Registered !" messages appears :D
(Before only the "Init !" was there :D)

But not a single "Blocked !" message appears when I attack a unit in-game...
Any ideas ? :S
 

Komaqtion

You can change this now in User CP.
Reaction score
469
You mean in the debug area ? :S

If I change that, AIDS errors appear saying that I used GetUnitId when I should've been using GetUnitIndex...
 

Komaqtion

You can change this now in User CP.
Reaction score
469
It is true, and I've got it working now :D
Though, can't remember how... :S XD

But this is the code atm, and as you can see I tried to make the unit still give bounty, and only disable exp giving, but it doesn't work (As you either just kill it, giving neither bounty or exp, or you make another unit kill it, but if that unit is an ally then there's still the exp gain if it's your own you get it all and if it's an enemy you get nothing...)

So, any ideas on how to enable bounty for a unit and not exp give ? :S

JASS:
library BlockExpGive initializer Init requires AIDS, Damage, Event, TimerUtils, optional DummyCaster
    
    static if not LIBRARY_DummyCaster then
    
        globals
            private constant integer DUMMY_ID = 'dumy'
            
            private unit Damage_Dummy
        endglobals
        
    endif

    static if DEBUG_MODE then
        
        globals
            private group ENUM
            private timer DEBUG
        endglobals
        
    endif

    struct ExpData extends array
        //! runtextmacro AIDS()
        
        boolean BlockingExp
        
        method AIDS_onCreate takes nothing returns nothing
            set BlockingExp = false
        endmethod
        
        static method Actions takes nothing returns boolean
            local unit u = GetTriggerUnit()
            local unit s = GetEventDamageSource()
            local player p = GetOwningPlayer( s )
            local thistype this = thistype[ u ]
            local real dmg = GetEventDamage()
            
            if BlockingExp and dmg >= GetWidgetLife( u ) then
                //call Damage_Block( dmg )
                call KillUnit( u )
                
                /*static if LIBRARY_DummyCaster then
                    call SetUnitOwner( DUMMY, p, false )
                    call Damage_EnableEvent( false )
                    call Damage_Pure( DUMMY, u, GetUnitState( u, UNIT_STATE_MAX_LIFE ) + dmg )
                    call Damage_EnableEvent( true )
                else
                    call Damage_EnableEvent( false )
                    call Damage_Pure( Damage_Dummies[ GetPlayerId( p ) ], u, GetUnitState( u, UNIT_STATE_MAX_LIFE ) + dmg )
                    call Damage_EnableEvent( true )
                endif*/
                
            endif
            
            set u = null
            set s = null
            set p = null
            
            
            return false
        endmethod
        
    endstruct
    
    static if DEBUG_MODE then
    
        private function Filters takes nothing returns boolean
            local unit u = GetFilterUnit()
            
            set ExpData( GetUnitIndex( u ) ).BlockingExp = true
            
            return false
        endfunction
        
        private function DebugStuff takes nothing returns nothing
            set ENUM = CreateGroup()
            
            call GroupEnumUnitsInRect( ENUM, bj_mapInitialPlayableArea, Filter( function Filters ) )
            call ReleaseTimer( GetExpiredTimer() )
        endfunction
        
    endif
    
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local player p = Player( PLAYER_NEUTRAL_PASSIVE )
        
        call Damage_RegisterEvent( t )
        call TriggerAddCondition( t, Condition( function ExpData.Actions ) )
        
        static if DEBUG_MODE then
            set DEBUG = NewTimer()
            
            call TimerStart( DEBUG, 0.00, false, function DebugStuff )
        endif
    
        static if not LIBRARY_DummyCaster then
            set Damage_Dummy = CreateUnit( p, DUMMY_ID, 0., 0., bj_UNIT_FACING )
        endif
        
        set p = null
    endfunction
    
endlibrary
 

the Immortal

I know, I know...
Reaction score
51
On lethal damage pick all heroes allied to the damage source, suspend their XP gain, start a 0 sec timer, and on expire revert the change (if it should be reverted). Shouldda work, neither tested nor anything but.. try it.

[ljass]native SuspendHeroXP takes unit whichHero, boolean flag returns nothing[/ljass]
is all you need.

A sample (freehanded, but there's the idea)

JASS:
    globals
        private unit array heroList   //list of heroes whose exp should be reset
        private integer h_c = 0       //count of heroes saved into heroList
        
        private group g = CreateGroup()   //instant enum group
        private timer t = CreateTimer()     //instant expire timer
        private player dmgSource             //player killing the unit
        private boolean timStarted = false   //whether timer is firing the next loop
        
        private constant integer EXP_RANGE = 1000
    endglobals
    
    private function onExpire takes nothing returns nothing
        //for each hero in the list, enable getting exp
        local integer i = 0
        loop
            exitwhen i == h_c
            call SuspendHeroXP(heroList<i>, false)
            set i = i + 1
        endloop
        set h_c = 0
        set timStarted = false
    endfunction
    
    function heroEnum takes nothing returns boolean
        //if the unit is a hero and is taking xp (ally of killer)
        if IsUnitType(GetEnumUnit(), UNIT_TYPE_HERO) and IsUnitAlly(GetFilterUnit(), dmgSource) and not IsSuspendedXP(GetEnumUnit()) then
            set heroList[h_c] = GetEnumUnit()   //add it to the list of heroes
            call SuspendHeroXP(heroList[h_c], true) //disable xp gain
            set h_c = h_c + 1                       //incr counter
        endif
        return false
    endfunction
    
    //when any unit takes damage
    function onDamage takes nothing returns nothing
        
        if /* lethal damage and suspended xp */ then
            set DmgSource = GetOwningPlayer(GetEventDamageSource()) //damaging player
            call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), EXP_RANGE, Condition(function heroEnum))    //enum units that would take xp
            if not timStarted then
                call TimerStart(t, 0., false, function onExpire) //instantly revert exp gain
                set timStarted = true   //so if multiple units are killed at the same time it wont fire multiplez?
            endif
        endif
    endfunction
</i>




EDIT: Tweaked a bit so it should work with mass-killing AoE effects nao. Not sure if that timer safety is needed, but it's cleaner anyway.
 

Komaqtion

You can change this now in User CP.
Reaction score
469
Thanks for that XD

Ok, so I've worked on this a little, and I came up with this:
JASS:
library BlockExpGive initializer Init requires AIDS, Damage, TimerUtils, optional DummyCaster

    /*static if DEBUG_MODE then
        
        globals
            private group ENUM
            private timer DEBUG
        endglobals
        
    endif*/
    
    static if not LIBRARY_DummyCaster then
        
        globals
            private constant integer DUMMY_ID = &#039;dmmy&#039;
            
            private unit Damage_Dummy = CreateUnit( Player( bj_PLAYER_NEUTRAL_EXTRA ), DUMMY_ID, 0., 0., 0. )
        endglobals
    
    endif
    
    globals
        private constant boolean GLOBAL_XP_DISTRIBUTION = false
    endglobals
    
    static if not GLOBAL_XP_DISTRIBUTION then
        
        globals
            private constant real EXP_GAIN_RANGE = 1200.
        endglobals
        
    endif
        
    globals
        private constant group ExpGroup = CreateGroup()
        
        private unit Damaged = null
        private unit array ExpHeroes
        
        private player Owner = null
        
        private integer HeroAmount = 0
    endglobals

    struct ExpData extends array
        //! runtextmacro AIDS()
        
        boolean BlockExp
        boolean BlockBounty
        boolean BlockGainExp
        boolean BlockGainBounty
        
        timer ExpTimer
        timer BountyTimer
        
        //static thistype EnumData
        
        method AIDS_onCreate takes nothing returns nothing
            set BlockExp = false
            set BlockBounty = false
        endmethod
        
        private static method SuspendExp takes nothing returns boolean
            local unit u = GetFilterUnit()
            local player p = GetOwningPlayer( u )
            
            if IsUnitType( u, UNIT_TYPE_HERO ) and UnitAlive( u ) and not IsUnitAlly( Damaged, p ) then
                set HeroAmount = HeroAmount + 1
                set ExpHeroes[ HeroAmount ] = u
                
                call SuspendHeroXP( u, true )
            endif
            
            set u = null
            set p = null
            
            return false
        endmethod
        
        private static method SuspendExpSingle takes nothing returns boolean
            local unit u = GetFilterUnit()
            local player p = GetOwningPlayer( u )
            
            if IsUnitType( u, UNIT_TYPE_HERO ) and UnitAlive( u ) and not IsUnitAlly( Damaged, p ) and thistype[ u ].BlockGainExp then
                set HeroAmount = HeroAmount + 1
                set ExpHeroes[ HeroAmount ] = u
                
                call SuspendHeroXP( u, true )
            endif
            
            set u = null
            set p = null
            
            return false
        endmethod
        
        private static method ReturnExpGain takes nothing returns nothing
            local integer i = 1
            
            loop
                exitwhen i &gt; HeroAmount
                
                call SuspendHeroXP( ExpHeroes[ i ], false )
                
                set ExpHeroes[ i ] = null
                
                set i = i + 1
            endloop
            
            call ReleaseTimer( GetExpiredTimer() )
        endmethod
        
        private static method ResetState takes nothing returns nothing
            call SetPlayerState( Owner, PLAYER_STATE_GIVES_BOUNTY, 1 )
            call ReleaseTimer( GetExpiredTimer() )
        endmethod
        
        private static method ResetAlliance takes nothing returns nothing
            call SetPlayerAlliance( Player( bj_PLAYER_NEUTRAL_EXTRA), Owner, ALLIANCE_SHARED_XP, false )
            call ReleaseTimer( GetExpiredTimer() )
        endmethod
        
        static method Actions takes nothing returns boolean
            local unit u = GetTriggerUnit()
            local unit s = GetEventDamageSource()
            local real dmg = GetEventDamage()
            local player p = GetOwningPlayer( u )
            local player so = GetOwningPlayer( s )
            local thistype this = thistype[ u ]
            
            if dmg &gt;= GetWidgetLife( u ) then
                set Damaged = u
                set ExpTimer = NewTimer()
                set HeroAmount = 0
            
                if BlockExp then
                    
                    static if GLOBAL_XP_DISTRIBUTION then
                        call GroupEnumUnitsInRect( ExpGroup, bj_mapInitialPlayableArea, Filter( function thistype.SuspendExp ) )
                    else
                        call GroupEnumUnitsInRange( ExpGroup, GetUnitX( u ), GetUnitY( u ), EXP_GAIN_RANGE, Filter( function thistype.SuspendExp ) )
                    endif
                    
                else
                    
                    static if GLOBAL_XP_DISTRIBUTION then
                        call GroupEnumUnitsInRect( ExpGroup, bj_mapInitialPlayableArea, Filter( function thistype.SuspendExpSingle ) )
                    else
                        call GroupEnumUnitsInRange( ExpGroup, GetUnitX( u ), GetUnitY( u ), EXP_GAIN_RANGE, Filter( function thistype.SuspendExpSingle ) )
                    endif
                    
                endif
                
                call TimerStart( ExpTimer, 0., false, function thistype.ReturnExpGain )
                
                if GetPlayerState( p, PLAYER_STATE_GIVES_BOUNTY ) &gt;= 1 then
                    
                    if BlockBounty then
                        set Owner = p
                        set BountyTimer = NewTimer()
                        
                        call SetPlayerState( p, PLAYER_STATE_GIVES_BOUNTY, 0 )
                        call TimerStart( BountyTimer, 0., false, function thistype.ResetState )
                    elseif thistype[ s ].BlockGainBounty then
                        
                        static if LIBRARY_DummyCaster then
                            call SetUnitOwner( DUMMY, Player( bj_PLAYER_NEUTRAL_EXTRA ), false )
                            
                            if not GetPlayerAlliance( Player( bj_PLAYER_NEUTRAL_EXTRA ), so, ALLIANCE_SHARED_XP ) then
                                set Owner = so
                                set BountyTimer = NewTimer()
                                
                                call SetPlayerAlliance( Player( bj_PLAYER_NEUTRAL_EXTRA ), so, ALLIANCE_SHARED_XP, true )
                                call TimerStart( BountyTimer, 0., false, function thistype.ResetAlliance )
                            endif
                            
                            call Damage_EnableEvent( false )
                            call Damage_Pure( DUMMY, u, GetUnitState( u, UNIT_STATE_MAX_LIFE ) + dmg )
                            call Damage_EnableEvent( true )
                        else
                            call SetUnitOwner( Damage_Dummy, Player( bj_PLAYER_NEUTRAL_EXTRA ), false )
                            
                            if not GetPlayerAlliance( Player( bj_PLAYER_NEUTRAL_EXTRA ), so, ALLIANCE_SHARED_XP ) then
                                set Owner = so
                                set BountyTimer = NewTimer()
                                
                                call SetPlayerAlliance( Player( bj_PLAYER_NEUTRAL_EXTRA ), so, ALLIANCE_SHARED_XP, true )
                                call TimerStart( BountyTimer, 0., false, function thistype.ResetAlliance )
                            endif
                            
                            call Damage_EnableEvent( false )
                            call Damage_Pure( Damage_Dummy, u, GetUnitState( u, UNIT_STATE_MAX_LIFE ) + dmg )
                            call Damage_EnableEvent( true )
                        endif
                        
                    endif
                    
                endif
                
            endif
            
            set u = null
            set p = null
            set so = null
            set s = null
            
            return false
        endmethod
        
    endstruct
    
    /*static if DEBUG_MODE then
    
        private function Filters takes nothing returns boolean
            local unit u = GetFilterUnit()
            
            set ExpData( GetUnitIndex( u ) ).BlockExp = false
            set ExpData( GetUnitIndex( u ) ).BlockBounty = false
            set ExpData( GetUnitIndex( u ) ).BlockGainExp = false
            set ExpData( GetUnitIndex( u ) ).BlockGainBounty = true
            
            return false
        endfunction
        
        private function DebugStuff takes nothing returns nothing
            call GroupEnumUnitsInRect( ENUM, bj_mapInitialPlayableArea, Filter( function Filters ) )
            call ReleaseTimer( GetExpiredTimer() )
        endfunction
        
    endif*/
    
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        
        call Damage_RegisterEvent( t )
        call TriggerAddCondition( t, Condition( function ExpData.Actions ) )
        
        /*static if DEBUG_MODE then
            set DEBUG = NewTimer()
            set ENUM = CreateGroup()
            
            call SetPlayerState( Player( 1 ), PLAYER_STATE_GIVES_BOUNTY, 1 )
            call TimerStart( DEBUG, 0.00, false, function DebugStuff )
        endif*/
        
    endfunction
    
endlibrary


Now, I am VERY uncertain if this is useful, but I thought well what the heck, I'll write it anyways XD

So, this snippet will enable you to make a certain unit not yield experience and/or bounty when killed, and you can also disable the ability for a unit to gain experience (Not too hard XD) and also not gain bounty from units :D

As said, might be useful to some people :S
Any comments on this idea ? :eek:
Or the code maybe ? :D
 

the Immortal

I know, I know...
Reaction score
51
Yeah, found a flaw. What I wrote about it being "fixed" when using mass-killing AoE abilities would be wrong, as if you kill a unit that doesn't give XP and one that does with, let's say, a thunder clap, it would most probably run the damage events instantly one after another, the 1st unit will disable xp, even though the 2nd won't, and instantly after that (next loop i.e. after 0 seconds) xp will be restored with hero not taking any exp at all.

Just a guess based on my understanding of how it works. Test it out, though.
 

Komaqtion

You can change this now in User CP.
Reaction score
469
Yeah, I'll try it out :D

But, you have any ideas on a workaround of it if that's how it is ? :S

EDIT: Ok, so it seems to work just fine with the experience, though it's the bounty that's making trouble as there you have to disable the entire player's ability to give bounty, meaning that in that if you kill two units owned by the same player with a AoE spell, then you won't get any bounty at all :(

So this is something I'd really need a solution too :S
 

Zwiebelchen

You can change this now in User CP.
Reaction score
60
Why dont you just trigger all bounty and xp and disable the default bounty and xp rules?

When mapping in wc3, you must get to a point where you have to realize that once you accept triggering everything in your map, you can get rid of almost all limitations of the wc3 engine.
 

Komaqtion

You can change this now in User CP.
Reaction score
469
Well, I know I can do that, but I just wanted to try to do it this way... :p
And this is less work (If I can get it to work sometime XD) since you don't have to redo everything ;)
 

Komaqtion

You can change this now in User CP.
Reaction score
469
Bump, any other thoughts about this ?! :S

Any ideas on how to fix the bounty-bug with AoE effect killing two units of the same player ? :eek:
 

Komaqtion

You can change this now in User CP.
Reaction score
469
Well, I am using AIDS... :S

And, the problem still is that two units owned by the same player can't get killed by the same AoE attack because you need to disable the bounty for the entire player and it takes 0.0 seconds of a timer to return the bounty giving so if one of those units has GIVE_BOUNTY on and the other doesn't, no bounty will be awarded anyways...
 

Jesus4Lyf

Good Idea™
Reaction score
397
And, the problem still is that two units owned by the same player can't get killed by the same AoE attack because you need to disable the bounty for the entire player and it takes 0.0 seconds of a timer to return the bounty giving so if one of those units has GIVE_BOUNTY on and the other doesn't, no bounty will be awarded anyways...
You know you can manually add XP if it's disabled at the time?
Dunno if that helps... :)
 

Jesus4Lyf

Good Idea™
Reaction score
397
The formula is based on constants in the map. You may be able to get the values by killing a bunch of units on map init and seeing how much xp they get.

It really depends what you want to achieve with your library, and why. Does anyone have a need for this?

The other option is never disable XP. Instead, add negative XP (through tomes if not straight JASS - I know this is possible) and record what abilities a unit has learned, relearn them if the unit loses a level from XP (I don't know if this is possible, anyway). :p
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top