Sarven Shepherd and Bash

Possibly a bug, or I don’t understand bash. I’ll try to post only the relevant code but can add the whole thing if that helps.

        #this works
        while enemy.health > 0:  
            self.bash(enemy)
            self.attack(enemy)

        #this causes infinite loop
        while enemy.health > 0:  
            self.bash(enemy)

Although I did use some more sophisticated code in the final result (cleave if ready, else bash if ready, else attack), this was a weird intermediate result. If I do a similar thing with cleave instead of bash I just end up dying (quickly!) instead of getting into an infinite loop.

And sort of an aside, I found this level impossible with the standard cleave/attack method (even with health 782) but really easy with the simplest bash method. Maybe that was the idea though, and if so sorry if I’m giving too much away! Also surprised me b/c I had not been introduced to bash on any earlier levels so it was something of a desperation guess to even try bash.

I cant really tell what is wrong without all your code so please post it all

In general, cleave is really weak against a single target. Cleave does 15 damage to each enemy affected, your normal attack does ~30.

Apart from that, I found out just yesterady that you can’t bash two doors after each other in “Deadly Dungeon Rescue”. Might be related, might not.

A full-code review might help to identify any formal errors, otherwise it is really bash() which is broken.

Here’s the whole program that goes into infinite loop for me. Just commenting out the attack right after bash will “fix” it, so it does seem to me like probably something is not quite right with bash.

loop:
    enemies = self.findEnemies()
    enemyIndex = 0
    # Wrap this logic in a while loop to attack all enemies.
    while enemyIndex < len(enemies):
        enemy = enemies[enemyIndex]
        if enemy.type != "sand-yak":
            # While the enemy's health is > 0, attack
            while enemy.health > 0:
                self.bash(enemy)
                #self.attack(enemy)
        enemyIndex += 1        
    # Between waves, move back to the center.
    self.moveXY(40,32)

Thanks! I did not realize cleave was so weak on a per enemy basis. That explains some things…

Btw, is there a fixed and known cleave radius? Info page just says cleave radius is “m” or something like that.

Ingame the range is given as 10m. You can hover over the respective command to see the actual stats.

Try the following code:

# The same as yours
while enemy.health > 0:
    self.bash(enemy)
    pass
# Rest also like yours

Also try:

while enemy.health > 0:
    if self.isReady("bash"):
        self.bash(enemy)
    pass    #try with and without this.

What are the results? While we’re on it, you generally want to attack when you can’t bash (though the better option is sometimes running).

The idea of JFBM seems good. Adding a test before bash make sense to solve your problem.
If bash is not ready, bash action does nothing, and the while will loop at fast rate without any action to slow it down, and nothing to decrease the health of enemy.
It’s why you get the “infinite” loop.
My proposal:

while enemy.health > 0:
    if self.isReady("bash"):
        self.bash(enemy)
    else
        self.attack(enemy)

(sorry if the syntax is not correct, it’s not the language I use)

To cleave only when you need, you can count the number of enemies in the 10m range. But it’s a far more complexe code to write, and you need special googles I think to get the DistanceTo function.

1 Like

@JFBM – thanks for the cleave tip, somehow I did not realize there was more info in game compared to the info when buying/equipping

None of your suggestions worked. The symptoms are all the same. The game freezes after running or submitting and eventually a message comes up about the code being slow or having an infinite loop.

@Vettax – I’m not in any way suggesting the way I coded it is correct or good, just that it shouldn’t result in an infinite loop. Misusing cleave in the same way (i.e. attempting to cleave without first checking if it is ready) does not result in an infinite loop, it just basically behaves harmlessly as if I had typed “pass”.

Yeah, I’ve been trying to do exactly that in order to beat Backwoods Brawl a second time but so far results are worse than simply using cleave whenever it’s ready! Maybe b/c by the time cleave is ready you’re almost always being attacked by several enemies at Backwoods Brawl. And as you note, it starts to get complex pretty quickly and I doubt I’m doing it very optimally.

I’m usually doing it by counting all enemies in range (which may or may not be the most efficient approach):

enemies = self.findEnemies()   # Note that your glasses must support that.
enemyIndex = 0
countInRange = 0

while enemyIndex < len(enemies):
    if self.distanceTo(enemies[enemyIndex]) < 10:
        countInRange += 1
    enemyIndex += 1

if countInRange > 2 and self.isReady("cleave"):
    self.cleave()
1 Like

Good point about the unforgiving bash behavior infinite loop. I actually have some workaround code to abort the bash if it’s not going to be ready for a while so your hero doesn’t just sit there dumbly, but I think in this case it might be malfiring and causing the action to not take even one frame, leading to the infinite loop. Instead it should probably take at least one frame before giving up due to cooldown, but I’ll have to test this out some more when I get more time.

@J_F_B_M – yeah, I attempted something similar to your code for counting enemies within range, but perhaps my implementation was poor b/c it didn’t work very well in practice (cue that Yogi Berra quote that I keep seeing!)

@nick – thanks, good to know you are aware of the issue and that I’m not crazy!