Bypass "...but it's dead!" hero freezing while using bash() in Javascript

I would like to use the bash function to deal more damage when I’m fighting, but if I cast “chain-lightning” using the dragon gloves before I go to bash an enemy who is a little distance away and it gets killed, my hero gets stuck on the hero.bash(enemy); function. This is very troublesome because it meant my hero would stop doing anything altogether. Any ideas to solve this? Like tell my hero to forcefully stop the bash() function if it runs for more than a set amount of time?

P.S. Not a dupe of https://discourse.codecombat.com/t/but-its-dead-and-my-people-freeze/13824 because that is Python.

Post your code, please.

This is the typical code I use in brawls:

while (true) {
    var enemy = hero.findNearestEnemy();
    var item = hero.findNearestItem();
    var friends = hero.findFriends();
    var flag = hero.findFlag("green");
    for (var i = 0; i < friends.length; i++) {
        hero.command(friends[i], "attack", friends[i].findNearestEnemy());
    }
    if (hero.gold >= hero.costOf("soldier")) {
        hero.summon("soldier");
    } else if (flag) {
        hero.pickUpFlag(flag);
    } else if (enemy && hero.distanceTo(enemy) < 10) {
        if (enemy && hero.canCast("chain-lightning", enemy)) {
            hero.cast("chain-lightning", enemy);
        } else if (enemy && hero.isReady("bash")) {
            hero.bash(enemy);
        } else if (enemy) {
            hero.attack(enemy);
        }
    } else if (item) {
        hero.move(item.pos);
    }
}

Maybe try using bash first, then do chain lightning, because chain lightning might also kill people you didn’t target. So your hero is running towards someone, to bash them who’ll subsequently be killed by your own chain lightning, causing an error.
:lion: :lion: :lion:
P.S. this happens quite a lot to me as well, I normally wait 0.1 and then check if they’re there again. If so, then I attack.

var attackingRange = 30;  // you are using 10m but the throwers attack you from 25 m
// I will put all my hero attack code under
    if ( enemy && enemy.health > 0 ){ 
       if (hero.distanceTo(enemy) < attackingRange) {
        //  attack code here 
        }
    }

Try first without summoning soldiers ( your target is maybe killed by your soldiers) and using flags, then increase the code complexity. ( I never use flags even in ‘flag’ levels, I’m too slow…) . Tell us the result of your tests.

Why your hero is freezing:
0 meaning is there is no item, enemy or flag:

 item | enemy| flag |     in code     | executed 
-------------------------------------------------
   0  |   0  |   0  |                 |
   0  |   0  |   1  | else if (flag)  | first 
   0  |   1  |   0  | else if (enemy) | second 
   0  |   1  |   1  |                 | 
   1  |   0  |   0  | else if (item)  | third
   1  |   0  |   1  |                 |
   1  |   1  |   0  |                 | 
   1  |   1  |   1  |                 | 

``
You are telling imperatively the order of execution but do not handle 5 remaining 
situation. You must at least have an else  ( your hero to stay at the same position 
or go somewhere). 
The hero freezes at item = 0 | enemy = 0 | flag = 0
1 Like

I believe you have misinterpreted my code, because if there is nothing then it just cycles through the while() indefinitely until it finds something it reacts to. My hero freezes only if the enemy he’s trying to bash dies before he bashes it. Maybe you thought that after it runs an else if it will run the else if after it as well.

Reality:

 item | enemy| flag |     in code     | executed 
-------------------------------------------------
   0  |   0  |   0  | while(true)     | N/A
   0  |   0  |   1  | if (flag)       | first 
   0  |   1  |   0  | else if (enemy) | second 
   0  |   1  |   1  | else if (enemy) | second
   1  |   0  |   0  | else if (item)  | third
   1  |   0  |   1  | if (flag)       | first
   1  |   1  |   0  | if (flag)       | first
   1  |   1  |   1  | if (flag)       | first

Also, after some extensive testing I think I have found a nice solution:

