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

[JASS] Count players and set food cap problem

Status
Not open for further replies.
Level 11
Joined
Sep 14, 2009
Messages
284
Hello. I'm making a map for 6 players, and depending on the number of players, each player may pick a certain number of heroes. To limit the heroes, i modify the food cap for each player.

Here is how it's supposed to work:
6 Players = 1 Food Cap
5 Players = 1 Food Cap (+1 Food Cap for 1 Random Player)
4 Players = 1 Food Cap (+1 Food Cap for 2 Random Players)
3 Players = 2 Food Cap
2 Players = 3 Food Cap
1 Player = 6 Food Cap

So it's pretty obvious that when there are 5 or 4 players, it get's more complicated.

I could easily use "ForcePickRandomPlayer", but I want to try and make it free from non-natives.
It's the last loop I have problem with. And it's not finished.
Here is the code so far:

JASS:
function CountPlayers_Actions takes nothing returns nothing
    local integer i = 0
    local integer playercount = 0
    local integer r = 0
    local force f = CreateForce()
    loop
        exitwhen i > 5
        if GetPlayerController(Player(i)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
            call ForceAddPlayer(f, (Player(i)))
            set playercount = playercount + 1
        endif
        set i = i + 1
    endloop
    set i = 0
    loop
        exitwhen i > 5
        if IsPlayerInForce(Player(i), f) == true then
            if playercount >= 6 then
                call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 1)
            else
                if playercount == 5 then
                    call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 1)
                    set r = 1
                else
                    if playercount == 4 then
                        call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 1)
                        set r = 2
                    else
                        if playercount == 3 then
                            call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 2)
                        else
                            if playercount == 2 then
                                call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 3)
                            else
                                call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 6)
                            endif
                        endif
                    endif
                endif
            endif
        endif
        set i = i + 1
    endloop
    set i = 0
    //This is the part I have problem with, setting the extra food cap for the 5 or 4 player case
    loop
        exitwhen i > r
        if IsPlayerInForce(Player(i), f) == true then
            call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 2)
            call ForceRemovePlayer(f, Player(i))
            
        else
            set i = i + 1
        endif
    endloop
    call DestroyForce(f)
    set f = null
endfunction

//===========================================================================
function InitTrig_CountPlayers takes nothing returns nothing
    set gg_trg_CountPlayers = CreateTrigger()
    call TriggerAddAction(gg_trg_CountPlayers, function CountPlayers_Actions)
endfunction
 
Level 13
Joined
Jun 20, 2014
Messages
479
youre pretty much there but i think you should try an easier approach.

set your max food then divide it with the number of players you should be able to correctly get the correct food cap. also check the modulo just in case theres a remainder then distribute it to random player. that should shorten your code.
 
Level 18
Joined
Nov 21, 2012
Messages
835
here solution for you:
JASS:
function SetFoodCap takes integer food returns nothing //call this at start with food 1
    call SetPlayerState(Player(0), PLAYER_STATE_RESOURCE_FOOD_CAP, food)
    call SetPlayerState(Player(1), PLAYER_STATE_RESOURCE_FOOD_CAP, food)
    call SetPlayerState(Player(2), PLAYER_STATE_RESOURCE_FOOD_CAP, food)
    call SetPlayerState(Player(3), PLAYER_STATE_RESOURCE_FOOD_CAP, food)
    call SetPlayerState(Player(4), PLAYER_STATE_RESOURCE_FOOD_CAP, food)
    call SetPlayerState(Player(5), PLAYER_STATE_RESOURCE_FOOD_CAP, food)    
