Clone: Difference between revisions

7,520 bytes added ,  10 days ago
no edit summary
No edit summary
No edit summary
Line 38:
{| class="wikitable"
|-
! Address !! Length !! [[Data types|Type]] !! Name !! Description
|-
| $00 || 2 || int16 || x || X position
|-
| $02 || 2 || int16 || y || Y position
|}
 
Line 49:
{| class="wikitable"
|-
! Address !! Length !! [[Data types|Type]] !! Name !! Description
|-
| $08 || 2 || pointer16 || sprite || Pointer to sprite
|-
| $0A || 2 || uint16 || framesUntilAnimUpdate || Number of frames until next animation frame
|-
| $0C || 2 || uint16 || animationFrame || Current animation frame (x2 during spawn animation)
|-
| $0E || 2 || direction || direction || Current direction
|-
| $10 || 2 || unused || || Unused
|-
| $12 || 2 || int16 || xPixels || X position in pixels (derived from $16)
|-
| $14 || 2 || int16 || yPixels || Y position in pixels (derived from $18)
|-
| $16 || 2 || int16 x4 || x || X position
|-
| $18 || 2 || int16 x4 || y || Y position
|-
| $1A || 2 || int16 || newXPixels || New X position in pixels
|-
| $1C || 2 || int16 || newYPixels || New Y position in pixels
|-
| $1E || 2 || int16 x4 || newX || New X position
|-
| $20 || 2 || int16 x4 || newY || New Y position
|-
| $22 || 2 || int16 0-based || health || Health
|-
| $24 || 2 || uint16 || mimicking || Current state (0 = targeting, 1 = mimicking)
|-
| $26 || 2 || uint16 || framesUntilStateSwitch || Number of frames until state change
|-
| $28 || 2 || pointer16 || spawnAnimation || Pointer to spawn animation
|-
| $2A || 2 || pointer16 || walkingAnimations || Pointer to walking animations table
|-
| $2C || 2 || uint16 x2 || clonedPlayer || Which player is being cloned
|-
| $2E || 2 || boolean || dead || Dead
|-
| $30 || 2 || sprite type || collidedSpriteType || Type of weapon shot sprite collided with
|- class="breakrow"
| $7E || 2 || unusedint16 0-based || ValuefreezeTimer || Number of istimes sethit butwith not[[fire usedextinguisher]]
|}
 
== Psuedocode ==
 