if (hero.isReady("bash")) {
            while (enemy && hero.distanceTo(enemy) > enemy.size) {
                hero.move(enemy.pos);
            }
            if (enemy) {
                hero.bash(enemy);
            }

This exploits the fact that the .size attribute of almost any interactive entity is the radius of it’s hitbox, so my hero can bash the enemy as he is right on the hitbox so he never misses.

Thanks for the help anyways.

BTW Is it just me, or are ogres actually roblox noobs in disguise? (“oof” death sound)

:thinking: intensifies

I will reply in detail later but you can check one of my first posts here :slight_smile:
see the BrokenSyntax post '...but it's dead!' and my people freeze!

Hi there, sorry for bumping an older thread, but it looks like the problem with hero completely freezing after using bash() on a dead enemy still persists. And it doesn’t seem to matter if it is Python, or JavaScript.

This is an example code where bash() on a dead enemy does cause the freeze, while attack() doesn’t:

...
enemy = self.findNearestEnemy()
...
self.say("Attacking nearest enemy: " + enemy.type)
if self.isReady("bash"):
    self.bash(enemy)
else:
    self.attack(enemy)

IMPORTANT: Note that say() takes 1s, so the found enemy may be killed in the meantime (enemy.health <= 0). Therefore omitting the say() “fixes” the problem, as well as the efficiency of the hero (yet, there is no other alternative “debug” command to say()?).

So shouldn’t we file a regular issue on GitHub for this? Or does anyone experience another behavior of the game? (reproducible on https://codecombat.com/play/level/siege-of-stonehold for me)

1 Like

Why don’t you check for the enemy when you’re bashing? You pretty much always need to and it would fix this problem. I think there’s a debug thing in Javascript… @xython what is it again? I don’t do Javascript much.
Or you could just put in enemy = self.findNearestEnemy() again.

Why do you think this is a bug? Attacking a dead ogre will obviously cause an error, just redefine enemy and put enemy in the if statement to check if it exists.
Maybe I’m missing something here, but it seems pretty simple to me.
Danny

Hi @Deadpool198, thanks for your response, I will try to clarify…

As I write “among the lines”, I do that already when necessary (BTW findNearestEnemy() already guarantees that the returned enemy is still alive; AFAIK one only needs to check enemy.health if taking other actions before the attack). I hoped I re-explained both the problem and its solutions.

I think the answer is simple: Because the game doesn’t behave consistently. It shouldn’t matter if hero attacks by attack(), bash() or cleave() for example. Last by not least, the current behavior needs to confuse lots of newbies. Moreover, there’s that slightly related problem of that adding a call to say() can break your existing code easily…

findNearestEnemy() guarantees that the returned enemy is alive when you called the variable. If you define enemy as hero.findNearestEnemy() you can be sure that in that instant the enemy is alive, but if you spend any amount of time doing something else, like hero.wait(0.2), then go and attack the enemy, for all you know it could be dead. Variables don’t update themselves. If you define enemy, then wait(100), then tell your hero to attack(enemy), your hero will still think the enemy is alive, it doesn’t know what’s happened to the enemy since you called the variable. Hence the surprised: “But it’s dead!”.

That’s simply because of what I mentioned above.
And:

I think this is because attack() is built differently from abilities. Attack has no cooldown (it just takes some time for each strike) and I think it has specific code that makes the hero move() towards the enemy while they’re alive like the code above in this topic. I just think bash() isn’t as forgiving of bad code technique.
It really isn’t a problem, it’s just that attack() is more forgiving of these kinds of code logic breaches, I think it’s coded that way. If you use it correctly it’s fine, I’ve never had any problems with it.
Danny

Hi Danny, thanks again, but it looks like you’ve overlooked that I don’t actually need any further explanation of what’s going on. So I can just say “yes” to your first two paragraphs, but they don’t bring anything new from my point of view.

So to keep it short and to-the-point, I just repeat that IMO the fact that the game reacts as it reacts, is confusing to (new) players and it should be changed, no matter what technical details are behind that. For example, it should always fail-fast, or it should always continue, but not mixing this. I haven’t convinced you, but maybe some other guy will grab that idea. Your saying that “If you use it correctly it’s fine, I’ve never had any problems with it.” is really not a valid argument to what I tried to discuss in here. Thanks for taking your time anyway. :slight_smile:

Petr

1 Like

Okay, sorry, I couldn’t quite tell whether you did understand it or not so I wanted to make sure.
As for your opinion, we might have to agree to disagree. Coding is not forgiving, that’s a fact. If you make any kind of mistake in a real coding environment there’s no fail-safe to save you. However as it is a code-learning game there could possibly be a fix for this, so that people don’t get confused. I personally think that it’s a good reflection of real coding, and that if there’s any mistake in your code it just won’t work.

I do get your idea, don’t get me wrong, but that doesn’t mean I’m convinced. I also think that you can go ahead and report it, but these kind of things don’t often get fixed. There are much bigger issues around. But that is no reason to not do it, so please do (not that you needed me to say that, but I do agree there is a kind of problem somewhere that could be fixed.)
Danny

2 Likes

I see, you have surely much better overview of all the issues around, so yeah, this might be just a minor one.

OK, here it comes: Calling bash() on a dead enemy freezes the hero (unlike attack()) · Issue #6033 · codecombat/codecombat · GitHub :slight_smile:


And regarding the alternatives to say(), I have found that this was discussed 5 years ago (unresolved so far): Access console.log in game?

All for now, I guess. Thanks again. :slight_smile:

2 Likes