• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Make Units Locust and Go Around Building

Status
Not open for further replies.
Level 4
Joined
Mar 20, 2014
Messages
67
Hey Guys,
So I'm trying to make a multiplayer Clash of Clans game for my friends and I through the world editor, and the biggest challenge has come to me yet. If you've played the game, you'd know that when you train a unit it goes to a random Army Camp (Like a food place) and just kinda runs around it every few seconds, just moving randomly around it. There's a max too at each Army Camp so I need to check the number of units they have. I have this trigger but it doesn't seem to work. I want to add locust to them obviously, but I don't know how I should check if the specific building has the max amount of currently allowed units. Right now I have it using a hashtable value which is safe, but why doesn't my below trigger work?
some globals you may need to decipher what happens.
integer array MaxArmyCampUnits
hashtable MUAC
group array ArmyCamps[200]
group array ArmyUnits[200]
JASS:
globals
    unit acu
endglobals

function ArmyLocustCond takes nothing returns boolean
local unit u = GetTriggerUnit()
local integer i = GetUnitTypeId(u)
    if ( i == 'e000' ) then
        set u = null
        return true
    endif
    if ( i == 'h008' ) then
        set u = null
        return true
    endif
    set u = null
    return false
endfunction

function ArmyLocustCondi takes nothing returns boolean
    if ( ArmyLocustCond() ) then
        return true
    endif
    return false
endfunction

function ArmyUnitCallback takes nothing returns nothing
    local unit u = GetEnumUnit()
    local integer i = LoadInteger(MUAC, 0, GetHandleId(u))
    local integer p = GetPlayerId(GetOwningPlayer(u))
    if ( i < MaxArmyCampUnits) then
        set acu = u
        call SaveInteger(MUAC, 0, GetHandleId(u), i + 1)
        set u = null
    endif
endfunction

function ArmyUnit takes integer p returns nothing
    call ForGroup(ArmyCamps, function ArmyUnitCallback)
endfunction

function ArmyLocustAct takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer p = GetPlayerId(GetOwningPlayer(u))
local location po
local location loc
    call ArmyUnit(p)
    set po = GetUnitLoc(acu)
    set loc = PolarProjectionBJ(po, GetRandomReal(50.00, 300.00), GetRandomDirectionDeg())
    call UnitAddAbility(u, 'Aloc')
    call IssuePointOrderLoc(u, "move", loc)
    call RemoveLocation(loc)
    call RemoveLocation(po)
    set u = null
endfunction

//===========================================================================
function InitTrig_Army_Locust takes nothing returns nothing
    set gg_trg_Army_Locust = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Army_Locust, EVENT_PLAYER_UNIT_TRAIN_FINISH )
    call TriggerAddCondition( gg_trg_Army_Locust, Condition( function ArmyLocustCondi ) )
    call TriggerAddAction( gg_trg_Army_Locust, function ArmyLocustAct )
endfunction
 
Never use TriggerAddAction. Use TriggerAddCondition and run everything through the conditions function.
Never use locations unless you are trying to get terrain z height.
You have to null all local handles.

change this.
JASS:
function ArmyLocustCond takes nothing returns boolean
local unit u = GetTriggerUnit()
local integer i = GetUnitTypeId(u)
    if ( i == 'e000' ) then
        set u = null
        return true
    endif
    if ( i == 'h008' ) then
        set u = null
        return true
    endif
    set u = null
    return false
endfunction
to this.
JASS:
function ArmyLocustCond takes nothing returns boolean
    local integer i = GetUnitTypeId(GetTriggerUnit())
    if ( i == 'e000' ) then
        return true
    else if ( i == 'h008' ) then
        return true
    endif
    return false
endfunction

Get rid of the BJs.

You should look at my tutorial converting gui to efficient jass.

As for your problem I would suggest a hashtable that stores the amounts of units you have at a specific building. If it is greater than the max stop them from going there.
Also asking us why it doesn't work without telling us what happens / what should happen / and what does happen is impossible for us to know how to help you.
 
Here you try to save the amount of camp units in a hashtable with relation to PlayerId.

But if a player can have more camps, this won't work anymore. You have to work with a specific Id of the camp building, for example with HandleId(Building).

You don't add any units to this UnitGroup. --> no ForGroup --> "function ArmyUnitCallback" never runs

And you could simply increase the UnitsCounter in same trigger where unit finishes training.

Just sth like this in function ArmyLocustAct:
JASS:
local integer Id = GetHanldeId(GetTriggerUnit())
local integer count = LoadInteger(MUAC, 0, Id)
if count < unitsLimit then
    call SaveInteger(MUAC, 0, Id, count + 1)
endif

Do you really wanna add locust to the units? What for exactly? And I think you don't need these 2 trigger conditions, just make one out of them. ;)

Local locations also have to be nulled. But as was said above actually no need of locations, working with reals would do it bit better.

