Sarven Siege coding error:


#1

So, in order to find the best coin for me to pick up during Sarven Siege, I have this code

def collect():
    coins = self.findItems()
    bestCoin = 0
    bestValue = 0
    for coin in coins:
        value = coin.value/self.distanceTo(coin)
        if value > bestValue:
            bestValue = value
            bestCoin = coin
    self.move(bestCoin.pos)

And for when I summon a peasant, I have the same code, appropriately adapted:

def peasantCollect():
    peasant = self.findByType("peasant")[0]
    if peasant:
        coins = self.findItems()
        bestCoin = 0
        bestValue = 0
        for coin in coins:
            value = coin.value/peasant.distanceTo(coin)
            if value > bestValue:
                bestValue = value
                bestCoin = coin
        self.command(peasant, "move", bestCoin.pos)

The peasant’s code works perfectly fine, but my character’s code just makes me run into the right wall. What is going wrong?


#2
if coin:
        self.move(bestCoin.pos)

#3

Yea, it sounds like your target doesn’t exist at all times (especially at the beginning). Maybe you meant :

if bestCoin:
    self.move(bestCoin.pos)

The walking straight into the wall symptom is usually a null target in my codes.


#4

Oh, I see. Thanks!
EDIT: I’m trying to assign my archers to two defendPoints, so I borrowed my code from Steelclaw Gap, tweaked it, ands ended up with this:

def commandTroops():
    friends = self.findByType("archer")
    for friendIndex in range(len(friends)):
        friend = friends[friendIndex]
        defendPoint = defendPoints[friendIndex % len(defendPoints)]
        self.command(friend, "defend", defendPoint)

In Steelclaw Gap, my troops, when I command them, just stay where I tell them to go, and it works perfectly, but in Sarven Siege, they start patrolling between the two points? What am I doing wrong?


#5

Looks good, do any archers die? 'cause that would cause them to switch (remove the dead guy from the list of friends and everybody after him/her switches defend points.)


#6

With the Boss Star III I can summon two archers right off the bat. They go to different defendPoints, then switch just before the first enemy arrives within range, causing the enemy to get in a few hits before the archers actually start attacking.


#7

Is commandTroops() the only place you tell them where to go? or does the summon step also do that?


#8

Yes, I believe it is.


#9

Double check to be sure (search for “command” to make sure there are no other command move or defends).
I can’t think of a reason why they should change their order in the array, except death.


#10

I checked, and there is no mention of commanding archers besides inside commandTroops.


#11

I don’t think the order of findByType("archer") is guaranteed to stay stable over time, even if none of them die.


#12

Edit : nevermind, the answer provided below is wrong as it doesn’t prevent switching when a unit dies. Too used to keep all my units alive in sarven siege I copy pasted a wrong piece of code. Still the idea of using this.built array is a good tip.

Sorry for the late (3days later) answer, I also faced the “patrolling syndrom” of my units.

I did a bunch of test about the order of arrays returned by findEnemies() and findByType(). What I found is : if order matters, I don’t use findByType anymore. (findEnemies works however). But the best way to assign correctly units (according to me) is to use the this.built array.

For example, when I have several areas to defend (like in sarven Siege), I use this structure to prevent my units to be reassigned to another area. (sorry, didn’t translate into python)

Structure
    nBuilt = this.built.length ;
    kArcher = 0;
    kSoldier = 0 ;
    for(iBuilt = 2 ; iBuilt < nBuilt ; iBuilt ++ ){
        builtUnit = this.built[iBuilt] ;
        if(builtUnit.type =="archer"){
            if (builtUnit.health>0) {
                this.command(builtUnit, "defend", archerPos[kArcher%6]);
                kArcher+=1 ;
            }
            
        }else if(builtUnit.type == "soldier"){
            if (builtUnit.health>0) {
                this.command(builtUnit, "defend", soldierPos[kSoldier %5]);
                kSoldier +=1 ;
            }
        }
    }

Obviously, soldierPos and archerPos are defined upstream as an array of positions : [ {x: , y: } , {x: ,y: }… ] and are the positions to be defended. (6 positions for the archers and 5 for the soldiers in this example)