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

[vJASS] Custom Hero XP Script Feedback

Status
Not open for further replies.
Level 31
Joined
Jul 10, 2007
Messages
6,306
update will be able to display hero level and will be able to use unit levels rather than point values

Update Specs
Safe Max Hero Level: 10000
Good Max Unit Level: 100000

Be able to add from .01% to 100% xp.
End Update Specs

Go Here

This script is also currently 100% untested (haven't even run it yet).


Anyways, with all of the masses of bugs concerning hero level/xp, I decided that it was better to just go 100% custom.


I called this library Hero Bounty since it handles all hero rewards-
hero xp
hero gold bounty
hero lumber bounty
hero ability leveling

It can also handle which units share kills with a unit


Right now its behavior is set up so that only heroes get bounty. If a player has multiple heroes, then that player gets bounty multiple times. If the player doesn't have a hero, then that player can't get bounty (since only heroes receive bounty). I'm not sure whether this is a desired behavior in an RTS or not =). It could be good as it would put more stress on the importance of heroes (heroes representing the player, not the units) This is more set up for non RTS maps. Even then, if a player kills a unit with like a pet and their hero is across the map, that player won't get bounty.
JASS:
library HeroBounty /* v1.0.0.0
*************************************************************************************
*
*   Benefits:
*
*       -   Bugless levels and xp up to any* level
*       -   More control of how heroes recieve xp and bounty
*       -   More control over ability leveling requirements
*
*   Cons:
*
*       -   Can't display hero level normally (hero will always be level 1)
*       -   Have to use custom functions to add/remove xp and levels
*       -   Have to use custom functions for ability level requirements
*
*   Requirements:
*
*       -   Ensure all hero level gameplay constants are set to default
*       -   A non hero level must be represented by point value in object editor
*
*************************************************************************************
*
*   */ uses /*
*
*       */ UnitIndexer /*       hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
*       */ UnitList /*          hiveworkshop.com/forums/jass-functions-413/snippet-unit-list-191657/
*       */ Bounty /*            hiveworkshop.com/forums/submissions-414/snippet-bounty-196926/
*
************************************************************************************
*
*   Run when unit is expected to recieve xp, gold, or lumber
*
*   This function can't call anything within the library. It is meant to handle things like
*   stat growths and ability point allocation.
*
*       unit whichUnit
*       integer bountyGold
*       integer bountyLumber
*       integer killedLevel
*       integer partySize
*       integer averagePartyLevel
*       integer maxPartyLevel
*       real distance
*
***********************************************************************************/
//! textmacro SETTINGS
    private function GiveBounty takes unit whichUnit, integer bountyGold, integer bountyLumber, integer killedLevel, integer partySize, integer averagePartyLevel, integer maxPartyLevel, real distance returns nothing
    endfunction
//! endtextmacro
/***********************************************************************************
*
*   Run when unit has leveled
*
*       unit whichUnit
*       integer prevLevel
*       integer newLevel
*
***********************************************************************************/
//! textmacro SETTINGS_2
    private function OnLevel takes unit whichUnit, integer prevLevel, integer newLevel returns nothing
    endfunction
//! endtextmacro
/***********************************************************************************
*
*   Run when unit levels abilities. Used to prevent units from upping abilities
*   that require too high a level.
*
*       unit whichUnit
*       integer whichAbility
*       integer abilityLevel
*
***********************************************************************************/
//! textmacro SETTINGS_3
    private function OnLevelAbility takes unit whichUnit, integer whichAbility, integer abilityLevel returns nothing
    endfunction
//! endtextmacro
/***********************************************************************************
*
*   Returns whether unit should be in party or not (share kill)
*
*       unit whichUnit
*       unit originUnit
*       unit killedUnit
*
***********************************************************************************/
//! textmacro SETTINGS_4
    private function IsUnitInParty takes unit whichUnit, unit originUnit, unit killedUnit, real distance returns boolean
        return GetPlayerAlliance(GetOwningPlayer(whichUnit),GetOwningPlayer(originUnit),ALLIANCE_SHARED_XP) and /*
        */distance<2500 and /*
        */IsUnitAlly(whichUnit,GetOwningPlayer(originUnit))
    endfunction
//! endtextmacro
/***********************************************************************************
*
*    Functions
*
*       function GetLevel takes unit whichUnit returns integer
*       function SetLevel takes unit whichUnit, integer level, boolean showEyeCandy returns nothing
*       function AddLevel takes unit whichUnit, integer levelsToAdd, boolean showEyeCandy returns nothing
*
*       function AddXP takes unit whichUnit, integer xp, boolean showEyeCandy returns nothing
*       function AddPercentXP takes unit whichUnit, real percent, boolean showEyeCandy returns nothing
*
*       function GetRequiredToLevelXP takes unit whichUnit returns integer
*       function GetRequiredToLevelPercentXP takes unit whichUnit returns real
*
*       function GetLevelXP takes unit whichUnit returns integer
*       function GetLevelPercentXP takes unit whichUnit returns real
*
************************************************************************************/
    //! runtextmacro SETTINGS_2()
    globals
        private integer array levels
        private unit lastUnit = null
        private timer reset
    endglobals
    function GetLevel takes unit whichUnit returns integer
        return levels[GetUnitUserData(whichUnit)]
    endfunction
    function SetLevel takes unit whichUnit, integer level, boolean showEyeCandy returns nothing
        local integer i = GetUnitUserData(whichUnit)
        local integer prev = levels[i]
        if (level!=prev) then
            call SuspendHeroXP(whichUnit,false)
            if (level>levels[i] and showEyeCandy) then
                call SetHeroLevel(whichUnit,2,true)
                call UnitStripHeroLevel(whichUnit,1)
            else
                set levels[i]=level
            endif
            call AddHeroXP(whichUnit,-200,false)
            if (0>levels[i]) then
                set levels[i]=1
            endif
            call SuspendHeroXP(whichUnit,true)
            call OnLevel(whichUnit,prev,level)
        endif
    endfunction
    function AddLevel takes unit whichUnit, integer levelsToAdd, boolean showEyeCandy returns nothing
        call SetLevel(whichUnit,levels[GetUnitUserData(whichUnit)]+levelsToAdd,showEyeCandy)
    endfunction
    function AddXP takes unit whichUnit, integer xp, boolean showEyeCandy returns nothing
        local integer i=GetUnitUserData(whichUnit)
        local integer prev = levels[i]
        call SuspendHeroXP(whichUnit,false)
        set xp=xp+GetHeroXP(whichUnit)
        set levels[i]=levels[i]+xp/200
        if (0>levels[i]) then
            set levels[i]=1
        endif
        if (0<xp and showEyeCandy) then
            call SetHeroLevel(whichUnit,2,true)
            call UnitStripHeroLevel(whichUnit,1)
        endif
        call SetHeroXP(whichUnit,xp-xp/200*200,false)
        call SuspendHeroXP(whichUnit,true)
        if (levels[i]!=prev) then
            call OnLevel(whichUnit,prev,levels[i])
        endif
    endfunction
    function AddPercentXP takes unit whichUnit, real percent, boolean showEyeCandy returns nothing
        call AddXP(whichUnit,R2I(percent*2),showEyeCandy)
    endfunction
    function GetRequiredToLevelXP takes unit whichUnit returns integer
        return 200-GetHeroXP(whichUnit)
    endfunction
    function GetRequiredToLevelPercentXP takes unit whichUnit returns real
        return .5*GetRequiredToLevelXP(whichUnit)
    endfunction
    function GetLevelXP takes unit whichUnit returns integer
        return GetHeroXP(whichUnit)
    endfunction
    function GetLevelPercentXP takes unit whichUnit returns real
        return .5*GetHeroXP(whichUnit)
    endfunction
    //! runtextmacro SETTINGS()
    //! runtextmacro SETTINGS_3()
    //! runtextmacro SETTINGS_4()
    private function Reset takes nothing returns nothing
        set lastUnit = null
    endfunction
    private function HandleReward takes nothing returns boolean
        local UnitList n
        local unit t = GetTriggerUnit()
        local unit u = GetKillingUnit()
        local player p = GetOwningPlayer(u)
        local integer array us
        local real array ud
        local integer c = 0
        local integer max = 0
        local integer avg = 0
        local integer l
        local real x
        local real y
        local real x2
        local real y2
        local integer gold
        local integer lumber
        local integer klevel
        local integer s
        
        if (null!=u and t!=lastUnit and IsUnitEnemy(t,p)) then
            set klevel=GetUnitPointValue(t)
            set lastUnit=t
            call TimerStart(reset,0,false,function Reset)
            set x = GetWidgetX(t)
            set y = GetWidgetY(t)
            set gold = Bounty.gold
            set lumber = Bounty.lumber
            set n = UnitList[0].next
            call SetPlayerState(p,PLAYER_STATE_RESOURCE_GOLD,GetPlayerState(p,PLAYER_STATE_RESOURCE_GOLD)-gold)
            call SetPlayerState(p,PLAYER_STATE_RESOURCE_LUMBER,GetPlayerState(p,PLAYER_STATE_RESOURCE_LUMBER)-lumber)
            loop
                exitwhen 0==n
                set x2=GetWidgetX(n.unit)-x
                set y2=GetWidgetY(n.unit)-y
                set ud[n]=SquareRoot(x2*x2+y2*y2)
                if ((n.unit == u and IsHeroUnitId(GetUnitTypeId(u))) or (not IsUnitType(n.unit,UNIT_TYPE_DEAD) and GetWidgetLife(n.unit)>=.405 and IsHeroUnitId(GetUnitTypeId(n.unit))) and IsUnitInParty(n.unit,u,t,ud[n])) then
                    set us[c]=n
                    set c=c+1
                    set l = GetHeroLevel(n.unit)
                    set avg = avg + l
                    if (l>max) then
                        set max=l
                    endif
                endif
                set n=n.next
            endloop
            if (0<c) then
                set s=c
                set avg = avg/c
                loop
                    exitwhen 0==c
                    set c=c-1
                    call GiveBounty(GetUnitById(us[c]),gold,lumber,klevel,s,avg,max,ud[us[c]])
                endloop
            endif
        endif
        
        set t=null
        set u=null
        set p=null
        return false
    endfunction
    private function Index takes nothing returns boolean
        set levels[GetIndexedUnitId()]=1
        call SuspendHeroXP(GetIndexedUnit(),true)
        return false
    endfunction
    private function HandleAbility takes nothing returns boolean
        call OnLevelAbility(GetTriggerUnit(),GetLearnedSkill(),GetLearnedSkillLevel())
        return false
    endfunction
    private module N
        private static method onInit takes nothing returns nothing
            local trigger deathHandler=CreateTrigger()
            local trigger abilityHandler=CreateTrigger()
            local integer i=15
            set reset = CreateTimer()
            call TriggerAddCondition(deathHandler,Condition(function HandleReward))
            call TriggerAddCondition(abilityHandler,Condition(function HandleAbility))
            call Bounty.event.register(Condition(function HandleReward))
            loop
                call TriggerRegisterPlayerUnitEvent(deathHandler,Player(i),EVENT_PLAYER_UNIT_DEATH,null)
                call TriggerRegisterPlayerUnitEvent(abilityHandler,Player(i),EVENT_PLAYER_HERO_SKILL,null)
                exitwhen 0==i
                set i=i-1
            endloop
            call RegisterUnitIndexEvent(Condition(function Index),UnitIndexer.INDEX)
            set deathHandler=null
            set abilityHandler=null
        endmethod
    endmodule
    private struct T extends array
        implement N
    endstruct
endlibrary
 
Last edited:
Level 7
Joined
Dec 3, 2006
Messages
339
Add this formula (from http://world-editor-tutorials.thehelper.net/cat_usersubmit.php?view=44516) and provide global variables that can be set. It'd make it more realistic and you could calculate percents from it as well. Cause having heroes constantly at level 1 seems annoying. If your worried about that bug with level 6531 or wtever it is it's not worth worry about most maps don't go anywhere near that high in levels.
5. Experience

Warcraft III Heroes are basically based on experience for their levels.


5.1 Formula Used?

A formula is used to calculate the experience required. At N level, it requires it's previous experience required at N-1 level.

a = Previous Value Factor
b = Level Factor
c = Constant Factor
XP for level N = ((XP for level N - 1) * a) + (N * b) + c

or :

ƒ(N)=((f(N-1)-1)*a)+(N*b)+c


Example for basic values for melee games :

a = 1.00
b = 100
c = 100

Level 1 = 0
Level 2 = ((Level (1-0) Exp)*1)+(1*100)+100 = 0+100+100 = 200
Level 3 = ((Level (2-1) Exp)*1)+(2*100)+100 = 200+200+100 = 500
Level 4 = ((Level (3-1) Exp)*1)+(3*100)+100 = 500+300+100 = 900
Level 5 = ((Level (4-1) Exp)*1)+(4*100)+100 = 900+400+100 = 1400
Level 6 = ((Level (5-1) Exp)*1)+(5*100)+100 = 1400+500+100 = 2000
Level 7 = ((Level (6-1) Exp)*1)+(6*100)+100 = 2000+600+100 = 2700
Level 8 = ((Level (7-1) Exp)*1)+(7*100)+100 = 2700+700+100 = 3500
Level 9 = ((Level (8-1) Exp)*1)+(8*100)+100 = 3500+800+100 = 4400
Level 10 = ((Level (9-1) Exp)*1)+(2*100)+100 = 4400+900+100 = 5400
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Ok, how is this
JASS:
library HeroReward /* v2.0.0.0
*************************************************************************************
*
*   Benefits:
*
*       -   Bugless levels and xp up to 10000
*       -   More control of how heroes recieve xp
*       -   More control of how players recieve bounty
*
*   Cons:
*
*       -   Have to use custom functions to add/remove xp and levels
*
*   Requirements:
*
*       This system will not work without these values
*       *************************************************************************************
*       *                                                                                   *
*       *   Advanced -> Gameplay Constants                                                  *
*       *                                                                                   *
*       *       Hero Attributes     - HP Regen. Bonus per Strength Point        0.00        *
*       *       Hero Attributes     - Mana Regen. Bonus per Intelligence Point  0.00        *
*       *                                                                                   *
*       *       Hero XP Required    - Constant Factor                           0.00        *
*       *       Hero XP Required    - Level Factor                              10000       *
*       *       Hero XP Required    - Previous Level Factor                     0.00        *
*       *       Hero XP Required    - Table                                     10000       *
*       *                                                                                   *
*       *       Unit Maximum Level                                              100000      *
*       *                                                                                   *
*       *************************************************************************************
*
*************************************************************************************
*
*   */ uses /*
*
*       */ UnitIndexer /*           hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
*       */ UnitList /*              hiveworkshop.com/forums/jass-functions-413/snippet-unit-list-191657/
*       */ Bounty /*                hiveworkshop.com/forums/submissions-414/snippet-bounty-196926/
*       */ GetLearnedAbilities /*   hiveworkshop.com/forums/submissions-414/get-learned-abilities-203539/
*
***********************************************************************************/
globals
    private real percent = 0
endglobals
private function UpdatePercentBounty takes integer count returns nothing
    local real perc = 1
    local real dec = .35
    loop
        exitwhen 1==count
        set perc = perc-dec
        set dec = dec*.5
    endloop
    set percent = perc
endfunction
/***********************************************************************************
*
*   Run when unit is expected to recieve xp
*
*       unit whichUnit
*       unit killedUnit
*       integer killedLevel
*       integer partySize
*       integer sumPartyLevel
*       integer maxPartyLevel
*       real distance
*
***********************************************************************************/
//! textmacro HERO_REWARD_AWARD_XP
    //the xp algorithm used here is extremely good
    private function AwardXP takes unit whichUnit, unit killedUnit, integer killedLevel, integer partySize, integer sumPartyLevel, integer maxPartyLevel, real distance returns nothing
        local integer level = GetHeroLevel(whichUnit)
        local real perc2
        local real perc3
        if (level*1.5>=maxPartyLevel) then
        
            if (killedLevel==level) then
                set perc2=1
            elseif (killedLevel<level) then
                set perc2 = 1+(killedLevel-level)*.13
            else
                set perc2 = 1+(level-killedLevel)*.1
            endif
            if (0>perc2) then
                set perc2=0
            endif
            
            set perc3 = I2R(level)/maxPartyLevel
            set perc3 = perc3*perc3*level/sumPartyLevel
            
            call AddXP(whichUnit,R2I(250*perc3*perc2*(1+.35*(partySize-1))+.5),true)
        endif
    endfunction
//! endtextmacro
/***********************************************************************************
*
*   Returns whether unit should be in party or not (share kill)
*
*       unit whichUnit
*       unit originUnit
*       real distance
*
***********************************************************************************/
//! textmacro HERO_REWARD_PARTY_SETTINGS
    private function IsUnitInParty takes unit whichUnit, unit originUnit, real distance returns boolean
        return (whichUnit == originUnit) or (/*
        */GetPlayerAlliance(GetOwningPlayer(whichUnit),GetOwningPlayer(originUnit),ALLIANCE_SHARED_XP) and /*
        */distance<=2500 and /*
        */IsUnitAlly(whichUnit,GetOwningPlayer(originUnit)) and /*
        */not IsUnitType(whichUnit,UNIT_TYPE_DEAD) and /*
        */GetWidgetLife(whichUnit)>.405 /*
        */)
    endfunction
//! endtextmacro
/***********************************************************************************
*
*   Runs when player is expected to recieve bounty
*
*       player whichPlayer
*       unit killedUnit
*       integer gold
*       integer lumber
*       integer playerCount
*
***********************************************************************************/
//! textmacro HERO_REWARD_AWARD_BOUNTY
    private function AwardBounty takes player whichPlayer, unit killedUnit, integer gold, integer lumber, integer playerCount returns nothing
        call SetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_GOLD)+R2I(gold*percent))
        call SetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_LUMBER)+R2I(lumber*percent))
    endfunction