What is "unit acu" for?
 
Level 4
Joined
Mar 20, 2014
Messages
67
Sorry for my lack of explanation. They act like this trigger doesn't even exist. The units get trained but they just sit there, no locust, just chilling out. I can't figure it out. I'm not going to be one of those guys that says "Here can you fix this" but here's my map attached if you need to look at the rest of the triggers. Also @deathismyfriend Thanks for the tutorial! I haven't coded in around four years but I used to be real good at it ;P.
Edit: Did some debugging. it's not running through the unit group with the ForGroup function, also ACU is the army camp that I want them to go to, which is why I was trying to pick it. Is there a way to stop a forgroup once I found the thing I want?
JASS:
globals
    unit acu
endglobals

function ArmyLocustCond takes nothing returns boolean
local integer i = GetUnitTypeId(GetTrainedUnit())
    if ( i == 'e000' ) then
        return true
    endif
    if ( i == 'h008' ) then
        return true
    endif
    return false
endfunction

function ArmyLocustCondi takes nothing returns boolean
    if ( ArmyLocustCond() ) then
        return true
    endif
    return false
endfunction

function ArmyUnitCallback takes nothing returns nothing
    local unit u = GetEnumUnit()
    local integer i = LoadInteger(MUAC, 0, GetHandleId(u))
    local integer p = GetPlayerId(GetOwningPlayer(u))
    call DisplayTextToForce(bj_FORCE_PLAYER[0], "Made it in the group.")
    if ( i < MaxArmyCampUnits) then
        set acu = u
        call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(u))], "Set ACU up.")
        call SaveInteger(MUAC, 0, GetHandleId(u), i + 1)
        set u = null
    endif
    set u = null
endfunction

function ArmyUnit takes nothing returns nothing
    local integer p = GetPlayerId(GetOwningPlayer(GetTrainedUnit()))
    call ForGroup(ArmyCamps, function ArmyUnitCallback)
endfunction

function ArmyLocustAct takes nothing returns nothing
local unit u = GetTrainedUnit()
local integer p = GetPlayerId(GetOwningPlayer(u))
local real x
local real y
    call ArmyUnit()
    call DisplayTextToForce(bj_FORCE_PLAYER[GetPlayerId(GetOwningPlayer(u))], "Made it past the function call.")
    set y = GetUnitY(acu) + GetRandomReal(50, 100) * Sin(GetRandomDirectionDeg() * bj_DEGTORAD)
    set x = GetUnitY(acu) + GetRandomReal(50, 100) * Cos(GetRandomDirectionDeg() * bj_DEGTORAD)
    call UnitAddAbility(u, 'Aloc')
    call DisplayTextToForce(bj_FORCE_PLAYER, "Added Locust Ability and Moving unit to camp")
    call IssuePointOrder(u, "move", x, y)
    set u = null
    set acu = null
endfunction

//===========================================================================
function InitTrig_Army_Locust takes nothing returns nothing
    set gg_trg_Army_Locust = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Army_Locust, EVENT_PLAYER_UNIT_TRAIN_FINISH )
    call TriggerAddCondition( gg_trg_Army_Locust, Condition( function ArmyLocustCondi ) )
    call TriggerAddAction( gg_trg_Army_Locust, function ArmyLocustAct )
endfunction
 

Attachments

  • COC Remake.w3x
    666.6 KB · Views: 33
Last edited:
Level 4
Joined
Mar 20, 2014
Messages
67
No the ones inside the ForGroup aren't and I don't understand why. The group has units in it, I add one at map initialization no matter what. It just doesn't work. I've also tried rewriting the script at least 4 times and I can't get it to work no matter what. It's as if the ForGroup isn't even running. It doesn't get past that part in the script either, meaning it just goes there then the whole function stops.
 
Level 4
Joined
Mar 20, 2014
Messages
67
I'm not sure if I should post a new thread or not, but I kind of have the trigger working, now It's the second trigger to move them every 8 seconds. Also, the trigger (this one that this thread is about) doesn't limit the number when there's two barracks training at once, which is a problem. They all went to one army camp even though they should be splitting up equally. Any help? In addition, the second trigger is supposed to load the army camp that the unit went around the first time, but it loads some other thing somewhere else and I don't understand, they start to run off the side of my zone into another players zone.
Here's both triggers.
JASS:
scope ArmyLocust
globals
    private unit acu
endglobals

function ArmyLocustCond takes nothing returns boolean
local integer i = GetUnitTypeId(GetTrainedUnit())
    if ( i == 'e000' ) then
        return true
    endif
    if ( i == 'h008' ) then
        return true
    endif
    return false
endfunction

