SpelunkyFan wiki

Nearest-enemy hits

Verified against the spelunky.ai port v0.1.10 on .

Nearest-enemy hits are a quirk of Spelunky Classic in which a thrown item hurts, and a crouching player picks up, the enemy nearest, not the one touched.

The same two lines go wrong in both places: a test for a monster touching the thing, then a pick of the monster nearest it. They usually agree, and disagree when two monsters are close together, so a Rock thrown at one can kill its neighbour, and a crouching player can lift a stunned enemy he isn't standing over.

What happens

#

The player throws a Rock up at a Spider and a Bat hanging side by side. It hits the Spider, but the Bat dies [1].

A thrown rock hurts the nearest enemy, not the one it hits. The player throws a rock up at a spider and a bat hanging side by side. It hits the spider, but the bat dies: a fast thrown item hurts the enemy nearest to it, not the one it touched.

The player stuns a Caveman and a Yeti, then crouches over the Yeti to pick it up, and lifts the Caveman beside it [2].

Picking up a stunned enemy takes the nearest one. The player stuns a caveman and a yeti, then crouches over the yeti to pick it up, but lifts the caveman beside it: picking up a stunned enemy takes the enemy nearest to the player, not the one under him.

Why

#

While an item moves faster than 2 pixels a step, the code most items share looks for an enemy inside a small box around it, then hurts the enemy nearest it, of any kind [3]:

else if (abs(xVel) > 2 or abs(yVel) > 2)
{
    if (collision_rectangle(x-2, y-2, x+2, y+2, oEnemy, 0, 0))
    {
        obj = instance_nearest(x, y, oEnemy);
        if (not obj.invincible and obj.type != "Magma Man")
        {
            obj.xVel = xVel;
objects/oItem/step.gml:256-263, from spelunky.gmk, Spelunky Classic 1.1's source, © 2008, 2009 Derek Yu and Mossmouth, LLC (Spelunky User License v1.1b).

collision_rectangle tests the monsters' collision boxes, but instance_nearest measures to their positions, and most monsters' position is their sprite's top left corner. An item touching one monster's right side can be nearer the next one's corner, and that one is hurt. The test for invincibility is the nearest one's too, so an invincible monster beside the one hit spares it [4]. The Jar, the Skull and the dice have their own copies of the code, with the same pick [5] [6].

Picking an enemy up has it too: crouched with empty hands, the attack key looks for an enemy at the player's feet, then takes the nearest one, and lifts it only if that one is stunned [7]:

else if (collision_rectangle(x-8, y, x+8, y+8, oEnemy, 0, 0))
{
    obj = instance_nearest(x, y, oEnemy);
    if (obj.status >= 98 and obj.canPickUp)
    {
        holdItem = obj;
        holdItem.held = true;
objects/oPlayer1/step.gml:1300-1306, from spelunky.gmk, Spelunky Classic 1.1's source, © 2008, 2009 Derek Yu and Mossmouth, LLC (Spelunky User License v1.1b).

So a live enemy beside a stunned one can keep the stunned one on the ground. Items come first, with the same pick, and collecting treasure does it as well [8] [4].

The pick works the other way too. The player's check for an arrow hitting him finds one touching him, then tests the nearest arrow's speed, so a fast arrow does nothing while a slow one lies nearer [9], and the shared monster code's check for a Spear Trap's spears reads the nearest spears' frame [10] [4].

Reproducing it

#

Throw a Rock at one of two monsters close together, or stun two monsters side by side and crouch over the right side of the one on the left. The replays of the clips' staged scenes pin both: the Rock touching the hanging Spider's box and the Bat dying [11], and the player crouched over the stunned Yeti's right side lifting the stunned Caveman [12]. In the same scenes without the Bat, the Rock kills the Spider, and without the Caveman, the player lifts the Yeti.

In the port

#

The spelunky.ai port reproduces it exactly: the three rows are in docs/quirks.md's list of the 1.1 source's bugs [4], and instance_nearest measures as GameMaker 8 does, to positions [13]. The arrows' and spears' version is read in the code and not yet in a replay, as it needs two at once. No option turns it off.

FAQ

#
Why did my thrown rock kill the wrong monster in Spelunky Classic?

A fast thrown item checks that it touches a monster, then hurts the monster nearest it, which can be another one beside it. Monsters are measured from their top left corners, so the one touched isn't always the nearest.

Why does the player pick up the wrong stunned enemy?

Crouching to pick one up takes the enemy nearest the player, not the one at his feet. If that one isn't stunned, he picks up nothing at all.

Is hitting the nearest enemy a bug?

It's in the 1.1 source: the code finds a monster touching the item or the player, then uses the nearest one instead of the one it found. The spelunky.ai port keeps it.

See also

#

References

#
  1. Clip quirks/thrown-item-nearest-enemy
  2. Clip quirks/pickup-nearest-enemy
  3. objects/oItem/step.gml:256-263
  4. Quirk 1 (docs/quirks.md)
  5. objects/oJar/step.gml:106-108
  6. objects/oSkull/step.gml:104-106
  7. objects/oPlayer1/step.gml:1300-1309
  8. objects/oPlayer1/step.gml:1206-1209
  9. objects/oPlayer1/step.gml:1513-1516
  10. objects/oEnemy/step.gml:76-79
  11. Replay fidelity/replays/action-throw-rock-nearest-enemy.txt
  12. Replay fidelity/replays/action-pickup-nearest-enemy.txt
  13. Quirk 5 (docs/quirks.md)

Source code

  • objects/oItem/step.gml
  • objects/oPlayer1/step.gml
#