//! endtextmacro
/***********************************************************************************
*
*    Functions
*
*       function GetLevel takes unit whichUnit returns integer
*       function SetLevel takes unit whichUnit, integer level, boolean showEyeCandy returns nothing
*       function AddLevel takes unit whichUnit, integer levelsToAdd, boolean showEyeCandy returns nothing
*
*       function AddXP takes unit whichUnit, integer xp, boolean showEyeCandy returns nothing
*       function AddPercentXP takes unit whichUnit, real percent, boolean showEyeCandy returns nothing
*
*       function GetRequiredToLevelXP takes unit whichUnit returns integer
*       function GetRequiredToLevelPercentXP takes unit whichUnit returns real
*
*       function GetLevelXP takes unit whichUnit returns integer
*       function GetLevelPercentXP takes unit whichUnit returns real
*
************************************************************************************/
    function GetLevel takes unit whichUnit returns integer
        return GetHeroLevel(whichUnit)
    endfunction
    function SetLevel takes unit whichUnit, integer level, boolean showEyeCandy returns nothing
        local integer l = GetHeroLevel(whichUnit)
        local integer array levels
        local integer c
        local LearnedAbilities abils
        local integer total
        local integer total2
        local unit check
        local real pm
        local real pl
        if (l!=level) then
            call SuspendHeroXP(whichUnit,false)
            
            if (level>GetHeroLevel(whichUnit)) then
                call SetHeroLevel(whichUnit,level,showEyeCandy)
            else
                //retrieve skills total
                set UnitIndexer.enabled = false
                set check = CreateUnit(Player(15),GetUnitTypeId(whichUnit),GetRectMaxX(bj_mapInitialPlayableArea),GetRectMaxY(bj_mapInitialPlayableArea),0)
                if (level>1) then
                    call SetHeroLevel(check,level,false)
                endif
                set total = GetHeroSkillPoints(check)
                call RemoveUnit(check)
                set check=null
                set UnitIndexer.enabled = true
                
                //retrieve life and mana of unit
                if (0<GetUnitState(whichUnit,UNIT_STATE_MAX_MANA)) then
                    set pm=GetUnitState(whichUnit,UNIT_STATE_MAX_MANA)
                endif
                set pl=GetWidgetLife(whichUnit)/GetUnitState(whichUnit,UNIT_STATE_MAX_LIFE)
                
                //strip hero levels
                if (showEyeCandy) then
                    //if show eye candy, add a level
                    call SetHeroLevel(whichUnit,l+1,true)
                    call UnitStripHeroLevel(whichUnit,l-level+1)
                else
                    call UnitStripHeroLevel(whichUnit,l-level)
                endif
                
                //get total skills on hero
                set abils = LearnedAbilities[whichUnit]
                set c = abils.count
                set total2 = GetHeroSkillPoints(whichUnit)
                loop
                    exitwhen 0==c
                    set c=c-1
                    set total2 = total2 + GetUnitAbilityLevel(whichUnit,abils[c])
                endloop
                
                //if totals aren't equal, add missing skill points
                if (total2!=total) then
                    call UnitModifySkillPoints(whichUnit,total-total2)
                endif
                
                //set life and mana of unit
                if (0<pm) then
                    call SetUnitState(whichUnit,UNIT_STATE_MANA,GetUnitState(whichUnit,UNIT_STATE_MAX_MANA)*pm)
                endif
                if (0<pl) then
                    call SetUnitState(whichUnit,UNIT_STATE_LIFE,GetUnitState(whichUnit,UNIT_STATE_MAX_LIFE)*pl)
                endif
            endif
            
            //clear xp bar
            call AddHeroXP(whichUnit,-10000,false)
            
            call SuspendHeroXP(whichUnit,true)
        endif
    endfunction
    function AddLevel takes unit whichUnit, integer levels, boolean showEyeCandy returns nothing
        call SetLevel(whichUnit,GetHeroLevel(whichUnit)+levels,showEyeCandy)
    endfunction
    function SetXP takes unit whichUnit, integer xp, boolean showEyeCandy returns nothing
        local integer l=GetHeroLevel(whichUnit)
        if (xp!=GetHeroXP(whichUnit)) then
            call SuspendHeroXP(whichUnit,false)
            
            //if new xp is less than current level, update level
            if (xp<l*10000) then
                call SetLevel(whichUnit,xp/10000,showEyeCandy)
                call SuspendHeroXP(whichUnit,false)
            endif
            
            if (xp!=GetHeroXP(whichUnit)) then
                call SetHeroXP(whichUnit,xp,showEyeCandy)
            endif
            
            call SuspendHeroXP(whichUnit,true)
        endif
    endfunction
    function AddXP takes unit whichUnit, integer xp, boolean showEyeCandy returns nothing
        call SetXP(whichUnit,GetHeroXP(whichUnit)+xp,showEyeCandy)
    endfunction
    function AddPercentXP takes unit whichUnit, real percent, boolean showEyeCandy returns nothing
        call AddXP(whichUnit,R2I(percent*100),showEyeCandy)
    endfunction
    function GetRequiredToLevelXP takes unit whichUnit returns integer
        return 10000-GetHeroXP(whichUnit)
    endfunction
    function GetRequiredToLevelPercentXP takes unit whichUnit returns real
        return .01*GetRequiredToLevelXP(whichUnit)
    endfunction
    function GetLevelXP takes unit whichUnit returns integer
        return GetHeroXP(whichUnit)-GetHeroLevel(whichUnit)*10000
    endfunction
    function GetLevelPercentXP takes unit whichUnit returns real
        return .01*GetLevelXP(whichUnit)
    endfunction
    //! runtextmacro HERO_REWARD_PARTY_SETTINGS()
    //! runtextmacro HERO_REWARD_AWARD_BOUNTY()
    //! runtextmacro HERO_REWARD_AWARD_XP()
    globals
        private integer array unitPointer
        private real array unitDistance
        private integer sumLevel
        private integer maxLevel
        private integer unitCount
        private integer array playerPointer
        private integer playerCount
        private real ox
        private real oy
    endglobals
    private function Setup takes nothing returns nothing
        local UnitList node = UnitList[0].next
        
        local real x2
        local real y2
        
        local boolean array added
        
        local unit triggerUnit = GetTriggerUnit()
        local unit killingUnit = GetKillingUnit()
        
        local integer playerId
        
        local integer level
        
        set unitCount = 0
        set playerCount = 0
        set sumLevel = 0
        set maxLevel = 0
        
        set ox = GetWidgetX(triggerUnit)
        set oy = GetWidgetY(triggerUnit)
        
        loop
            exitwhen 0==node
            
            set x2 = GetWidgetX(node.unit) - ox
            set y2 = GetWidgetY(node.unit) - oy
            set unitDistance[node] = SquareRoot(x2*x2+y2*y2)
            
            if (IsUnitInParty(node.unit,killingUnit,unitDistance[node])) then
                set playerId = GetPlayerId(GetOwningPlayer(node.unit))
                if (not added[playerId]) then
                    set playerPointer[playerCount] = playerId
                    set playerCount = playerCount+1
                    set added[playerId] = true
                endif
                
                if (IsUnitType(node.unit, UNIT_TYPE_HERO)) then
                    set unitPointer[unitCount] = node
                    set unitCount = unitCount + 1
                    
                    set level = GetHeroLevel(node.unit)
                    set sumLevel = sumLevel + level
                    
                    if (level>maxLevel) then
                        set maxLevel = level
                    endif
                endif
            endif
            
            set node=node.next
        endloop
        
        call UpdatePercentBounty(playerCount)
        
        set killingUnit = null
        set triggerUnit = null
    endfunction
    private function HandleBounty takes nothing returns boolean
        local integer gold
        local integer lumber
        local player killingPlayer
        local integer i
        local unit triggerUnit
        
        if (null!=GetKillingUnit() and IsUnitEnemy(GetKillingUnit(),GetTriggerPlayer())) then
            set gold = Bounty.gold
            set lumber = Bounty.lumber
            set killingPlayer = GetOwningPlayer(GetKillingUnit())
            set triggerUnit = GetTriggerUnit()
            
            call Setup()
            
            call SetPlayerState(killingPlayer,PLAYER_STATE_RESOURCE_GOLD,GetPlayerState(killingPlayer,PLAYER_STATE_RESOURCE_GOLD)-gold)
            call SetPlayerState(killingPlayer,PLAYER_STATE_RESOURCE_LUMBER,GetPlayerState(killingPlayer,PLAYER_STATE_RESOURCE_LUMBER)-lumber)
            
            set i = playerCount
            loop
                exitwhen 0 == i
                set i = i-1
                call AwardBounty(Player(playerPointer[i]),triggerUnit,gold,lumber,playerCount)
            endloop
            
            set killingPlayer = null
            set triggerUnit = null
        endif
        
        return false
    endfunction
    private function HandleXP takes nothing returns boolean
        local integer i
        local unit triggerUnit
        local integer triggerLevel
        
        if (null!=GetKillingUnit() and IsUnitEnemy(GetKillingUnit(),GetTriggerPlayer())) then
            set triggerUnit = GetTriggerUnit()
            set triggerLevel = GetUnitLevel(triggerUnit)
            
            set i = unitCount
            loop
                exitwhen 0 == i
                set i = i-1
                call AwardXP(GetUnitById(unitPointer[i]),triggerUnit,triggerLevel,unitCount,sumLevel,maxLevel,unitDistance[unitPointer[i]])
            endloop
            
            set triggerUnit = null
        endif
        
        return false
    endfunction
    private module N
        private static method onInit takes nothing returns nothing
            local integer i=15
            local trigger handleXP=CreateTrigger()
            call TriggerAddCondition(handleXP,Condition(function HandleXP))
            call Bounty.event.register(Condition(function HandleBounty))
            loop
                call TriggerRegisterPlayerUnitEvent(handleXP,Player(i),EVENT_PLAYER_UNIT_DEATH,null)
                exitwhen 0==i
                set i=i-1
            endloop
            set handleXP=null
        endmethod
    endmodule
    private struct T extends array
        implement N
    endstruct