endfunction
//=========================================================
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
    local integer i = 0
    local integer playercount = 0
    local integer array playerList
    local integer x=0
    
    loop
        exitwhen i > 5
        if GetPlayerController(Player(i)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
            set playercount = playercount + 1
            set playerList[playercount] = i
        endif
        set i = i + 1
    endloop
    
    if playercount == 1 then
        call SetFoodCap(6)     
    elseif playercount == 2 then
        call SetFoodCap(3)
    elseif playercount == 3 then
        call SetFoodCap(2)
    
    elseif playercount == 4 then //2 random players 2food:
        set x = GetRandomInt(0, playercount)
        call SetPlayerState(Player(playerList[x]), PLAYER_STATE_RESOURCE_FOOD_CAP, 2)
        set playerList[x] = playerList[playercount]
        set playercount=playercount-1
        
        set x = GetRandomInt(0, playercount)
        call SetPlayerState(Player(playerList[x]), PLAYER_STATE_RESOURCE_FOOD_CAP, 2)
        set playerList[x] = playerList[playercount]
        set playercount=playercount-1
        
    elseif playercount == 5 then //1 random player 2food:
        set x = GetRandomInt(0, playercount)
        call SetPlayerState(Player(playerList[x]), PLAYER_STATE_RESOURCE_FOOD_CAP, 2)
        set playerList[x] = playerList[playercount]
        set playercount=playercount-1
        
    endif

endfunction

zibi
 
Level 11
Joined
Sep 14, 2009
Messages
284
Too Many if's.

What do you mean to many? Is it bad to use many ifs? I see no problem with it.

Anyways I solved the problem.

Here is the final code:

JASS:
function CountPlayers_Actions takes nothing returns nothing
    local integer i = 0
    local integer playercount = 0
    local integer r = 0
    local force f = CreateForce()
    loop
        exitwhen i > 5
        if GetPlayerController(Player(i)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
            call ForceAddPlayer(f, (Player(i)))
            set playercount = playercount + 1
        endif
        set i = i + 1
    endloop
    set i = 0
    loop
        exitwhen i > 5
        if IsPlayerInForce(Player(i), f) == true then
            if playercount >= 6 then
                call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 1)
                call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_LUMBER, 3)
            else
                if playercount == 5 then
                    call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 1)
                    call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_LUMBER, 3)
                    set r = 1
                else
                    if playercount == 4 then
                        call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 1)
                        call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_LUMBER, 3)
                        set r = 2
                    else
                        if playercount == 3 then
                            call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 2)
                            call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_LUMBER, 6)
                        else
                            if playercount == 2 then
                                call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 3)
                                call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_LUMBER, 9)
                            else
                                call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 6)
                                call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_LUMBER, 18)
                            endif
                        endif
                    endif
                endif
            endif
        endif
        set i = i + 1
    endloop
    set i = 0
    if playercount == 5 or playercount == 4 then
        loop
            exitwhen i > r
                if IsPlayerInForce(Player(i), f) == true then
                    call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_FOOD_CAP, 2)
                    call SetPlayerState(Player(i), PLAYER_STATE_RESOURCE_LUMBER, 6)
                    call ForceRemovePlayer(f, Player(i))
                    set i = i + 1
                endif
        endloop
    endif
    call DestroyForce(f)
    set f = null
endfunction

//===========================================================================
function InitTrig_CountPlayers takes nothing returns nothing
    set gg_trg_CountPlayers = CreateTrigger()
    call TriggerAddAction(gg_trg_CountPlayers, function CountPlayers_Actions)
endfunction
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
I think this version would be better. It certainly looks neater and more maintainable. Notice the lack of case statement style "if then" blocks.
JASS:
function CountPlayers_Actions takes nothing returns nothing
    // some constants for conveinence
    local integer foodcap = 6

    local integer i = 0
    local integer playercount = 0
    local integer r
    local integer amount
    local integer give
    local player p
    local player array players

    // enumerate and count active players
    loop
        exitwhen i > 5
        set p = Player(i)
        if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
            set players[playercount] = p
            set playercount = playercount + 1
        endif
        set i = i + 1
    endloop

    // food remainder (inlined simplified modulo)
    set r = foodcap - (foodcap / playercount) * playercount

    // base amount per player
    set amount = foodcap / playercount

    set i = 0
    loop
        exitwhen i >= playercount
        set p = players[i]
        
        // determine amount to give
        set give = amount
        if GetRandomInt(1, playercount - i) <= r then
            // lucky player also gets part of remainder
            set give = give + 1
            set r = r - 1
        endif

        // distribute properties
        call SetPlayerState(p, PLAYER_STATE_RESOURCE_FOOD_CAP, give)
        call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, give * 3)

        // local variable bugfix (technically not required for player)
        set players[i] = null

        set i = i + 1
    endloop

    // local variable bugfix (technically not required for player)
    set p = null
