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

[General] Preventing heroes from gaining 2 levels at once

Status
Not open for further replies.
Level 11
Joined
Sep 14, 2009
Messages
284
Hi. Sometimes in my map when heroes face boss units, the experience gain is quite large, so large in fact that the heroes gain 2 levels at once.
This is a problem since it messes up the skill points gained, since my map uses this skill point code:

JASS:
function CharacterLvlUpSkillPoint_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local integer i = GetHeroLevel(u)
    if i != 20 and i != 16 and i != 12 and i != 8 and i != 4 then
        call ModifyHeroSkillPoints(u, bj_MODIFYMETHOD_SUB, 1)
    endif
    set u = null
endfunction

//===========================================================================
function InitTrig_CharacterLvlUpSkillPoint takes nothing returns nothing
    set gg_trg_CharacterLvlUpSkillPoint = CreateTrigger()
    call TriggerRegisterPlayerUnitEventSimple(gg_trg_CharacterLvlUpSkillPoint, Player(8), EVENT_PLAYER_HERO_LEVEL)
    call TriggerAddAction(gg_trg_CharacterLvlUpSkillPoint, function CharacterLvlUpSkillPoint_Actions)
endfunction

As you can see the heroes are supposed to only gain 1 skill point at level 4, 8, 12, 16 and 20. And all other levels the skill points are substracted by 1.
But when the hero gain2 levels at once the event fails to detect both levels and ends up with 1 skill point at an invalid level.

So my question is how can I solve this problem?
All experience gained is gained from triggers.
 
Level 11
Joined
Jan 23, 2015
Messages
788
How about setting the highest XP reward to the XP needed to gain a level and/or increasing the XP needed?

Example: You need 1000 experience to gain a level, and the highest amount of experience you can get by a boss is 1000, so, you will never get 2 levels at once.
However if your XP needed increases per level you need to check that through your trigger and increase the amount of exp bosses give you according to the level. I recommend you to make the bosses give you a percent of the exp needed to gain a level, so, the highest would be 100%.
 
Level 12
Joined
May 22, 2015
Messages
1,051
You could make the bosses low level and manually level each player.

In my map, I am adding an extra skill point each time they level. I keep track of their level in an array (one slot per player) and add points equal to the difference in their level after leveling up and the stored level, then update the stored level.
 
Level 11
Joined
Jan 23, 2015
Messages
788
If you want the hero's level-up to be blocked when the exp gained together with the current exp of the hero is enough for two level-ups, then you need to calculate this every time a boss dies:

if
ExpReward is greater than (MaxExp - CurrentExp)
then
check if
(ExpReward - (MaxExp - CurrentExp)) is greater than ((MaxExp + CurrentLevel + 1) x MaxIncreasePerLevel)
then
give (((MaxExp - CurrentExp) + ((MaxExp + CurrentLevel + 1) x MaxIncreasePerLevel)) - 1))to the killer of the boss

This isn't JASS nor GUI, I think it's the best way for you to understand.
Let's say the hero is level 4 and it gets exp enough for 2 levels, but using this, it'll level-up to level 5 and get exp for the next level - 1 (to prevent it from levelling-up again at the same time).
With fewer words, it won't get the full exp reward just to block the second level-up.
 
Level 11
Joined
Sep 14, 2009
Messages
284
Nvm I fixed it. I calculated all the levels of the learnable abilties. Kinda complicated if you don't know how my system works but it's bug free now. Kinda suprised that I managed to pull it off by myself.

Won't prevent heroes from gaining 2 levels, but doesn't matter since the skill points works correctly now.

Solved.

Another thing. I tried to make the GetSkillLevels function take a unit and return an integer but it failed. If anyone know how I can do that please show me. Thanks.

JASS:
function GetSkillLevels takes nothing returns nothing
    set udg_GetSkillLevelsInt = udg_GetSkillLevelsInt + GetUnitAbilityLevelSwapped('A00F', udg_GetSkillLevelsUnit)
    set udg_GetSkillLevelsInt = udg_GetSkillLevelsInt + GetUnitAbilityLevelSwapped('A00E', udg_GetSkillLevelsUnit)
    set udg_GetSkillLevelsInt = udg_GetSkillLevelsInt + GetUnitAbilityLevelSwapped('A00G', udg_GetSkillLevelsUnit)
    set udg_GetSkillLevelsInt = udg_GetSkillLevelsInt + GetUnitAbilityLevelSwapped('A00H', udg_GetSkillLevelsUnit)
    set udg_GetSkillLevelsInt = udg_GetSkillLevelsInt + GetUnitAbilityLevelSwapped('A00I', udg_GetSkillLevelsUnit)
    set udg_GetSkillLevelsInt = udg_GetSkillLevelsInt + GetUnitAbilityLevelSwapped('A00J', udg_GetSkillLevelsUnit)
    set udg_GetSkillLevelsInt = udg_GetSkillLevelsInt + GetUnitAbilityLevelSwapped('A00K', udg_GetSkillLevelsUnit)
    set udg_GetSkillLevelsInt = udg_GetSkillLevelsInt + GetUnitAbilityLevelSwapped('A00L', udg_GetSkillLevelsUnit)
endfunction