endlibrary

10,000 xp needed to level

10 vs 15 - 375 xp
10 vs 14 - 350 xp
10 vs 13 - 325 xp
10 vs 12 - 300 xp
10 vs 11 - 275 xp
10 vs 10 - 250 xp
10 vs 9 - 218 xp
10 vs 8 - 185 xp
10 vs 7 - 153 xp
10 vs 6 - 120 xp
10 vs 5 - 88 xp
10 vs 4 - 55 xp
10 vs 3 - 23 xp
10 vs 2 - 0 xp


60 partied with a 90 killing a 90

60 gets: 240 xp
90 gets: 203 xp

90 with 90 killing a 90
90 gets: 169 xp

3 90s killing a 90
90 gets: 142 xp


Ofc the group bonus and the xp rate can be scaled depending on the difficulty of the monsters. For example, if the monsters are very easy, you'd want to increase the group bonus to get players to group with each other and decrease the xp rate. If they are very hard, you'd want to increase the xp rate and keep the group bonus the same.
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
Well, I'm still working on it. I'll submit it once it's done.


It still needs to be tested and it can still be improved.


I'm satisfied with this version, just gotta debug it now ^)^. I've yet to even run it once ; P
JASS:
library HeroReward /* v2.1.0.0
*************************************************************************************
*
*   Benefits:
*
*       -   Bugless levels and xp up to 10000
*       -   More control of how heroes recieve xp
*       -   More control of how players recieve bounty
*
*   Cons:
*
*       -   Have to use custom functions to add/remove xp and levels
*
*   Requirements:
*
*       This system will not work without these values
*       *************************************************************************************
*       *                                                                                   *
*       *   Advanced -> Gameplay Constants                                                  *
*       *                                                                                   *
*       *       Hero Attributes     - HP Regen. Bonus per Strength Point        0.00        *
*       *       Hero Attributes     - Mana Regen. Bonus per Intelligence Point  0.00        *
*       *                                                                                   *
*       *       Hero XP Required    - Constant Factor                           0.00        *
*       *       Hero XP Required    - Level Factor                              10000       *
*       *       Hero XP Required    - Previous Level Factor                     0.00        *
*       *       Hero XP Required    - Table                                     10000       *
*       *                                                                                   *
*       *       Unit Maximum Level                                              100000      *
*       *                                                                                   *
*       *************************************************************************************
*
*************************************************************************************
*
*   */ uses /*
*
*       */ UnitIndexer /*           hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
*       */ UnitList /*              hiveworkshop.com/forums/jass-functions-413/snippet-unit-list-191657/
*       */ Bounty /*                hiveworkshop.com/forums/submissions-414/snippet-bounty-196926/
*       */ GetLearnedAbilities /*   hiveworkshop.com/forums/submissions-414/get-learned-abilities-203539/
*
************************************************************************************
*
*   Run when unit is expected to recieve xp
*
*       unit whichUnit
*       unit killedUnit
*       integer killedLevel
*       integer partySize
*       integer sumPartyLevel
*       integer maxPartyLevel
*       real distance
*
***********************************************************************************/
//! textmacro HERO_REWARD_AWARD_XP
    globals
        //the xp rate
        private constant real XP_RATE = 350
        
        //increase in how much xp a unit gives (1.8 is max)
        private constant real XP_GIVE_RATE = 1.8
        
        //increase in how much xp is required to level per level (2.1 is max)
        private constant real XP_REQ_RATE = 2.1
        
        //party bonus per member (additive)
        private constant real PARTY_BONUS = .35
        
        //xp decline for killing weaker units
        private constant real LOW_DEGRADE = .13
        
        //xp increase for killing stronger units
        private constant real HIGH_BONUS = .1
        
        //max level a player can party with and still get xp
        //1.5 means level*1.5 = max
        private constant real PARTY_MAX_LEVEL = 1.5
    endglobals
    
    //the xp algorithm used here is extremely good
    private function AwardXP takes unit whichUnit, unit killedUnit, integer killedLevel, integer partySize, integer sumPartyLevel, integer maxPartyLevel, real distance returns nothing
        local integer level = GetHeroLevel(whichUnit)
        local real levelDifBonus
        local real partyBonus
        local real xp
        local real xpReq
        
        if (level*PARTY_MAX_LEVEL>=maxPartyLevel) then
        
            //calculate level difference bonus
            if (killedLevel==level) then
                set levelDifBonus=1
            elseif (killedLevel<level) then
                set levelDifBonus = 1+(killedLevel-level)*LOW_DEGRADE
            else
                set levelDifBonus = 1+(level-killedLevel)*HIGH_BONUS
            endif
            if (0>levelDifBonus) then
                set levelDifBonus=0
            endif
            
            //calculate party bonus
            set partyBonus = I2R(level)/maxPartyLevel
            set partyBonus = partyBonus*partyBonus*level/sumPartyLevel
            set partyBonus = partyBonus*(1+PARTY_BONUS*(partySize-1))
            
            //calculate xp
            set xp = Pow(killedLevel+1,XP_GIVE_RATE)
            
            //calculate xp required
            set xpReq = Pow(level,XP_REQ_RATE)
            
            //add xp
            call AddXP(whichUnit,R2I(xp/xpReq*XP_RATE*partyBonus*levelDifBonus+.5),true)
        endif
        
    endfunction