function ArmyUnitCallback takes nothing returns nothing
    local unit u = GetEnumUnit()
    local integer i = LoadInteger(MUAC, 0, GetHandleId(u))
    local integer p = GetPlayerId(GetOwningPlayer(u))
    if ( i < MaxArmyCampUnits) then
        set acu = u
        call SaveInteger(MUAC, 0, GetHandleId(u), i + 1)
        set u = null
    endif
    set u = null
endfunction

function ArmyLocustAct takes nothing returns nothing
local unit u = GetTrainedUnit()
local integer p = GetPlayerId(GetOwningPlayer(u))
local integer h = GetHandleId(u)
local real x
local real y
    call ForGroup(ArmyCamps, function ArmyUnitCallback)
    set x = GetUnitX(acu) + GetRandomReal(50, 300) * Cos(GetRandomDirectionDeg() * bj_DEGTORAD)
    set y = GetUnitY(acu) + GetRandomReal(50, 300) * Sin(GetRandomDirectionDeg() * bj_DEGTORAD)
    call SaveUnitHandle(MUAC, 2, h, acu)
    call GroupAddUnit(ArmyUnits, u)
    call UnitAddAbility(u, 'Aloc')
    call IssuePointOrder(u, "move", x, y)
    set u = null
    set acu = null
endfunction

//===========================================================================
function InitTrig_Army_Locust takes nothing returns nothing
    set gg_trg_Army_Locust = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Army_Locust, EVENT_PLAYER_UNIT_TRAIN_FINISH )
    call TriggerAddCondition( gg_trg_Army_Locust, Condition( function ArmyLocustCond ) )
    call TriggerAddAction( gg_trg_Army_Locust, function ArmyLocustAct )
endfunction
endscope
JASS:
function TimedGroupMovement takes nothing returns nothing
local unit u = GetEnumUnit()
local unit acu = LoadUnitHandle(MUAC, 2, GetHandleId(u))
local real x = GetUnitX(acu) + GetRandomReal(50, 300) * Cos(GetRandomDirectionDeg() * bj_DEGTORAD)
local real y = GetUnitY(acu) + GetRandomReal(50, 300) * Sin(GetRandomDirectionDeg() * bj_DEGTORAD)
local integer i = GetUnitTypeId(u)
local integer barbarian = 'h008'
local integer archer = 'e000'
    if (i == barbarian ) or (i == archer) and (GetOwningPlayer(acu) == GetOwningPlayer(u)) then
        call IssuePointOrder(u, "move", x, y)
    endif
set u = null
set acu = null
endfunction

function TimedArmyMovements takes nothing returns nothing
local integer i = 0
local integer stop = GetPlayers()
    loop
        call ForGroup( ArmyUnits[i] , function TimedGroupMovement )
        exitwhen i == stop
        set i = i + 1
    endloop
endfunction

//===========================================================================
function InitTrig_Timed_Army_Units takes nothing returns nothing
    set gg_trg_Timed_Army_Units = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_Timed_Army_Units, 8.00 )
    call TriggerAddAction( gg_trg_Timed_Army_Units, function TimedArmyMovements )
endfunction
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
They all went to one army camp even though they should be splitting up equally
Not really, pseudo random is not 50/50.
Well i have not the words to explain more, but anyway i suppose you have an option enabled on the editor ("use fixed seed" or something like that, can't remember the name)
Basically it will give you the same "random" numbers each time when you test the map through the editor.

If you really want a perfect 50/50 you don't have to use randoms functions, just a boolean and when a new unit is trained :

set my_bool = not my_bool
if my_bool then
... send the unit to A
else
... send the unit to B
endif

And for units which go back for no reason, i suppose you use neutral players, maybe you can fix this behavior with some jass commands/tricks, but really just use computer slots and that won't happen anymore.
Neural units are the devil.
 
Level 4
Joined
Mar 20, 2014
Messages
67
Well it's rather that it picks a unit in the group, how to know which unit I don't know, but it picks one of the army camps owned by the player and sets it equal to acu, acu is then saved in a hashtable under the unit that was just trained. The trained unit then is set to move to the acu army camp and it does that. But two things I found problems with. 1. Training two units at the same time caused them to go to the same army camp even though theres a specific variable that is counting to make sure their's not more than a specified amount (at this point in time it's 20) that value is then also saved in the hashtable. 2. When the units go to the random places, the problem is that they don't have a unit that's loaded. I load the acu back through the unit because I add those trained units to a group as I can't pick them (They have locust) so when I loop through the group I load acu from the hashtable and they SHOULD have the correct acu loaded, but why don't they?
- Zach
Oh how I wish you had warcraft 3 installed Troll-Brain lol.
 
Level 4
Joined
Mar 20, 2014
Messages
67
I apologize, however I fixed it, it seems that it was just JASS being weird.
It turns out that when you call InitHashtable() then set a variable to the last created hashtable, it doesn't work.
Fun fact of the day. Thanks Troll-Brain
 
Status
Not open for further replies.
Top