• 🏆 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!

Bonus Exp System

Status
Not open for further replies.
Level 19
Joined
Mar 18, 2012
Messages
1,716
The last project I was working on before I stopped modding was some sort of Diablo3 wc3 clone. Howevery quite awesome compared to those, which already exist.
This may be useful for someone, instead of dumping it I rather post it here.

Doesn't work for minion/associated/summoned units, but it's not really difficult to implement such a feature aswell.

JASS:
library BonusExperience /* v1.0.0.0
*************************************************************************************
*
*   Adds bonus exp to hero type units after killing a specific amount of units
*   within a configurable time interval.
*
*   Unit Indexer version. Works with any Unit Indexer there is.
*
*************************************************************************************
*
*   */uses/*
*
*       */ TimerUtils  /* 
*       */ optional RegisterPlayerUnitEvent /*
*
************************************************************************************
*
*   Credits
*
*       To Vexorian
*       -----------------------
*
*           For TimerUtils
*
*       To Maghteridon96
*       -----------------------
*
*           For RegisterPlayerUnitEvent
*
**************************************************************************************
*
*   1. Import instruction
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*       Copy the BonusExperience script and TimerUtils into your map.
*       Your map needs an UnitIndexer.
*
*   2. API
*   ¯¯¯¯¯¯
*    function RegisterBonusExperienceUnit takes unit who returns nothing
*    function RemoveBonusExperienceUnit takes unit who returns nothing
*    function RestartBonusExperienceTimer takes unit who returns nothing
*    function RegisterBonusExperienceEvent takes code func returns triggercondition
*
*   3. Configuration
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*/
    globals
        /*
        *   You can read these 3 fields from everywhere. They are set before the exp event trigger fires.
        *   Simple put library BonusExperience as a requirement or declare it as a scope.
        */
        integer BONUS_EXP_EVENT_COUNTER = 0//Amount of killed units
        integer BONUS_EXP_EVENT_AMOUNT  = 0//Amount of gained bonus experience
        unit BONUS_EXP_EVENT_UNIT       = null//Event unit
        /*
        *   Within this timegap a new unit has to die in order to reset the countdown.
        *   The countdown can also be manually reset via function RestartBonusExperienceTimer(unit)
        */  
        private constant real CLOCK_EXPIRES           = 5.
        /*
        *   Eyecandy upon hero level up.
        */
        private constant boolean SHOW_EYE_CANDY       = true
        /*
        *   Minimum amount of units, triggering the exp event.
        */
        private constant integer MINIMUM_UNITS_KILLED = 5
    endglobals 
    /*  
    *   Filter out specific dying units, which are not included in the bonus exp system.
    */
    private function FilterUnit takes unit dying returns boolean
        return true
    endfunction
    /*
    *   Change the formula to your needs. This one is a very simple linear calculation.
    *   Your arguments are the unit gaining exp and the amount of killed units.
    */  
    private function GetExperience takes unit who, integer counter returns integer
        return 10*counter
    endfunction
    
//Script code. Do not change anything below 
    private keyword INITITALIZE_BONUS_EXP_SYSTEM

    private struct BonusExperience extends array
        timer clock
        integer counter
        unit hero
        static trigger EXP_EVENT_TRIGGER  = CreateTrigger()
        
        private static method callback takes nothing returns nothing
            local thistype this = thistype(GetTimerData(GetExpiredTimer()))
            if (counter >= MINIMUM_UNITS_KILLED) then
                set BONUS_EXP_EVENT_UNIT    = hero
                set BONUS_EXP_EVENT_COUNTER = counter
                set BONUS_EXP_EVENT_AMOUNT  = GetExperience(BONUS_EXP_EVENT_UNIT, BONUS_EXP_EVENT_COUNTER)
                
                call AddHeroXP(BONUS_EXP_EVENT_UNIT, BONUS_EXP_EVENT_AMOUNT, SHOW_EYE_CANDY)
                
                call TriggerEvaluate(EXP_EVENT_TRIGGER)
                set BONUS_EXP_EVENT_AMOUNT  = 0
                set BONUS_EXP_EVENT_UNIT    = null
                set BONUS_EXP_EVENT_COUNTER = 0
            endif
            set counter = 0
        endmethod
    
        private static method onDeathEvent takes nothing returns boolean
            local unit killer   = GetKillingUnit()
            local thistype this = thistype(GetUnitUserData(killer))
            if (clock != null) and (IsUnitEnemy(killer, GetTriggerPlayer())) and FilterUnit(GetTriggerUnit()) then
            
                set counter = counter + 1
                call TimerStart(clock, CLOCK_EXPIRES, false, function thistype.callback)
                
            endif
            set killer = null
            return false
        endmethod
    
        method restart takes nothing returns nothing
            debug if hero == null or clock == null then
            debug call BJDebugMsg("ERROR: library BonusExperience, method restart, unit or timer doesn't exist.")
            debug endif
            
            call TimerStart(clock, CLOCK_EXPIRES, false, function thistype.callback)
        endmethod
    
        method clear takes nothing returns nothing
            debug if (0 == this) then
            debug call BJDebugMsg("ERROR: library BonusExperience, method clear, 0 == UnitIndex, Attempt to remove a not indexed unit.")
            debug return
            debug endif
            
            debug if (hero == null) then
            debug call BJDebugMsg("ERROR: library BonusExperience, method clear, hero == null, Attempt to remove a not registered unit.")
            debug endif
            
            if (clock != null) then
                call ReleaseTimer(clock)
                set clock = null
            endif
            set hero = null
                
        endmethod
    
        static method register takes unit who returns nothing
            local thistype this = thistype(GetUnitUserData(who))
            
            debug if (0 == this) then
            debug call BJDebugMsg("ERROR: library BonusExperience, static method register, 0 == UnitIndex, Attempt to add a not indexed unit")
            debug return
            debug endif
            
            debug if not IsUnitType(who, UNIT_TYPE_HERO) then
            debug call BJDebugMsg("ERROR: library BonusExperience, static method register, UnitTypeCheck, Attempt to add a none hero unit" + GetUnitName(who)) 
            debug return
            debug endif
            
            if (clock == null) then
                set clock = NewTimerEx(this)
            endif
            
            if (hero != null) then
                
                debug if (hero == who) then
                debug call BJDebugMsg("ERROR: BonusExperience is already initialized for " + GetUnitName(who))
                debug return
                debug endif
                
                call this.clear()
                
            endif
            
            set counter = 0
            set hero    = who
            
        endmethod
    
        implement INITITALIZE_BONUS_EXP_SYSTEM
    endstruct
    
    private module INITITALIZE_BONUS_EXP_SYSTEM
        private static method onInit takes nothing returns nothing
            static if LIBRARY_RegisterPlayerUnitEvent then
                call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeathEvent)
            else
                local trigger t = CreateTrigger()
                call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
                call TriggerAddCondition(t, Condition(function thistype.onDeathEvent))
                set t = null
            endif
        endmethod
    endmodule
//Wrappers
    function RegisterBonusExperienceUnit takes unit who returns nothing
        call BonusExperience.register(who)
    endfunction
    
    function RemoveBonusExperienceUnit takes unit who returns nothing
        call BonusExperience(GetUnitUserData(who)).clear()
    endfunction
    
    function RestartBonusExperienceTimer takes unit who returns nothing
        call BonusExperience(GetUnitUserData(who)).restart()
    endfunction
    
    function RegisterBonusExperienceEvent takes code func returns triggercondition
        return TriggerAddCondition(BonusExperience.EXP_EVENT_TRIGGER, Condition(func))
    endfunction 
    
endlibrary
 
Status
Not open for further replies.
Top