Bat: Difference between revisions
Piranhaplant (talk | contribs) No edit summary |
Piranhaplant (talk | contribs) No edit summary |
||
(3 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
{{Infobox Entity|entity_pointer=$82:F03E}} |
{{Infobox Entity|img=Bat.png|entity_pointer=$82:F03E}} |
||
The bat is an entity that is spawned by [[vampire]]s. |
The bat is an entity that is spawned by [[vampire]]s. |
||
== Behavior == |
== 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/frame<sup>2</sup>, but its speed will not exceed |
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/frame<sup>2</sup>, 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. |
Every 3 frames the bat will switch to the next animation frame. There are 2 different sprites that it alternates between. |
||
Line 14: | Line 14: | ||
Once the bat dies, it plays a 32 frame death animation, then the entity is destroyed. |
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 == |
== RAM map == |
||
Line 56: | Line 60: | ||
| $1A || 2 || uint16 0-based || framesUntilDeath || Number of frames until death |
| $1A || 2 || uint16 0-based || framesUntilDeath || Number of frames until death |
||
|} |
|} |
||
{{Pseudocode header}} |
|||
main() { // $82:F03E |
|||
{{RAM name|$7E:00DE}} += 8 |
|||
this.sprite = init() |
|||
while (!this.dead) { |
|||
{{ROM name|$80:8353}}(1) |
|||
updateAnimation() |
|||
updatePosition() |
|||
} |
|||
this.sprite.tileData.bank = 0x8F |
|||
{{ROM name|$81:832C}}(deathAnimation) |
|||
{{RAM name|$7E:00DE}} -= 8 |
|||
while ({{RAM name|$7E:00DE}} < 0) { } |
|||
{{ROM name|$80:BE41}}(this.sprite) |
|||
} |
|||
deathAnimation = { { 0xF6CB, 8 }, { 0xF6D4, 8 }, { 0xF6DD, 8 }, { 0xF6E6, 8 }, { 0 } } // $82:F07F |
|||
updatePosition() { // $82:F091 |
|||
targetSprite = {{ROM name|$80:B123}}(this.x, this.y) |
|||
targetDirection = {{ROM name|$80:B22A}}(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 ({{ROM name|$80:AF2C}}(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 = { // $82:F0F7 |
|||
{ 0, 0 }, |
|||
{ 0, -1 }, |
|||
{ 1, -1 }, |
|||
{ 1, 0 }, |
|||
{ 1, 1 }, |
|||
{ 0, 1 }, |
|||
{ -1, 1 }, |
|||
{ -1, 0 }, |
|||
{ -1, -1 } |
|||
} |
|||
updateAnimation() { // $82:F11B |
|||
this.framesUntilAnimUpdate -= 1 |
|||
if (this.framesUntilAnimUpdate < 0) { |
|||
this.framesUntilAnimUpdate = 2 |
|||
this.animationFrame += 1 |
|||
this.sprite.tileData.lowBytes = animation[this.animationFrame % 2] |
|||
} |
|||
} |
|||
animation = { 0xDDB0, 0xDDB9 } // $82:F137 |
|||
init() { // $82:F13C |
|||
sprite = {{ROM name|$80:BE0C}}() |
|||
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 = {{RAM name|$7E:0008}} |
|||
sprite.visible = true |
|||
this.framesUntilDeath = 130 |
|||
this.dead = false |
|||
this.animationFrame = 0 |
|||
this.framesUntilAnimUpdate = 0 |
|||
{{ROM name|$80:8475}}(collisionHandler) |
|||
return sprite |
|||
} |
|||
startingVelocity = { // $82:F19E |
|||
{ 0, 0 }, |
|||
{ 0, -6 }, |
|||
{ 6, -6 }, |
|||
{ 6, 0 }, |
|||
{ 6, 6 }, |
|||
{ 0, 6 }, |
|||
{ -6, 6 }, |
|||
{ -6, 0 }, |
|||
{ -6, -6 } |
|||
} |
|||
collisionHandler(spriteType) { // $82:F1C2 |
|||
if (spriteType == VICTIM || spriteType == ZEKE || spriteType == JULIE || |
|||
(spriteType & 0x7FFF) >= SQUIRT_GUN) { |
|||
this.sprite.type = NONE |
|||
this.dead = true |
|||
} |
|||
} |
|||
{{Pseudocode footer}} |
|||
[[Category:Bug]] |
Latest revision as of 19:07, 17 August 2024
Entity data | |
---|---|
![]() | |
Entity pointer | $82:F03E |
The bat is an entity that is spawned by vampires.
Behavior[edit]
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[edit]
- 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[edit]
Entity arguments[edit]
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[edit]
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() { // $82:F03E $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 } } // $82:F07F updatePosition() { // $82:F091 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 = { // $82:F0F7 { 0, 0 }, { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 }, { -1, -1 } } updateAnimation() { // $82:F11B this.framesUntilAnimUpdate -= 1 if (this.framesUntilAnimUpdate < 0) { this.framesUntilAnimUpdate = 2 this.animationFrame += 1 this.sprite.tileData.lowBytes = animation[this.animationFrame % 2] } } animation = { 0xDDB0, 0xDDB9 } // $82:F137 init() { // $82:F13C 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 = { // $82:F19E { 0, 0 }, { 0, -6 }, { 6, -6 }, { 6, 0 }, { 6, 6 }, { 0, 6 }, { -6, 6 }, { -6, 0 }, { -6, -6 } } collisionHandler(spriteType) { // $82:F1C2 if (spriteType == VICTIM || spriteType == ZEKE || spriteType == JULIE || (spriteType & 0x7FFF) >= SQUIRT_GUN) { this.sprite.type = NONE this.dead = true } }