function CharacterLvlUpSkillPoint_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local integer i = GetHeroLevel(u)
    set udg_GetSkillLevelsInt = 0
    set udg_GetSkillLevelsUnit = u
    call GetSkillLevels()
    call DisplayTextToForce(GetPlayersAll(), I2S(udg_GetSkillLevelsInt))
    call ModifyHeroSkillPoints(u, bj_MODIFYMETHOD_SET, 0)
    if i >= 4 and i <= 7 then
        call ModifyHeroSkillPoints(u, bj_MODIFYMETHOD_SET, 1 - udg_GetSkillLevelsInt)
    else
        if i >= 8 and i <= 11 then
            call ModifyHeroSkillPoints(u, bj_MODIFYMETHOD_SET, 2 - udg_GetSkillLevelsInt)
        else
            if i >= 12 and i <= 15 then
                call ModifyHeroSkillPoints(u, bj_MODIFYMETHOD_SET, 3 - udg_GetSkillLevelsInt)
            else
                if i >= 16 and i <= 19 then
                    call ModifyHeroSkillPoints(u, bj_MODIFYMETHOD_SET, 4 - udg_GetSkillLevelsInt)
                else
                    if i == 20 then
                        call ModifyHeroSkillPoints(u, bj_MODIFYMETHOD_SET, 5 - udg_GetSkillLevelsInt)
                    endif
                endif
            endif
        endif
    endif
    //if i != 20 and i != 16 and i != 12 and i != 8 and i != 4 then
    //    call ModifyHeroSkillPoints(u, bj_MODIFYMETHOD_SUB, 1)
    //endif
    set u = null
endfunction

//===========================================================================
function InitTrig_CharacterLvlUpSkillPoint takes nothing returns nothing
    set gg_trg_CharacterLvlUpSkillPoint = CreateTrigger()
    call TriggerRegisterPlayerUnitEventSimple(gg_trg_CharacterLvlUpSkillPoint, Player(8), EVENT_PLAYER_HERO_LEVEL)
    call TriggerAddAction(gg_trg_CharacterLvlUpSkillPoint, function CharacterLvlUpSkillPoint_Actions)
endfunction
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
JASS:
function GetSkillLevels takes unit u returns integer
    local integer c = 0

    set c = c + GetUnitAbilityLevel(u, 'A00F')
    set c = c + GetUnitAbilityLevel(u, 'A00E')
    set c = c + GetUnitAbilityLevel(u, 'A00G')
    set c = c + GetUnitAbilityLevel(u, 'A00H')
    set c = c + GetUnitAbilityLevel(u, 'A00I')
    set c = c + GetUnitAbilityLevel(u, 'A00J')
    set c = c + GetUnitAbilityLevel(u, 'A00K')
    set c = c + GetUnitAbilityLevel(u, 'A00L')

    return c
endfunction

@initial question: You should store the level the hero had before, so you can see what levels it traversed. Then you make a loop over all levels in between.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
The solution is not to tame experience to only 1 level up at a time, but to rather abstract the level up event to fire for every level up. Use a hashtable to restore the "last level of hero" for every hero. On a level up you get their current level and their last level of hero and work out the difference. you then loop the "actions" for every number of level up to the current. Use a global variable or custom function call to get the current level the action execution corresponds to.

An alternative is to change the level response triggers from sequential to functional based on current level. On each level up you destroy all the level up changes (which need to be destroyed, such as remove low level abilities etc) and then apply all the appropriate level up changes he should have at that level (add all abilities, etc). This way if 2 or more level ups occur simultaneously it does not matter as it will still modify the hero into the correct state based on the hero's current level.

I see you took the second approach to solve this. Here is a slight improvement (with WaterKnight's function).
JASS:
function GetSkillLevels takes unit u returns integer
     local integer c = 0

     set c = c + GetUnitAbilityLevel(u, 'A00F')
     set c = c + GetUnitAbilityLevel(u, 'A00E')
     set c = c + GetUnitAbilityLevel(u, 'A00G')
     set c = c + GetUnitAbilityLevel(u, 'A00H')
     set c = c + GetUnitAbilityLevel(u, 'A00I')
     set c = c + GetUnitAbilityLevel(u, 'A00J')
     set c = c + GetUnitAbilityLevel(u, 'A00K')
     set c = c + GetUnitAbilityLevel(u, 'A00L')

     return c
endfunction

function CharacterLvlUpSkillPoint_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local integer level = GetHeroLevel(u)
    local integer skilled = GetSkillLevels(u)

    //call DisplayTextToForce(GetPlayersAll(), I2S(skilled))
    call UnitModifySkillPoints(u, level / 4 - GetHeroSkillPoints(u) - skilled)

    set u = null
endfunction

//===========================================================================
function InitTrig_CharacterLvlUpSkillPoint takes nothing returns nothing
    set gg_trg_CharacterLvlUpSkillPoint = CreateTrigger()
    call TriggerRegisterPlayerUnitEventSimple(gg_trg_CharacterLvlUpSkillPoint, Player(8), EVENT_PLAYER_HERO_LEVEL)
    call TriggerAddAction(gg_trg_CharacterLvlUpSkillPoint, function CharacterLvlUpSkillPoint_Actions)
endfunction
 
Status
Not open for further replies.
Top