init() {
{{ROM name|$81:8000}}()
this.x = args.x * 4
this.y = args.y * 4
this.sprite.tileData = $90:9F0D
this.sprite.visible = true
this.framesUntilAnimUpdate = 7
this.animationFrame = 0
this.sprite.tileData.bank = 0x90
this.framesUntilStateSwitch = 1
{{ROM name|$80:CC3B}}(0x1A)
this.animationFrame = 0
while (this.animationFrame < 11) {
this.sprite.tileData.lowBytes = this.spawnAnimation[this.animationFrame]
{{ROM name|$80:8353}}(10)
this.animationFrame += 1
}
this.health = 0
this.sprite.type = MONSTER
this.sprite.alternatePalette = 6
{{ROM name|$80:8475}}(this.collisionHandler)
this.mimicking = false
this.collidedSpriteType = 0
this.animationFrame = 0
this.dead = false
this.freezeTimer = 0
}
determineClonedPlayer() {
clonedCharacter = null
player = 1
while (player >= 0) {
if (!{{RAM name|$7E:1E88}}[player]) {
clonedCharacter = {{RAM name|$7E:1E84}}[(player + 1) % 2]
break
}
player -= 1
}
if (clonedCharacter = null) {
clonedCharacter = {{ROM name|$80:9D39}}() % 2
}
this.walkingAnimations = this.walkingAnimationsPerCharacter[clonedCharacter]
this.spawnAnimation = this.spawnAnimationPerCharacter[clonedCharacter]
if ({{RAM name|$7E:1E88}}[0] && {{RAM name|$7E:1E84}}[0] == clonedCharacter) {
this.clonedPlayer = 0
} else {
this.clonedPlayer = 1
}
}
move(direction) {
this.newX = this.x + moveAmount[direction][0]
this.newXPixels = this.newX / 4
this.newY = this.y + moveAmount[direction][1]
this.newYPixels = this.newY / 4
if (!{{ROM name|$80:AE97}}(this.newXPixels, this.yPixels) &&
!{{ROM name|$80:BF67}}(this.sprite, this.newXPixels, this.yPixels)) {
this.x = this.newX
this.xPixels = this.newXPixels
}
if (!{{ROM name|$80:AE97}}(this.xPixels, this.newYPixels) &&
!{{ROM name|$80:BF67}}(this.sprite, this.xPixels, this.newYPixels)) {
this.y = this.newY
this.yPixels = this.newYPixels
}
this.sprite.x = this.xPixels
this.sprite.y = this.yPixels
if (this.direction < DOWN_LEFT) {
this.sprite.flipX = false
} else {
this.sprite.flipX = true
}
}
moveAmount = { { 0, 0 },
{ 0, -3 },
{ 3, -3 },
{ 3, 0 },
{ 3, 3 },
{ 0, 3 },
{ -3, 3 },
{ -3, 0 },
{ -3, -3 } }
updateAnimation() {
this.framesUntilAnimUpdate -= 1
if (this.framesUntilAnimUpdate == 0) {
this.framesUntilAnimUpdate = 7
this.animationFrame = (this.animationFrame + 1) % 4
this.sprite.tileData.lowBytes = this.walkingAnimations[this.direction][this.animationFrame]
}
}
target() {
this.xPixels = this.x / 4
this.yPixels = this.y / 4
this.direction = {{ROM name|$80:B2A5}}(0xF0, this.xPixels, this.yPixels)
this.move(this.direction)
}
mimick() {
this.direction = {{RAM name|$7E:0072}}[this.clonedPlayer]
this.move(this.direction)
}
mainNormal() {
if (!{{RAM name|$7E:1E88}}[0] && !{{RAM name|$7E:1E88}}[1]) {
return
}
{{RAM name|$7E:00DE}} += 0x18
this.determineClonedPlayer()
this.init()
while (true) {
{{ROM name|$80:8353}}(1)
if (this.dead) {
break
}
this.updateAnimation()
if (this.mimicking) {
this.mimick()
} else {
this.target()
if (this.direction == NONE) {
break
}
}
this.framesUntilStateSwitch -= 1
if (this.framesUntilStateSwitch == 0) {
this.mimicking = !this.mimicking
this.framesUntilStateSwitch = {{ROM name|$80:9D39}}()
}
}
if (this.collidedSpriteType != 0) {
{{ROM name|$80:C7D9}}(this.collidedSpriteType & 0x8000, 20)
{{RAM name|$7E:1F76}} += 1
{{ROM name|$81:83A3}}(this.deathAnimationNormal, 0xF5F5, 0x90)
}
{{ROM name|$80:BE41}}(this.sprite)
{{RAM name|$7E:00DE}} -= 0x18
while ({{RAM name|$7E:00DE}} < 0) { }
}
deathAnimationNormal = { { 0xA01D, 5 }, { 0xA06E, 5 }, { 0xA0A7, 5 }, { 0xA0D8, 5 },
{ 0xA0F9, 5 }, { 0xA11A, 5 } }
mainHard() {
if (!{{RAM name|$7E:1E88}}[0] && !{{RAM name|$7E:1E88}}[1]) {
return
}
{{RAM name|$7E:00DE}} += 0x18
this.determineClonedPlayer()
this.init()
while (true) {
{{ROM name|$80:8353}}(1)
if (this.health < 0) {
break
}
this.updateAnimation()
this.target()
if (this.direction == NONE) {
break
}
this.target()
if (this.direction == NONE) {
break
}
}
if (this.collidedSpriteType != 0) {
{{ROM name|$80:C7D9}}(this.collidedSpriteType & 0x8000, 20)
{{RAM name|$7E:1F76}} += 1
{{ROM name|$81:83A3}}(this.deathAnimationHard, 0xF5F5, 0x90)
}
{{ROM name|$80:BE41}}(this.sprite)
{{RAM name|$7E:00DE}} -= 0x18
while ({{RAM name|$7E:00DE}} < 0) { }
}
deathAnimationHard = { { 0xA01D, 5 }, { 0xA06E, 5 }, { 0xA0A7, 5 }, { 0xA0D8, 5 },
{ 0xA0F9, 5 }, { 0xA11A, 5 } }
walkingAnimationsPerCharacter = { walkingAnimationsZeke, walkingAnimationsJulie }
walkingAnimationsZeke = { { 0x90ED, 0x90ED, 0x90ED, 0x90ED },
{ 0x9210, 0x9229, 0x9242, 0x925B },
{ 0x9138, 0x9159, 0x9172, 0x9193 },
{ 0x9138, 0x9159, 0x9172, 0x9193 },
{ 0x9138, 0x9159, 0x9172, 0x9193 },
{ 0x91AC, 0x91C5, 0x91DE, 0x91F7 },
{ 0x9138, 0x9159, 0x9172, 0x9193 },
{ 0x9138, 0x9159, 0x9172, 0x9193 },
{ 0x9138, 0x9159, 0x9172, 0x9193 } }
walkingAnimationsJulie = { { 0x8285, 0x8285, 0x8285, 0x8285 },
{ 0x83B8, 0x83D1, 0x83EA, 0x8403 },
{ 0x82E0, 0x8301, 0x831A, 0x833B },
{ 0x82E0, 0x8301, 0x831A, 0x833B },
{ 0x82E0, 0x8301, 0x831A, 0x833B },
{ 0x8354, 0x836D, 0x8386, 0x839F },
{ 0x82E0, 0x8301, 0x831A, 0x833B },
{ 0x82E0, 0x8301, 0x831A, 0x833B },
{ 0x82E0, 0x8301, 0x831A, 0x833B } }
spawnAnimationPerCharacter = { spawnAnimationZeke, spawnAnimationJulie }
spawnAnimationZeke = { 0x9F0D, 0x9F16, 0x9F27, 0x9F48, 0x9F69, 0x9F92, 0x9FC3, 0x9FF4,
0x9627, 0x9640, 0x9659 }
spawnAnimationJulie = { 0x9F0D, 0x9F16, 0x9F27, 0x9F48, 0x9F69, 0x9F92, 0x9FC3, 0x9FF4,
0x87C7, 0x87E0, 0x87F9 }
collisionHandler(spriteType) {
if (spriteType < SQUIRT_GUN) {
return false
}
this.collidedSpriteType = spriteType
weaponType = spriteType & 0x7FFF
if (weaponType == MARTIAN_BUBBLE_GUN) {
return {{ROM name|$81:83C6}}()
} else if (weaponType == FIRE_EXTINGUISHER) {
return {{ROM name|$81:847E}}()
} else {
newHealth = this.health - {{ROM name|$81:8561}}[weaponType - SQUIRT_GUN]
if (newHealth < 0) {
this.dead = true
this.health = newHealth
this.freezeTimer = 0
return true
} else if (newHealth != this.health {
this.health = newHealth
return {{ROM name|$81:8506}}()
}
return false
}
}
 
[[Category:Respawning monster]]