//! endtextmacro
/***********************************************************************************
*
*   Returns whether unit should be in party or not (share kill)
*
*       unit whichUnit
*       unit originUnit
*       real distance
*
***********************************************************************************/
//! textmacro HERO_REWARD_PARTY_SETTINGS
    globals
        private constant real MAX_DISTANCE = 2500
    endglobals
    private function IsUnitInParty takes unit whichUnit, unit originUnit, real distance returns boolean
        return (whichUnit == originUnit) or (/*
        */GetPlayerAlliance(GetOwningPlayer(whichUnit),GetOwningPlayer(originUnit),ALLIANCE_SHARED_XP) and /*
        */distance<=MAX_DISTANCE and /*
        */IsUnitAlly(whichUnit,GetOwningPlayer(originUnit)) and /*
        */not IsUnitType(whichUnit,UNIT_TYPE_DEAD) and /*
        */GetWidgetLife(whichUnit)>.405 /*
        */)
    endfunction
//! endtextmacro
/***********************************************************************************
*
*   Runs when player is expected to recieve bounty
*
*       player whichPlayer
*       unit killedUnit
*       integer gold
*       integer lumber
*       integer playerCount
*
***********************************************************************************/
//! textmacro HERO_REWARD_AWARD_BOUNTY
    private function AddPlayerState takes player whichPlayer, playerstate whichState, integer delta returns nothing
        call SetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_GOLD)+delta)
    endfunction
    private function AwardBounty takes player whichPlayer, unit killedUnit, integer gold, integer lumber, integer playerCount returns nothing
        //calculate party bonus
        local real partyBonus = 1/playerCount*(1+.35*(playerCount-1))
        
        //calculate new values
        set gold = R2I(gold*partyBonus+.5)
        set lumber = R2I(lumber*partyBonus+.5)
        
        //add player states
        call AddPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_GOLD, gold)
        call AddPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_LUMBER, lumber)
    endfunction