endfunction

//===========================================================================
function InitTrig_CountPlayers takes nothing returns nothing
    set gg_trg_CountPlayers = CreateTrigger()
    call TriggerAddAction(gg_trg_CountPlayers, function CountPlayers_Actions)
endfunction
 
Level 11
Joined
Sep 14, 2009
Messages
284
Some people are not worthy to help them because they treat helper's work like a thin air.

Not sure if you mean me here or someone else. But in any case I went through your code and there's a slight problem with it if the empty player slot is not necessarily 5 or 6, but might as well be 2, 3 or 4 etc.

@Dr Super Good
I have made my code alot simpler since last post, but even then your version still looks way better. I will look through it and consider using it later. Thanks.

EDIT:
I went through your code now, and it seems you forget one important thing just like ZiBi. Just becuase there are (for example) 4 active players, doesn't mean they are necessarily in slot 1-4. Thus, if player slot 3 and 5 are the empty ones etc, the values get messed up if I use your code.

Anyways, here is my final solution:

JASS:
function CountPlayers_Actions takes nothing returns nothing
    local integer i = 0
    local integer playercount = 0
    local integer r = 0
    local force f = CreateForce()
    local integer food = 0
    local integer lumber = 0
    local player array p
    local boolean array inForce
    loop
        exitwhen i > 5
        set p[i] = Player(i)
        if GetPlayerController(p[i]) == MAP_CONTROL_USER and GetPlayerSlotState(p[i]) == PLAYER_SLOT_STATE_PLAYING then
            call ForceAddPlayer(f, (p[i]))
            set playercount = playercount + 1
        endif
        set inForce[i] = IsPlayerInForce(p[i], f)
        set i = i + 1
    endloop
    set i = 0
    loop
        exitwhen i > 5
        if inForce[i] == true then
            if playercount >= 6 then
                set food = 1
                set lumber = 3
            else
                if playercount == 5 then
                    set food = 1
                    set lumber = 3
                    set r = 1
                else
                    if playercount == 4 then
                        set food = 1
                        set lumber = 3
                        set r = 2
                    else
                        if playercount == 3 then
                            set food = 2
                            set lumber = 6
                        else
                            if playercount == 2 then
                                set food = 3
                                set lumber = 9
                            else
                                set food = 6
                                set lumber = 18
                            endif
                        endif
                    endif
                endif
            endif
            call SetPlayerState(p[i], PLAYER_STATE_RESOURCE_FOOD_CAP, food)
            call SetPlayerState(p[i], PLAYER_STATE_RESOURCE_LUMBER, lumber)
        endif
        set i = i + 1
    endloop
    set i = 0
    if playercount == 5 or playercount == 4 then
        loop
            exitwhen i > r
                if inForce[i] == true then
                    call SetPlayerState(p[i], PLAYER_STATE_RESOURCE_FOOD_CAP, 2)
                    call SetPlayerState(p[i], PLAYER_STATE_RESOURCE_LUMBER, 6)
                    call ForceRemovePlayer(f, p[i])
                    set i = i + 1
                endif
        endloop
    endif
    set i = 0
    loop
        exitwhen i > 5
        set p[i] = null
        set i = i + 1
    endloop
    call DestroyForce(f)
    set f = null
endfunction

//===========================================================================
function InitTrig_CountPlayers takes nothing returns nothing
    set gg_trg_CountPlayers = CreateTrigger()
    call TriggerAddAction(gg_trg_CountPlayers, function CountPlayers_Actions)
endfunction
 
Last edited:
Status
Not open for further replies.
Top