Bat
Entity data | |
---|---|
Entity pointer | $82:F03E |
The bat is an entity that is spawned by vampires.
Behavior
A bat starts out moving in a given direction specified in the entity arguments. The initial velocity of the bat is 6 px/frame in this direction. If the direction is diagonal, the velocity is 6 px/frame on both axes. Every frame, the bat will accelerate towards the nearest target at a rate of 1 px/frame2, but its speed will not exceed 5 px/frame on each axis. After the acceleration is applied, then the position is updated based on the current velocity.
Every 3 frames the bat will switch to the next animation frame. There are 2 different sprites that it alternates between.
A bat will die if any of the following conditions are met:
- It contacts a tile that is solid to weapons
- It touches a player, victim, or any weapon shot
- It has been alive for 131 frames
Once the bat dies, it plays a 32 frame death animation, then the entity is destroyed.
Bugs
- A bat starts at a speed of 6 px/frame on each axis, but the routine that updates the speed will not allow it to exceed 5 px/frame. Thus if a bat's speed ever goes below the initial 6 px/frame, it will not be able to reach it again. This is likely a mistake.
RAM map
Entity arguments
Address | Length | Type | Name | Description |
---|---|---|---|---|
$00 | 2 | int16 | x | X position |
$02 | 2 | int16 | y | Y position |
$04 | 2 | direction x2 | direction | Direction |
Entity memory
Address | Length | Type | Name | Description |
---|---|---|---|---|
$08 | 2 | pointer16 | sprite | Pointer to sprite |
$0A | 2 | int16 | x | X position |
$0C | 2 | int16 | y | Y position |
$0E | 2 | int16 | velocityX | X velocity |
$10 | 2 | int16 | velocityY | Y velocity |
$12 | 2 | unused | unused12 | Value is set, but never used |
$14 | 2 | boolean | dead | Dead |
$16 | 2 | uint16 | animationFrame | Low bit is the current animation frame |
$18 | 2 | uint16 0-based | framesUntilAnimUpdate | Number of frames until the next animation frame |
$1A | 2 | uint16 0-based | framesUntilDeath | Number of frames until death |
Pseudocode
main() { $7E:00DE += 8 this.sprite = init() while (!this.dead) { waitFrames(1) updateAnimation() updatePosition() } this.sprite.tileData.bank = 0x8F showAnimation(deathAnimation) $7E:00DE -= 8 while ($7E:00DE < 0) { } deleteSprite(this.sprite) } deathAnimation = { { 0xF6CB, 8 }, { 0xF6D4, 8 }, { 0xF6DD, 8 }, { 0xF6E6, 8 }, { 0 } } updatePosition() { targetSprite = findTarget(this.x, this.y) targetDirection = getDirectionToTarget(this.sprite, targetSprite) newVelocityX = this.velocityX + accelerationAmouont[targetDirection][0] if (abs(newVelocityX) < 6) { this.velocityX = newVelocityX } newVelocityY = this.velocityY + accelerationAmouont[targetDirection][1] if (abs(newVelocityY) < 6) { this.velocityY = newVelocityY } this.x += this.velocityX this.y += this.velocityY if (bgSolidToWeapons(this.x, this.y)) { this.dead = true } else { this.sprite.x = this.x this.sprite.y = this.y this.framesUntilDeath -= 1 if (this.framesUntilDeath < 0) { this.dead = true } } } accelerationAmouont = { { 0, 0 }, { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 }, { -1, -1 } } updateAnimation() { this.framesUntilAnimUpdate -= 1 if (this.framesUntilAnimUpdate < 0) { this.framesUntilAnimUpdate = 2 this.animationFrame += 1 this.sprite.tileData.lowBytes = animation[this.animationFrame % 2] } } animation = { 0xDDB0, 0xDDB9 } init() { sprite = createSprite() this.x = args.x sprite.x = args.x sprite.z = 12 this.y = args.y sprite.y = args.y this.unused12 = args.direction * 2 this.velocityX = startingVelocity[args.direction][0] this.velocityY = startingVelocity[args.direction][1] sprite.tileData = $90:DDB0 sprite.entity = currentEntity sprite.visible = true this.framesUntilDeath = 130 this.dead = false this.animationFrame = 0 this.framesUntilAnimUpdate = 0 setCollisionHandler(collisionHandler) return sprite } startingVelocity = { { 0, 0 }, { 0, -6 }, { 6, -6 }, { 6, 0 }, { 6, 6 }, { 0, 6 }, { -6, 6 }, { -6, 0 }, { -6, -6 } } collisionHandler(spriteType) { if (spriteType == VICTIM || spriteType == ZEKE || spriteType == JULIE || (spriteType & 0x7FFF) >= SQUIRT_GUN) { this.sprite.type = NONE this.dead = true } }