//! endtextmacro
/***********************************************************************************
*
*    Functions
*
*       function GetLevel takes unit whichUnit returns integer
*       function SetLevel takes unit whichUnit, integer level, boolean showEyeCandy returns nothing
*       function AddLevel takes unit whichUnit, integer levelsToAdd, boolean showEyeCandy returns nothing
*
*       function AddXP takes unit whichUnit, integer xp, boolean showEyeCandy returns nothing
*       function AddPercentXP takes unit whichUnit, real percent, boolean showEyeCandy returns nothing
*
*       function GetRequiredToLevelXP takes unit whichUnit returns integer
*       function GetRequiredToLevelPercentXP takes unit whichUnit returns real
*
*       function GetLevelXP takes unit whichUnit returns integer
*       function GetLevelPercentXP takes unit whichUnit returns real
*
************************************************************************************/
    function GetLevel takes unit whichUnit returns integer
        return GetHeroLevel(whichUnit)
    endfunction
    
    function SetLevel takes unit whichUnit, integer level, boolean showEyeCandy returns nothing
        local integer l = GetHeroLevel(whichUnit)
        local integer array levels
        local integer c
        local LearnedAbilities abils
        local integer total
        local integer total2
        local unit check
        local real pm
        local real pl
        if (l!=level) then
            call SuspendHeroXP(whichUnit,false)
            
            if (level>GetHeroLevel(whichUnit)) then
                call SetHeroLevel(whichUnit,level,showEyeCandy)
            else
                //retrieve skills total
                set UnitIndexer.enabled = false
                set check = CreateUnit(Player(15),GetUnitTypeId(whichUnit),GetRectMaxX(bj_mapInitialPlayableArea),GetRectMaxY(bj_mapInitialPlayableArea),0)
                if (level>1) then
                    call SetHeroLevel(check,level,false)
                endif
                set total = GetHeroSkillPoints(check)
                call RemoveUnit(check)
                set check=null
                set UnitIndexer.enabled = true
                
                //retrieve life and mana of unit
                if (0<GetUnitState(whichUnit,UNIT_STATE_MAX_MANA)) then
                    set pm=GetUnitState(whichUnit,UNIT_STATE_MAX_MANA)
                endif
                set pl=GetWidgetLife(whichUnit)/GetUnitState(whichUnit,UNIT_STATE_MAX_LIFE)
                
                //strip hero levels
                call UnitStripHeroLevel(whichUnit,l-level)
                
                //get total skills on hero
                set abils = LearnedAbilities[whichUnit]
                set c = abils.count
                set total2 = GetHeroSkillPoints(whichUnit)
                loop
                    exitwhen 0==c
                    set c=c-1
                    set total2 = total2 + GetUnitAbilityLevel(whichUnit,abils[c])
                endloop
                
                //if totals aren't equal, add missing skill points
                if (total2!=total) then
                    call UnitModifySkillPoints(whichUnit,total-total2)
                endif
                
                //set life and mana of unit
                if (0<pm) then
                    call SetUnitState(whichUnit,UNIT_STATE_MANA,GetUnitState(whichUnit,UNIT_STATE_MAX_MANA)*pm)
                endif
                if (0<pl) then
                    call SetUnitState(whichUnit,UNIT_STATE_LIFE,GetUnitState(whichUnit,UNIT_STATE_MAX_LIFE)*pl)
                endif
            endif
            
            //clear xp bar
            call AddHeroXP(whichUnit,-10000,false)
            
            call SuspendHeroXP(whichUnit,true)
        endif
    endfunction
    
    function AddLevel takes unit whichUnit, integer levels, boolean showEyeCandy returns nothing
        call SetLevel(whichUnit,GetHeroLevel(whichUnit)+levels,showEyeCandy)
    endfunction
    
    function SetXP takes unit whichUnit, integer xp, boolean showEyeCandy returns nothing
        local integer l=GetHeroLevel(whichUnit)
        if (xp!=GetHeroXP(whichUnit)) then
            call SuspendHeroXP(whichUnit,false)
            
            //if new xp is less than current level, update level
            if (xp<l*10000) then
                call SetLevel(whichUnit,xp/10000,showEyeCandy)
                call SuspendHeroXP(whichUnit,false)
            endif
            
            if (xp!=GetHeroXP(whichUnit)) then
                call SetHeroXP(whichUnit,xp,showEyeCandy)
            endif
            
            call SuspendHeroXP(whichUnit,true)
        endif
    endfunction
    
    function AddXP takes unit whichUnit, integer xp, boolean showEyeCandy returns nothing
        call SetXP(whichUnit,GetHeroXP(whichUnit)+xp,showEyeCandy)
    endfunction
    
    function AddPercentXP takes unit whichUnit, real percent, boolean showEyeCandy returns nothing
        call AddXP(whichUnit,R2I(percent*100),showEyeCandy)
    endfunction
    
    function GetRequiredToLevelXP takes unit whichUnit returns integer
        return 10000-GetHeroXP(whichUnit)
    endfunction
    
    function GetRequiredToLevelPercentXP takes unit whichUnit returns real
        return .01*GetRequiredToLevelXP(whichUnit)
    endfunction
    
    function GetLevelXP takes unit whichUnit returns integer
        return GetHeroXP(whichUnit)-GetHeroLevel(whichUnit)*10000
    endfunction
    
    function GetLevelPercentXP takes unit whichUnit returns real
        return .01*GetLevelXP(whichUnit)
    endfunction
    
    //! runtextmacro HERO_REWARD_PARTY_SETTINGS()
    //! runtextmacro HERO_REWARD_AWARD_BOUNTY()
    //! runtextmacro HERO_REWARD_AWARD_XP()
    
    globals
        private integer array unitPointer
        private real array unitDistance
        private integer sumLevel
        private integer maxLevel
        private integer unitCount
        private integer array playerPointer
        private integer playerCount
        private real ox
        private real oy
    endglobals
    private function Setup takes nothing returns nothing
        local UnitList node = UnitList[0].next
        
        local real x2
        local real y2
        
        local boolean array added
        
        local unit triggerUnit = GetTriggerUnit()
        local unit killingUnit = GetKillingUnit()
        
        local integer playerId
        
        local integer level
        
        set unitCount = 0
        set playerCount = 0
        set sumLevel = 0
        set maxLevel = 0
        
        set ox = GetWidgetX(triggerUnit)
        set oy = GetWidgetY(triggerUnit)
        
        loop
            exitwhen 0==node
            
            set x2 = GetWidgetX(node.unit) - ox
            set y2 = GetWidgetY(node.unit) - oy
            set unitDistance[node] = SquareRoot(x2*x2+y2*y2)
            
            if (IsUnitInParty(node.unit,killingUnit,unitDistance[node])) then
                set playerId = GetPlayerId(GetOwningPlayer(node.unit))
                if (not added[playerId]) then
                    set playerPointer[playerCount] = playerId
                    set playerCount = playerCount+1
                    set added[playerId] = true
                endif
                
                if (IsUnitType(node.unit, UNIT_TYPE_HERO)) then
                    set unitPointer[unitCount] = node
                    set unitCount = unitCount + 1
                    
                    set level = GetHeroLevel(node.unit)
                    set sumLevel = sumLevel + level
                    
                    if (level>maxLevel) then
                        set maxLevel = level
                    endif
                endif
            endif
            
            set node=node.next
        endloop
        
        set killingUnit = null
        set triggerUnit = null
    endfunction
    private function HandleBounty takes nothing returns boolean
        local integer gold
        local integer lumber
        local player killingPlayer
        local integer i
        local unit triggerUnit
        
        if (null!=GetKillingUnit() and IsUnitEnemy(GetKillingUnit(),GetTriggerPlayer())) then
            set gold = Bounty.gold
            set lumber = Bounty.lumber
            set killingPlayer = GetOwningPlayer(GetKillingUnit())
            set triggerUnit = GetTriggerUnit()
            
            call Setup()
            
            call SetPlayerState(killingPlayer,PLAYER_STATE_RESOURCE_GOLD,GetPlayerState(killingPlayer,PLAYER_STATE_RESOURCE_GOLD)-gold)
            call SetPlayerState(killingPlayer,PLAYER_STATE_RESOURCE_LUMBER,GetPlayerState(killingPlayer,PLAYER_STATE_RESOURCE_LUMBER)-lumber)
            
            set i = playerCount
            loop
                exitwhen 0 == i
                set i = i-1
                call AwardBounty(Player(playerPointer[i]),triggerUnit,gold,lumber,playerCount)
            endloop
            
            set killingPlayer = null
            set triggerUnit = null
        endif
        
        return false
    endfunction
    private function HandleXP takes nothing returns boolean
        local integer i
        local unit triggerUnit
        local integer triggerLevel
        
        if (null!=GetKillingUnit() and IsUnitEnemy(GetKillingUnit(),GetTriggerPlayer())) then
            set triggerUnit = GetTriggerUnit()
            set triggerLevel = GetUnitLevel(triggerUnit)
            
            set i = unitCount
            loop
                exitwhen 0 == i
                set i = i-1
                call AwardXP(GetUnitById(unitPointer[i]),triggerUnit,triggerLevel,unitCount,sumLevel,maxLevel,unitDistance[unitPointer[i]])
            endloop
            
            set triggerUnit = null
        endif
        
        return false
    endfunction
    private module N
        private static method onInit takes nothing returns nothing
            local integer i=15
            local trigger handleXP=CreateTrigger()
            call TriggerAddCondition(handleXP,Condition(function HandleXP))
            call Bounty.event.register(Condition(function HandleBounty))
            loop
                call TriggerRegisterPlayerUnitEvent(handleXP,Player(i),EVENT_PLAYER_UNIT_DEATH,null)
                exitwhen 0==i
                set i=i-1
            endloop
            set handleXP=null
        endmethod
    endmodule
    private struct T extends array
        implement N
    endstruct
endlibrary
 
Last edited:
Status
Not open for further replies.
Top