AbePralle-FGB/Source/Class.asm

14438 lines
378 KiB
NASM

;1.2.2000 by Abe Pralle
;functions that compose the 'classes' of FGB.
;Each class begins a vector table of jump instructions.
;Each method call takes the following inputs:
; c - class index
; de - pointer to object
;The various methods behave as follows:
; redraw - Draws itself and its tile attributes into the shadowbuffers
; update - performs any required AI
; adjusts its own position within the map
INCLUDE "Source/Defs.inc"
INCLUDE "Source/Start.inc"
INCLUDE "Source/Items.inc"
GRENADE_CINDEX EQU 2048+ 12
WALLCREATURE_CINDEX EQU 2048+ 19
BEE_CINDEX EQU 2048+ 22
RECIPROCATOR_POWERUP_CINDEX EQU 2048+ 35
TRI_CINDEX EQU 2048+ 37
TRILING_CINDEX EQU 2048+ 39
BAT_CINDEX EQU 2048+ 45
BURROWER_CINDEX EQU 2048+ 47
BURROWER_DIRT_CINDEX EQU 2048+ 49
DANDELION_CINDEX EQU 2048+ 51
DANDELIONPUFF_CINDEX EQU 2048+ 52
SHEEP_CINDEX EQU 2048+ 96
CHICKEN_CINDEX EQU 2048+ 98
WOLF_CINDEX EQU 2048+104
NEANDERTHAL_CINDEX EQU 2048+108
BOW_CINDEX EQU 2048+146
CROUTONBULLET_CINDEX EQU 2048+154
WIZARDBULLET_CINDEX EQU 2048+158
ARROWBULLET_CINDEX EQU 2048+162
CROUTONROCKET_CINDEX EQU 2048+164
COWBOYBULLET_CINDEX EQU 2048+166
BIGSPIDER_CINDEX EQU 2048+210
LITTLESPIDER_CINDEX EQU 2048+218
TCUBE_CINDEX EQU 2048+220
TCUBE2_CINDEX EQU 2048+224
B12SOLDIERBULLET_CINDEX EQU 2048+246
TREEBULLET_CINDEX EQU 2048+253
STUNNEDWALL_CINDEX EQU 2048+256
INVISIBLEBAT_CINDEX EQU 2048+258
SLIME_CINDEX EQU 2048+260
MONKEY_CINDEX EQU 2048+267
BANANABULLET_CINDEX EQU 2048+269
DUKE_CINDEX EQU 2048+271
PIG_CINDEX EQU 2048+281
EGG_CINDEX EQU 2048+283
BLOWER_CINDEX EQU 2048+284
SLEEPINGMONKEY_CINDEX EQU 2048+286
BELL_CINDEX EQU 2048+287
RINGINGBELL_CINDEX EQU 2048+291
BANANATREE_CINDEX EQU 2048+295
HERMITINSHELL_CINDEX EQU 2048+301
CRAB_CINDEX EQU 2048+311
CRABBURROWING_CINDEX EQU 2048+313
UBERMOUSE_CINDEX EQU 2048+314
TURRET_CINDEX EQU 2048+322
TURRETBULLET_CINDEX EQU 2048+334
FAKEBA_CINDEX EQU 2048+336
FAKEBS_CINDEX EQU 2048+338
FAKEHAIKU_CINDEX EQU 2048+340
HEROLADY_CINDEX EQU 2048+350
HEROFLOUR_CINDEX EQU 2048+352
FLOUR_BULLET_CINDEX EQU 2048+406
LADY_BULLET_CINDEX EQU 2048+408
BA_MAX_HEALTH EQU 20
BS_MAX_HEALTH EQU 10
HAIKU_MAX_HEALTH EQU 20
FLOUR_MAX_HEALTH EQU 40
LADY_MAX_HEALTH EQU 40
GRENADE_MAX_HEALTH EQU 30
SECTION "ClassTableSection",ROMX
classTable:: ;starts with ptr to FIRSTOBJTILE
;BG classes
REPT 27 ;0-26
DW classGenericBG
ENDR
DW classAppomattoxBG ;27
REPT 78 ;28-105
DW classGenericBG
ENDR
DW classShiftPlusOneBG ;106 destructable pumpkin
DW classShiftPlusOneBG ;107 destructable pumpkin
DW classShiftPlusOneBG ;108 destructable pumpkin
DW classDestructableBG ;109 destructable pumpkin
DW classGenericBG ;110 blue thingy
REPT 9 ;111-119 purple destructable
DW classChangeTo120BG
ENDR
DW classShiftPlusOneBG ;120 purple destroy stage 1
DW classShiftPlusOneBG ;121 purple destroy stage 2
DW classDestructableBG ;122 purple destroy stage 3
DW classSplitterBG ;123 four-way shot splitter
REPT 133 ;124-256
DW classGenericBG
ENDR
REPT 46 ;257-302
DW classHiveBG
ENDR
REPT 588 ;303-890
DW classGenericBG
ENDR
DW classNoExplosionBG ;891 grey door
REPT 181 ;892-1072
DW classGenericBG
ENDR
DW classLandingLightsBG ;1073
REPT 328 ;1074-1401
DW classGenericBG
ENDR
DW classChangeToBigSpiderBG ;TL corner big spider weed
DW classAdjoinWestBG ;big spider weed
DW classAdjoinNorthBG ;big spider weed
DW classAdjoinNorthBG ;big spider weed
DW classChangeToLittleSpiderBG ;small spider weed
REPT 57 ;1407-1463
DW classGenericBG
ENDR
;1464-1475 destructable shrooms
REPT 12
DW classDestructableBG
ENDR
DW classNoExplosionBG ;wall tile
;1477-1493
REPT 17
DW classGenericBG
ENDR
;1494-1511 Destructable foliage
REPT 18
DW classDestructableBG
ENDR
DW classEdibleCheeseBG ;1512 edible cheese
DW classCheeseBG ;1513 cheese
DW classCheeseBG ;1514 cheese
DW classCheeseBG ;1515 cheese
DW classCheeseBG ;1516 cheese
DW classCheeseBG ;1517 cheese
DW classCheeseBG ;1518 cheese
DW classCheeseBG ;1519 cheese
DW classCheeseBG ;1520 cheese
DW classCheeseBG ;1521 cheese
DW classCheeseBG ;1522 cheese
DW classCheeseBG ;1523 cheese
DW classCheeseBG ;1524 cheese
DW classCheeseBG ;1525 cheese
DW classCheeseBG ;1526 cheese
DW classCheeseBG ;1527 cheese
DW classCheeseBG ;1528 cheese
DW classCheeseBG ;1529 cheese
DW classCheeseBG ;1530 cheese
DW classCheeseBG ;1531 cheese
DW classCheeseBG ;1532 cheese
DW classInvisibleWallBG ;1533 Invisible Wall
DW classPorkBG ;1534 Bacon
DW classPorkBG ;1535 Ham
DW classPorkBG ;1536 Sausage
DW classFriedEggBG ;1537 Fried Egg
DW classDrumstickBG ;1538 Drumstick
;1539-1571
REPT 33
DW classGenericBG
ENDR
DW classHermitCrabShellBG ;1572 Hermit Crab Shell
DW classBananaBG ;1573 Banana
;1574-1642
REPT 69
DW classGenericBG
ENDR
DW classGeneratorBG ;1643
DW classGeneratorBG
DW classGeneratorBG
DW classGeneratorBG
DW classGeneratorBG
DW classGeneratorBG
DW classGeneratorBG
DW classGeneratorBG
DW classGeneratorBG ;1651
DW classSlugTrailBG ;1652 slug trail
;1653-1854
REPT 202
DW classGenericBG
ENDR
;1855-1874
DW classDestructableBG
DW classDestructableBG
DW classDestructableBG
DW classDestructableBG
DW classDestructableAdjoinRightBG
DW classDestructableAdjoinLeftBG
DW classDestructableAdjoinRightBG
DW classDestructableAdjoinLeftBG
DW classDestructableAdjoinRightBG
DW classDestructableAdjoinLeftBG
DW classDestructableAdjoinRightBG
DW classDestructableAdjoinLeftBG
DW classDestructableAdjoinBottomBG
DW classDestructableAdjoinTopBG
DW classDestructableAdjoinBottomBG
DW classDestructableAdjoinTopBG
DW classDestructableAdjoinBottomBG
DW classDestructableAdjoinTopBG
DW classDestructableAdjoinBottomBG
DW classDestructableAdjoinTopBG
;1875-2042
REPT 168
DW classGenericBG
ENDR
DW classClearanceBG
;2044-2047
REPT 4
DW classGenericBG
ENDR
;FG classes
;pansies o+0, +2, +4
REPT 3
DW classPansy,0
ENDR
DW classBAPlayer,0 ;BA +6
DW classBSPlayer,0 ;BS +8
DW classHaikuPlayer, 0 ;+10 Haiku
DW classGrenade, 0 ;+12 Grenade
DW classGeneric ;+14 old Stunned Wall Creature (unused)
DW classVacuum, 0 ;+15 vacuum
DW classSlug, 0 ;+17 Slug
DW classWallCreature, 0 ;+19 Wall Creature
DW classSmallBeeHive ;+21 small bee hive
DW classBee, 0 ;+22 bee
DW classGeneric ;+24 yinyang
DW classGeneric, 0 ;+25 yin
DW classGeneric, 0 ;+27 yang
DW classScaredie, 0 ;+29 scaredie
DW classChomper, 0 ;+31 big mouth (chomper)
DW classReciprocator, 0 ;+33 purple energy dude lo power
DW classReciprocatorPowerup,0 ;+35 purple dude hi power
DW classTri, 0 ;+37 yellow thing
DW classTriling, 0 ;+39 small yellow thing
DW classTree ;+41 tree
DW classBush ;+42 bush
DW classNeedle,0 ;+43 needle thing
DW classBat, 0 ;+45 bat
DW classBurrower,0 ;+47 burrower
DW classBurrowerDirt,0 ;+49 burrower dirt mound
DW classDandelion ;+51 dandelion
DW classDandelionPuff,0 ;+52 dandelion puff
DW classGeneric,0,0,0,0,0,0,0 ;+54 King Grenade
DW classMouse, 0 ;+62 mouse
DW classPenguin, 0 ;+64 penguin
DW classBIOS,0 ;+66 BIOS soldier
DW classGeneric,0,0,0 ;+68 king snake
DW classCroutonHulk,0,0,0,0,0,0,0 ;+72 crouton hulk
DW classCroutonGrunt, 0 ;+80 crouton grunt
;BA Bullet +82
DW classBABullet, 0
;Pansy Bullet +84
DW classPansyBullet, 0
;Big Long Laser +86
DW classBigLongLaser, 0
DW classLadyFlower, 0 ;Lady Flower +88
;DW classBSPlayer,0 ;BS +8
DW classCaptainFlour, 0 ;Captain Flour +90
DW classBigBeeHive, 0, 0, 0 ;+92 big bee hive
DW classSheep, 0 ;+96 sheep
DW classChicken, 0 ;+98 chicken
DW classPurpleWisp, 0 ;+100 wisp
DW classQuatrain,0 ;+102 quatrain
DW classWolf, 0 ;+104 ice wolf
DW classSnake, 0 ;+106 snake
DW classNeanderthal, 0 ;+108 neanderthal
DW classGeneric,0,0,0,0,0,0,0 ;+110 genie
DW classCrow,0 ;+118 crow
DW classScarecrow,0,0,0,0,0,0,0 ;+120 scarecrow
DW classTalker, 0 ;+128 hermit
DW classTalker, 0 ;+130 grey hermit
DW classGeneric, 0 ;+132 red villager
DW classGeneric, 0 ;+134 blue villager
DW classAlligator,0,0,0,0,0,0,0 ;+136 alligator
DW classScorpion, 0 ;+144 scorpion
DW classBow,0 ;+146 archer
DW classCowboy, 0 ;+148 blue villager
DW classCowboy, 0 ;+150 brown villager
DW classCroutonDoctor, 0 ;+152 doctor crouton / guard
DW classCroutonBullet, 0 ;+154 crouton bullet
DW classCroutonWizard, 0 ;+156 wizard crouton
DW classWizardBullet, 0 ;+158 spiral wizard bullet
DW classGeneric, 0 ;+160 mud?
DW classArrowBullet, 0 ;+162 arrow bullet
DW classRocketBullet, 0 ;+164 rocket bullet
DW classCowboyBullet, 0 ;+166 yellow bolt bullet
DW classGeneric, 0 ;+168 purple sparkley bullet
DW classBSBullet, 0 ;+170 bs bullet
DW classCroutonGoblin, 0 ;+172 goblin crouton
DW classGeneralGyro,0,0,0,0,0,0,0 ;+174 General Gyro
DW classCroutonArtillery,0,0,0,0,0,0,0 ;+182 artillery tank crouton
DW classGeneric,0,0,0,0,0,0,0 ;+190 stabbing tank crouton
DW classMajorSkippy,0,0,0,0,0,0,0 ;+198 Major Skippy
DW classBAPlayer,0 ;+206 RA
DW classBSPlayer,0 ;+208 CS
DW classBigSpider,0,0,0,0,0,0,0 ;+210 Big Spider
DW classLittleSpider,0 ;+218 Little Spider
DW classTeleportCube,0,0,0 ;+220 Teleport Field
DW classTeleportCube2,0,0,0 ;+224 Teleport Field
DW classDandelionGuard,0 ;+228 Dandelion guard
DW classB12Soldier,0 ;+230 Purple Soldier
DW classB12Soldier,0 ;+232 Grey Soldier
DW classB12Soldier,0 ;+234 Yellow Soldier
DW classGeneric,0 ;+236 Orange Specialist
DW classGeneric,0 ;+238 Grey Specialist
DW classGeneric,0 ;+240 Green Specialist
DW classActor,0 ;+242 Red Ninja (Iambic)
DW classHaikuPlayer,0 ;+244 Purple Ninja (Free Verse)
DW classB12SoldierBullet,0 ;+246 B12 Soldier Bullet
DW classGeneric ;+248 bomb thing
DW classGeneric,0,0,0 ;+249 BRAINIAC
DW classTreeBullet,0 ;+253 Tree and bush bullet
DW 0 ;+255 pad
DW classStunnedWall,0 ;+256 Stunned wall creature
DW classInvisibleBat,0 ;+258 Invisible Bat
DW classSlime,0 ;+260 Small slime
DW classYellowWisp,0 ;+262 Yellow wisp
DW classGeneric ;+264 Immobile armor
DW classGeneric,0 ;+265 Suit of armor
DW classMonkey,0 ;+267 Brown Monkey
DW classBananaBullet,0 ;+269 Bananna bullet
DW classDuke,0,0,0,0,0,0,0 ;+271 Duke the one-armed orangutan
DW classGeneric,0 ;+279 leprechaun
DW classPig,0 ;+281 pig
DW classEgg ;+283 egg
DW classBlower,0 ;+284 Crouton Blower
DW classSleepingMonkey ;+286 Sleeping Monkey
DW classBell,0,0,0 ;+287 Bell
DW classRingingBell,0,0,0 ;+291 Ringing Bell
DW classBananaTree,0,0,0 ;+295 Banana Tree
DW classHermitNoShell,0 ;+299 Hermit Crab, no shell
DW classHermitInShell,0 ;+301 Hermit Crab inside shell
DW classSwampThang,0,0,0,0,0,0,0 ;+303 Swamp Thang
DW classCrab,0 ;+311 Red Crab
DW classCrabBurrowing ;+313 Red Crab Burrowing
DW classUberMouse,0,0,0,0,0,0,0 ;+314 Uber Mouse
DW classTurret,0,0,0 ;+322 Turret
DW classCroutonKing,0,0,0,0,0,0,0 ;+326 Turret Bullet
DW classTurretBullet,0 ;+334 Turret Bullet
DW classActor,0 ;+336 Fake BA
DW classActor,0 ;+338 Fake BS
DW classActor,0 ;+340 Fake Haiku
DW classGrenadePlayer,0,0,0,0,0,0,0 ;+342 Fake King Grenade
DW classHeroLady,0 ;+350 Hero Lady Flower
DW classHeroFlour,0 ;+352 Hero Captain Flour
DW classGeneric,0 ;+354 Disco Dancer
DW classActor,0,0,0 ;+356 Lying Head single 2x2 frame
DW classActor2x2,0,0,0,0,0,0,0 ;+360 Thaddius Pencilbody
DW classActor,0 ;+368 Blue Skull
DW classActor2x2,0,0,0,0,0,0,0 ;+370 Santa
DW classActor2x2,0,0,0,0,0,0,0 ;+378 Queen Bee
DW classActor2x2,0,0,0,0,0,0,0 ;+386 Rocking Horse
DW classActor,0 ;+394 Candy Cane
DW classActor,0 ;+396 Doll
DW classActor2x2,0,0,0,0,0,0,0 ;+398 Reindeer
DW classFlourBullet,0 ;+406 Captain Flour Bullet
DW classLadyBullet,0 ;+408 Hero Lady Flower Bullet
;DW classLadyBullet,0 ;+410 Hero Lady Flower Bullet
;DW classLadyBullet,0 ;+412 Hero Lady Flower Bullet
;DW classLadyBullet,0 ;+414 Hero Lady Flower Bullet
classDoNothing::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW DoNothingCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classDoNothing2::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW DoNothingCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classDoNothing3::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW DoNothingCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classHeroIdle::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW IdleCantDieCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classGeneric::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW GenericCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classTalker::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW TalkerCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classActor::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ActorCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classActor2::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ActorCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classGuard::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW GuardCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classActorSpeed1::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ActorSpeed1Check ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classActor2x2::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ActorCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classPansy::
DW PansyInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW PansyCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classHippiePansy::
DW PansyInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW HippiePansyCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classPansyBullet::
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW StdBulletCheck ;vector for check method
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBAPlayer::
DW BAInit
DW StandardRedraw
DW BAPlayerCheck
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBAPlayerSpace::
DW BAInit
DW StandardRedraw
DW BAPlayerCheckSpace
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBSPlayer::
DW BSInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BSPlayerCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBSPlayerSpace::
DW BSInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BSPlayerCheckSpace ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classHaikuPlayer::
DW HaikuInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW HaikuPlayerCheck ;vector for check method
DW HaikuTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classHaikuPlayerSpace::
DW HaikuInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW HaikuPlayerCheckSpace ;vector for check method
DW HaikuTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classHeroLady::
DW LadyInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW LadyPlayerCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classHeroFlour::
DW FlourInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW FlourPlayerCheck ;vector for check method
;DW HaikuTakeDamage ;vector for take damage method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classFlourBullet::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW FlourBulletCheck ;vector for check method
DW HaikuTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classLadyBullet::
DW LadyBulletInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW LadyBulletCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classGrenadePlayer::
DW GrenadePlayerInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW GrenadePlayerCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classBSActor::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ActorCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBee:
DW BeeInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BeeCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classStunnedWall::
DW StunnedWallInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW StunnedWallCheck ;vector for check method
DW WallTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classGrenade:
DW GrenadeInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW GrenadeCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classVacuum:
DW VacuumInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW VacuumCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classSlug:
DW SlugInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW SlugCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classWallCreature::
DW WallCreatureInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW WallCreatureCheck ;vector for check method
DW WallTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classWallTalker::
DW WallCreatureInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW TalkerCheck ;vector for check method
DW WallTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classSmallBeeHive:
DW SmallBeeHiveInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW SmallBeeHiveCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classScaredie:
DW ScardieInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ScardieCheck ;vector for check method
DW ScardieTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classChomper::
DW ChomperInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ChomperCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classReciprocator:
DW ReciprocatorInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ReciprocatorCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classReciprocatorPowerup:
DW ReciprocatorInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ReciprocatorPowerupCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classTri:
DW TriInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW TriCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classTriling:
DW TrilingInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW TrilingCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classTree::
DW TreeInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW TreeCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classTreeTalker::
DW TreeInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW TreeTalkerCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBush:
DW BushInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BushCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classNeedle:
DW NeedleInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW NeedleCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBat:
DW BatInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BatCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBurrower:
DW BurrowerInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BurrowerCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBurrowerDirt:
DW BurrowerDirtInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BurrowerDirtCheck ;vector for check method
DW TakeZeroDamage ;vector for take damage method
DW StandardDie ;vector for die method
classDandelion::
DW DandelionInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW DandelionCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classDandelionPuff:
DW DandelionPuffInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW DandelionPuffCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBABullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW BASuperFastBulletCheck
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBigLongLaser::
DW StdBulletInit ;vector for init method
DW StreamRedraw ;vector for redraw method
DW StreamCheck ;vector for check method
DW DoNothing ;vector for take damage method
DW StreamDie ;vector for die method
classExplosion::
DW ExplosionInit ;vector for init method
DW ExplosionRedraw ;vector for redraw method
DW ExplosionCheck ;vector for check method
DW ExplosionCheck ;vector for take damage method
DW ExplosionDie ;vector for die method
classLadyFlower::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ActorCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCaptainFlour::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ActorCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classMouse::
DW MouseInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW MouseCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classPenguin::
DW PenguinInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW PenguinCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBIOS::
DW BIOSInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BIOSCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCroutonHulk::
DW CroutonHulkInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW CroutonHulkCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classCroutonGrunt::
DW CroutonGruntInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW CroutonGruntCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBigBeeHive:
DW BigBeeHiveInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BigBeeHiveCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classSheep:
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW SheepCheck ;vector for check method
DW CowboyTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classChicken::
DW ChickenInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ChickenCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classPurpleWisp::
DW WispInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW WispCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classQuatrain::
DW QuatrainInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW QuatrainCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classWolf::
DW WolfInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW WolfCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classSnake::
DW SnakeInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW SnakeCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classNeanderthal::
DW NeanderthalInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW NeanderthalCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCrow::
DW CrowInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW CrowCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classScarecrow::
DW ScarecrowInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ScarecrowCheck ;vector for check method
DW ScarecrowTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classAlligator:
DW AlligatorInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW AlligatorCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classWolfSheep::
DW WolfSheepInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW WolfSheepCheck ;vector for check method
DW WolfSheepTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classScorpion:
DW ScorpionInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ScorpionCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBow:
DW BowInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BowCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCowboy::
DW CowboyInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW CowboyCheck ;vector for check method
DW CowboyTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classAngryCowboy::
DW CowboyInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW AngryCowboyCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCowboyTalker::
DW CowboyInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW TalkerCheck ;vector for check method
DW CowboyTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCroutonDoctor::
DW CroutonDoctorInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW CroutonDoctorCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCroutonBullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW StdBulletCheck ;vector for check method
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCroutonWizard::
DW CroutonWizardInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW CroutonWizardCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classWizardBullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW WizardBulletCheck ;vector for check method
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBSBullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
IF UPGRADES
DW HeroSuperFastBulletCheck
ELSE
;DW HeroBulletCheck ;vector for check method
DW HeroSuperFastBulletCheck
ENDC
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classArrowBullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW StdBulletCheck ;vector for check method
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classRocketBullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW ExplodingBulletCheck ;vector for check method
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCowboyBullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW SuperFastBulletCheck ;vector for check method
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCroutonGoblin::
DW CroutonGoblinInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW CroutonGoblinCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classGeneralGyro::
DW GeneralGyroInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ActorCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classCroutonArtillery::
DW CroutonArtilleryInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW CroutonArtilleryCheck;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classMajorSkippy::
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW ActorCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classTeleportCube::
DW TeleportCubeInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW TeleportCubeCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classTeleportCube2::
DW TeleportCubeInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW TeleportCubeCheck2 ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classDandelionGuard::
DW DandelionGuardInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW DandelionGuardCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classB12Soldier::
DW B12SoldierInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW B12SoldierCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classB12SoldierBullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW StdBulletCheck ;vector for check method
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBigSpider:
DW BigSpiderInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BigSpiderCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classLittleSpider:
DW LittleSpiderInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW LittleSpiderCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classTreeBullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW SuperFastBulletCheck
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBushBullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW StdBulletCheck
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classInvisibleBat:
DW BatInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW InvisibleBatCheck ;vector for check method
DW InvisibleBatTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classSlime::
DW SlimeInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW SlimeCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classYellowWisp::
DW WispInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW WispCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classMonkey::
DW MonkeyInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW MonkeyCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBananaBullet:
DW YellowBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW SuperFastBulletCheck
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classDuke:
DW DukeInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW DukeCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classPig:
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW PigCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classEgg::
DW EggInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW EggCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBlower:
DW BlowerInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BlowerCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classSleepingMonkey:
DW SleepingMonkeyInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW SleepingMonkeyCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classBell:
DW BellInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW DoNothingCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classRingingBell:
DW BellInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW DoNothingCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classBananaTree:
DW BananaTreeInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW BananaTreeCheck ;vector for check method
DW BananaTreeTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classHermitNoShell:
DW HermitNoShellInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW HermitNoShellCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classHermitInShell:
DW HermitNoShellInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW HermitInShellCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classSwampThang:
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW GenericCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classCrab:
DW CrabInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW CrabCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classCrabBurrowing:
DW CrabBurrowingInit ;vector for init method
DW DoNothing ;vector for redraw method
DW CrabBurrowingCheck ;vector for check method
DW StdTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
classUberMouse:
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW UberMouseCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classTurret::
DW TurretInit ;vector for init method
DW StandardRedraw ;vector for redraw method
DW TurretCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classCroutonKing:
DW InitTwoHealth ;vector for init method
DW StandardRedraw ;vector for redraw method
DW GenericCheck ;vector for check method
DW StdTakeDamage2x2 ;vector for take damage method
DW StandardDie ;vector for die method
classTurretBullet:
DW StdBulletInit ;vector for init method
DW StdBulletRedraw ;vector for redraw method
DW SuperSuperFastBulletCheck
DW BulletTakeDamage ;vector for take damage method
DW StandardDie ;vector for die method
SECTION "ClassesSection",ROMX,BANK[CLASSROM]
;---------------------------------------------------------------------
;bg methods
;are passed parameters:
; a - method type (BGACTION_HIT,BGACTION_MOVEOVER)
; c - tile index (eg class index 24, not class 1045)
; hl - map location
;---------------------------------------------------------------------
classGenericBG:
ret
classAppomattoxBG::
ret
classLandingLightsBG::
ret
classInvisibleWallBG::
ret
classChangeTo120BG:
cp BGACTION_HIT
ret nz
ld bc,classShiftPlusOneBG
call FindClassIndex
push af
ld a,MAPBANK
ldio [$ff70],a
pop af
ld [hl],a
ret
classShiftPlusOneBG:
cp BGACTION_HIT
ret nz
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
inc a
ld [hl],a
ret
classGeneratorBG:
classDestructableBG:
cp BGACTION_HIT
ret nz
;remove myself from the map
ld a,MAPBANK
ldio [$ff70],a
ld [hl],0
ld hl,levelVars+15
inc [hl]
ret
classDestructableAdjoinRightBG:
cp BGACTION_HIT
ret nz
;remove myself & neighbor from the map
ld a,MAPBANK
ldio [$ff70],a
xor a
ld [hl+],a
ld [hl],a
inc a
ld hl,levelVars+15
inc [hl]
ret
classDestructableAdjoinLeftBG:
cp BGACTION_HIT
ret nz
;remove myself & neighbor from the map
ld a,MAPBANK
ldio [$ff70],a
xor a
ld [hl-],a
ld [hl],a
inc a
ld hl,levelVars+15
inc [hl]
ret
classDestructableAdjoinBottomBG:
cp BGACTION_HIT
ret nz
;remove myself & neighbor from the map
ld a,MAPBANK
ldio [$ff70],a
ld [hl],0
ld a,[mapPitch]
add l
ld l,a
ld a,h
adc 0
ld h,a
ld [hl],0
ld hl,levelVars+15
inc [hl]
ret
classDestructableAdjoinTopBG:
cp BGACTION_HIT
ret nz
;remove myself & upper neighbor from the map
ld a,MAPBANK
ldio [$ff70],a
ld [hl],0
ld a,[mapOffsetNorth]
add l
ld l,a
ld a,[mapOffsetNorth+1]
adc h
ld h,a
ld [hl],0
ld hl,levelVars+15
inc [hl]
ret
classSplitterBG:
cp BGACTION_HIT
jr nz,.done
;get class of bullet
ld a,[bulletClassIndex]
ld c,a
call GetFGAttributes
and FLAG_ISBULLET
ret z
ld a,[bulletDirection]
ld b,a
ld [fireBulletDirection],a
;create a bullet continuing in the same direction
call CreateBulletOfClass
;and 90 CW
ld a,b
inc a
and %11
ld [fireBulletDirection],a
call CreateBulletOfClass
;and 90 CCW
ld a,b
dec a
and %11
ld [fireBulletDirection],a
call CreateBulletOfClass
.done
xor a ;no explosion
ret
classNoExplosionBG:
xor a
ret
classChangeToBigSpiderBG:
cp BGACTION_HIT
ret nz
;I'm corner of 2x2 tile; remove tile
ld a,MAPBANK
ldio [$ff70],a
xor a
ld [hl+],a
ld [hl-],a
push hl
ld a,[mapPitch]
add l
ld l,a
ld a,h
adc 0
ld h,a
ld [hl+],a
ld [hl-],a
pop hl
;create a big spider here
ld bc,classBigSpider
call FindClassIndex
ret z
ld c,a
jp CreateInitAndDrawObject
classAdjoinWestBG:
cp BGACTION_HIT
ret nz
;pass the buck to the west
ld a,MAPBANK
ldio [$ff70],a
dec hl
ld c,[hl]
ld a,BGACTION_HIT
jp CallBGAction
classAdjoinNorthBG:
cp BGACTION_HIT
ret nz
;pass the buck to the north
ld a,MAPBANK
ldio [$ff70],a
ld a,[mapOffsetNorth]
ld e,a
ld d,$ff
add hl,de
ld c,[hl]
ld a,BGACTION_HIT
jp CallBGAction
classChangeToLittleSpiderBG:
cp BGACTION_HIT
ret nz
;create a little spider right here
ld a,MAPBANK
ldio [$ff70],a
xor a
ld [hl],a
ld bc,classLittleSpider
call FindClassIndex
ret z
ld c,a
jp CreateInitAndDrawObject
classHiveBG:
call FindEmptyLocationAround1x1Loc
or a
ret z
;create an adjacent bee when the wall is shot
ld bc,classBee
call FindClassIndex
ret z
ld c,a
jp CreateInitAndDrawObject
classCheeseBG:
call FindEmptyLocationAround1x1Loc
or a
ret z
ld bc,classEdibleCheeseBG
call FindClassIndex
push af
ld a,MAPBANK
ldio [$ff70],a
pop af
ld [hl],a
jp ResetMyBGSpecialFlags
classHermitCrabShellBG:
ret
classEdibleCheeseBG:
jr HealthPlusOneBG
classPorkBG:
jr HealthPlusOneBG
classFriedEggBG:
jr HealthPlusOneBG
classDrumstickBG:
jr HealthPlusOneBG
classBananaBG:
jr HealthPlusOneBG
HealthPlusOneBG:
cp BGACTION_MOVEOVER
ret nz
ldio a,[firstMonster]
ld b,a
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
call EnsureTileIsHead
cp b
ret c ;not a monster
ld c,a
call GetFGAttributes
and FLAG_ISBULLET
ret nz ;want monster not bullet
;clear out tile shadow bank at this loc
;(egg->nothing under creature)
call ClearBGUnderSprite
call GetObjectOnBG
;ld a,MAPBANK
;ldio [$ff70],a
;ld a,[hl]
;call EnsureTileIsHead
;ld d,h
;ld e,l
;call FindObject ;get that monster
call GetHealth ;increase its health
cp 63
ret nc
inc a
call SetHealth
ld a,BANK(eat_gbw)
ld hl,eat_gbw
jp PlaySample
classSlugTrailBG:
cp BGACTION_MOVEOVER
ret nz
push hl
call GetObjectOnBG
pop hl
call GetFGAttributes
and FLAG_ISBULLET
ret nz
call ClearBGUnderSprite
ld a,30
jp SetMoveDelay
GetObjectOnBG:
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
call EnsureTileIsHead
ld c,a
ld d,h
ld e,l
jp FindObject ;get that monster
ClearBGUnderSprite:
ld a,TILESHADOWBANK
ldio [$ff70],a
xor a
ld [hl],a
ret
classClearanceBG:
cp BGACTION_MOVEOVER
ret nz
push hl
call GetObjectOnBG
pop hl
call IsHero
ret z
call ClearBGUnderSprite
;add appropriate code to inventory
ld hl,mapToCodeIndexTable
ld a,[curLevelStateIndex]
call LookupIndexOfData8
ld hl,codeIndexToItemTable
call Lookup16
push hl
pop bc
call AddInventoryItem
;increase clearance level
ld bc,ITEM_ALPHACLEAR
call HasInventoryItem
jr nz,.foundCurLevel
ld bc,ITEM_BETACLEAR
call HasInventoryItem
jr nz,.foundCurLevel
ld bc,ITEM_GAMMACLEAR
call HasInventoryItem
jr nz,.foundCurLevel
ld bc,ITEM_DELTACLEAR
call HasInventoryItem
jr nz,.foundCurLevel
ld bc,ITEM_EPSILONCLEAR
call HasInventoryItem
jr nz,.foundCurLevel
ld bc,ITEM_ZETACLEAR
call HasInventoryItem
ret nz ;don't go higher than zeta
;start with alpha clearance
ld bc,ITEM_ALPHACLEAR
call AddInventoryItem
ret
.foundCurLevel
call RemoveInventoryItem
rlc c
call AddInventoryItem
ret
IsHero:
ld a,[hero0_index]
cp c
jr z,.returnTrue
ld a,[hero1_index]
cp c
jr z,.returnTrue
.returnFalse
xor a
ret
.returnTrue
ld a,1
or a
ret
mapToCodeIndexTable:
DB $04,$09,$2a,$6a,$a4,$73
codeIndexToItemTable:
DW ITEM_CODE0400,ITEM_CODE0900,ITEM_CODE1002,ITEM_CODE1006
DW ITEM_CODE0410,ITEM_CODE0307
; Arguments: bc - item corresponding to clearance
RemoveClearanceIfTaken::
call HasInventoryItem
ret z ;not taken yet
ld hl,classClearanceBG
call FindFirstBGLoc
ret z
xor a
ld [hl],a
ret
;---------------------------------------------------------------------
;obj methods
;---------------------------------------------------------------------
SuperInit::
push hl
ld a,OBJBANK
ldio [$ff70],a
ld hl,OBJ_FRAME
add hl,de
xor a
ld [hl+],a ;frame
ld a,1
ld [hl+],a ;move countdown
xor a
ld [hl+],a ;limit
ld [hl+],a ;health
ld [hl+],a ;
ld [hl+],a ;
ld [hl+],a ;state
ld [hl+],a ;group
ld [hl+],a ;destl
ld [hl+],a ;desth
ld a,$ff
ld [hl+],a ;spritelo
xor a
ld [hl+],a ;13
ld [hl+],a ;14
;leave NEXTL alone
pop hl
ret
SuperDie::
push hl
xor a
call SetHealth
jr SuperDieFreeSprite
FreeSpriteLoPtr:
push hl
SuperDieFreeSprite:
call GetSpriteLo
call FreeSprite
ld a,$ff
call SetSpriteLo
pop hl
ret
InitTwoHealth:
ld hl,.initTwoHealthTable
jp StdInitFromTable
.initTwoHealthTable
DB 4 ;initial facing
DB 2 ;health (max)
DB GROUP_MONSTERN ;group friends with everyone
DB 0 ;has bullet
DoNothing:
ret
StandardRedraw:
push bc
push de
push hl
call GetFacing
bit 7,a
jr z,StandardRedrawAfterPush ;not a sprite
push bc
ld c,a
call RemoveFromMap
pop bc
jr StandardRedrawAfterPush
StandardRedrawNoCheckSprite:
StandardChooseColor:
push bc
push de
push hl
StandardRedrawAfterPush:
;white if dandelion puffs on me
call GetPuffCount
or a
jr z,.noPuffs
ld b,0
jr StandardDraw
.noPuffs
call GetFGAttributes
and %111
ld b,a
;falling through from above
StandardDraw:
;bc, de, hl already pushed in chooseColor
ld a,c
ld [curObjIndex],a
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
;save map location for later use
ld a,[de]
inc de
ld [methodParamL],a
ld a,[de]
inc de
ld [methodParamH],a
;get frame (facing + animation)
;check isSprite flag
ld a,[de]
bit 7,a
jr z,.drawTileBased
jp .drawSpriteBased
.drawTileBased
and %111 ;mask off facing stuff
push af ;save frame for later
ld d,0
ld e,a ;done with original de
;get attributes of tile
ld hl,.attributeLookup
ld a,[fgFlags]
bit BIT_NOROTATE,a
jr z,.afterLoadAttributeLookup
ld hl,.attributeLookup+8
.afterLoadAttributeLookup
add hl,de ;hl is &attributeLookup[frame]
ld a,[hl] ;flip attributes for this frame
or b ;combined
ld b,a ;B is full attributes
ld a,TILEINDEXBANK ;select RAM bank of tile index maps
ldio [$ff70],a
;add 16+(is2x2*16) to attributeLookup to get tile offset Lookup
ld e,16
ldio a,[curObjWidthHeight]
cp 2
jr nz,.eHasCorrectValue
ld e,32
.eHasCorrectValue
add hl,de ;[hl] is tile offset
ld e,c ;index of tile is low byte
ld d,((fgTileMap>>8) & $ff) ;de pts to base tile
ld a,[de] ;get base tile
pop de ;frame in d
ld e,c ;save class index in e
cp $ff
jr z,.afterAddOffset
add [hl] ;add offset
.afterAddOffset
ld c,a ;c is tile to draw
;retrieve ptr to map location of this object
ld a,[methodParamL] ;hl = ptr to draw dest
ld l,a
ld a,[methodParamH]
ld h,a
ldio a,[curObjWidthHeight]
cp 2
jr nz,.draw1x1tileBased
jp Draw2x2tileBased
.draw1x1tileBased
;use frame to determine how many tiles to spread this across
;and in what direction
bit 2,d ;d is frame
jr z,.drawSingleTile
bit 0,d
jr z,.drawNorthToSouthSplit
.drawEastToWestSplit
ld a,MAPBANK ;select map RAM
ldio [$ff70],a
ld a,e
ld [hl+],a ;draw class index
ld a,CLASS_ADJOIN_W
ld [hl-],a ;in next tile too
ld a,TILESHADOWBANK ;select tile shadow RAM
ldio [$ff70],a
ld a,c
ld [hl+],a ;draw tile to tile shadow RAM
;tile plus one or minus one for frame modifier
bit 1,d
jr z,.EWIncrement
dec a
jr .EWDone
.EWIncrement
inc a
.EWDone
ld [hl-],a ;and again
ld a,ATTRSHADOWBANK ;select attribute shadow RAM
ldio [$ff70],a
ld a,b
ld [hl+],a ;draw attribute to attribute shadow RAM
ld [hl-],a ;and again
jr .done
.drawNorthToSouthSplit
call .drawAtHL
push de
ld d,0
ld a,[mapPitch]
ld e,a
add hl,de
pop de
ld e,CLASS_ADJOIN_N
;tile plus one or minus one for frame modifier
bit 1,d
jr z,.NSIncrement
;handle NOROTATE
ld a,[fgFlags]
bit BIT_NOROTATE,a
jr nz,.NSIncrement
dec c
jr .NSDone
.NSIncrement
inc c
.NSDone
call .drawAtHL
jr .done
.drawSingleTile
call .drawAtHL
jr .done
.drawAtHL
ld a,MAPBANK ;select map RAM
ldio [$ff70],a
ld [hl],e ;draw class index
.drawShadowAtHL
ld a,TILESHADOWBANK ;select tile shadow RAM
ldio [$ff70],a
ld [hl],c ;draw tile to tile shadow RAM
ld a,ATTRSHADOWBANK ;select attribute shadow RAM
ldio [$ff70],a
ld [hl],b ;draw attribute to attribute shadow RAM
ret
.done pop hl
pop de
pop bc
ret
.drawSpriteBased
push bc
push af ;save frame
dec de
dec de
call GetCurLocation
;copy map underneath current to tile & attribute shadow buffers
call .copyMapToShadowBuffers
pop af ;get frame back
bit 2,a ;split?
jr z,.updateSprite ;done copying tile stuff
bit 0,a ;n/s or e/w?
jr z,.spriteNS
;e/w split
inc hl
call .copyMapToShadowBuffers
jr .updateSprite
.spriteNS
;n/s split
push de ;retrieve vertical offset
ld d,0
ld a,[mapPitch]
ld e,a
add hl,de
pop de
call .copyMapToShadowBuffers
.updateSprite
pop bc
push bc
ld a,[curObjIndex]
ld c,a
;draw the object's id to the map buffer
call GetFacing
ld b,a
call GetCurLocation
ld a,MAPBANK
ldio [$ff70],a
ld [hl],c ;head of obj
ld a,b
and %00000101
cp %00000101 ;E/W split
jr nz,.checkNS_Split
inc hl
ld [hl],CLASS_ADJOIN_W
jr .doneDrawID
.checkNS_Split
ld a,b
and %00000100
jr z,.doneDrawID
;N/S split
ld a,[mapOffsetSouth]
add l
ld l,a
ld a,[mapOffsetSouth+1]
adc h
ld h,a
ld [hl],CLASS_ADJOIN_N
.doneDrawID
pop bc
call GetCurLocation
ld a,TILESHADOWBANK
ldio [$ff70],a
ld a,[hl]
or a
jr z,.afterCallMoveOverBG
push bc
ld c,a
ld a,BGACTION_MOVEOVER
call CallBGAction
pop bc
.afterCallMoveOverBG
;attempt to allocate sprite if we don't have one
call GetSpriteLo
cp $ff
jr nz,.haveSprite
;see if the sprite will show up onscreen
call GetCurLocation
call ConvertLocHLToSpriteCoords
;ld a,l
;or a
;jr z,.spdone ;won't show up anyways
call AllocateSprite
cp $ff
jr z,.spdone ;no sprite for you
call SetSpriteLo
.coordsOkay
;initialize the sprite's position
push af
push de
ld e,a
ld d,((spriteOAMBuffer>>8) & $ff)
ld a,l
ld [de],a
inc de
ld a,h
ld [de],a
pop de
pop af
;if split bit is set scoot in one direction or another
push bc
push af
call GetFacing
bit 2,a
jr z,.afterScoot
bit 0,a ;N/S or E/W?
jr nz,.scootEW
;scoot down for N/S split
ld b,%00000010
jr .doSplit
.scootEW ;scoot right for E/W split
ld b,%00000001
.doSplit
pop af
push af
call ScootSprite
.afterScoot
pop af
pop bc
.haveSprite ;set up the sprite to reflect the current facing
push bc
call GetSpritePtrInHL
inc hl
inc hl
call GetFGTileMapping
ld c,a
call GetFacing
bit 0,a
jr nz,.facingEastWest
;facing north/south
inc c
inc c
bit 1,a
jr z,.checkAnim ;facing north no flip
;facing south
set 6,b ;flip tile vertically
jr .checkAnim
.facingEastWest
bit 1,a ;facing east or west?
jr z,.checkAnim ;facing east, no flip
set 5,b ;facing west, flip horizontally
.checkAnim
bit 2,a ;check split bit
jr z,.baseAnimOkay
inc c
.baseAnimOkay
ld a,c ;tile number
ld [hl+],a
ld a,b
or %00001000 ;attributes
ld [hl],a
pop bc
;clear vflip bit if NOROTATE flag set
call GetFGAttributes
and FLAG_NOROTATE
jr z,.spdone
res 6,[hl]
.spdone pop hl
pop de
pop bc
ret
.copyMapToShadowBuffers
;assumes hl points to location
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl] ;get map tile
;get bg attributes of this map tile
ld c,a
ld b,((bgAttributes>>8) & $ff)
ld a,TILEINDEXBANK
ldio [$ff70],a
ld a,[bc]
;clear off all but the palette
and %00000111
ld b,a
call .drawShadowAtHL
ret
.attributeLookup
DB %00001000,%00001000,%01001000,%00101000 ;1x1 normal
DB %00001000,%00001000,%01001000,%00101000
DB %00001000,%00001000,%00001000,%00101000 ;no rotate
DB %00001000,%00001000,%00001000,%00101000
.tileOffsetLookup
DB 0, 3, 0, 3, 1, 4, 2, 5 ;1x1 creature n,e,s,w,nsp,esp,ssp,wsp
DB 0, 3, 0, 3, 1, 4, 1, 5 ;1x1 no rotate
DB 0,10, 2,11, 4,14, 8,16 ;2x2 creature
DB 0,10, 2,11, 4,14, 8,16 ;2x2 creature
DB 0 ;pad to make emulator not freak the disasm
Draw2x2tileBased:
;use frame to determine how many tiles to spread this across
;and in what direction
bit 2,d ;d is frame
jr nz,.decideWhichSplit
jp .drawNonSplit
.decideWhichSplit
bit 0,d
jr z,.drawNorthToSouthSplit
.drawEastToWestSplit
bit 1,d
jr nz,.drawSplitFacingWest
.drawSplitFacingEast
push hl
call .drawHeadOfEWSplit
call .drawSplitE_PatternAndAttrNumbers
ld a,c
add 3
ld c,a
;move hl to start of next row
pop hl
call HLToNextRow
;repeat for row 2
call .drawSecondRowOfEWSplit
call .drawSplitE_PatternAndAttrNumbers
jp .done
.drawSplitFacingWest
push hl
call .drawHeadOfEWSplit
call .drawSplitW_PatternAndAttrNumbers
ld a,c
add 3
ld c,a
;move hl to start of next row
pop hl
call HLToNextRow
;repeat for row 2
call .drawSecondRowOfEWSplit
call .drawSplitW_PatternAndAttrNumbers
jp .done
.drawNorthToSouthSplit
bit 1,d
jr nz,.drawSplitFacingSouth
.drawSplitFacingNorth
push hl
call .drawHeadOfNSSplit
call .drawSplitNS_PatternAndAttrNumbers
inc c
inc c
;move hl to start of next row
pop hl
call HLToNextRow
;repeat for row 2 & 3
push hl
call .drawSecondRowOfNSSplit
call .drawSplitNS_PatternAndAttrNumbers
inc c
inc c
pop hl
call HLToNextRow
call .drawSecondRowOfNSSplit
call .drawSplitNS_PatternAndAttrNumbers
jp .done
.drawSplitFacingSouth
push hl
call .drawHeadOfNSSplit
call .drawSplitNS_PatternAndAttrNumbers
dec c
dec c
;move hl to start of next row
pop hl
call HLToNextRow
;repeat for row 2 & 3
push hl
call .drawSecondRowOfNSSplit
call .drawSplitNS_PatternAndAttrNumbers
dec c
dec c
pop hl
call HLToNextRow
call .drawSecondRowOfNSSplit
call .drawSplitNS_PatternAndAttrNumbers
jr .done
.drawNonSplit
bit 1,d
jr z,.drawNonSplitNorE
bit 0,d
jr nz,.drawNonSplitW
.drawNonSplitS
push hl
call .drawHeadOfNSSplit
call .drawSplitNS_PatternAndAttrNumbers
dec c
dec c
;move hl to start of next row
pop hl
call HLToNextRow
;repeat for next row
call .drawSecondRowOfNSSplit
call .drawSplitNS_PatternAndAttrNumbers
jr .done
.drawNonSplitW
push hl
ld a,MAPBANK
ldio [$ff70],a
ld a,e
ld [hl+],a
ld a,CLASS_ADJOIN_W
ld [hl-],a
call .drawWPatternAndAttributeNumbers
inc c
inc c
pop hl
call HLToNextRow
ld a,MAPBANK
ldio [$ff70],a
ld a,CLASS_ADJOIN_N
ld [hl+],a
ld [hl-],a
call .drawWPatternAndAttributeNumbers
jr .done
.drawNonSplitNorE
push hl
call .drawHeadOfNSSplit
call .drawSplitNS_PatternAndAttrNumbers
inc c
inc c
pop hl
call HLToNextRow
call .drawSecondRowOfNSSplit
call .drawSplitNS_PatternAndAttrNumbers
.done pop hl
pop de
pop bc
ret
.drawHeadOfEWSplit
ld a,MAPBANK ;select map RAM
ldio [$ff70],a
ld a,e
ld [hl+],a ;draw class index
ld a,CLASS_ADJOIN_W
ld [hl+],a
ld [hl-],a
dec hl
ret
.drawSecondRowOfEWSplit
ld a,MAPBANK ;select map RAM
ldio [$ff70],a
ld a,CLASS_ADJOIN_N
ld [hl+],a
ld [hl+],a
ld [hl-],a
dec hl
ret
.drawSplitE_PatternAndAttrNumbers
;draw pattern numbers to tile shadow bank
ld a,TILESHADOWBANK ;select tile shadow RAM
ldio [$ff70],a
ld a,c
ld [hl+],a ;draw tile to tile shadow RAM
inc a
ld [hl+],a
inc a
ld [hl],a
;draw colors to attr shadow bank
ld a,ATTRSHADOWBANK ;select attribute shadow RAM
ldio [$ff70],a
ld a,b
ld [hl-],a ;draw attribute to attribute shadow RAM
ld [hl-],a
ld [hl],a
ret
.drawSplitW_PatternAndAttrNumbers
;draw pattern numbers to tile shadow bank
ld a,TILESHADOWBANK ;select tile shadow RAM
ldio [$ff70],a
ld a,c
ld [hl+],a ;draw tile to tile shadow RAM
dec a
ld [hl+],a
dec a
ld [hl],a
;draw colors to attr shadow bank
ld a,ATTRSHADOWBANK ;select attribute shadow RAM
ldio [$ff70],a
ld a,b
ld [hl-],a ;draw attribute to attribute shadow RAM
ld [hl-],a
ld [hl],a
ret
.drawHeadOfNSSplit
ld a,MAPBANK ;select map RAM
ldio [$ff70],a
ld a,e
ld [hl+],a ;draw class index
ld a,CLASS_ADJOIN_W
ld [hl-],a
ret
.drawSecondRowOfNSSplit
ld a,MAPBANK ;select map RAM
ldio [$ff70],a
ld a,CLASS_ADJOIN_N
ld [hl+],a
ld [hl-],a
ret
.drawSplitNS_PatternAndAttrNumbers
;draw pattern numbers to tile shadow bank
ld a,TILESHADOWBANK ;select tile shadow RAM
ldio [$ff70],a
ld a,c
ld [hl+],a ;draw tile to tile shadow RAM
inc a
ld [hl],a
;draw colors to attr shadow bank
ld a,ATTRSHADOWBANK ;select attribute shadow RAM
ldio [$ff70],a
ld a,b
ld [hl-],a ;draw attribute to attribute shadow RAM
ld [hl],a
ret
.drawWPatternAndAttributeNumbers
ld a,TILESHADOWBANK
ldio [$ff70],a
ld a,c
ld [hl+],a
dec a
ld [hl],a
ld a,ATTRSHADOWBANK
ldio [$ff70],a
ld a,b
ld [hl-],a
ld [hl],a
ret
HLToNextRow:
push de
ld d,0
ld a,[mapPitch]
ld e,a
add hl,de
pop de
ret
GenericCheck:
ld hl,.genericCheckTable
jp StdCheckFromTable
.genericCheckTable
DB 5 ;move delay
DB 0 ;attack type (0=no attack,1=melee,2=missile)
DB 0 ;bullet damage
DW nullSound
DB 10 ;fire delay
DW StdVectorToState
IF 0
;push bc
;push de
;push hl
;am I dead?
call GetHealth
or a
jr nz,.checkTimeToMove
call StandardDie
jr .done
.checkTimeToMove
;time to move?
ld a,5 ;2
call TestMove
or a
jr z,.skipMove ;timer lsb==frame lsb, don't move yet
ld a,1
ld [moveAlignPrecision],a
call StdVectorToState
or a
jr z,.skipMove
;call GetRandomMovement
;ld b,2 ;everyone move this way
call StandardValidateMoveAndRedraw
.skipMove
.done ;pop hl
;pop de
;pop bc
ret
ENDC
TalkerCheck:
ld hl,talkerCheckTable
TalkerCheckAfterSetupHL:
ld a,c
ld [dialogBalloonClassIndex],a
call StdCheckDead
ret z
call StdCheckTimeToMove
ret z
push hl
call StdCheckTalk
pop hl
ret z
call StdMove
ret
talkerCheckTable:
DB 5 ;move delay
DW StdVectorToState
GetRandomMovement:
;returns random value in b
;alters a, b, and hl
;pick a "random value" ((counter+=17))
ld a,%00001111
call GetRandomNumMask
;ldio a,[randomLoc]
;add 17
;ldio [randomLoc],a
;and %00001111 ;restrict to 0-15
cp 4
jr c,.randomDir ;less than 4 move in a different direction
;move in direction we're currently facing
;get current frame
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
ld hl,2
add hl,de
ld a,[hl]
and %00000011 ;clear off all but the direction bits
ld b,a ;b is same direction as before
ret
.randomDir
and %00000011 ;mask off our random # to a direction
ld b,a
ret
;---------------------------------------------------------------------
; Routine: EnforceLegalMove
; Arguments: b - original desired move direction
; c - class index
; de - "this"
; Returns: b - modified move direction
; Alters: a, b, hl
; Description: Adjusts move direction stored in b so that it is legal.
; A creature can always turn 180 around, but otherwise
; this means that it will travel forward if it is split
; between two tiles or if there is a wall in the desired
; direction.
;---------------------------------------------------------------------
EnforceLegalMove:
;get current frame in a
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
ld hl,2
add hl,de
ld a,[hl]
;is object split between two tiles?
bit 2,a
jr z,.notSplit
;It is split. This makes our job easy - creature can only
;turn around or go forward
ld h,a ;save current direction in h
add 2 ;add two and mask off to reverse
and %00000011
cp b ;reverse dir equal to desired?
jr nz,.splitMF ;no, move forward
ret ;allow move in reverse direction
.splitMF
;force the wee bairn to move forward
ld a,h
and %00000011
ld b,a
ret
.notSplit
;critter's not split. Maybe it just wants to turn around
;without a lot of fuss?
ld h,a ;save current direction in h
add 2 ;add two and mask off to reverse
and %00000011
cp b ;reverse dir equal to desired?
jr nz,.noReverse ;hmm guess not
ret ;let 'im turn around slowly like
.noReverse
push de
push hl
jr .moveAnywhere
;setup de with ptr to current location
ld h,d
ld l,e
ld a,[hl+]
ld d,[hl]
ld e,a ;de has ptr to cur location
ld a,MAPBANK ;select map RAM
ldio [$ff70],a
;Determine offset to check for wall and store in HL.
ld a,b ;desired dir
add b ;times two
ld h,((mapOffsetNorth>>8)&$ff)
add (mapOffsetNorth & $ff)
ld l,a ;hl pts to offset
ld a,[hl+]
ld h,[hl]
ld l,a ;hl IS offset
;don't examine my tail in the process; multiply offset
;by two if 2x2 and facing east or south
ldio a,[curObjWidthHeight]
cp 2
jr nz,.afterModifyOffset
ld a,b
and %00000011
cp %01 ;east
jr z,.offsetTimesTwo
cp %10 ;south
jr nz,.afterModifyOffset
.offsetTimesTwo
sla l ;hl<<=1 (same as *2)
rl h
.afterModifyOffset
add hl,de ;hl is &location in desired dir
ldio a,[firstMonster] ;d = firstMonster
ld d,a
ld a,[hl] ;what's there?
or a
jr z,.moveAnywhere ;nothing there
cp d
jr nc,.moveAnywhere
;wall there, move forward unless special flag says okay
push af
ld a,ZONEBANK
ldio [$ff70],a
pop af
bit 7,[hl] ;marked as special somehow?
jr z,.moveForwardIfNotBlocked ;nope
call GetBGAttributes
bit BG_BIT_ATTACKABLE,a
jr nz,.moveAnywhere
bit BG_BIT_WALKOVER,a
jr z,.moveForwardIfNotBlocked
ldio a,[curObjWidthHeight]
cp 1
jr z,.moveAnywhere ;can walk over
jr .moveForwardIfNotBlocked
;nuttin there or a monster to face, let the creature move in
;whatever direction it wants, bless its little heart (direction
;B is fine)
.moveAnywhere
pop hl
pop de
ret
.moveForwardIfNotBlocked
pop hl
pop de
ld l,b
ld a,h
and %00000011
ld b,a
push hl
ld a,1
call CheckDestEmpty
pop hl
or a
jr nz,.done
ld b,l ;allow turn anywhere if blocked ahead
ret
.moveForward
;hey, you can only move forward asshole
ld a,h ;desired dir = cur dir
and %00000011
ld b,a
.done
ret
;---------------------------------------------------------------------
; Routine: ScootSprite
; Arguments: a - loptr to sprite
; b - desired move direction
; Alters: af
; Description: Moves an existing sprite 4 pixels in a given
; direction.
;---------------------------------------------------------------------
ScootSprite:
cp $ff
ret z
push hl
ld l,a
ld h,((spriteOAMBuffer>>8) & $ff)
bit 0,b ;test direction of travel
jr nz,.eastWest
ld a,[hl]
bit 1,b
jr nz,.south
;north
sub 4
ld [hl],a
jr .afterUpdateSpritePos
.south
add 4
ld [hl],a
jr .afterUpdateSpritePos
.eastWest
inc hl
ld a,[hl]
bit 1,b
jr nz,.west
;east
add 4
ld [hl],a
jr .afterUpdateSpritePos
.west
sub 4
ld [hl],a
.afterUpdateSpritePos
pop hl
ret
;---------------------------------------------------------------------
; Routine: Move
; Arguments: b - desired move direction
; c - class index
; de - "this"
; Returns: Nothing
; Alters: a, hl
; Description: If desired dir is != current dir then turns creature
; to desired dir. Otherwise takes a step forward.
; If it moves AND changes zones the curPathPos
; (frame bits 6:5) is set to zero.
;
; There are three steps:
; 1) Remove From Map
; If the IsSprite flag is set (FRAME:7) then the
; map is restored from the contents of the
; tileShadowBuffer. Otherwise the map tiles creature
; is occupying are cleared to zero.
;
; 2) Adjust IsSprite flag (FRAME:7)
; If 0: If [bgFlags] contains FLAG_WALKOVER or
; FLAG_SHOOTOVER then IsSprite is set to 1.
; Else If 1:
; If frame:split is 0 and tile under is zero
; then IsSprite is set to zero.
;
; 3) Redraw
; If the IsSprite flag is set then the map
; underneath is copied to the tileShadowBuffer.
;
; Regardless the class index of the object is drawn
; into the map.
; If [bgFlags] contains either BG_FLAG_WALKOVER or
; BG_FLAG_SHOOTOVER then
;---------------------------------------------------------------------
Move:
push bc
;save current zone to see if it changes when we move
call GetCurZone
ld [oldZone],a
;get current direction in c
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
ld hl,OBJ_FRAME
add hl,de
ld a,[hl] ;a = frame
ld c,a
;same as desired direction?
and %00000011
cp b
jr z,.sameDirection
;Different direction. Turn to desired direction.
ld a,c
and %11111100 ;preserve non-direction other bits
or b ;combined with new direction
ld [hl],a ;and that's our new frame!
;have to remove from map if we're a sprite
call GetFacing
bit 7,a
jr z,.doneTurn
call RemoveFromMap
.doneTurn
pop bc
ret
.sameDirection
call RemoveFromMap ;gonna be drawin again real soon, Baby!
ld a,OBJBANK ;select object RAM
ld [$ff70],a
;if we were split facing west or north then we don't actually
;move, we just turn off the split bit
bit 2,c
jr z,.noSplitCheckEastSouth
;facing west?
ld a,c
and %00000111
cp %00000111
jr nz,.checkSplitFacingNorth
.noMoveToggleSplit
ld a,c
xor %00000100
ld c,a
jr .stowNewFrame
.checkSplitFacingNorth
cp %00000100
jr z,.noMoveToggleSplit
jr .moveForwardToggleSplit
.noSplitCheckEastSouth
;if we're not split and we're heading East or South then again
;we just toggle the split bit as our move
ld a,c
and %00000111
cp %00000001 ;facing East?
jr z,.noMoveToggleSplit
cp %00000010 ;facing South?
jr z,.noMoveToggleSplit
.moveForwardToggleSplit
push hl
push de
;setup de with ptr to current location
ld h,d
ld l,e
ld a,[hl+]
ld d,[hl]
ld e,a ;de has ptr to cur location
;Determine offset to check for wall and store in HL.
ld a,b ;desired dir
add b ;times two
ld hl,mapOffsetNorth
add l
ld l,a ;hl pts to offset
ld a,[hl+]
ld h,[hl]
ld l,a ;hl IS offset
add hl,de
ld d,h
ld e,l
;toggle the split bit for the new frame
ld a,c
xor %00000100
ld c,a ;c has new frame
;store new location in object
pop hl ;hl is ptr to this
ld a,e
ld [hl+],a
ld a,d
ld [hl-],a
;restore de
ld d,h
ld e,l
pop hl
.stowNewFrame
;if IsSprite bit off, check to see if we want to turn
;it on
bit 7,c
jr nz,.spriteBitIsOn
ld a,[bgFlags]
and BG_FLAG_SPECIAL
jr z,.reallyStowNewFrame
set 7,c ;turn sprite flag on
;call AllocateSprite
;call StoreSpriteLo
jr .reallyStowNewFrame
.spriteBitIsOn
;can we turn it off?
bit 2,c ;is frame bit zero?
jr nz,.updateSpritePos ;no, leave it on
;maybe turn it off; see what we're over
push hl
call GetCurLocation
ld a,MAPBANK
ld [$ff70],a
ld a,[hl]
push af
ld a,OBJBANK
ld [$ff70],a
pop af
pop hl
or a
jr nz,.updateSpritePos ;leave it on
res 7,c ;turn it off
call FreeSpriteLoPtr
jr .reallyStowNewFrame
.updateSpritePos
;since the sprite has been on let's scoot the sprite 4
;pixels in the direction we've moved
call GetSpriteLo
call ScootSprite
.reallyStowNewFrame
ld a,OBJBANK
ld [$ff70],a
ld a,c ;new frame
ld [hl],a
;if oldZone != curZone then set curPathPos to zero
call GetCurZone
ld hl,oldZone
cp [hl]
jr z,.done
call ResetCurPathPos
.done pop bc
ret
;---------------------------------------------------------------------
; Routine: RemoveFromMap
; Arguments: c - current frame
; de - "this"
; Returns: Nothing
; Alters: af
; Description: Removes the this object's class index from the main
; map buffa
;---------------------------------------------------------------------
RemoveFromMap::
push bc
push de
push hl
call GetCurLocation
;is object currently a sprite?
bit 7,c
jr nz,.clearSprite
ld a,MAPBANK ;select map RAM
ldio [$ff70],a
ldio a,[curObjWidthHeight]
cp 2
jr z,.clear2x2tiles
;clear out this location
xor a
ld [hl+],a
;if we were a split tile then clear out the next one to the
;right OR to the bottom
bit 2,c
jr z,.done
bit 0,c
jr z,.splitNS
;split E/W
ld [hl+],a ;clear out the next location too, sucka
jr .done
.splitNS
;scoot HL down a row
ld d,0
ld a,[mapPitchMinusOne]
ld e,a
add hl,de
ld [hl],d ;clear 'em all
jr .done
.clearSprite
call .getTilePreviouslyHere
;if we were a split tile then clear out the next one to the
;right OR to the bottom
bit 2,c
jr z,.done
bit 0,c
jr z,.spriteSplitNS
;split E/W
inc hl
call .getTilePreviouslyHere
jr .done
.spriteSplitNS
;scoot HL down a row
ld d,0
ld a,[mapPitch]
ld e,a
add hl,de
call .getTilePreviouslyHere
.done pop hl
pop de
pop bc
ret
.getTilePreviouslyHere
ld a,TILESHADOWBANK
ld [$ff70],a
ld b,[hl]
ld a,MAPBANK
ld [$ff70],a
ld [hl],b
ret
.clear2x2tiles
push hl
call .clear2x2row
pop hl
call HLToNextRow
push hl
call .clear2x2row
pop hl
ld a,c
and %00000101
cp %00000100
jr nz,.done2x2
call HLToNextRow
call .clear2x2row
.done2x2
pop hl
pop de
pop bc
ret
.clear2x2row
xor a
ld [hl+],a
ld [hl+],a
ld a,c
and %00000101
xor %00000101
ret nz
ld [hl+],a
ret
;---------------------------------------------------------------------
; Routine: CheckDestEmpty
; Arguments: b - desired direction
; de - "this"
; a - 0=don't consider facing, 1=consider facing
;
; Returns: a - dest is empty
; !a - dest is not empty
; Alters: a, hl
; Description: Checks along direction of travel for empty tile
;---------------------------------------------------------------------
CheckDestEmpty:
ld [temp],a
xor a
ld [bgFlags],a
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
;load cur frame into a
ld hl,2
add hl,de
ld a,[hl]
;don't bother if split bit is set, we're fine
bit 2,a
ret nz
;and don't bother if direction of travel is not equal to
;current facing (just turning)
ld a,[temp]
or a
jr z,.check
ld a,[hl]
and %00000011
cp b
jr z,.check
ld a,1 ;set return value A to non-zero
ret
.check
push de
push hl
;setup de with ptr to current location
ld h,d
ld l,e
ld a,[hl+]
ld d,[hl]
ld e,a ;de has ptr to cur location
ld a,MAPBANK ;select map RAM
ldio [$ff70],a
call GetMapOffset
;don't examine my tail in the process; multiply offset
;by two if 2x2 and facing east or south
ldio a,[curObjWidthHeight]
cp 2
jr nz,.afterModifyOffset
ld a,b
and %00000011
cp %01 ;east
jr z,.offsetTimesTwo
cp %10 ;south
jr nz,.afterModifyOffset
.offsetTimesTwo
sla l ;hl<<=1 (same as *2)
rl h
.afterModifyOffset
add hl,de ;hl is ptr to new location
ldio a,[curObjWidthHeight]
cp 2
jr z,.check2x2
;check 1x1
ld a,[hl] ;contents of dest into a
call .checkCanMoveOver
pop hl
pop de
ret
.check2x2
;check first adjacent tile
ld a,[hl]
call .checkCanMoveOver
or a
jr z,.done ;blocked on first, no use checking second
;first clear; check second adj tile
ld a,b
and 1 ;now 0=n/s, 1=e/w
add 1 ;now check adj in e for original n/s, s for e/w
call AdvanceLocHLInDirection
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
call .checkCanMoveOver
.done pop hl
pop de
ret
.checkCanMoveOver
or a ;zero?
jr nz,.checkSpecialFlags
ld a,1 ;return true
ret
.checkSpecialFlags
ld e,a
ldio a,[firstMonster]
cp e
jr z,.false ;is a monster
jr c,.false ;is a monster
ld a,TILEINDEXBANK
ld [$ff70],a
ld d,((bgAttributes>>8) & $ff)
ld a,[de]
ld [bgFlags],a
and BG_FLAG_WALKOVER
jr z,.false
ldio a,[curObjWidthHeight]
cp 1
jr nz,.false
;return true
ld a,1
ret
.false xor a ;return false
ret
;---------------------------------------------------------------------
; Routines: GetMapOffset
; Arguments: b - map direction to get offset in
; Returns: hl - desired offset
; Alters: a, hl
;---------------------------------------------------------------------
GetMapOffset:
ld a,b ;desired dir
add b ;times two
ld hl,mapOffsetNorth
add l
ld l,a ;hl pts to offset
ld a,[hl+]
ld h,[hl]
ld l,a ;hl IS offset
ret
;---------------------------------------------------------------------
; Routines: TestMove
; HeroTestMove
; Arguments: a - value to reset counter to if it reaches zero
; de - "this"
; Returns: a - time to move
; !a - don't move
; Alters: a,hl
; Description:
;---------------------------------------------------------------------
TestMove:
push af
call PointToSpecialFlags
bit OBJBIT_THROWN,[hl]
jr nz,TestMoveThrown
pop af
TestMoveNoCheckSpecial:
push bc
ld c,a
ld a,[objTimer60ths] ;get timer
and %00011000 ;get rid of other bits
ld b,a
ld hl,OBJ_FRAME ;offset of frame variable
add hl,de
xor a,[hl] ;xor timer4:3 w/frame4:3, hl=&move
push af
ld a,[hl] ;current state
and %11100111 ;mask off area for timer
or b ;store bits from current timer
ld [hl],a
pop af
and %00011000 ;get rid of other bits
jr z,.skipMove ;already moved this turn
push bc
inc hl
dec [hl]
jr z,.timeToMove
;no move but save modified timer
pop bc
pop bc
xor a
ret
.timeToMove
;time to move!
push hl
ld hl,OBJ_DESTZONE ;point to # puffs
add hl,de
ld a,[hl]
and %1111
pop hl
add a,c ;reset move counter (add #puffs)
;or b
ld [hl-],a
pop bc
ld a,1 ;return true/able to move
.skipMove
pop bc
ret
HeroTestMove:
push af
call PointToSpecialFlags
bit OBJBIT_THROWN,[hl]
jr nz,TestMoveThrown
pop af
push bc
ld c,a
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
ld a,[heroTimer60ths] ;get timer
and %00011000 ;get rid of other bits
ld b,a
ld hl,OBJ_FRAME ;offset of frame variable
add hl,de
xor a,[hl] ;xor timer4:3 w/frame4:3, hl=&move
push af
ld a,[hl] ;current state
and %11100111 ;mask off area for timer
or b ;store bits from current timer
ld [hl],a
pop af
and %00011000 ;get rid of other bits
jr z,.skipMove ;already moved this turn
push bc
inc hl
dec [hl]
jr z,.timeToMove
;no move but save modified timer
pop bc
pop bc
xor a
ret
.timeToMove
;time to move!
push hl
ld hl,OBJ_DESTZONE ;point to # puffs
add hl,de
ld a,[hl]
and %1111
pop hl
add a,c ;reset move counter (add #puffs)
ld [hl-],a
pop bc
ld a,1 ;return true/able to move
.skipMove
pop bc
ret
TestMoveThrown:
;move one in current facing and return "unable to move"
pop af
ld a,1
call TestMoveNoCheckSpecial
or a
ret z
ldio a,[firstMonster]
ld b,a
ld a,4
call GetLocInFront
or a
jr z,.emptyAhead
cp b
jr nc,.stop
ld a,[bgFlags]
bit BG_BIT_WALKOVER,a
jr z,.stop
ldio a,[curObjWidthHeight]
cp 1
jr z,.emptyAhead
.stop call PointToSpecialFlags
res OBJBIT_THROWN,[hl]
ld a,[hero0_index]
cp c
jr z,.heroJiggle
ld a,[hero1_index]
cp c
jr z,.heroJiggle
xor a
ret
.heroJiggle
ld a,5
ldio [jiggleDuration],a
xor a
ret
.emptyAhead
call GetCurLocation
push hl
call GetFacing
and %111
ld b,a
push bc
and %11
ld b,a
call StandardValidateMoveAndRedraw
pop bc
pop hl
;check if way blocked after all (2x2 monster)
call GetFacing
and %111
cp b
jr nz,.done
ld a,[de]
cp l
jr nz,.done
inc de
ld a,[de]
dec de
cp h
jr z,.stop
.done
xor a
ret
;---------------------------------------------------------------------
; Routines: StdVectorToState
; EatVectorToState
; TrackEnemyVectorToState
; ActorVectorToState
; FleeVectorToState
; Arguments: de - "this"
; Returns: b - direction to move
; a - non-zero for move valid, zero for no move
; Alters: a, b, hl
;---------------------------------------------------------------------
VectorToStateCommonInit:
call GetState
rlca
and %01111110
ret
StdVectorToState:
call VectorToStateCommonInit
add (stdStateTable & $ff)
ld l,a
ld h,((stdStateTable>>8) & $ff)
VectorToStateCommon:
ld a,[hl+]
ld h,[hl]
ld l,a
jp hl
EatVectorToState:
call VectorToStateCommonInit
add (eatStateTable & $ff)
ld l,a
ld h,((eatStateTable>>8) & $ff)
jr VectorToStateCommon
TrackEnemyVectorToState:
call VectorToStateCommonInit
add (trackEnemyStateTable & $ff)
ld l,a
ld h,((trackEnemyStateTable>>8) & $ff)
jr VectorToStateCommon
ActorVectorToState:
call VectorToStateCommonInit
add (actorStateTable & $ff)
ld l,a
ld h,((actorStateTable>>8) & $ff)
jr VectorToStateCommon
FleeVectorToState:
call VectorToStateCommonInit
add (fleeStateTable & $ff)
ld l,a
ld h,((fleeStateTable>>8) & $ff)
jr VectorToStateCommon
LadyVectorToState:
call VectorToStateCommonInit
add (ladyBulletStateTable & $ff)
ld l,a
ld h,((ladyBulletStateTable>>8) & $ff)
jr VectorToStateCommon
;---------------------------------------------------------------------
; STATE METHODS
; Arguments: de - "this"
; Returns: b - direction to move
; a - non-zero for move valid, zero for no move
; Alters: a, b, hl
;---------------------------------------------------------------------
SetupRandomMoveState:
ld a,6
call SetState
xor a
ret
EatOrTrackState:
;move in direction of food next to me
ld b,0
.checkDirectionForFood
ld a,b
call GetLocInFront
or a
jr z,.continue
push bc
push hl
ld b,a
call GetDestL ;min index I can eat
cp b
jr z,.maybeFood
jr nc,.notFood
.maybeFood
call GetDestH ;max index I can eat
cp b
jr nc,.food
.notFood
pop hl
pop bc
jr .continue
.food
pop hl
pop bc
;remove tile in direction I'm facing that way and I'm not split
call GetFacing
bit 2,a
jr nz,.foundFood
and %11
cp b
jr nz,.foundFood
ld a,MAPBANK
ldio [$ff70],a
xor a
ld [hl],a
ld hl,eatSound
call PlaySound
.foundFood
ld a,1 ;b contains valid move
ret
.continue
inc b
ld a,b
cp 4
jr nz,.checkDirectionForFood
jp TrackEnemyVectorToState ;no food around, track hero
SetupTrackEnemy:
call GetCurZone
ld b,a
;Use bit 5 of my object address to determine which hero
;to try and follow.
ld a,e
swap a
and %10 ;from %00 or %10 we get...
ld h,a
rrca
xor %01
or h ;%01 or %10
call GetHeroZone
cp b
jr z,.inSameZone
call SetDestZone
ld a,1
call SetState
xor a
ret
.inSameZone
;ld a,1 ;bit of slack
xor a ;no slack
jp MoveToLocation
;return zero for no move
SetupMoveToLoc:
call GetActorDestLoc
ld a,h
or a
jr nz,.moveToLoc
;ret z ;no dest loc
;1/32 chance of face random direction
ld a,31
call GetRandomNumMask
or a
jr z,.faceRandom
xor a
ret
.faceRandom
call GetFacing
bit 2,a
ret nz ;don't change dir if split
and %11111000
ld b,a
ld a,3
call GetRandomNumMask
or b
call SetFacing
call StandardRedraw
xor a
ret
.moveToLoc
push hl
call GetCurZone
pop hl
ld b,a
call GetActorDestZone
cp b
jr z,.inSameZone
call SetDestZone
ld a,1
call SetState
xor a
ret
.inSameZone
call GetActorDestLoc
xor a
ld [moveAlignPrecision],a
call AmAtLocation
or a
jr z,.findLocation
ld hl,0
call SetActorDestLoc
;call GetFacing
;and %11111011 ;set split bit to zero
;call SetFacing
xor a
ret
.findLocation
xor a ;no slack
ld [moveAlignPrecision],a
jp MoveToLocation
MoveToZone:
;-------------------------------------------------------------
; State 1: MOVE TOWARDS DEST ZONE
; if (curZone == destZone){
; this->state = 0;
; }else{
; nextWayPoint=GetNextWayPoint(curZone,destZone);
; if(this->pos == nextWayPoint){
; curPathPos++;
; }else{
; int r = ChooseDirection(nextWayPoint, &dir);
; if(!r){
; this->moveLimit = 3;
; this->majorAxis = dir:7;
; this->state = 2; //try to the right
; }
; return r;
; }
; }
; return 0;
;-------------------------------------------------------------
call GetCurZone
ld b,a ;save curZone
call GetDestZone
;if(curZone==destZone)
cp b
jr nz,.cur_NE_dest
xor a
call SetState
xor a
ret
.cur_NE_dest
swap a
or b ;destZone in 7:4, curZone in 3:0
call GetNextWayPoint ;returns next WP loc in hl
xor a
cp h
jr nz,.validWayPoint
cp l
jr nz,.validWayPoint
;invalid way point, try just moving towards hero w/dumb ai
;Use bit 5 of my object address to determine which hero
;to try and follow.
ld a,e
swap a
and %10 ;from %00 or %10 we get...
ld h,a
rrca
xor %01
or h ;%01 or %10
call GetHeroZone
xor a ;no slack
jp MoveToLocation
.validWayPoint
call AmAtLocation
or a
jr z,.moveToLocation
call IncrementPathPos ;at next waypoint, increment waypoint
xor a
ret
.moveToLocation
ld a,1 ;cut some slack on alignment
MoveToLocation:
;use "dumb-AI" to move towards waypoint
;hl should be destination location
call ChooseDirection ;args hl=curWP
;returns a=1 on success, b=dir
or a
jr z,.decideDirectionLeftOrRight
;success!
ret
.decideDirectionLeftOrRight
ld a,b
call SetDesiredDirection
ld a,6
call SetMoveLimit
call GetMoveRightOfDesiredDir
or a
jr z,.tryLeft ;try left if no exit to right
ld a,[secondChoiceDirection]
cp b
jr z,.tryRight ;right matches our second choice
.tryLeft ;try left then right
ld a,8
call SetState
xor a
ret
.tryRight
;set critter to try along its right for a while
ld a,2
call SetState
xor a
ret
TryRight:
;-------------------------------------------------------------
; State 2: MOVE RIGHT TO LOOK FOR PASSAGE
;-------------------------------------------------------------
call GetMoveRightOfDesiredDir
or a
jr z,.changeState2To4 ;can't move right
;if move limit has expired switch to looking left
call DecrementMoveLimit
or a
jr z,.changeState2To4
.moveRightCheckForward
ld a,3 ;check for forward passage next
call SetState
ld a,1
ret
.changeState2To4
ld a,15
call SetMoveLimit
ld a,4
call SetState
xor a
ret
TryFwdAfterRight:
;-------------------------------------------------------------
; State 3: JUST MOVED RIGHT, CHECK FOR FORWARD PASSAGE
;-------------------------------------------------------------
call CheckForwardPassage
or a
jr nz,.changeState3ToState7
ld a,2
call SetState
xor a
ret
.changeState3ToState7
;passage exists, MF twice (once to turn, once to move)
ld a,7
call SetState
ld a,1
ret
TryLeft:
;-------------------------------------------------------------
; State 4: MOVE LEFT CHECKING FOR FORWARD PROGRESS
;-------------------------------------------------------------
call GetMoveLeftOfDesiredDir
or a
jr z,.changeState4To6 ;can't move left, move random
;if move limit has expired switch to moving random
call DecrementMoveLimit
or a
jr z,.changeState4To6
ld a,5 ;check for forward passage next
call SetState
ld a,1
ret
.changeState4To6
ChangeToStateRandom:
ld a,15
call SetMoveLimit
ld a,6
call SetState
xor a
ret
TryFwdAfterLeft:
;-------------------------------------------------------------
; State 5: CHECK FORWARD AFTER HAVING MOVED LEFT
;-------------------------------------------------------------
call CheckForwardPassage
or a
jr nz,.changeState5ToState7
ld a,4
call SetState
xor a
ret
.changeState5ToState7
;passage exists, MF twice (once now to turn, once to move)
ld a,7
call SetState
ld a,1
ret
RandomMove:
;-------------------------------------------------------------
; State 6: MOVE IN A RANDOM DIRECTION
;-------------------------------------------------------------
call GetRandomMovement
call DecrementMoveLimit
or a
jr z,.randomBackToState0
ret
.randomBackToState0
;a is zero
call SetState
ret
MoveFwdThenState1:
;-------------------------------------------------------------
; State 7: Move Forward, Go to state 1
;-------------------------------------------------------------
ld a,1
call SetState
call CheckForwardPassage
ret
TryLeftFirst:
;-------------------------------------------------------------
; State 8: MOVE LEFT CHECKING FOR FORWARD PROGRESS
;-------------------------------------------------------------
call GetMoveLeftOfDesiredDir
or a
jr z,.changeState8To10 ;can't move left, move right
;if move limit has expired switch to looking right
call DecrementMoveLimit
or a
jr z,.changeState8To10
ld a,9 ;check for forward passage next
call SetState
ld a,1
ret
.changeState8To10
;look to the right
ld a,15
call SetMoveLimit
ld a,10
call SetState
xor a
ret
TryFwdAfterLeftFirst:
;-------------------------------------------------------------
; State 9: CHECK FORWARD AFTER HAVING MOVED LEFT
;-------------------------------------------------------------
call CheckForwardPassage
or a
jr nz,.changeState9ToState7
ld a,8 ;go back to checking left
call SetState
xor a
ret
.changeState9ToState7
;passage exists, MF twice (once now to turn, once to move)
ld a,7
call SetState
ld a,1
ret
TryRightSecond:
;-------------------------------------------------------------
; State 10: MOVE RIGHT TO LOOK FOR PASSAGE
;-------------------------------------------------------------
call GetMoveRightOfDesiredDir
or a
jr z,.changeState10To6 ;can't move right, move random
;if move limit has expired switch to moving random
call DecrementMoveLimit
or a
jr z,.changeState10To6
.moveRightCheckForward
ld a,11 ;check for forward passage next
call SetState
ld a,1
ret
.changeState10To6
ld a,15
call SetMoveLimit
ld a,6
call SetState
xor a
ret
TryFwdAfterRightSecond:
;-------------------------------------------------------------
; State 11: JUST MOVED RIGHT, CHECK FOR FORWARD PASSAGE
;-------------------------------------------------------------
call CheckForwardPassage
or a
jr nz,.changeState11ToState7
.keepGoing
ld a,10
call SetState
xor a
ret
.changeState11ToState7
;passage exists, MF twice (once to turn, once to move)
ld a,7
call SetState
ld a,1
ret
NoMove:
;-------------------------------------------------------------
; Default: RETURN "NO MOVE"
;-------------------------------------------------------------
xor a
ret
;---------------------------------------------------------------------
; Routine: GetCurZone
; Arguments: de - "this"
; Returns: a - ID of current zone
; hl - current location
; Alters: a, hl
;---------------------------------------------------------------------
GetCurZone::
call GetCurLocation
ld a,ZONEBANK ;select zone RAM parallel to map ram
ldio [$ff70],a
ld a,[hl] ;A is curZone
and $0f
ret
;---------------------------------------------------------------------
; Routine: GetHeroZone
; Arguments: a - prefer which hero? 1=Hero0, 2=Hero1, 0/3=Either
; de - "this"
; Returns: a - ID of zone hero is in
; hl - current location
; Alters: a, hl
;---------------------------------------------------------------------
GetHeroZone:
push de
ld d,a
ld a,[heroesPresent]
and d
jr z,.pickFirstAvailable
cp 3
jr c,.getChosenHero
.pickFirstAvailable
ld a,[heroesPresent]
and %01
jr nz,.getChosenHero
ld a,%10
.getChosenHero
;a has the valid, desired hero %10 or %01.
ld hl,hero0_object
cp %01 ;do we want hero 0?
jr z,.haveHeroObjAddr
ld l,(hero1_object & $ff) ;we want hero 1
.haveHeroObjAddr
;Load the Hero object
ld a,[hl+] ;heroX_objectL
ld e,a
ld d,[hl] ;heroX_objectH
call GetCurZone
pop de
ret
;---------------------------------------------------------------------
; Routine: GetState
; Arguments: de - "this"
; Returns: a - this->state
; hl - &this->state
; Alters: a, hl
;---------------------------------------------------------------------
GetState:
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
ld hl,OBJ_STATE
add hl,de
ld a,[hl]
and %00111111
ret
;---------------------------------------------------------------------
; Routine: SetState
; Arguments: de - "this"
; a - desired state
; Returns: hl - &this->state
; Alters: a, hl
;---------------------------------------------------------------------
SetState::
push bc
and %00111111
ld b,a
ld a,OBJBANK ;select object RAM
ld [$ff70],a
ld hl,OBJ_STATE
add hl,de
ld a,[hl] ;get old state
and %11000000
or b
ld [hl],a ;save new state
pop bc
ret
;---------------------------------------------------------------------
; Routine: GetAttackDirState
; Arguments: de - "this"
; Returns: a - 2-bit value[1:0] from this->state[7:6]
; hl - &this->state
; Alters: a, hl
;---------------------------------------------------------------------
GetAttackDirState:
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
ld hl,OBJ_STATE
add hl,de
ld a,[hl]
rlca
rlca
and %00000011
ret
;---------------------------------------------------------------------
; Routine: SetAttackDirState
; Arguments: de - "this"
; a - desired state (lower 2 bits)
; Returns: hl - &this->state
; Alters: a, hl
; Description: Sets the upper two bits of "state" to be the value
; passed in.
;---------------------------------------------------------------------
SetAttackDirState:
push bc
rrca
rrca
and %11000000
ld b,a
call GetState
or b
ld [hl],a
pop bc
ret
;---------------------------------------------------------------------
; Routine: SetDestZone
; Arguments: de - "this"
; a - desired dest zone
; Returns: hl - &this->state
; Alters: a, hl
;---------------------------------------------------------------------
SetDestZone:
ld hl,OBJ_DESTZONE ;hl = &this->move
add hl,de
push af
ld a,OBJBANK ;select object RAM
ld [$ff70],a
ld a,[hl]
and %00001111 ;mask off old zone
ld [hl],a
pop af
swap a ;destZone in 7:4
or [hl] ;combine with move
ld [hl],a ;save in move
ret
;---------------------------------------------------------------------
; Routine: GetDestZone
; Arguments: de - "this"
; Returns: a - dest zone
; hl - &this->destzone
; Alters: a, hl
;---------------------------------------------------------------------
GetDestZone:
ld a,OBJBANK ;select object RAM
ld [$ff70],a
ld hl,OBJ_DESTZONE ;hl = &this->destzone
add hl,de
ld a,[hl] ;get this->destzone
swap a
and %00001111
ret
;---------------------------------------------------------------------
; Routine: GetPuffCount
; Arguments: de - "this"
; Returns: a - dest zone
; hl - &this->state
; Alters: a, hl
;---------------------------------------------------------------------
GetPuffCount::
ld a,OBJBANK ;select object RAM
ld [$ff70],a
ld hl,OBJ_DESTZONE ;hl = &this->state
add hl,de
ld a,[hl] ;get this->state
and %00001111
ret
;---------------------------------------------------------------------
; Routine: SetPuffCount
; Arguments: a - # of puffs
; de - "this"
; Returns: a - dest zone
; hl - &this->state
; Alters: a, hl
;---------------------------------------------------------------------
SetPuffCount::
push bc
ld b,a
ld a,OBJBANK ;select object RAM
ld [$ff70],a
ld hl,OBJ_DESTZONE ;hl = &this->state
add hl,de
ld a,[hl]
and %11110000
or b
ld [hl],a ;get this->state
pop bc
ret
;---------------------------------------------------------------------
; Routine: GetNextWayPoint
; Arguments: de - "this"
; a - curZone[7:4], destZone[3:0]
; Returns: hl - position of next waypoint
; Alters: a, hl
; C Code:
; int curPath = pathMatrix[curZone][destZone];
; int curWPIndex = pathList[curPath][this->pathPos];
; int nextWayPoint = wayPointList[curWPIndex];
; return nextWayPoint
;---------------------------------------------------------------------
GetNextWayPoint:
push bc
ld b,0
ld c,a ;BC gets index to array
call GetPathPos
push de
ld d,0
ld e,a ;E gets pathPos
ld a,WAYPOINTBANK ;select object list RAM
ld [$ff70],a
ld hl,pathMatrix
add hl,bc
ld a,[hl] ;A = curPath
ld c,a ;Setup curPath*4 as offset into
xor a ; pathlist
sla c
rla
sla c
rla
ld b,a ;bc = curPath*4
ld hl,pathList
add hl,bc ;hl = &pathList[curPath]
add hl,de ;hl = &pathList[curPath][pathPos]
ld a,[hl] ;a = curWPIndex
ld c,a ;offset into WP list = curWPIndex*2
xor a
sla c
rla
ld b,a ;bc = offset
ld hl,wayPointList
add hl,bc
ld a,[hl+] ;low byte of waypoint location
ld h,[hl] ;high byte
ld l,a ;hl is location of next waypoint
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: GetPathPos
; Arguments: de - "this"
; Returns: a - current path position (0-3)
; hl - &this->frame
; Alters: a, hl
;---------------------------------------------------------------------
GetPathPos:
ld a,OBJBANK ;select object RAM
ld [$ff70],a
ld hl,OBJ_FRAME
add hl,de
ld a,[hl] ;get frame var
swap a
rrca
and %00000011 ;get pathPos in 1:0
ret
;---------------------------------------------------------------------
; Routine: AmAtLocation
; Arguments: de - "this"
; hl - a location
; [moveAlignPrecision]
; Returns: a - 1 if this->loc == location, 0 if not
; Alters: a
; Note: Compares X,Y coordinates +/- [moveAlignPrecision]
;---------------------------------------------------------------------
AmAtLocation::
push bc
push de
push hl
ld a,OBJBANK ;select object RAM
ld [$ff70],a
;not there if split bit is set
call GetFacing
and %100
ld a,0
jr nz,.done
;cur loc in bc
ld a,[de] ;low byte of cur pos
inc de
ld c,a
ld a,[de] ;high byte
ld b,a
;dest XY in de
call ConvertLocHLToXY
ld d,h
ld e,l
;cur XY in hl
ld h,b
ld l,c
call ConvertLocHLToXY
;compare sourceX to destX +/- 1
;ld a,h
;add 1
ld a,[moveAlignPrecision] ;x + precision
add h
cp d
jr c,.returnFalse
;sub 3
ld a,[moveAlignPrecision] ;x - precision
cpl
add 1
add h
cp d
jr z,.checkY
jr nc,.returnFalse
.checkY
;compare sourceY to destY +/- 1
ld a,[moveAlignPrecision] ;y + precision
add l
cp e
jr c,.returnFalse
ld a,[moveAlignPrecision] ;y - precision
cpl
add 1
add l
cp e
jr z,.returnTrue
jr nc,.returnFalse
.returnTrue
ld a,1
jr .done
.returnFalse
xor a
.done
pop hl
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: IsActorAtDest
; Arguments: de - "this"
; Returns: a - 1 if actor stopped moving, 0 if not
; Alters: af
;---------------------------------------------------------------------
IsActorAtDest::
push hl
call GetActorDestLoc
ld a,h
or a
jr z,.returnTrue
xor a
pop hl
ret
.returnTrue
ld a,1
pop hl
ret
;---------------------------------------------------------------------
; Routine: ResetCurPathPos
; Arguments: de - "this"
; Returns: Nothing
; Alters: a,hl
; Description: Sets curPathPos (bits 6:5 of this->frame) to zero
;---------------------------------------------------------------------
ResetCurPathPos:
ld a,OBJBANK ;select object RAM
ld [$ff70],a
ld hl,OBJ_FRAME
add hl,de
ld a,[hl]
and %10011111
ld [hl],a
ret
;---------------------------------------------------------------------
; Routine: IncrementPathPos
; Arguments: de - "this"
; Returns: Nothing
; Alters: a,hl
; Description: Adds 1 to bits 6:5 of this->frame, preserving others
;---------------------------------------------------------------------
IncrementPathPos:
ld a,OBJBANK ;select object RAM
ld [$ff70],a
ld hl,OBJ_FRAME
add hl,de
ld a,[hl]
bit 7,a
jr nz,.bit7WasOne
add %00100000
res 7,a
ld [hl],a
ret
.bit7WasOne
add %00100000
set 7,a
ld [hl],a
ret
;---------------------------------------------------------------------
; Routine: ChooseDirection
; Arguments: [moveAlignPrecision] 0=go to exact spot, 1=+/-1
; de - "this"
; hl - location of destination
; Returns: a - 1 for valid move, 0 for no move
; b - direction of desired move (N,E,S,W)
; Alters: a,b,hl
; Description: Converts current "source" location and destination
; location into x,y coordinates, then picks a direction
; based on the following "dumb-AI" algorithm:
;
; int order = GetDirectionAttemptOrder(sx,sy,dx,dy);
; if(CheckDestEmpty(order[0]))
; { dir = order[0]; return 1;}
; return 0;
;---------------------------------------------------------------------
ChooseDirection:
push bc
push de
ld [moveAlignPrecision],a
call ConvertLocHLToXY
push hl
call GetCurLocation ;into hl
call ConvertLocHLToXY
ld b,h
ld c,l
pop de ;source in bc, dest in de
call GetDirectionAttemptOrder ;check order in A
pop de ;retrieve ptr to this
;check first direction
rlca ;get first direction in 1:0
rlca
ld c,a
and %00000011 ;mask off other choices
ld b,a
xor a
call CheckDestEmpty
or a ;check result
jr z,.checkDir2
.foundDirection
ld a,b ;setup b with direction, return 1
pop bc
ld b,a
ld a,1
ret
.checkDir2
ld a,c
rlca ;get second direction in 1:0
rlca
ld c,a
and %00000011 ;mask off other choices
ld [secondChoiceDirection],a ;save for left/right decision
;ld b,a
;xor a
;call CheckDestEmpty
;or a ;check result
;jr z,.checkDir3
;foundDirection
;ld a,b ;setup b with direction, return 1
;pop bc
;ld b,a
;ld a,1
;ret
.checkDir3
;ld a,c
;rlca ;get third direction in 1:0
;rlca
;ld c,a
;and %00000011 ;mask off other choices
;ld b,a
;xor a
;call CheckDestEmpty
;or a ;check result
;jr z,.checkDir4
;foundDirection
;ld a,b ;setup b with direction, return 1
;pop bc
;ld b,a
;ld a,1
;ret
.checkDir4
;no direction found, load b with desired direction and return
;false
ld a,b
pop bc
ld b,a
xor a
ret
;---------------------------------------------------------------------
; Routine: GetDirectionAttemptOrder
; Arguments: de - x,y of destination
; bc - x,y of origin
; Returns: a - every two bits is a direction to attempt;
; [7:6] is the first direction and so on.
; Alters: a,hl
; Description: Based off the following formula:
;
; if(sx>=dx-2){
; if(sy < dy) order = SWEN;
; else order = NEWS;
; }else if(sy==dy){
; if(sx < dx) order = ESNW;
; else order = WNSE;
; }else{
; offset_x = abs(sx - dx);
; offset_y = abs(sy - dy);
; if(offset_x < offset_y){ //close horizontal gap
; if(sx < dx){
; if(sy < dy) order = ESWN;
; else order = ENWS;
; }else{
; if(sy < dy) order = WSEN;
; else order = WNES;
; }
; }else{ //close vertical gap first
; if(sx < dx){
; if(sy < dy) order = SENW;
; else order = NESW;
; }else{
; if(sy < dy) order = SWNE;
; else order = NWSE;
; }
; }
; }
;
; Note: precision of "cur==dest" depends on current value
; stored in [moveAlignPrecision], e.g. value of 1 yields
; cur>=(dest-1) && cur<=(dest+1)
; e.g. (cur+1)>=dest && (cur-1)<=dest
;---------------------------------------------------------------------
GetDirectionAttemptOrder:
IF 0
;if abs(dx-sx) <= 1 and abs(dy-sY)<=1 then set tolerance to
;zero. dx-sx yields $ff, 0, or 1 - plus one gives 0, 1, or 2
ld h,3
ld a,b
sub d
cp h
jr nc,.afterSetAlignPrecision
ld a,c
sub e
cp h
jr nc,.afterSetAlignPrecision
xor a
ld [moveAlignPrecision],a
.afterSetAlignPrecision
ENDC
ld h,0
ld a,[moveAlignPrecision]
add b
;ld a,b
;add 1
cp d
jr c,.sx_LessThan_dx
ld a,[moveAlignPrecision]
cpl
add 1
add b
cp d
jr c,.sx_Equals_dx
jr z,.sx_Equals_dx
;sx > dx
jr .checkYCoords
.sx_Equals_dx
set 3,h
jr .checkYCoords
.sx_LessThan_dx
set 1,h
.checkYCoords
;ld a,c
;add 1
ld a,[moveAlignPrecision]
add c
cp e
jr c,.sy_LessThan_dy
ld a,[moveAlignPrecision]
cpl
add 1
add c
;sub 3
cp e
jr c,.sy_Equals_dy
jr z,.sy_Equals_dy
;sy>dy
jr .checkOffsets
.sy_Equals_dy
set 2,h
jr .pickOrder
.sy_LessThan_dy
set 0,h
.checkOffsets
bit 3,h
jr nz,.pickOrder
;set bit 4 if abs(sx-dx) < abs(sy-dy)
ld a,b
cp d ;is sx < dx?
jr c,.subtract_sx_from_dx
sub d
jr .getAbsY
.subtract_sx_from_dx
ld a,d
sub b
.getAbsY
ld l,a ;save abs(sx-dx) in l
ld a,c
cp e
jr c,.subtract_sy_from_dy
sub e
jr .haveAbsValues
.subtract_sy_from_dy
ld a,e
sub c
.haveAbsValues
cp l ;is abs(sy-dy) < abs(sx-dx)?
jr nc,.pickOrder ;no, leave bit 4 alone
set 4,h
.pickOrder
ld a,h
add (.orderTable & $ff)
ld l,a
ld a,0 ;not xoring to leave the carry alone
adc ((.orderTable >> 8) & $ff)
ld h,a ;hl is &orderTable[directionFlags]
ld a,[hl]
ret
.orderTable
;first half of table is for closing x-distance first
DB %11000110 ;WNES 0000 sx > dx, sy > dy
DB %11100100 ;WSEN 0001 sx > dx, sy < dy
DB %01001101 ;ENWS 0010 sx < dx, sy > dy
DB %01101100 ;ESWN 0011 sx < dx, sy < dy
DB %11100001 ;WSNE 0100 sy==dy, sx > dx
DB %11100001 ;WSNE 0101 sy==dy, sx > dx (invalid)
DB %01001011 ;ENSW 0110 sy==dy, sx < dx
DB %01001011 ;ENSW 0111 sy==dy, sx < dx (invalid)
DB %00011110 ;NEWS 1000 sx==dx, sy > dy
DB %10110100 ;SWEN 1001 sx==dx, sy < dy
DB %00011110 ;NEWS 1010 sx==dx, sy > dy (invalid)
DB %10110100 ;SWEN 1011 sx==dx, sy < dy (invalid)
DB %00011110 ;NEWS 1100 sx==dx, sy==dy (invalid)
DB %00011110 ;NEWS 1101 sx==dx, sy==dy (invalid)
DB %00011110 ;NEWS 1110 sx==dx, sy==dy (invalid)
DB %00011110 ;NEWS 1111 sx==dx, sy==dy (invalid)
;second half of table is for closing y-distance first
DB %00111001 ;NWSE 0000 sx > dx, sy > dy
DB %10110001 ;SWNE 0001 sx > dx, sy < dy
DB %00011011 ;NESW 0010 sx < dx, sy > dy
DB %10010011 ;SENW 0011 sx < dx, sy < dy
DB %10110100 ;SWEN 0100 sy==dy, sx > dx
DB %10110100 ;SWEN 0101 sy==dy, sx > dx (invalid)
DB %00011110 ;NEWS 0110 sy==dy, sx < dx
DB %00011110 ;NEWS 0111 sy==dy, sx < dx (invalid)
DB %01001011 ;ENSW 1000 sx==dx, sy > dy
DB %11100001 ;WSNE 1001 sx==dx, sy < dy
DB %01001011 ;ENSW 1010 sx==dx, sy > dy (invalid)
DB %11100001 ;WSNE 1011 sx==dx, sy < dy (invalid)
DB %00011110 ;NEWS 1100 sx==dx, sy==dy (invalid)
DB %00011110 ;NEWS 1101 sx==dx, sy==dy (invalid)
DB %00011110 ;NEWS 1110 sx==dx, sy==dy (invalid)
DB %00011110 ;NEWS 1111 sx==dx, sy==dy (invalid)
;---------------------------------------------------------------------
; Routine: SetDesiredDirection
; Arguments: a - (0-3) - direction critter was trying to travel
; when it ran into a wall.
; Returns: Nothing
; Alters: a,hl
; Description: Sets bits 7:6 of this->health to be value passed in
;---------------------------------------------------------------------
SetDesiredDirection:
push bc
rrca
rrca
and %11000000
ld b,a
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
ld hl,OBJ_HEALTH
add hl,de
ld a,[hl]
and %00111111
or b
ld [hl],a
pop bc
ret
;---------------------------------------------------------------------
; Routine: SetMoveLimit / SetFireDirection
; Arguments: a - move limit 0-15
; Returns: Nothing
; Alters: a,hl
; Description: Sets bits 3:0 of the obj->misc to indicate how many
; moves should be made before changing to a new state
;---------------------------------------------------------------------
SetMoveLimit:
SetFireDirection:
push bc
ld b,a
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
ld hl,OBJ_LIMIT
add hl,de
ld a,[hl]
and %11110000
or b
ld [hl],a
pop bc
ret
;---------------------------------------------------------------------
; Routine: GetMoveLimit / GetFireDirection
; Returns: a - value
; Alters: a,hl
; Description: Retrieves bits 3:0 of the obj->limit
;---------------------------------------------------------------------
GetMoveLimit:
GetFireDirection:
ld a,OBJBANK ;select object RAM
ldio [$ff70],a
ld hl,OBJ_LIMIT
add hl,de
ld a,[hl]
and %00001111
ret
;---------------------------------------------------------------------
; Routine: PointToSpecialFlags
; Arguments: de - this
; Returns: Nothing.
; Alters: a,hl
; Description: Sets HL to point to obj->limit.
;---------------------------------------------------------------------
PointToSpecialFlags:
ld a,OBJBANK
ldio [$ff70],a
ld hl,OBJ_LIMIT
add hl,de
ret
;---------------------------------------------------------------------
; Routines: GetMoveRightOfDesiredDir
; GetMoveLeftOfDesiredDir
; Arguments: None.
; Returns: a - 0=no move, 1=move
; b - direction of move if move possible
; Alters: a,b,hl
; Description: Uses the value of this->desiredDirection to determine the
; direction to move right of the major axis. If that
; move is possible, returns 1 and the direction in b.
;---------------------------------------------------------------------
GetMoveRightOfDesiredDir:
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_HEALTH
add hl,de
ld a,[hl]
rlca
rlca
inc a ;"turn" right
and %00000011
ld b,a
xor a
call CheckDestEmpty
ret
GetMoveLeftOfDesiredDir:
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_HEALTH
add hl,de
ld a,[hl]
rlca
rlca
dec a ;"turn" left
and %00000011
ld b,a
xor a
call CheckDestEmpty
ret
;---------------------------------------------------------------------
; Routines: CheckForwardPassage
; Arguments: None.
; Returns: a - 0=no move, 1=move
; b - direction of move if move possible
; Alters: a,hl
; Description: Uses the value of this->desiredDirection along with
; current facing to determine the direction to move
; forward.
; Note: Returns zero if the creature is split between
; tiles (this->frame:2 == 1)
;---------------------------------------------------------------------
CheckForwardPassage:
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FRAME
add hl,de
;check for split tile first
ld a,[hl+]
and %00000100
jr z,.continue
xor a
ret
.continue
inc hl ;state to misc
inc hl ;misc to health
ld a,[hl] ;get health byte
rlca ;bits 7:6 have desired dir
rlca
and %00000011
ld b,a
xor a
call CheckDestEmpty
ret
;---------------------------------------------------------------------
; Routines: DecrementMoveLimit
; Arguments: None.
; Returns: a - moves left = non-zero, no moves = 0
; Alters: a,hl
; Description: Decrements bits 3:0 of this->misc
; Does not decrement if split across tiles
;---------------------------------------------------------------------
DecrementMoveLimit:
push bc
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FRAME
add hl,de
ld a,[hl+] ;check for split tiles
and %00000100
jr z,.continue
pop bc
ld a,1
ret
.continue
inc hl
ld a,[hl]
ld c,a
and %11110000
ld b,a
ld a,c
dec a
and %00001111
or b
ld [hl],a
and %00001111 ;set a to be zero/nonzero
pop bc
ret
BAInit:
push bc
push de
ld a,OBJBANK ;select object RAM
ld bc,8
inc de
inc de
ld hl,.baInitTable
call MemCopy
pop de
pop bc
;setup baUpgrades
push bc
ld hl,baUpgrades
ld [hl],0
ld bc,ITEM_BAHIGHIMPACT
call HasInventoryItem
jr z,.afterSetHighImpactBullets
set UPGRADE_BAHIGHIMPACT,[hl]
.afterSetHighImpactBullets
pop bc
;Load BA's bullet-type
call SaveFGTileInfo
ld a,HERO_BA_FLAG
call SetHeroTileSet
ld de,classBABullet
ld hl,BABULLET_CINDEX
xor a
call LoadAssociatedClass
call GetAssociated
ld b,a
ld a,HERO_BA_FLAG
call SetHeroBulletIndex
call RestoreFGTileInfo
.done
ret
.baInitTable
DB 1,1,$0f,BA_MAX_HEALTH,0,0,0,GROUP_HERO
BAPlayerCheck:
ld b,BA_MAX_HEALTH
call StdPlayerCheckDead
ret z
call StdPlayerGetInput
jr z,.checkButtons
call PlayerValidateMoveAndRedraw
ld a,1
call SetHeroMoved
.noDirPressed
;xor a
;call SetMisc
.checkButtons
call DecrementAttackDelay
or a
jr z,.done
;ld a,HERO_BA_FLAG
call GetHeroJoyInput
bit 4,a ;button A pressed?
jr z,.checkButtonB
call GetFireDirection
ld b,a
cp 4
jr nc,.noStrafe ;button not held down previously
.strafeCheckSplit
;can only fire if not split frame or firing perpendicular
call GetFacing
bit 2,a
jr z,.gotFireDirection
xor b
bit 0,a ;bit zero = 0 if parallel direction
jr z,.gotFireDirection
jr .forceMoveForward ;can't fire
.noStrafe
call GetFacing
and %00000011
ld b,a
call SetFireDirection
.gotFireDirection
ld a,b
call GetLocInFront
push bc
push af
push hl
ld a,l
ld [fireBulletLocation],a
ld a,h
ld [fireBulletLocation+1],a
ld hl,baFireSound
IF UPGRADES
ld a,4 ;four points of damage
ELSE
ld a,2 ;two points of damage
ENDC
call StdFireBullet
ld a,22
call SetAttackDelay
pop hl
pop af
ld b,a
ldio a,[firstMonster]
cp b
pop bc
jr z,.checkUpgrade
jr nc,.afterThrowMonster
.checkUpgrade
ld a,[baUpgrades]
bit UPGRADE_BAHIGHIMPACT,a
jr z,.afterThrowMonster
call ThrowObjAtHLInDirB
.afterThrowMonster
jr .checkButtonB
.forceMoveForward
call GetHeroMoved
;ld a,[baMoved]
or a
jr nz,.checkButtonB
call GetFacing
and %00000011
ld b,a
call PlayerValidateMoveAndRedraw
.checkButtonB
.done
ret
BAPlayerCheckSpace:
ld b,BA_MAX_HEALTH
call StdPlayerCheckDead
ret z
call StdPlayerGetInput
jr z,.checkButtons
;can only move if in different direction than facing
;and not opposite to fire direction
call GetFacing
and %11
cp b
jr z,.checkButtons
call GetFireDirection
cp 4
jr nc,.move
add 2
and %11
cp b
jr z,.checkButtons
.move
call PlayerValidateMoveAndRedraw
ld a,1
call SetHeroMoved
.noDirPressed
;xor a
;call SetMisc
.checkButtons
call DecrementAttackDelay
or a
jp z,.done
;ld a,HERO_BA_FLAG
call GetHeroJoyInput
bit 4,a ;button A pressed?
jp z,.checkButtonB
call GetFireDirection
ld b,a
cp 4
jr nc,.noStrafe ;button not held down previously
.strafeCheckSplit
;can only fire if not split frame or firing perpendicular
call GetFacing
bit 2,a
jr z,.gotFireDirection
xor b
bit 0,a ;bit zero = 0 if parallel direction
jr z,.gotFireDirection
jr .forceMoveForward ;can't fire
.noStrafe
call GetFacing
and %00000011
ld b,a
call SetFireDirection
.gotFireDirection
ld a,b
call GetLocInFront
push bc
push af
push hl
ld a,l
ld [fireBulletLocation],a
ld a,h
ld [fireBulletLocation+1],a
ld hl,baFireSound
IF UPGRADES
ld a,4 ;four points of damage
ELSE
ld a,2 ;two points of damage
ENDC
call StdFireBullet
ld a,22
call SetAttackDelay
;reverse fire direction for travel direction
call GetFacing
and %11
push af
call GetCurLocation
ld a,b
add 2
and %11
push af
call ShiftObjectInDirection
call GetCurLocation
pop af
push af
call ShiftObjectInDirection
call GetCurLocation
pop af
call ShiftObjectInDirection
call GetFacing
and %11111100
ld b,a
pop af
or b
call SetFacing
call StandardRedrawNoCheckSprite
pop hl
pop af
ld b,a
ldio a,[firstMonster]
cp b
pop bc
jr z,.checkUpgrade
jr nc,.afterThrowMonster
.checkUpgrade
ld a,[baUpgrades]
bit UPGRADE_BAHIGHIMPACT,a
jr z,.afterThrowMonster
call ThrowObjAtHLInDirB
.afterThrowMonster
jr .checkButtonB
.forceMoveForward
call GetHeroMoved
;ld a,[baMoved]
or a
jr nz,.checkButtonB
call GetFacing
and %00000011
ld b,a
call PlayerValidateMoveAndRedraw
.checkButtonB
.done
ret
IF 0
BAPlayerCheck:
ld b,BA_MAX_HEALTH
call StdPlayerCheckDead
ret z
call StdPlayerGetInput
jr z,.checkButtons
call PlayerValidateMoveAndRedraw
ld a,1
call SetHeroMoved
.checkButtons
call DecrementAttackDelay
or a
jr z,.done
;ld a,HERO_BA_FLAG
call GetHeroJoyInput
bit 4,a ;button A pressed?
ret z
call HeroSetupFireDirection
ret z
ld a,b
call GetLocInFront
push bc
push af
push hl
ld hl,baFireSound
IF UPGRADES
ld a,4 ;four points of damage
ELSE
ld a,2 ;two points of damage
ENDC
call StdFireBullet
ld a,22
call SetAttackDelay
pop hl
pop af
jr BAThrowMonster
.done
ret
BAThrowMonster:
ld b,a
ldio a,[firstMonster]
cp b
pop bc
jr z,.checkUpgrade
ret nc
.checkUpgrade
ld a,[baUpgrades]
bit UPGRADE_BAHIGHIMPACT,a
ret z
call ThrowObjAtHLInDirB
ret
ENDC
;---------------------------------------------------------------------
; Routine: SetHeroBulletIndex
; Arguments: a - flag of hero (e.g. HERO_BA_FLAG)
; b - bullet index of hero
; Returns: Nothing.
; Alters: af
; Description: Stores the bullet index in the appropriate
; hero0_bullet_index or hero1_bullet_index.
;---------------------------------------------------------------------
SetHeroBulletIndex:
push hl
ld hl,heroJoyIndex
and [hl]
ld a,b
jr nz,.useIndex1 ;note flags are still from AND
.useIndex0
ld [hero0_bullet_index],a
jr .done
.useIndex1
ld [hero1_bullet_index],a
.done
pop hl
ret
;---------------------------------------------------------------------
; Routine: SetHeroTileSet
; Arguments: a - flag of hero (e.g. HERO_BA_FLAG)
; Returns: Nothing.
; Alters: af
; Description: Sets [numFGTiles] to be either 6 or 26 depending on
; who's controlling the hero. Note that the original
; value of [numFGTiles] must be saved and restored
; separately. Also sets [fgDestPtr] and [numClasses]
;---------------------------------------------------------------------
SetHeroTileSet:
push bc
push de
push hl
ld hl,heroJoyIndex
and [hl]
jr nz,.secondTileSet
ld a,6
ld bc,$9060
ld d,1
jr .pickedTileSet
.secondTileSet
ld a,26
ld bc,$91a0
ld d,3
.pickedTileSet
ld [numFGTiles],a
ld a,c
ld [fgDestPtr],a
ld a,b
ld [fgDestPtr+1],a
ld a,[firstHero]
add d
ld [numClasses],a
pop hl
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: GetHeroJoyInput
; Arguments: c - hero class index
; Returns: a - current input from [curJoy0] or [curJoy1]
; Alters: af
;---------------------------------------------------------------------
GetHeroJoyInput:
ld a,[hero0_index]
cp c
jr nz,.useIndex1
ld a,[curJoy0]
ret
.useIndex1
ld a,[curJoy1]
ret
GetAssocJoyInput:
call GetAssociated
push bc
ld b,a
ld a,[hero0_index]
cp b
pop bc
jr nz,.useIndex1
ld a,[curJoy0]
ret
.useIndex1
ld a,[curJoy1]
ret
;---------------------------------------------------------------------
; Routine: SetHeroMoved
; Arguments: a - value to set to (1 or 0)
; c - class index of current hero
; Returns: Nothing.
; Alters: af
;---------------------------------------------------------------------
SetHeroMoved:
push af
ld a,[hero0_index]
cp c
jr nz,.useIndex1
pop af
ld [hero0_moved],a
ret
.useIndex1
pop af
ld [hero1_moved],a
ret
;---------------------------------------------------------------------
; Routine: GetHeroMoved
; Arguments: c - class index of current hero
; Returns: a - "moved" value
; Alters: af
;---------------------------------------------------------------------
GetHeroMoved:
ld a,[hero0_index]
cp c
jr nz,.useIndex1
ld a,[hero0_moved]
ret
.useIndex1
ld a,[hero1_moved]
ret
;---------------------------------------------------------------------
; BS
;---------------------------------------------------------------------
BSInit:
push bc
push de
push hl
push bc
push de
ld a,OBJBANK ;select object RAM
ld bc,8
inc de
inc de
ld hl,.bsInitTable
call MemCopy
pop de
pop bc
;setup bsUpgrades
push bc
ld hl,bsUpgrades
ld [hl],0
ld bc,ITEM_BSSHOOTFAST
call HasInventoryItem
jr z,.afterSetShootFast
set UPGRADE_BSSHOOTFAST,[hl]
.afterSetShootFast
pop bc
;Load BS's bullet-type
call SaveFGTileInfo
ld a,HERO_BS_FLAG
call SetHeroTileSet
ld de,classBSBullet
ld hl,BSBULLET_CINDEX
xor a
call LoadAssociatedClass
call GetAssociated
ld b,a
ld a,HERO_BS_FLAG
call SetHeroBulletIndex
call RestoreFGTileInfo
pop hl
pop de
pop bc
ret
.bsInitTable
DB 1,1,$0f,BS_MAX_HEALTH,0,0,0,GROUP_HERO
BSPlayerCheck:
ld b,BS_MAX_HEALTH
call StdPlayerCheckDead
ret z
call StdPlayerGetInput
jr z,.checkButtons
call PlayerValidateMoveAndRedraw
ld a,1
call SetHeroMoved
.checkButtons
call HeroCheckCanFire
jr z,.done
call GetHeroJoyInput
bit 4,a ;button A pressed?
jr z,.checkButtonB
call HeroSetupFireDirection
jr z,.checkButtonB
ld hl,bsFireSound
ld a,1 ;one point of damage
call StdFireBullet
ld a,[bsUpgrades]
bit UPGRADE_BSSHOOTFAST,a
jr z,.shootSlow
.shootFast
ld a,10
jr .setAttackD
.shootSlow
ld a,18
.setAttackD
call SetAttackDelay
jr .checkButtonB
.checkButtonB
.done
ret
BSPlayerCheckSpace:
ld b,BS_MAX_HEALTH
call StdPlayerCheckDead
ret z
call StdPlayerGetInput
jr z,.checkButtons
;can only move if in different direction than facing
;and not opposite to fire direction
call GetFacing
and %11
cp b
jr z,.checkButtons
call GetFireDirection
cp 4
jr nc,.move
add 2
and %11
cp b
jr z,.checkButtons
.move
call PlayerValidateMoveAndRedraw
ld a,1
call SetHeroMoved
.checkButtons
call HeroCheckCanFire
jr z,.done
call GetHeroJoyInput
bit 4,a ;button A pressed?
jr z,.checkButtonB
call HeroSetupFireDirection
jr z,.checkButtonB
ld hl,bsFireSound
ld a,1 ;one point of damage
call StdFireBullet
ld a,[bsUpgrades]
bit UPGRADE_BSSHOOTFAST,a
jr z,.shootSlow
.shootFast
ld a,10
jr .setAttackD
.shootSlow
ld a,18
.setAttackD
call SetAttackDelay
;reverse fire direction for travel direction
call GetFacing
and %11
push af
call GetCurLocation
ld a,b
add 2
and %11
push af
call ShiftObjectInDirection
call GetCurLocation
pop af
push af
call ShiftObjectInDirection
call GetCurLocation
pop af
call ShiftObjectInDirection
call GetFacing
and %11111100
ld b,a
pop af
or b
call SetFacing
call StandardRedrawNoCheckSprite
;call ThrowObjAtHLInDirB
jr .checkButtonB
.checkButtonB
.done
ret
HeroCheckCanFire:
call DecrementAttackDelay
or a
ret z
call GetAssociated ;has a gun?
or a
ret
HeroSetupFireDirection:
call GetFireDirection
ld b,a
cp 4
jr nc,.noStrafe ;button not held down previously
.strafeCheckSplit
;can only fire if not split frame or firing perpendicular
call GetFacing
bit 2,a
jr z,.gotFireDirection
xor b
bit 0,a ;bit zero = 0 if parallel direction
jr z,.gotFireDirection
jr .forceMoveForward ;can't fire
.noStrafe
call GetFacing
and %00000011
ld b,a
call SetFireDirection
.gotFireDirection
ld a,b
call GetLocInFront
ld a,l
ld [fireBulletLocation],a
ld a,h
ld [fireBulletLocation+1],a
or a
ret
.forceMoveForward
call GetHeroMoved
or a
jr nz,.done
call GetFacing
and %00000011
ld b,a
call PlayerValidateMoveAndRedraw
.done
xor a
ret
;---------------------------------------------------------------------
; HAIKU
;---------------------------------------------------------------------
HaikuInit:
ld a,OBJBANK ;select object RAM
ld bc,8
inc de
inc de
ld hl,.haikuInitTable
call MemCopy
ret
.haikuInitTable
DB 3,1,$0f,HAIKU_MAX_HEALTH,0,0,0,GROUP_HERO
HaikuPlayerCheck:
;am I dead?
ld b,HAIKU_MAX_HEALTH
call StdPlayerCheckDead
ret z
call StdPlayerGetInput
jr z,.checkButtons
call PlayerValidateMoveAndRedraw
or a
jr z,.checkButtons
call GetHeroJoyInput ;no attack if braking
bit JOY_B_BIT,a
jr nz,.checkButtons
call HaikuHitObject
.checkButtons
call DecrementAttackDelay
or a
jr z,.done
call GetHeroJoyInput
bit 4,a ;button A pressed?
jr z,.checkButtonB
;clip to edges of map
;and (JOY_DOWN | JOY_A)
;cp (JOY_DOWN | JOY_A)
;jr nz,.skip
;ld b,b
;.skip
call GetFacing
and %11
ld b,a
call AmAtEdgeInDirection
jr nz,.checkButtonB
call GetFacing
and %00000011
ld b,a
call GetLocInFront
ld a,b
call AdvanceLocHLInDirection
call LocIsPassable
jr z,.checkButtonB
;haiku teleports two squares ahead
call GetFacing
push af
push bc
ld c,a
call RemoveFromMap
pop bc
call SetCurLocation
pop af
push hl
res 2,a ;turn off split
bit 7,a ;sprite?
jr z,.afterFreeSprite
push af
call FreeSpriteLoPtr
pop af
res 7,a
.afterFreeSprite
call SetFacing
pop hl
;----BEGIN call MOVEOVER method
push bc
ld a,[bgFlags]
ld b,a
push af
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
push af
ld a,b
bit BG_BIT_WALKOVER,a
jr z,.afterSetSpriteBit
call GetFacing
set 7,a
call SetFacing
.afterSetSpriteBit
call StandardRedrawNoCheckSprite
pop af
ld c,a
pop af
bit BG_BIT_WALKOVER,a
jr z,.afterAction
ld a,BGACTION_MOVEOVER
call CallBGAction
.afterAction
pop bc
;----END call MOVEOVER method
ld a,15
call SetAttackDelay
jr .checkButtonB
.forceMoveForward
.checkButtonB
.done
ret
HaikuPlayerCheckSpace:
;am I dead?
ld b,HAIKU_MAX_HEALTH
call StdPlayerCheckDead
ret z
call StdPlayerGetInput
jr z,.checkButtons
;can only move if in different direction than facing
;or object in front
ld a,4
call GetLocInFront
or a
jr nz,.move
call GetFacing
and %11
cp b
jr z,.checkButtons
.move
call PlayerValidateMoveAndRedraw
or a
jr z,.checkButtons
call GetHeroJoyInput ;no attack if braking
bit JOY_B_BIT,a
jr nz,.checkButtons
call HaikuHitObject
.checkButtons
call DecrementAttackDelay
or a
jr z,.done
call GetHeroJoyInput
bit 4,a ;button A pressed?
jr z,.checkButtonB
;clip to edges of map
call GetFacing
and %11
ld b,a
call AmAtEdgeInDirection
jr nz,.checkButtonB
call GetFacing
and %00000011
ld b,a
call GetLocInFront
ld a,b
call AdvanceLocHLInDirection
call LocIsPassable
jr z,.checkButtonB
;haiku teleports two squares ahead
call GetFacing
push af
push bc
ld c,a
call RemoveFromMap
pop bc
call SetCurLocation
pop af
push hl
res 2,a ;turn off split
bit 7,a ;sprite?
jr z,.afterFreeSprite
push af
call FreeSpriteLoPtr
pop af
res 7,a
.afterFreeSprite
call SetFacing
pop hl
;----BEGIN call MOVEOVER method
push bc
ld a,[bgFlags]
ld b,a
push af
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
push af
ld a,b
bit BG_BIT_WALKOVER,a
jr z,.afterSetSpriteBit
call GetFacing
set 7,a
call SetFacing
.afterSetSpriteBit
call StandardRedrawNoCheckSprite
pop af
ld c,a
pop af
bit BG_BIT_WALKOVER,a
jr z,.afterAction
ld a,BGACTION_MOVEOVER
call CallBGAction
.afterAction
pop bc
;----END call MOVEOVER method
ld a,15
call SetAttackDelay
jr .checkButtonB
.forceMoveForward
.checkButtonB
.done
ret
HaikuHitObject:
;attack forward
call GetFacing
and %00000011
ld b,a
ld [fireBulletDirection],a
ld a,4
call GetLocInFront
ld a,MAPBANK
ldio [$ff70],a
ldio a,[firstMonster]
ld b,a
ld a,[hl]
cp b
jr nc,.hitMonster
.hitAttackableWall
call HitWall
jr .afterHit
.hitMonster
ld b,a ;index of monster being hit
ld a,l
ld [fireBulletLocation],a
ld a,h
ld [fireBulletLocation+1],a
ld a,1 ;one point of damage
ld [methodParamL],a
ldio a,[curObjWidthHeight]
push af
ld a,[fireBulletDirection]
call HitObject
pop af
ldio [curObjWidthHeight],a
.afterHit
ld hl,haikuSound
call PlaySound
ld a,15
call SetAttackDelay
call GetFacing
ld h,a
add 2
and %00000011
ld l,a
ld a,h
and %11111100
or l
call SetFacing
push bc
call GetFacing
ld c,a
call RemoveFromMap
pop bc
call StandardRedrawNoCheckSprite ;turn around
ret
HaikuTakeDamage:
push bc
push hl
;store object palette color to be the explosion color later
call GetFGAttributes
and %111
ld [bulletColor],a
;take damage only if I'm not facing bullet
call GetFacing
add 2
and %11
ld hl,bulletDirection ;was fireBulletDirection
cp [hl]
jr nz,.notFacingBullet
;take no damage
xor a
pop hl
pop bc
ret
.notFacingBullet
ld a,OBJBANK
ld [$ff70],a
;play the explosion sound effect
ld hl,stdExplosionSound
call PlaySound
;blow off a puff instead of taking damage?
ld hl,OBJ_DESTZONE
add hl,de
ld a,[hl]
and %1111
jr z,.noPuffs
dec [hl]
ld b,METHOD_DRAW
call CallMethod
ld b,1
jr .done
.noPuffs
ld a,[methodParamL]
ld c,a ;c is damage
ld hl,OBJ_HEALTH
add hl,de
ld a,[hl]
;ld b,a
ld b,0
and %00111111
jr z,.done ;already dead
ld b,c ;b is damage inflicted
sub c
jr nc,.notNegative
add c ;original health
ld b,a ;is damage inflicted
xor a ;less than zero is zero
.notNegative
ld c,a
ld a,[hl]
;ld a,b
and %11000000
or c
ld [hl],a
.done
ld a,b ;return damage inflicted
pop hl
pop bc
ret
;---------------------------------------------------------------------
; Hero Lady Flower
;---------------------------------------------------------------------
LadyInit:
;initialize object
push bc
push de
ld a,OBJBANK ;select object RAM
ld bc,8
inc de
inc de
ld hl,.ladyInitTable
call MemCopy
pop de
pop bc
;Load Lady's bullet-type
push bc
push de
call SaveFGTileInfo
ld a,HERO_FLOWER_FLAG
call SetHeroTileSet
ld de,classLadyBullet
ld hl,LADY_BULLET_CINDEX
xor a
call LoadAssociatedClass
call GetAssociated
ld b,a
ld a,HERO_FLOWER_FLAG
call SetHeroBulletIndex
call RestoreFGTileInfo
pop de
pop bc
ret
.ladyInitTable
DB 1,1,$0f,LADY_MAX_HEALTH,0,0,0,GROUP_HERO
LadyPlayerCheck:
ld b,LADY_MAX_HEALTH
call StdPlayerCheckDead
ret z
call LadyGetInput
jr z,.checkButtons
call PlayerValidateMoveAndRedraw
ld a,1
call SetHeroMoved
.checkButtons
call HeroCheckCanFire
jr z,.done
call GetHeroJoyInput
bit 4,a ;button A pressed?
jr z,.checkButtonB
call HeroSetupFireDirection
jr z,.checkButtonB
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl] ;way obstructed?
or a
jr nz,.checkShootOver
ld a,[numFreeObjects]
cp 200
jr c,.done
.checkShootOver ;don't shoot on shootover-only tiles
ldio a,[firstMonster]
push bc
ld b,a
ld a,[hl]
cp b
pop bc
jr nc,.fire
call GetBGAttributes
bit BG_BIT_WALKOVER,a
jr nz,.fire
bit BG_BIT_SHOOTOVER,a
jr nz,.done
.fire
ld hl,ladyFireSound
ld a,1 ;one point of damage
call StdFireBullet
ld a,20
call SetAttackDelay
jr .checkButtonB
.checkButtonB
.done
ret
ladyFireSound:
DB 1,$35,$80,$f3,$00,$c4
LadyGetInput:
call GetHeroJoyInput
bit JOY_A_BIT,a ;check strafe release
jr nz,.afterStrafeRelease ;nope
push af
ld a,15 ;yep
call SetFireDirection
pop af
.afterStrafeRelease
bit JOY_B_BIT,a
jr z,.normalMove
.slowMove
xor a
ret
.normalMove
ld a,2
.testMove
call HeroTestMove
or a
ret z
jp HeroDoSparks
LadyBulletInit:
;ld a,3
;call GetRandomNumMask
;add c
;call ChangeMyClass
ld hl,.pansyInitTable
call StdInitFromTable
ld a,[methodParamL]
and %00000011
ld b,a
call GetFacing
and %11111100
or b
call SetFacing
call PointToSpecialFlags
set OBJBIT_THROWN,[hl]
xor a
call SetMisc
ret
.pansyInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_HERO ;group
DB 1 ;has bullet
DW classPansyBullet ;associated bullet class ptr
DW PANSYBULLET_CINDEX
LadyBulletCheck:
call GetMisc
or a
jr nz,.changedClass
.changedClass
ld hl,.pansyCheckTable
jp StdCheckFromTable
.pansyCheckTable
DB 4 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW pansyFireSound
DB 10 ;fire delay
DW LadyVectorToState
;---------------------------------------------------------------------
; Hero Captain Flour
;---------------------------------------------------------------------
FlourInit:
;initialize object
push bc
push de
ld a,OBJBANK ;select object RAM
ld bc,9
inc de
inc de
ld hl,.flourInitTable
call MemCopy
pop de
pop bc
;Load Captain's bullet-type
push bc
push de
call SaveFGTileInfo
ld a,HERO_FLOUR_FLAG
call SetHeroTileSet
ld de,classFlourBullet
ld hl,FLOUR_BULLET_CINDEX
xor a
call LoadAssociatedClass
call GetAssociated
ld b,a
ld a,HERO_FLOUR_FLAG
call SetHeroBulletIndex
call RestoreFGTileInfo
pop de
pop bc
call LinkAssocToMe
ret
.flourInitTable
DB 1,1,$0f,FLOUR_MAX_HEALTH,0,0,0,GROUP_HERO,1
FlourPlayerCheck:
ld b,FLOUR_MAX_HEALTH
call StdPlayerCheckDead
ret z
call StdPlayerGetInput
jr z,.checkButtons
call PlayerValidateMoveAndRedraw
.checkButtons
call DecrementAttackDelay
or a
jr z,.done
call GetHeroJoyInput
bit 4,a ;button A pressed?
jr z,.done
ld hl,flourAttackSound
call PlaySound
;turn into bullet
xor a
call SetMisc
call ChangeMyClassToAssociatedAndRedraw
.done
ret
flourAttackSound:
DB 1,$43,$81,$f7,$00,$c3
FlourBulletCheck:
call .flourBulletCheckDead
ret z
.checkTimeToMove
;time to move?
ld a,1
call HeroTestMove
or a
ret z
call .flourBulletCheckMain ;move first of two
;ret
call GetHealth
ld b,FLOUR_MAX_HEALTH
call HealthSparks
call GetHealth ;died yet?
or a
ret z
ld a,1 ;no, move again
call .flourBulletCheckMain ;move first of two
call GetHealth ;died yet?
or a
ret z
ld a,1 ;no, move again
.flourBulletCheckMain
or a
jr z,.done ;timer lsb==frame lsb, don't move yet
ldio a,[firstMonster]
ld b,a
ld a,4
call GetLocInFront ;4=in front, split included
or a
jr z,.keepGoing ;nothing in front
cp b ;is a monster or what?
jr nc,.hitMonster
;bg in front flagged as shoot over?
ld a,[bgFlags]
bit BG_BIT_SHOOTOVER,a
jr z,.hitWall
;and BG_FLAG_SHOOTOVER
;jr z,.hitWall
jr .keepGoing
.hitMonster
call .flourBulletHitMonster
ret
.hitWall
call .flourBulletHitWall
ret
.keepGoing
jp .flourBulletKeepGoing
.done
ret
.flourBulletCheckDead
call GetHealth
cp b
jr c,.afterLimitHealth
ld a,b
push af
call SetHealth
pop af
.afterLimitHealth
or a
ret nz
ld a,[amShowingDialog] ;don't die while showing dialog
or a
ret nz
IF INFINITEHEALTH==0
call ChangeMyClassToAssociatedAndRedraw
xor a
ELSE
ld a,1
or a
ENDC
ret
.flourBulletHitMonster
;object in front, hit it for damage
ld b,a ;monster index in b, loc in hl
;get damage
ld a,1
ld [methodParamL],a
ld a,4 ;use direction of this object for expl
call HitObject
call .changeDirection
ret
.flourBulletHitWall
bit BG_BIT_ATTACKABLE,a
jr z,.afterHitWall
ld b,16 ;initial frame
call HitWall
.afterHitWall
call .changeDirection
ret
.flourBulletKeepGoing
call GetMisc ;bounced over three times?
cp 1
jr c,.afterCheckStop
.checkStop
call GetFacing ;can't be split
bit 2,a
jr nz,.afterCheckStopSound ;can't be sprite
bit 7,a
jr nz,.afterCheckStopSound
call ChangeMyClassToAssociatedAndRedraw
ret
.afterCheckStopSound
ld hl,flourAttackSound
call PlaySound
.afterCheckStop
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FRAME ;get current direction
add hl,de
ld a,[hl]
and %00000011 ;keep going same direction
ld b,a
call Move
call StdBulletRedraw ;draw me please
ret
.changeDirection
call GetMisc
inc [hl]
call GetFacing
ld b,a
call GetAssocJoyInput ;allow user to dictate dir of exit
and %1111
jr z,.reverseDir
push bc
call JoyAToDirB
ld a,b
pop bc
push bc
ld c,a
xor b
and %11
ld a,c
pop bc
jr nz,.gotDir
.reverseDir
ld a,2
add b
and %11
.gotDir
;call GetRandomNumZeroToN
;inc a
res 0,b
res 1,b
or b
push af
call SetFacing
pop af
and %11
ld b,a
;call Move
;call StdBulletRedraw
push bc
call GetFacing
ld c,a
call RemoveFromMap
pop bc
call StandardRedrawNoCheckSprite ;turn around
ret
StdPlayerCheckDead:
call GetHealth
cp b
jr c,.afterLimitHealth
ld a,b
push af
call SetHealth
pop af
.afterLimitHealth
or a
ret nz
ld a,[amShowingDialog] ;don't die while showing dialog
or a
ret nz
IF INFINITEHEALTH==0
call RemoveHero
xor a
ELSE
ld a,1
or a
ENDC
ret
StdPlayerGetInput:
;args: b - max health
;returns: z - no move, nz=has move
; b - dir of move
call GetHeroJoyInput
bit JOY_A_BIT,a ;check strafe release
jr nz,.afterStrafeRelease ;nope
push af
ld a,15 ;yep
call SetFireDirection
pop af
.afterStrafeRelease
bit JOY_B_BIT,a
jr z,.normalMove
.slowMove
ld a,2
jr .testMove
.normalMove
ld a,1
.testMove
call HeroTestMove
or a
ret z
;fall through below
;falling through above
HeroDoSparks:
xor a
call SetHeroMoved
call GetHealth
;ld b,HAIKU_MAX_HEALTH ;b should be set up
call HealthSparks
call GetHeroJoyInput
and %1111 ;get directions only
ret z
;jr nz,.checkEast
;jp .checkButtons
call JoyAToDirB
ld a,1
or a
ret
JoyAToDirB:
.checkEast
bit 0,a
jr z,.checkWest
ld b,DIR_EAST
ret
.checkWest
bit 1,a
jr z,.checkNorth
ld b,DIR_WEST
ret
.checkNorth
bit 2,a
jr z,.checkSouth
ld b,DIR_NORTH
ret
.checkSouth
ld b,DIR_SOUTH
ret
;---------------------------------------------------------------------
; Routine: LocIsPassable
; Arguments: hl - location
; Alters: af
; Returns: a - 1 if passable, 0 if not
; [bgFlags]
;---------------------------------------------------------------------
LocIsPassable:
push bc
ldio a,[firstMonster]
ld b,a
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
or a
jr z,.returnTrueSetBG
cp b
jr nc,.returnFalse
call GetBGAttributes
ld [bgFlags],a
bit BG_BIT_WALKOVER,a
jr nz,.returnTrue
.returnFalse
xor a
pop bc
ret
.returnTrueSetBG
call GetBGAttributes
ld [bgFlags],a
.returnTrue
pop bc
ld a,1
or a
ret
;---------------------------------------------------------------------
; Routine: AmAtEdgeInDirection
; Arguments: b - direction
; c - class index of object
; de - this
; Alters: af,hl
; Returns: a - 1=at edge, 0=not at edge
; zflag - or a
;---------------------------------------------------------------------
AmAtEdgeInDirection:
;clip and make sure I'm at least 2 from the edge
call GetCurLocation
call ConvertLocHLToXY
ld a,b
cp DIR_NORTH
jr z,.checkNorth
cp DIR_EAST
jr z,.checkEast
cp DIR_SOUTH
jr z,.checkSouth
.checkWest
ld a,h
cp 2
jr c,.returnTrue
jr .returnFalse
.checkNorth
ld a,l
cp 2
jr c,.returnTrue
jr .returnFalse
.checkEast
;add 1 to X if split
call GetFacing
bit 2,a
jr z,.xOkay
inc h
.xOkay
ld a,[mapWidth]
sub 3
cp h
jr c,.returnTrue
jr .returnFalse
.checkSouth
;add 1 to Y if split
call GetFacing
bit 2,a
jr z,.yOkay
inc l
.yOkay
ld a,[mapHeight]
sub 3
cp l
jr c,.returnTrue
.returnFalse
xor a
ret
.returnTrue
ld a,1
or a
ret
;---------------------------------------------------------------------
; Hero King Grenade
;---------------------------------------------------------------------
GrenadePlayerInit:
;initialize object
push bc
push de
ld a,OBJBANK ;select object RAM
ld bc,9
inc de
inc de
ld hl,.grenadeInitTable
call MemCopy
pop de
pop bc
xor a
call SetMisc
ret
.grenadeInitTable
DB 1,1,$0f,GRENADE_MAX_HEALTH,0,0,0,GROUP_HERO,1
GrenadePlayerCheck:
ld b,GRENADE_MAX_HEALTH
call StdPlayerCheckDead
ret z
call GrenadeGetInput
jr z,.checkButtons
call PlayerValidateMoveAndRedraw
.checkButtons
call DecrementAttackDelay
or a
jp z,.done
call GetHeroJoyInput
bit 4,a ;button A pressed?
jp z,.done
call GetMisc ;already started explosion?
or a
jr nz,.done
ld a,1
call SetMisc
push bc
push de
ld a,3
ld [bulletColor],a
ld a,15
ldio [jiggleDuration],a
call GetCurLocation
call ConvertLocHLToXY
dec h
dec l
call ConvertXYToLocHL
ld bc,$0404
ld de,$1407
call CreateBigExplosion
ld hl,bigExplosionSound
call PlaySound
pop de
pop bc
xor a
call SetHealth
;on correct level $1010 to blow up gate?
ld a,[curLevelIndex]
or a
jr nz,.done
ld a,[curLevelIndex+1]
cp $10
jr nz,.done
call GetCurZone
cp 4
jr nz,.done
ld a,1
ld [levelVars+4],a ;used in $1000 VAR_EXPLODEDGATE
;ld hl,heroesAvailable
;res HERO_GRENADE_BIT,[hl]
call levelCheckRAM ;start gate exploding before death
IF 0
ld a,[hero0_type]
cp HERO_GRENADE_FLAG
jr nz,.resetHero1
;reset hero to bs
ld hl,2056 ;bs
ld a,l
ld [hero0_class],a
ld a,h
ld [hero0_class+1],a
ld a,HERO_BS_FLAG
ld [hero0_type],a
jr .done
.resetHero1
;reset hero to bs
ld hl,2056 ;bs
ld a,l
ld [hero1_class],a
ld a,h
ld [hero1_class+1],a
ld a,HERO_BS_FLAG
ld [hero1_type],a
ENDC
.done
ret
GrenadeGetInput:
call GetHeroJoyInput
bit JOY_A_BIT,a ;check strafe release
jr nz,.afterStrafeRelease ;nope
push af
ld a,15 ;yep
call SetFireDirection
pop af
.afterStrafeRelease
bit JOY_B_BIT,a
jr z,.normalMove
.slowMove
ld a,5
jr .testMove
.normalMove
ld a,4
.testMove
call HeroTestMove
or a
ret z
jp HeroDoSparks
;---------------------------------------------------------------------
; Routine: StdBulletInit
; Arguments: c - class index, de - this
; [methodParamL] - 4:2=color, 1:0=direction
;---------------------------------------------------------------------
StdBulletInit:
push bc
push hl
ld a,OBJBANK
ld [$ff70],a
ld a,[methodParamL]
ld b,a
ld hl,OBJ_FRAME
add hl,de
ld a,b
and %10000011
ld c,a
ld a,[objTimer60ths] ;set to cur timer so no move this round
or c
ld [hl+],a ;set frame
push af ;save frame for later
ld a,1
ld [hl+],a ;move one
ld a,b
and %00011100 ;extract color palette
srl a
srl a
ld [hl+],a ;store in misc
ld a,1
ld [hl+],a ;health = 1
inc hl ;skip nextL
inc hl ;skip nextH
ld a,1
ld [hl+],a ;state=1 (length for long bullets)
ld a,GROUP_FFA
ld [hl+],a ;group = FFA
ld a,[fireBulletDamage]
ld [hl+],a ;DESTL/Damage
inc hl ;skip DESTH
;allocate a sprite if the isSprite flag starts out at 1
pop af ;retrieve frame
bit 7,a ;sprite flag set?
jr z,.afterAlloc
;call AllocateSprite
;ld [hl+],a ;set SPRITELO
.afterAlloc
pop hl
pop bc
ret
YellowBulletInit:
ld hl,methodParamL
ld a,[hl]
and %11100011
or %00010100 ;yellow
ld [hl],a
jp StdBulletInit
StdBulletRedraw:
push bc
push de
push hl
ld a,OBJBANK
ld [$ff70],a
xor a
ld [fgFlags],a
ld hl,OBJ_LIMIT ;get my color
add hl,de
ld b,[hl]
jp StandardDraw
StdCheckDead:
push hl
call GetHealth
pop hl
or a
ret nz
call StandardDie
xor a
ret ;return z flag set
StdCheckTimeToMove:
;time to move?
ld a,[hl+]
ld [checkTemp],a
or a
jr nz,.goAhead
inc a
ret ;return nz - no move but can attack
.goAhead
push hl
call TestMove
pop hl
or a
ret nz ;can move
xor a ;return z
ret ;timer lsb==frame lsb, don't move yet
StdCheckAttack:
.checkAttack
;can I attack yet?
push hl
call DecrementAttackDelay
pop hl
or a
jr nz,.attackOkay
inc hl
.didntFindEnemy
inc hl
inc hl
inc hl
inc hl
jr .skipAttack
.attackOkay
ld a,[hl+]
or a
jr z,.didntFindEnemy
cp 1
jr z,.meleeOnly
;Got an enemy in my sights?
xor a
ld [losLimit],a
call LookForEnemyInLOS ;returns dir of enemy in b
or a
jr z,.didntFindEnemy
jr .foundEnemy
.meleeOnly
ld a,1
ld [losLimit],a
call LookForEnemyInLOS ;returns dir of enemy in b
or a
jr z,.didntFindEnemy
.foundEnemy
;Fire instead of moving
ld a,[curObjWidthHeight]
push af
ld a,[hl+] ;bullet damage
push hl
push af
ld a,[hl+] ;hl = fire sound
ld h,[hl]
ld l,a
pop af ;damage
call StdFireBullet ;b is direction to fire
pop hl
inc hl
inc hl
ld a,[hl+] ;delay
call SetAttackDelay
pop af
ld [curObjWidthHeight],a
;turn to face the direction we just fired
ld a,[checkTemp]
or a
jr z,.skipMove
call GetFacing
and %11
cp b
jr z,.skipMove ;no need to turn
ld a,1
ld [moveAlignPrecision],a
call StandardValidateMoveAndRedraw
jr .skipMove
.skipAttack
ld a,1 ;return nz (go ahead and move)
or a
ret
.skipMove
xor a ;return z (skip move)
ret
StdCheckTalk:
ld a,[dialogNPC_speakerIndex] ;someone else talking?
or a
jr nz,.skipTalk
call GetMisc ;already talked?
or a
ret nz
call GetCurLocation
inc hl
.checkTalkEast
ld b,DIR_EAST
call .getHeroAtHL
or a
jr nz,.foundHero
.checkTalkWest
ld b,DIR_WEST
dec hl
dec hl
call .getHeroAtHL
or a
jr nz,.foundHero
.checkTalkSouth
ld b,DIR_SOUTH
ld a,[mapPitch]
inc hl
call ConvertLocHLToXY
push hl
inc l
call ConvertXYToLocHL
call .getHeroAtHL
pop hl
or a
jr nz,.foundHero
.checkTalkNorth
ld b,DIR_NORTH
dec hl
call ConvertXYToLocHL
call .getHeroAtHL
or a
jr z,.skipTalk
.foundHero
ld a,1
call SetMisc
call GetFacing
and %11
cp b
jr z,.skipMove ;no need to turn
ld a,1
ld [moveAlignPrecision],a
call StandardValidateMoveAndRedraw
jr .skipMove
.skipTalk
ld a,1 ;return nz (go ahead and move)
or a
ret
.skipMove
xor a ;return z (skip move)
ret
.getHeroAtHL
;if a hero is at HL, sets up [dialogNPC*] with appropriate
;values
ld a,MAPBANK
ldio [$ff70],a
push bc
ld a,[hl]
or a
jr z,.checkHero1
push hl
call EnsureTileIsHead
pop hl
ld b,a
ld a,[hero0_index]
or a
jr z,.checkHero1
cp b
jr z,.isHero
.checkHero1
ld a,[hero1_index]
or a
jr z,.notHero
cp b
jr z,.isHero
.notHero
pop bc
xor a
ret
.isHero
pop bc
ld [dialogNPC_heroIndex],a
ld a,c
ld [dialogNPC_speakerIndex],a
ret
StdMove:
ld a,1
ld [moveAlignPrecision],a
ld a,c
ld bc,.vectorToStateReturnAddress
push bc
ld c,a
ld a,[hl+]
ld h,[hl]
ld l,a
or a ;no movement if vector table is zero
jr nz,.jumpToVector
cp h
jr nz,.jumpToVector
pop bc
jr .vectorToStateReturnAddress
.jumpToVector
jp hl
.vectorToStateReturnAddress
or a
ret z
call StandardValidateMoveAndRedraw
.done
ret
;----bullet check methods---------------------------------------------
WizardBulletCheck:
call StdCheckDead
ret z
.checkTimeToMove
;time to move?
ld a,2
call TestMove
or a
jr z,.done ;timer lsb==frame lsb, don't move yet
ldio a,[firstMonster]
ld b,a
ld a,4
call GetLocInFront ;4=in front, split included
or a
jr z,.keepGoing ;nothing in front
cp b ;is a monster or what?
jr nc,.hitMonster
;bg in front flagged as shoot over?
ld a,[bgFlags]
and BG_FLAG_SHOOTOVER
jr z,.hitWall
jr .keepGoing
.hitMonster
;'a' is class index of monster hit, hl it's location
ld b,a
call StandardDie
ld c,b
ld d,h
ld e,l
call FindObject
;perform a random effect on the monster hit
ld a,1
call GetRandomNumMask
or a
jr nz,.checkMonsterRand1
;freeze the monster for a bit
ld a,60
call SetMoveDelay
ret
.checkMonsterRand1
;don't let the monster attack for a bit
ld a,[hero0_index]
cp c
jr z,.setHeroAttackDelay
ld a,[hero1_index]
cp c
jr z,.setHeroAttackDelay
;set monster attack delay
ld a,20
call SetAttackDelay
ret
.setHeroAttackDelay
ld a,200
call SetAttackDelay
ret
.hitWall
call StdBulletHitWall
ret
.keepGoing
jp StdBulletKeepGoing
.done
ret
SuperSuperFastBulletCheck:
call StdCheckDead
ret z
.checkTimeToMove
;time to move?
ld a,1
call TestMove
or a
ret z
call BulletCheckCommon ;move first of two
call GetHealth ;died yet?
or a
ret z
;no, move again
call BulletCheckCommon
call GetHealth ;died yet?
or a
ret z
;no, move yet again
jr BulletCheckCommon
SuperFastBulletCheck:
call StdCheckDead
ret z
.checkTimeToMove
;time to move?
ld a,1
call TestMove
or a
ret z
call BulletCheckCommon ;move first of two
call GetHealth ;died yet?
or a
ret z
ld a,1 ;no, move again
jr BulletCheckCommon
StdBulletCheck:
call StdCheckDead
ret z
.checkTimeToMove
;time to move?
ld a,2
call TestMove
BulletCheckCommon:
or a
jr z,.done ;timer lsb==frame lsb, don't move yet
ldio a,[firstMonster]
ld b,a
ld a,4
call GetLocInFront ;4=in front, split included
or a
jr z,.keepGoing ;nothing in front
cp b ;is a monster or what?
jr nc,.hitMonster
;bg in front flagged as shoot over?
ld a,[bgFlags]
and BG_FLAG_SHOOTOVER
jr z,.hitWall
jr .keepGoing
.hitMonster
call StdBulletHitMonster
ret
;jr .done
.hitWall
call StdBulletHitWall
ret
;jr .done
.keepGoing
jp StdBulletKeepGoing
.done
bulletCheckDone:
ret
StdBulletHitMonster:
;object in front, hit it for damage
ld b,a ;monster index in b, loc in hl
;get damage from object
push hl
call GetBulletDamage
pop hl
ld [methodParamL],a
ld a,4 ;use direction of this object for expl
call HitObject
call StandardDie
ret
StdBulletHitWall:
ld b,16 ;initial frame
call HitWall
call StandardDie
ret
StdBulletKeepGoing:
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FRAME ;get current direction
add hl,de
ld a,[hl]
and %00000011 ;keep going same direction
ld b,a
call Move
call StdBulletRedraw ;draw me please
ret
BASuperFastBulletCheck:
call StdCheckDead
ret z
.checkTimeToMove
;time to move?
ld a,1
call HeroTestMove
or a
ret z
call BABulletCheckCommon ;move first of two
call GetHealth ;died yet?
or a
ret z
ld a,1 ;no, move again
BABulletCheckCommon:
or a
jr z,.done ;timer lsb==frame lsb, don't move yet
ldio a,[firstMonster]
ld b,a
ld a,4
call GetLocInFront ;4=in front, split included
or a
jr z,.keepGoing ;nothing in front
cp b ;is a monster or what?
jr nc,.hitMonster
;bg in front flagged as shoot over?
ld a,[bgFlags]
and BG_FLAG_SHOOTOVER
jr z,.hitWall
jr .keepGoing
.hitMonster
push hl
call StdBulletHitMonster
pop hl
ld a,[baUpgrades]
bit UPGRADE_BAHIGHIMPACT,a
ret z
call GetFacing
and %11
ld b,a
call ThrowObjAtHLInDirB
ret
;jr .done
.hitWall
call StdBulletHitWall
ret
;jr .done
.keepGoing
jp StdBulletKeepGoing
.done
ret
HeroBulletCheck:
;am I dead?
call StdCheckDead
ret z
.checkTimeToMove
;time to move?
ld a,1
call HeroTestMove
jp BulletCheckCommon
HeroSuperFastBulletCheck:
call StdCheckDead
ret z
.checkTimeToMove
;time to move?
ld a,1
call HeroTestMove
or a
ret z
call BulletCheckCommon ;move first of two
call GetHealth ;died yet?
or a
ret z
ld a,1 ;no, move again
jp BulletCheckCommon
ExplodingBulletCheck:
;am I dead?
call GetHealth
or a
jr nz,.checkTimeToMove
call StandardDie
jr .done
.checkTimeToMove
;time to move?
ld a,2
call TestMove
or a
jr z,.done ;timer lsb==frame lsb, don't move yet
ldio a,[firstMonster]
ld b,a
ld a,4
call GetLocInFront ;4=in front, split included
or a
jr z,.keepGoing ;nothing in front
cp b ;is a monster or what?
jr nc,.hitSomething
;bg in front flagged as shoot over?
ld a,[bgFlags]
and BG_FLAG_SHOOTOVER
jr nz,.keepGoing
.hitWall
call GetMoveLimit
and %00000111
ld [bulletColor],a
call GetBulletDamage
ld b,a
call GetCurLocation
call StandardDie
call BombLocation
jr .done
.hitSomething
;get damage from object
push hl
call GetMoveLimit
and %00000111
ld [bulletColor],a
call GetBulletDamage
pop hl
ld b,a
call StandardDie
call BombLocation
jr .done
.keepGoing
call GetFacing
and %00000011 ;keep going same direction
ld b,a
call Move
call StdBulletRedraw ;draw me please
.done
ret
;---------------------------------------------------------------------
; Routine: GetLocInFront
; Arguments: a - 4=in front, same directon, split tile included
; returns zero
; 0-3=this direction AFTER split tile
; c - class index
; de - this
; Returns: a - tile index in front of object
; hl - location in front of object
; [bgFlags] - if tile in front is non-zero bg tile,
; its flags are loaded here
; Alters: af,hl
; Description: For 2x2 creatures facing east or south, returns
; location one tile further away to avoid tail of obj.
;---------------------------------------------------------------------
GetLocInFront:
push bc
push de
cp 4
jr nz,.checkArbitraryAfterSplit
xor a
ld [bgFlags],a
;check in direction of current facing
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FRAME ;get facing
add hl,de
ld a,[hl]
bit 2,a
jr z,.notSplit
;is split, return zero and location in hl
ld h,d
ld l,e ;hl = location
ld a,[hl+]
ld h,[hl]
ld l,a
xor a ;return zero
jr .done
.notSplit
and %00000011 ;left with cur direction in A
.checkArbitraryAfterSplit
ld b,a ;b is dir to check
ld [getLocInitFacing],a
xor a
ld [bgFlags],a
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FRAME ;get facing
add hl,de
ld a,[hl]
bit 2,a
jr nz,.isSplit
;not split, get offset, get location & we're done
call .getLocInHLAndOffsetInDE
jr .addedOnceOrTwice
;ld a,[hl]
;jr .done
.isSplit
;combine desired facing + cur facing in B
rlca
rlca
and %00001100
or b
ld b,a ;B is combo cur facing+desired check
ld hl,getLocSplitTable
add l
ld l,a
ld a,[hl]
or a
jr nz, .addTwice
;add once
call .getLocInHLAndOffsetInDE
jr .addedOnceOrTwice
.addTwice
ldio a,[curObjWidthHeight]
push af
ld a,1
ldio [curObjWidthHeight],a
call .getLocInHLAndOffsetInDE
add hl,de
pop af
ldio [curObjWidthHeight],a
.addedOnceOrTwice
ldio a,[firstMonster]
ld b,a
ld a,[hl]
or a
jr z,.done
cp b
jr nc,.done
;non-zero bg tile, get attribute flags in [bgFlags]
ld e,a
ld d,((bgAttributes>>8) & $ff)
ld a,TILEINDEXBANK
ld [$ff70],a
ld a,[de]
ld [bgFlags],a
ld a,MAPBANK
ld [$ff70],a
ld a,e
.done
pop de
pop bc
ret
.getLocInHLAndOffsetInDE
;location in hl
ld a,OBJBANK
ld [$ff70],a
ld h,d
ld l,e ;hl = location
ld a,[hl+]
ld h,[hl]
ld l,a
;direction offset in de
ld a,MAPBANK
ld [$ff70],a
ld d,((mapOffsetNorth>>8)&$ff) ;add offset to go in front
ld a,b
and %00000011
rla ;times two
add (mapOffsetNorth & $ff)
ld e,a ;de pts to offset
ld a,[de]
ld c,a
inc de
ld a,[de]
ld e,c
ld d,a ;de IS offset
;2x2 creatures facing east or south should be +1 more tile
ldio a,[curObjWidthHeight]
cp 2
jr nz,.afterAdjust
ld a,[getLocInitFacing]
cp 1
jr z,.offsetTimesTwo
cp 2
jr nz,.afterAdjust
.offsetTimesTwo
sla e
rl d
.afterAdjust
add hl,de ;hl += offset
ret
;---------------------------------------------------------------------
; Routine: StdFireBullet
; Arguments: a - amount of damage
; b - direction to fire (0-3) or 4=in dir of facing
; c - class index of firing object
; de - "this"
; hl - ptr to fire sound data for channel 1
; Alters: af
;---------------------------------------------------------------------
StdFireBullet:
push bc
push de
push hl
push hl ;save temp copy of fire sound
ld [fireBulletDamage],a
ld a,1
ld [guardAlarm],a
;save my facing for later
ld a,b
cp 4 ;use current facing if b=4
jr nz,.gotFacing ;otherwise b is facing
call GetFacing
and %00000011
ld b,a
call GetLocInFront
ld a,l
ld [fireBulletLocation],a
ld a,h
ld [fireBulletLocation+1],a
ld a,b
.gotFacing
ld [fireBulletDirection],a
;Position to place bullet
ldio a,[firstMonster]
ld b,a
;ld a,[fireBulletDirection]
;call GetLocInFront ;a is direction
ld a,MAPBANK
ldio [$ff70],a
ld a,[fireBulletLocation]
ld l,a
ld a,[fireBulletLocation+1]
ld h,a
ld a,[hl]
or a
jr z,.okayToFire
cp b
jr nc,.hitMonsterRightAway
ld a,[bgFlags]
bit BG_BIT_SHOOTOVER,a
jr nz,.okayToFire
bit BG_BIT_ATTACKABLE,a
jr nz,.hitWallRightAway
;wall straight ahead, can't fire
pop hl ;get rid of fire sound
jr .done
.hitWallRightAway
ld a,[fireBulletDirection]
ld [bulletDirection],a
call GetFGAttributes
and %111
ld [bulletColor],a
call GetAssociated
push bc
ld c,a
call HitWallAfterSetDirection
pop bc
jr .playFireSound
.hitMonsterRightAway
;object in front, hit it for damage
ld b,a ;monster index in b, loc in hl
ld a,[fireBulletDamage] ;one point of damage
ld [methodParamL],a
ld a,[fireBulletDirection]
call HitObject
pop hl ;fire sound
call PlaySound
jr .done
.okayToFire
;Get class index of bullet
call GetAssociated
ld b,c ;save class index
ld c,a ;retreive class index
;create the bullet
call CreateObject
;init bullet sending my color palette and my facing
ld a,TILEINDEXBANK
ld [$ff70],a
ld l,b ;retrieve my class index
ld h,((fgAttributes>>8) & $ff)
ld a,[hl]
rlca
rlca ;b has palette in 4:2
and %00011100
ld b,a
;retrieve facing
ld a,[fireBulletDirection]
or b
;set isSprite if firing over background
ld b,a
ld a,[bgFlags]
and BG_FLAG_SHOOTOVER
jr z,.doneSetSprite
set 7,b
.doneSetSprite
ld a,b
ld [methodParamL],a ;param is combo color+facing
ld b,METHOD_INIT
call CallMethod
ld b,METHOD_DRAW
call CallMethod
.playFireSound
pop hl ;fire sound
call PlaySound
.done
pop hl
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: CreateBulletOfClass
; Arguments: [fireBulletDamage] - amount of damage
; [fireBulletDirection] - 1:0 - direction to fire
; [bulletColor] - bullet color
; hl - location of bullet origin
; c - class index of bullet
; Alters: af, de
;---------------------------------------------------------------------
CreateBulletOfClass:
push bc
push de
push hl
ld a,[fireBulletDirection]
call AdvanceLocHLInDirection
;Position to place bullet
ldio a,[firstMonster]
ld b,a
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
push af
call GetBGAttributes
ld [bgFlags],a
pop af
or a
jr z,.okayToFire
cp b
jr nc,.hitMonsterRightAway
ld a,[bgFlags]
bit BG_BIT_SHOOTOVER,a
jr nz,.okayToFire
bit BG_BIT_ATTACKABLE,a
jr nz,.hitWallRightAway
;wall straight ahead, can't fire
jr .done
.hitWallRightAway
ld a,[fireBulletDirection]
ld [bulletDirection],a
call HitWallAfterSetDirection
jr .done
.hitMonsterRightAway
;object in front, hit it for damage
ld b,a ;monster index in b, loc in hl
ld a,[fireBulletDamage] ;one point of damage
ld [methodParamL],a
ld a,[fireBulletDirection]
call HitObject
jr .done
.okayToFire
;create the bullet
call CreateObject
ld a,[bulletColor]
and %111
rlca
rlca
ld b,a
ld a,[fireBulletDirection]
or b
;set isSprite if firing over background
ld b,a
ld a,[bgFlags]
and BG_FLAG_SHOOTOVER
jr z,.doneSetSprite
set 7,b
.doneSetSprite
ld a,b
ld [methodParamL],a ;param is combo color+facing
ld b,METHOD_INIT
call CallMethod
ld b,METHOD_DRAW
call CallMethod
.done
pop hl
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: SetFireTimer
; Arguments: a - value to set fire timer to
; Alters: af,hl
;---------------------------------------------------------------------
SetFireTimer:
push af
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FIRETIMER
add hl,de
pop af
ld [hl],a
ret
;---------------------------------------------------------------------
; Routine: DecrementAttackDelay
; Arguments: c - class index of object
; de - "this"
; Returns: a - 1=can attack now, 2=can't attack
; Alters: af,hl
; Description: If this->attackDelay==0 returns 1.
; Otherwise decrements attackDelay and returns zero
;---------------------------------------------------------------------
DecrementAttackDelay:
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FIRETIMER
add hl,de
ld a,[hl]
or a
jr z,.returnTrue
dec [hl]
xor a
ret
.returnTrue
ld a,1
ret
;---------------------------------------------------------------------
; Routine: SetAttackDelay
; Arguments: a - desired attack delay 0-15
; c - class index of object
; de - "this"
; Alters: af,hl
; Description: Stores attack delay in OBJ_FIRETIMER
;---------------------------------------------------------------------
SetAttackDelay::
push bc
ld b,a
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FIRETIMER
add hl,de
ld a,b
ld [hl],a
pop bc
ret
;---------------------------------------------------------------------
; Routine: GetAttackDelay
; Arguments: c - class index of object
; de - "this"
; Returns: a - remaining attack delay
; Alters: af,hl
; Description: Stores attack delay in OBJ_FIRETIMER
;---------------------------------------------------------------------
GetAttackDelay::
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FIRETIMER
add hl,de
ld a,[hl]
ret
;---------------------------------------------------------------------
; Routine: HitObject
; Arguments: a - 0-3=direction of explosion, 4=use this obj 4 dir
; b - class index of monster hit
; c - class index of object
; de - "this"
; hl - map location of monster hit
; [methodParamL] - points of damage
; Alters: af
; Description: Locates the creature that's been hit and calls its
; TAKE_DAMAGE method.
;---------------------------------------------------------------------
HitObject:
push bc
push de
push hl
;Get direction bullet was travelling
cp a,4
jr nz,.gotBulletDirection
;use this objects facing for bullet direction
ld a,OBJBANK
ld [$ff70],a
inc de
inc de
ld a,[de]
.gotBulletDirection
and %11
ld [bulletDirection],a
ld a,l
ld [bulletLocation],a
ld a,h
ld [bulletLocation+1],a
ld a,b ;store monster class index in c
call EnsureTileIsHead
ld d,h ;de stores location of monster
ld e,l
ld c,a ;a is class of monster
call FindObject
ld b,METHOD_TAKE_DAMAGE ;should fill [bulletColor] w/obj color
call CallMethod
or a
jr z,.done ;zero damage, skip explosion
ld b,1
call CreateExplosion
.done
pop hl
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: HitWall
; Arguments: b - initial frame
; c - class index of object
; de - "this"
; hl - map location of wall hit
; [bgFlags]
; [bulletDirection]
; Alters: af,hl
; Description: Creates an explosion over the wall that's been hit
; If wall is flagged as BG_FLAG_ATTACKABLE, wall's
; method is called with BGACTION_HIT.
;---------------------------------------------------------------------
HitWallAfterSetDirection:
push bc
push de
jr HitWallAfterSetDirectionPushedBCDE
HitWall:
push bc
push de
ld a,[bgFlags]
and BG_FLAG_ATTACKABLE
jr z,HitWall_WallNotAttackable
;set bullet's facing
call GetFacing
and %11
;ld [fireBulletDirection],a
ld [bulletDirection],a
;save bullet's damage and color
push hl
call GetDestL
ld [fireBulletDamage],a
call GetMoveLimit
ld [bulletColor],a
pop hl
HitWallAfterSetDirectionPushedBCDE:
;save bullet's class index
ld a,c
ld [bulletClassIndex],a
;set 'b' to directional blast over wall
ld b,1
ld a,l
ld [bulletLocation],a
ld a,h
ld [bulletLocation+1],a
;get the bg tiles color
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
ld c,a
call GetBGAttributes
and %111
push af
ld a,BGACTION_HIT
call CallBGAction
jr z,HitWall_DoneAF
pop af
ld [bulletColor],a
;call GetHealth
;cp 2
;jr nc,.skipSound ;kludge for captain flour
ld hl,stdExplosionSound
call PlaySound
.skipSound
jr HitWall_CreateExplosion
HitWall_WallNotAttackable:
;Get direction bullet was travelling
ld a,OBJBANK
ld [$ff70],a
ld h,d
ld l,e
ld a,[hl+]
ld [bulletLocation],a
ld a,[hl+]
ld [bulletLocation+1],a
;get bullet color
ld hl,OBJ_LIMIT
add hl,de
ld a,[hl]
ld [bulletColor],a
;call GetHealth
;cp 2
;jr nc,.skipSound ;kludge for captain flour
ld hl,bigExplosionSound
call PlaySound
.skipSound
HitWall_CreateExplosion:
call CreateExplosion ;uses b as initial frame
HitWall_Done:
pop de
pop bc
ret
HitWall_DoneAF:
pop af
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: StdTakeDamage
; Arguments: [methodParamL] - points of damage
; c - class index of object
; de - "this"
; Returns: [bulletColor] - color of this obj for explosion
; a - points of damage actually taken by this creature
; Alters: af
;---------------------------------------------------------------------
StdTakeDamage:
push bc
push hl
;store object palette color to be the explosion color later
call GetFGAttributes
and %111
ld [bulletColor],a
ld a,OBJBANK
ld [$ff70],a
;play the explosion sound effect
ld hl,stdExplosionSound
call PlaySound
TakeDamageCommon:
;blow off a puff instead of taking damage?
ld hl,OBJ_DESTZONE
add hl,de
ld a,[hl]
and %1111
jr z,.noPuffs
dec [hl]
ld b,METHOD_DRAW
call CallMethod
jr .resetState
.noPuffs
ld a,[methodParamL]
ld c,a ;c is damage
ld hl,OBJ_HEALTH
add hl,de
ld a,[hl]
;ld b,a
ld b,0
and %00111111
jr z,.done ;already dead
ld b,c ;b is damage inflicted
sub c
jr nc,.notNegative
add c ;original health
ld b,a ;is damage inflicted
xor a ;less than zero is zero
.notNegative
ld c,a
ld a,[hl]
;ld a,b
and %11000000
or c
ld [hl],a
.resetState
;reset state to zero (rethink where I'm going)
ld a,0
call SetState
.done
ld a,b ;return damage inflicted
pop hl
pop bc
ret
;---------------------------------------------------------------------
; Routine: CowboyTakeDamage
; Alters: af
; Description: Pisses the cowboys off (group M becomes enemy)
;---------------------------------------------------------------------
CowboyTakeDamage:
push bc
push de
push hl
xor a
ld b,GROUP_HERO
ld c,GROUP_MONSTERM
call SetFOF
;change any remaining CowboyTalkers to Angry Cowboys
ld bc,classCowboyTalker
ld de,classAngryCowboy
call ChangeClass
;change any regular cowboys to angry cowboys
ld bc,classCowboy
ld de,classAngryCowboy
call ChangeClass
;change music to hoedown music
ld a,BANK(cowboy_gbm)
ld hl,cowboy_gbm
call IsCurMusic
jr z,.afterChangeMusic ;not in cowboy land
ld a,BANK(hoedown_gbm)
ld hl,hoedown_gbm
call InitMusic
.afterChangeMusic
;zero talker index
xor a
ld [dialogBalloonClassIndex],a
pop hl
pop de
pop bc
jp StdTakeDamage
;---------------------------------------------------------------------
; Routine: WallTakeDamage
; Description: Toggles the wall creature between stunned and
; normal.
;---------------------------------------------------------------------
WallTakeDamage:
;change to other state (stunned<->normal)
call ChangeMyClassToAssociatedAndRedraw
ld b,METHOD_DRAW
call CallMethod
.done
xor a
ld [bulletColor],a
ld a,1
ret
;---------------------------------------------------------------------
; Routine: TakeZeroDamage
;---------------------------------------------------------------------
TakeZeroDamage:
xor a
ret
;---------------------------------------------------------------------
; Routine: BulletTakeDamage
; Arguments: [methodParamL] - points of damage
; c - class index of object
; de - "this"
; Returns: [bulletColor] - color of this bullet for explosion
; Alters: af
;---------------------------------------------------------------------
BulletTakeDamage:
push bc
push hl
;store bullet palette color to be the explosion color later
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_LIMIT
add hl,de
ld a,[hl]
and %00000111
ld [bulletColor],a
;play the explosion sound effect
ld hl,stdExplosionSound
call PlaySound
jp TakeDamageCommon
;---------------------------------------------------------------------
; Routine: StdTakeDamage2x2
; Arguments: c - class index of object
; de - this
; Alters: af
; Description: Like StandardTakeDamage except creates 4 explosion
; sprites over the area of the object when it dies.
;---------------------------------------------------------------------
StdTakeDamage2x2:
push bc
push hl
;store object palette color to be the explosion color later
call GetFGAttributes
and %111
ld [bulletColor],a
ld a,OBJBANK
ld [$ff70],a
;play the explosion sound effect
ld hl,stdExplosionSound
call PlaySound
ld a,[methodParamL]
ld c,a ;c is damage
ld b,c ;b is damage actually inflicted
call GetHealth
and %00111111
jr z,.doneReturnZero ;already dead
sub c
jr nc,.notNegative
add c
ld b,a
xor a ;less than zero is zero
.notNegative
ld c,a
ld a,[hl]
and %11000000
or c
ld [hl],a
and %00111111
jr nz,.done
;it's dead; blow up the 2x2 creature
;save original bullet hit location
push bc
ld a,[bulletLocation]
ld l,a
ld a,[bulletLocation+1]
ld h,a
push hl
;create explosions
call GetCurLocation
push hl
ld a,l
ld [bulletLocation],a
ld a,h
ld [bulletLocation+1],a
xor a
call .createExplosion
ld a,[bulletLocation]
inc a
ld [bulletLocation],a
ld a,1
call .createExplosion
pop hl
call ConvertLocHLToXY
inc l
call ConvertXYToLocHL
ld a,l
ld [bulletLocation],a
ld a,h
ld [bulletLocation+1],a
ld a,2
call .createExplosion
ld a,[bulletLocation]
inc a
ld [bulletLocation],a
ld a,3
call .createExplosion
;restore original bullet location
pop hl
ld a,l
ld [bulletLocation],a
ld a,h
ld [bulletLocation+1],a
pop bc
jr .done
.doneReturnZero
ld b,0
.done
ld a,b
pop hl
pop bc
ret
.createExplosion
rlca ;times 8
rlca
rlca
and %00011000
add 32
ld b,a
call CreateExplosion
or a
ret z
;offset sprites +0,+0 to +4,+4
call IndexToPointerHL
ld a,l
add 12
ld l,a
ld l,[hl]
ld h,((spriteOAMBuffer>>8) & $ff)
push hl
call GetFacing
pop hl
bit 2,a
jr z,.afterSetOffset
bit 0,a
jr nz,.eastWest
;facing north/south, add +4 offset
ld a,[hl]
add 4
ld [hl],a
jr .afterSetOffset
.eastWest
inc hl
ld a,[hl]
add 4
ld [hl],a
dec hl
.afterSetOffset
ret
;---------------------------------------------------------------------
; Routine: StandardDie
; Arguments: c - class index of object
; de - this
; Alters: af
; Description: Removes the object from the map and deletes it
;---------------------------------------------------------------------
StandardDie:
push bc
push de
push hl
ld b,c
call GetFacing
ld c,a
call RemoveFromMap
ld c,b
call SuperDie
call DeleteObject
pop hl
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: GetHealth
; Arguments: c - class index of object
; de - this
; Returns: a - number of health points
; Alters: af,hl
;---------------------------------------------------------------------
GetHealth::
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_HEALTH
add hl,de
ld a,[hl]
and %00111111
ret
;---------------------------------------------------------------------
; Routine: SetHealth
; Arguments: a - health to set to
; de - this
; Returns: Nothing.
; Alters: af,hl
;---------------------------------------------------------------------
SetHealth::
push af
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_HEALTH
add hl,de
ld a,[hl]
and %11000000
ld [hl],a
pop af
or [hl]
ld [hl],a
ret
;---------------------------------------------------------------------
; Routine: SetMoveDelay
; Arguments: a - move delay to set to (0-255)
; de - this
; Returns: Nothing.
; Alters: af,hl
;---------------------------------------------------------------------
SetMoveDelay:
push af
ld a,OBJBANK
ldio [$ff70],a
ld hl,OBJ_MOVE
add de
pop af
ld [hl],a
ret
;push bc
;ld b,a
;ld a,OBJBANK
;ldio [$ff70],a
;ld hl,OBJ_MOVE
;add de
;ld a,[hl]
;and %11110000
;or b
;ld [hl],a
;pop bc
;ret
;---------------------------------------------------------------------
; Routine: ConvertLocHLToSpriteCoords
; Arguments: hl - map location
; Returns: hl - h = x, l = y sprite coords
; Alters: af,hl
;---------------------------------------------------------------------
ConvertLocHLToSpriteCoords::
;calculate screen pixel positions
;x = (((tile_x * 8) - (mapLeft * 8)) - pixelOffset_x) + 8
; = (((tile_x - mapLeft) * 8) - pixelOffset_x) + 8
;y = (((tile_y - mapTop) * 8) - pixelOffset_y) + 16
call ConvertLocHLToXY
;----------------------x coordinate---------------------------
ld a,[mapLeft] ;a = -mapLeft
cpl
add 1
add h ;a += tile_x
cp 32 ;any chance of being visible?
jr nc,.returnZero
rlca ;a *= 8
rlca
rlca
ld h,a ;tile_x = a
ld a,[desiredPixelOffset_x]
cpl
add 1
add h
add 8
ld h,a ;tile_x=(tile_x-pixelOffset_x)+8
;----------------------y coordinate---------------------------
ld a,[mapTop] ;a = -mapTop
cpl
add 1
add l ;a += tile_y
cp 32 ;any chance of being visible?
jr nc,.returnZero
rlca ;a *= 8
rlca
rlca
ld l,a ;tile_y = a
ld a,[desiredPixelOffset_y]
cpl
add 1
add l
add 16
ld l,a ;tile_y=(tile_y-pixelOffset_y)+16
ret
.returnZero
ld hl,0 ;sprite not visible
ret
;---------------------------------------------------------------------
; Routine: CreateExplosion
; Arguments: b - 1=moves in direction, >1 initial frame
; c - class index of object (if directed)
; de - this (if directed)
; [bulletColor]
; [bulletLocation]
; Returns: a - explosion object index
; Alters: af
; Description: Creates an explosion sprite positioned over this
; object with this object's color
; Object memory usage for sprites:
; Bytes 0,1: screen coordinate location (x,y)
; Byte 2: frame
; bit[1:0] - direction
; bit[2] - 1 if no direction
; bit[3] - unused
; bit[6:4] - color palette (0-7)
; Byte 3: (move)
; Byte 4: bit[2:0] - animation frame (0-7)
; Byte 10: initial frame (0,8,16,24,32,64,...)
; Byte 12: Lo-Ptr to OAM table position
;---------------------------------------------------------------------
CreateExplosion::
push bc
push de
push hl
call AllocateSprite ;returns sprite OAM lo-ptr in a or $ff
inc a
jr z,.done ;no free sprites for explosion
dec a
ld [methodParamL],a
ld hl,bulletLocation
ld a,[hl+]
ld h,[hl]
ld l,a
call ConvertLocHLToSpriteCoords
ld a,b
cp 1 ;directional or round?
jr nz,.roundExplosion
;directed explosion
xor a
ld [explosionInitialFrame],a
ld a,[bulletColor]
ld b,a
swap b
ld a,[bulletDirection]
and %00000011
or b
jr .aIsSetup
.roundExplosion
ld [explosionInitialFrame],a
ld a,[bulletColor]
swap a
or %00000100
.aIsSetup
ld [methodParamH],a
ld c,CLASS_EXPLOSION
call CreateObject
ld b,METHOD_INIT
call CallMethod
call PointerDEToIndex ;return index of explosion object
.done pop hl
pop de
pop bc
ret
ExplosionInit:
push bc
push de
push hl
push de
ld a,[methodParamL]
call SetSpriteLo
;set up other stuff
ld hl,OBJ_FRAME
add hl,de
ld a,[methodParamH] ;color + direction
ld b,a
ld [hl+],a
inc hl
xor a
ld [hl],a ;anim frame zero
dec hl ;hl = move
ld d,((spriteOAMBuffer>>8) & $ff)
ld a,[methodParamL] ;loptr
ld e,a
ld a,1
ld [hl-],a ;move = 1
dec hl
inc de
ld a,[hl-] ;copy y pixel coordinate
ld [de],a
dec de
ld a,[hl+] ;copy x pixel coordinate
ld [de],a
inc de
inc de ;de pts to pattern
;make hl point to frame lookup table
ld a,b ;get color+dir byte
and %00000111 ;mask off all but dir
add (explosionFrameTable & $ff)
ld l,a
ld h,((explosionFrameTable>>8) & $ff)
ld a,[explosionInitialFrame]
add [hl] ;pattern
ld [de],a
inc de ;de now pts to flags
set 3,l ;hl += 8
ld a,b
swap a
and %00001111
ld b,a
ld a,[hl]
or b
ld b,a
;set flak to be randomly flipped
ld a,[explosionInitialFrame]
cp 64 ;flack or spark?
ld a,b
jr c,.afterFlipFlack
ld a,%01100000
call GetRandomNumMask
.afterFlipFlack
or b
ld [de],a ;store attributes
pop de
;---extra setup-----------------------------------------------
;store initial frame in DESTL
ld a,[explosionInitialFrame]
ld hl,OBJ_DESTL
add hl,de
ld [hl],a
pop hl
pop de
pop bc
ret
ExplosionRedraw:
ExplosionCheck:
push hl
ld a,OBJBANK
ldio [$ff70],a
;Check timer slower for flack & 2x2 explosions
ld hl,OBJ_DESTL ;storage of initial frame
add hl,de
ld a,[hl]
cp 32
jr c,.faster
cp 72
jr nc,.faster
.slower
ld a,3 ;slower
jr .checkMove
.faster
ld a,1
.checkMove
;my turn yet?
call TestMove
or a
jr z,.skipTurn ;timer lsb==frame lsb, don't move yet
ld hl,OBJ_FRAME
add hl,de
ld a,[hl]
bit 2,a ;should explosion move position?
jr nz,.afterMove
;figger out which direction to move
;get ptr to sprite in hl
ld hl,OBJ_SPRITELO
add hl,de
ld l,[hl]
ld h,((spriteOAMBuffer>>8) & $ff)
bit 1,a
jr nz,.moveSouthOrWest
bit 0,a
jr z,.moveNorth
.moveEast
inc hl
inc [hl]
inc [hl]
jr .afterMove
.moveNorth
dec [hl]
dec [hl]
jr .afterMove
.moveSouthOrWest
bit 0,a
jr z,.moveSouth
.moveWest
inc hl
dec [hl]
dec [hl]
jr .afterMove
.moveSouth
inc [hl]
inc [hl]
.afterMove
ld hl,OBJ_LIMIT ;get current frame
add hl,de
inc [hl] ;add one
ld a,[hl+] ;get frame in a
;get lo-ptr to sprite
ld hl,OBJ_SPRITELO
add hl,de
ld l,[hl]
ld h,((spriteOAMBuffer>>8) & $ff)
bit 3,a ;become 8?
jr z,.keepGoing
;run out of frames, delete myself
call SuperDie
call ExplosionDie
jr .skipTurn
.keepGoing
inc hl ;add one to actual sprite frame
inc hl
inc [hl]
.skipTurn
pop hl
ret
ExplosionDie:
call DeleteObject ;delete myself
ret
IdleCantDieCheck:
ret
DoNothingCheck:
;am I dead?
call GetHealth
or a
jr nz,.skipMove
call StandardDie
.skipMove
ret
;---------------------------------------------------------------------
; Routine: StdInitFromTable
; Arguments: hl - table containing
; BYTE initial facing (4 = random)
; BYTE health (last value popped off)
; BYTE monster group (e.g. MONSTER_A)
; BYTE hasBullet
; WORD bullet class ptr
; WORD bullet class index
; Alters: all
; Returns: Nothing.
; Description: Sets
; - state to zero
; - facing to random
; - fire delay to 1
; - group to specified
; - health to specified
; Loads associated bullet class
;---------------------------------------------------------------------
StdInitFromTable:
ld a,[hl+]
cp 4
jr nz,.setFacing
ld a,3
call GetRandomNumZeroToN
.setFacing
push hl
call SetFacing
xor a
call SetState
xor a
call SetFireTimer
pop hl
ld a,[hl+]
push hl
call SetHealth
pop hl
ld a,[hl+]
call SetGroup
push de
ld a,[hl+] ;has bullet?
or a
jr z,.afterLoadAssociated
ld a,[hl+]
ld e,a
ld a,[hl+]
ld d,a
ld a,[hl+]
ld h,[hl]
ld l,a
ld a,1
call LoadAssociatedClass
.afterLoadAssociated
;hl screwed up here
pop de
ret
;---------------------------------------------------------------------
; Routine: StdCheckFromTable
; Arguments: hl - pointer to table containing:
; BYTE move delay
; BYTE attack type (0=no attack,1=melee,2=missile)
; BYTE bullet damage
; WORD fire sound effect address
; BYTE fire delay
; WORD vectore to state routine pointer
; Alters: all
; Returns: Nothing.
;---------------------------------------------------------------------
StdCheckFromTable:
call StdCheckDead
ret z
StdCheckFromTableNotDead:
call StdCheckTimeToMove
ret z
call StdCheckAttack
ret z
call StdMove
ret
ActorSpeed1Check:
ld hl,.actorCheckTable
jp StdCheckFromTable
.actorCheckTable
DB 1 ;move delay
DB 0 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW nullSound
DB 3 ;fire delay
DW ActorVectorToState
GuardCheck:
;this guy can only attack in the direction he's facing
;call GetFacing
;and %00000011
;call SetAttackDirState
call StdCheckDead
ret z
ld hl,.guardCheckTable
call StdCheckFromTableNotDead
;sound the alarm if I attacked recently (attack delay non-zero)
ld a,OBJBANK
ldio [$ff70],a
ld hl,OBJ_FIRETIMER
add hl,de
ld a,[hl]
or a
ret z
ld a,1
ld [guardAlarm],a
ret
.guardCheckTable
DB 4 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW guardFireSound
DB 6 ;fire delay
DW ActorVectorToState
;----bee--------------------------------------------------------------
BeeInit:
ld hl,.beeInitTable
jp StdInitFromTable
.beeInitTable
DB 4 ;initial facing
DB 1 ;health
DB GROUP_MONSTERC ;group
DB 0 ;has bullet
BeeCheck:
push bc
ld bc,ITEM_BUGSPRAY
call HasInventoryItem
pop bc
jr z,.fastCheck
.slowCheck
ld hl,.beeCheckTableSlow
jp StdCheckFromTable
.fastCheck
ld hl,.beeCheckTableFast
jp StdCheckFromTable
.beeCheckTableFast
DB 1 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW beeSound
DB 20 ;fire delay
DW TrackEnemyVectorToState
.beeCheckTableSlow
DB 2 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW beeSound
DB 20 ;fire delay
DW StdVectorToState
;----Stunned Wall-----------------------------------------------------
StunnedWallInit:
ld hl,.stunnedWallInitTable
call StdInitFromTable
jp LinkAssocToMe
.stunnedWallInitTable
DB 4 ;initial facing
DB 63 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classWallCreature
DW WALLCREATURE_CINDEX
StunnedWallCheck:
ld hl,.stunnedWallCheckTable
jp StdCheckFromTable
.stunnedWallCheckTable
DB 0 ;move delay
DB 0 ;attack type (0=no attack,1=melee,2=missile)
DB 0 ;bullet damage
DW nullSound
DB 64 ;fire delay
DW 0
;----Grenade----------------------------------------------------------
GrenadeInit:
ld hl,.grenadeInitTable
jp StdInitFromTable
.grenadeInitTable
DB 4 ;initial facing
DB 3 ;health
DB GROUP_HERO ;group
DB 0 ;has bullet
GrenadeCheck:
call GetHealth
or a
jr nz,.check
call GetCurLocation
ld b,4
call BombLocation
ld hl,bigExplosionSound
call PlaySound
ld a,5
ld [jiggleDuration],a
.check
ld hl,.grenadeCheckTable
jp StdCheckFromTable
.grenadeCheckTable
DB 4 ;move delay
DB 0 ;attack type (0=no attack,1=melee,2=missile)
DB 0 ;bullet damage
DW nullSound
DB 20 ;fire delay
DW TrackEnemyVectorToState
;----Vacuum-----------------------------------------------------------
VacuumInit:
ld hl,.vacuumInitTable
jp StdInitFromTable
.vacuumInitTable
DB 4 ;initial facing
DB 6 ;health
DB GROUP_MONSTERC ;group
DB 0 ;has bullet
VacuumCheck:
call StdCheckDead
ret z
ld hl,.vacuumCheckTable
call StdCheckFromTableNotDead
;handle 'firing' ourselves
;can we attack yet?
call DecrementAttackDelay
or a
ret z
push de
call GetFacing
push af
and %11
call GetLocInFront
pop af
rlca
and %110
push hl
ld l,a
ld a,(mapOffsetNorth & $ff)
add l
ld l,a
ld h,((mapOffsetNorth>>8)&$ff)
ld a,[hl+]
ld e,a
ld a,[hl]
ld d,a
pop hl
xor a
ld [losLimit],a
call ScanDirectionForEnemy ;returns dir of enemy in b
or a
jr z,.doneDE
;suck the enemy towards me
ld a,[fireBulletLocation] ;enemy's location
ld l,a
ld a,[fireBulletLocation+1]
ld h,a
pop de
call GetFacing
add 2
and %11
call ShiftObjectInDirection
ld a,3
call SetAttackDelay
ld hl,.vacuumSuckSound
call PlaySound
ret
.doneDE pop de
ret
.vacuumCheckTable
DB 4 ;move delay
DB 1 ;attack type (0=none,1=melee,2=missile)
DB 1 ;bullet damage
DW .vacuumAttackSound
DB 25 ;fire delay
DW TrackEnemyVectorToState
.vacuumAttackSound
DB 1,$54,$c0,$f2,$00,$83
.vacuumSuckSound
DB 1,$55,$80,$f3,$00,$84
;----Slug-------------------------------------------------------------
SlugInit:
ld hl,.slugInitTable
call StdInitFromTable
ld bc,classSlugTrailBG
call FindClassIndex
jp SetMisc
.slugInitTable
DB 4 ;initial facing
DB 5 ;health
DB GROUP_MONSTERC ;group
DB 0 ;has bullet
SlugCheck:
call GetCurLocation
call GetFacing
and %111
cp %100
jr z,.adjustSouth
cp %111
jr nz,.foundCurLocation
.adjustWest
call ConvertLocHLToXY
inc h
jr .convertBack
.adjustSouth
call ConvertLocHLToXY
inc l
.convertBack
call ConvertXYToLocHL
.foundCurLocation
push hl
call GetHealth
push af
ld hl,.slugCheckTable
call StdCheckFromTable
pop af
or a
jr nz,.notDead
pop af ;dead
ret
.notDead
call GetMisc
ld b,a
pop hl ;retrieve old location
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl] ;empty now?
or a
ret nz ;still something in there
;leave a slime trail
ld [hl],b
jp ResetMyBGSpecialFlags
.slugCheckTable
DB 6 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW .slugFireSound
DB 15 ;fire delay
DW StdVectorToState
.slugFireSound
DB 1,$14,$80,$f0,$00,$c1
;----Wall Creature----------------------------------------------------
WallCreatureInit:
ld hl,.wallCreatureInitTable
call StdInitFromTable
jp LinkAssocToMe
.wallCreatureInitTable
DB 4 ;initial facing
DB 63 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classStunnedWall
DW STUNNEDWALL_CINDEX
WallCreatureCheck:
ld hl,.wallCreatureCheckTable
jp StdCheckFromTable
.wallCreatureCheckTable
DB 4 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW .wallCreatureFireSound
DB 25 ;fire delay
DW TrackEnemyVectorToState
.wallCreatureFireSound
DB 1,$7b,$40,$f0,$00,$c6
;----Small Bee Hive---------------------------------------------------
BigBeeHiveInit:
SmallBeeHiveInit:
ld hl,.smallBeeHiveInitTable
jp StdInitFromTable
.smallBeeHiveInitTable
DB DIR_EAST ;initial facing
DB 5 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classBee ;associated bullet class ptr
DW BEE_CINDEX
SmallBeeHiveCheck:
ld hl,.smallBeeHiveCheckTable
jp StdCheckFromTable
.smallBeeHiveCheckTable
DB 0 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW beeSound
DB 20 ;fire delay
DW 0
;----Scardie----------------------------------------------------------
ScardieInit:
ld hl,.scardieInitTable
jp StdInitFromTable
.scardieInitTable
DB 4 ;initial facing
DB 4 ;health
DB GROUP_FFA ;group
DB 0 ;has bullet
ScardieCheck:
call StdCheckDead
ret z
ld hl,.scardieCheckTable
call StdCheckFromTableNotDead
;test if either hero in zone
call GetCurZone
ld b,a
ld a,1
call GetHeroZone
cp b
jr z,.heroHere
ld a,2
call GetHeroZone
cp b
ret nz
.heroHere
jp ScardieFlee
.scardieCheckTable
DB 2 ;move delay
DB 0 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW nullSound
DB 20 ;fire delay
DW StdVectorToState
;If scardie's dest zone is == cur zone or not moving to zone then pick
;a new dest zone
ScardieFlee:
call GetCurZone
ld b,a
call GetDestZone
or a
jr z,ScardiePickNewZone
cp b
jr z,ScardiePickNewZone
call GetState
or a
ret nz
ld a,1
jp SetState
ScardiePickNewZone:
;starting at my current zone, run through the zone path matrix
;to see what's available
ld a,b
swap a
or b
ld l,a
ld h,((pathMatrix>>8)&$ff)
ld a,WAYPOINTBANK
ldio [$ff70],a
ld b,15
.checkNewZone
push bc ;increment dest zone
ld a,l
add 1
and %1111
ld b,a
ld a,l
and %11110000
or b
ld l,a
and %1111
jr nz,.afterIncL
inc l ;dest zone can't be zero
.afterIncL
pop bc
ld a,[hl]
or a
jr nz,.foundPath
dec b
jr nz,.checkNewZone
ret ;can do nothing
.foundPath
ld a,l
and %1111
call SetDestZone
ld a,1
jp SetState
ScardieTakeDamage:
call ScardieFlee
jp StdTakeDamage
LadyBulletMove:
ld a,[hero0_type]
cp HERO_FLOWER_FLAG
jr nz,.useJoy1
ld hl,curJoy0
jr .gotJoy
.useJoy1
ld hl,curJoy1
.gotJoy
ld a,[hl]
and %1111
ret z
call JoyAToDirB
ld a,1
or a
ret
;----Chomper----------------------------------------------------------
ChomperInit:
ld hl,.chomperInitTable
jp StdInitFromTable
.chomperInitTable
DB 4 ;initial facing
DB 4 ;health
DB GROUP_MONSTERC ;group
DB 0 ;has bullet
ChomperCheck:
ld hl,.chomperCheckTable
call StdCheckDead
ret z
call StdCheckTimeToMove
ret z
call StdCheckAttack
ret z
;see if an enemy is +2 in any direction; if so eat
;through the wall towards it
push hl
call AmAtEdge
jr nz,.stdMove
ld b,0
.checkNextDirection
call GetMapOffset
sla l ;offset times 2
rl h
push de
push hl
call GetCurLocation
pop de
add hl,de
pop de
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
call IsMyEnemy
cp 1
jr nz,.continue
;remove wall if in-between, not split and facing
;correct direction and not a walkover tile
call GetFacing
bit 2,a
;jr nz,.gotDirection
jr nz,.directionToB
and %11
cp b
;jr nz,.gotDirection
jr nz,.directionToB
;remove wall before moving
push de
call GetMapOffset
push hl
call GetCurLocation
pop de
add hl,de
pop de
ld a,MAPBANK
ldio [$ff70],a
ldio a,[firstMonster]
cp [hl]
jr z,.gotDirection
jr c,.gotDirection ;is not a wall
;make sure not walkover
push hl
ld l,[hl]
ld a,TILEINDEXBANK
ld [$ff70],a
ld h,((bgAttributes>>8) & $ff)
ld a,[hl]
pop hl
bit BG_BIT_WALKOVER,a
jr nz,.gotDirection ;is a walkover
ld a,MAPBANK
ldio [$ff70],a
xor a
ld [hl],a
ld hl,eatSound
call PlaySound
.gotDirection
call StandardValidateMoveAndRedraw
pop hl
ret
.directionToB
ld b,a
jr .gotDirection
.continue
inc b
ld a,b
cp 4
jr nz,.checkNextDirection
.stdMove
pop hl
call StdMove ;nothing special found
ret
.chomperCheckTable
DB 5 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW .chomperSound
DB 3 ;fire delay
DW TrackEnemyVectorToState
.chomperSound
DB 1,$59,$00,$f0,$00,$c4
;---------------------------------------------------------------------
; Routine: AmAtEdge
; Arguments: c - class index of object
; de - this
; Alters: af,hl
; Returns: a - 1=at edge, 0=not at edge
; zflag - or a
;---------------------------------------------------------------------
AmAtEdge:
;clip and make sure I'm at least 2 from the edge
call GetCurLocation
call ConvertLocHLToXY
ld a,h
cp 2
jr c,.returnTrue
ld a,l
cp 2
jr c,.returnTrue
ld a,[mapWidth]
sub 3
cp h
jr c,.returnTrue
ld a,[mapHeight]
sub 3
cp l
jr c,.returnTrue
xor a
ret
.returnTrue
ld a,1
or a
ret
;----Reciprocator-----------------------------------------------------
ReciprocatorInit:
ld hl,.reciprocatorInitTable
jp StdInitFromTable
.reciprocatorInitTable
DB 4 ;initial facing
DB 10 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classReciprocatorPowerup
DW RECIPROCATOR_POWERUP_CINDEX
ReciprocatorCheck:
call GetHealth
cp 10
jr nc,.afterChangeToPowerup
jp ChangeMyClassToAssociatedAndRedraw
.afterChangeToPowerup
ld hl,.reciprocatorCheckTable
jp StdCheckFromTable
.reciprocatorCheckTable
DB 10 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW reciprocatorSound
DB 5 ;fire delay
DW TrackEnemyVectorToState
reciprocatorSound:
DB 1,$2e,$80,$f0,$00,$c7
;----ReciprocatorPowerup----------------------------------------------
ReciprocatorPowerupCheck:
;use $c000 as temporary check table, fill in with:
; moveDelay = health;
; bulletDamage = 11 - health;
call GetHealth
ld b,a
ld hl,$c000
ld [hl+],a
ld [hl],1
inc hl
ld a,11
sub b
ld [hl+],a
ld a,(reciprocatorSound & $ff)
ld [hl+],a
ld a,((reciprocatorSound>>8) & $ff)
ld [hl+],a
ld [hl],10
inc hl
ld a,(TrackEnemyVectorToState & $ff)
ld [hl+],a
ld a,((TrackEnemyVectorToState>>8) & $ff)
ld [hl],a
ld hl,$c000
jp StdCheckFromTable
;----Tri--------------------------------------------------------------
TriInit:
ld hl,.triInitTable
jp StdInitFromTable
.triInitTable
DB 4 ;initial facing
DB 4 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classTriling
DW TRILING_CINDEX
TriCheck:
call GetHealth
or a
jr nz,.afterCheckSplit
;split into 3 trilings
call GetCurLocation
push bc
call GetAssociated
ld c,a
ld b,3
.createTrilings
call FindEmptyLocationAround1x1
or a
jr z,.doneCreateTrilings
push de
call CreateInitAndDrawObject
pop de
dec b
jr nz,.createTrilings
.doneCreateTrilings
pop bc
call StandardDie
ret
.afterCheckSplit
ld hl,.triCheckTable
jp StdCheckFromTable
.triCheckTable
DB 12 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW .triSound
DB 25 ;fire delay
DW TrackEnemyVectorToState
.triSound
DB 1,$43,$c0,$f0,$00,$c2
;----Triling----------------------------------------------------------
TrilingInit:
ld hl,.trilingInitTable
jp StdInitFromTable
.trilingInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classTri
DW TRI_CINDEX
TrilingCheck:
call StdCheckDead
ret z
ld hl,.trilingCheckTable
call StdCheckFromTableNotDead
call GetMisc ;mature into adult after 256 cycles
inc a
ld [hl],a
ret nz
jp ChangeMyClassToAssociatedAndRedraw
.trilingCheckTable
DB 3 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW .trilingSound
DB 20 ;fire delay
DW TrackEnemyVectorToState
.trilingSound
DB 1,$43,$c0,$f0,$00,$c4
;----Tree-------------------------------------------------------------
TreeInit:
ld hl,.treeInitTable
jp StdInitFromTable
.treeInitTable
DB DIR_EAST ;initial facing
DB 8 ;health
DB GROUP_MONSTERA ;group
DB 1 ;has bullet
DW classTreeBullet ;associated bullet class ptr
DW TREEBULLET_CINDEX
TreeCheck:
ld hl,.treeCheckTable
jp StdCheckFromTable
.treeCheckTable
DB 0 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW treeFireSound
DB 10 ;fire delay
DW 0
TreeTalkerCheck:
ld hl,.treeTalkerCheckTable
jp TalkerCheckAfterSetupHL
.treeTalkerCheckTable
DB 0 ;move delay
DW 0
;----Bush-------------------------------------------------------------
BushInit:
ld hl,.bushInitTable
jp StdInitFromTable
.bushInitTable
DB DIR_EAST ;initial facing
DB 4 ;health
DB GROUP_MONSTERA ;group
DB 1 ;has bullet
DW classBushBullet ;associated bullet class ptr
DW TREEBULLET_CINDEX
BushCheck:
ld hl,.bushCheckTable
jp StdCheckFromTable
.bushCheckTable
DB 0 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW bushFireSound
DB 15 ;fire delay
DW 0
;----Needle-----------------------------------------------------------
NeedleInit:
ld hl,.needleInitTable
call StdInitFromTable
ld a,3
call SetDestL ;bullet damage
xor a
call SetMoveLimit ;bullet color
xor a
jp SetMisc ;not triggered
.needleInitTable
DB 4 ;initial facing
DB 8 ;health
DB GROUP_MONSTERC
DB 0 ;has bullet
NeedleCheck:
call GetMisc ;triggered?
or a
jr z,.notTriggered
jp SuperFastBulletCheck
.notTriggered
ld hl,.needleCheckTable
call StdCheckDead
ret z
call StdCheckTimeToMove
ret z
call GetFacing
bit 2,a ;split tile?
jr nz,.noEnemy ;don't "fire" on the split tile
xor a
ld [losLimit],a
ld a,4
.lookInAllDirections
push af
call LookForEnemyInLOS
or a
jr nz,.foundEnemy
pop af
dec a
jr nz,.lookInAllDirections
jr .noEnemy
.foundEnemy
pop af
ld a,1
call SetMisc ;mark as triggered
ld hl,.needleTriggeredSound
call PlaySound
call .amFacingB
ret z
;close split tile or turn in dir
push bc
call StandardValidateMoveAndRedraw ;move in dir 'b'
pop bc
call .amFacingB
ret z
;closed split tile, now turn in dir
jp StandardValidateMoveAndRedraw ;move in dir 'b'
.noEnemy
;move forward if possible
call GetFacing
and %11
ld b,a
xor a
call CheckDestEmpty
or a
jr z,.turnInRandomDir
jp StandardValidateMoveAndRedraw
.turnInRandomDir
ld a,%11
call GetRandomNumMask
ld b,a
jp StandardValidateMoveAndRedraw
.amFacingB
call GetFacing ;turn to face enemy
and %11
cp b
ret ;z=1 facing direction of enemy, z=0 not
.needleCheckTable
DB 8 ;move delay
.needleTriggeredSound
DB 1,$15,$00,$f0,$00,$c4
;----Bat--------------------------------------------------------------
BatInit:
ld hl,.batInitTable
call StdInitFromTable
;countdown until turn invisible
ld a,15
call GetRandomNumMask
add 10
call SetMisc
ld b,c ;this->assoc->assoc = this
call GetAssociated
ld c,a
call SetAssociated
ret
.batInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_MONSTERC
DB 1 ;has bullet
DW classInvisibleBat
DW INVISIBLEBAT_CINDEX
BatCheck:
call StdCheckDead
ret z
ld hl,.batCheckTable
call StdCheckFromTableNotDead
call GetAttackDelay ;attacked someone?
or a
jr z,.checkInvisible
ld a,50 ;delay until invisible
call SetMisc
ret
.checkInvisible
call GetMisc
dec a
ld [hl],a
ret nz
jp ChangeMyClassToAssociatedAndRedraw
.batCheckTable
DB 3 ;move delay
DB 1 ;attack type (0=none,1=melee,2=missile)
DB 1 ;bullet damage
DW batFireSound
DB 20 ;fire delay
DW TrackEnemyVectorToState
batFireSound:
DB 1,$35,$00,$f0,$00,$c7
;----Burrower--------------------------------------------------------------
BurrowerInit:
ld hl,.burrowerInitTable
call StdInitFromTable
ld a,10 ;keep track of my health
call SetMisc
ld b,c ;this->assoc->assoc = this
call GetAssociated
ld c,a
call SetAssociated
ret
.burrowerInitTable
DB 4 ;initial facing
DB 10 ;health (above also)
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classBurrowerDirt
DW BURROWER_DIRT_CINDEX
BurrowerCheck:
;burrow if I've taken damage
call GetHealth
ld b,a
call GetMisc
cp b
jr z,.normalCheck ;same health, no burrow
ld a,64 ;cycles until unburrow
call SetMisc
jp ChangeMyClassToAssociatedAndRedraw
.normalCheck
ld hl,.burrowerCheckTable
jp StdCheckFromTable
.burrowerCheckTable
DB 5 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW .burrowerSound
DB 20 ;fire delay
DW TrackEnemyVectorToState
.burrowerSound
DB 1,$2c,$c0,$f0,$00,$c4
;----BurrowerDirt----------------------------------------------------------
BurrowerDirtInit:
ld hl,.burrowerDirtInitTable
jp StdInitFromTable
.burrowerDirtInitTable
DB 4 ;initial facing
DB 10 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classBurrower
DW BURROWER_CINDEX
BurrowerDirtCheck:
;unburrow at end of 64 cycles
call GetMisc
dec [hl]
jr nz,.normalCheck
call GetHealth ;track my health
call SetMisc
jp ChangeMyClassToAssociatedAndRedraw
.normalCheck
ld hl,.burrowerDirtCheckTable
jp StdCheckFromTable
.burrowerDirtCheckTable
DB 7 ;move delay
DB 0 ;attack type (0=no attack,1=melee,2=missile)
DB 0 ;bullet damage
DW nullSound
DB 20 ;fire delay
DW TrackEnemyVectorToState
;----Dandelion--------------------------------------------------------
DandelionInit:
ld hl,.dandelionInitTable
call StdInitFromTable
jp LinkAssocToMe
.dandelionInitTable
DB 1 ;initial facing
DB 1 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classDandelionPuff
DW DANDELIONPUFF_CINDEX
DandelionCheck:
call GetHealth
or a
ret nz
call GetCurLocation
push bc
call GetAssociated
ld c,a
ld b,4
.createPuffs
call FindEmptyLocationAround1x1
or a
jr z,.doneCreatePuffs
push de
call CreateInitAndDrawObject
pop de
dec b
jr nz,.createPuffs
.doneCreatePuffs
pop bc
jp StdCheckDead
;----Dandelion Puff---------------------------------------------------
DandelionPuffInit:
ld hl,.dandelionPuffInitTable
call StdInitFromTable
ld a,255 ;countdown till take root
jp SetMisc
.dandelionPuffInitTable
DB 4 ;initial facing
DB 1 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classDandelion
DW DANDELION_CINDEX
DandelionPuffCheck:
call GetMisc
dec [hl] ;countdown till root
jr nz,.checkAttach
ld a,[numFreeObjects]
cp (255-60)
jr nc,.takeRoot
xor a
jp SetHealth
.takeRoot
call MoveForwardIfSplit
jp ChangeMyClassToAssociatedAndRedraw
.checkAttach
ld hl,.dandelionPuffCheckTable
call StdCheckDead
ret z
call StdCheckTimeToMove
ret z
.checkAttack
ld a,1
ld [losLimit],a
call LookForEnemyInLOS
or a
jr z,.noEnemy
.enemyFound
xor a
call SetHealth ;die next time
ld hl,.dandelionPuffAttackSound
call PlaySound
ld a,[fireBulletLocation] ;location of enemy
ld l,a
ld a,[fireBulletLocation+1]
ld h,a
ld a,MAPBANK
ld [$ff70],a
ld a,[hl] ;enemy class index
call EnsureTileIsHead
ld c,a
ld d,h
ld e,l
call FindObject
call GetPuffCount
cp 15
ret z
add 1
call SetPuffCount
ret
.noEnemy
inc hl
inc hl
inc hl
inc hl
inc hl
jp StdMove
.dandelionPuffCheckTable
DB 4 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 0 ;bullet damage
DW .dandelionPuffAttackSound
DB 1 ;fire delay
DW StdVectorToState
.dandelionPuffAttackSound
DB 1,$7c,$80,$f4,$00,$84
;----Mouse------------------------------------------------------------
MouseInit:
ld hl,.mouseInitTable
jp StdInitFromTable
.mouseInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_HERO ;group
DB 1 ;has bullet
DW classUberMouse ;associated bullet class ptr
DW UBERMOUSE_CINDEX
MouseCheck:
;health >= 5?
call GetHealth
cp 5
jr c,.mouseCheck
;want to become UberMouse
ld a,63
call SetHealth
call GetFacing ;must not be split or sprite
and %10000100
jr nz,.mouseCheck
;adjacent locations must be clear
call GetCurLocation
inc hl
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
or a
jr nz,.mouseCheck ;not empty
ld a,[mapPitch]
add l
ld l,a
ld a,h
adc 0
ld h,a
ld a,[hl-]
or a
jr nz,.mouseCheck
ld a,[hl]
or a
jr nz,.mouseCheck
jp ChangeMyClassToAssociatedAndRedraw
.mouseCheck
ld hl,.mouseCheckTable
jp StdCheckFromTable
.mouseCheckTable
DB 4 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW .mouseFireSound
DB 4 ;fire delay
DW StdVectorToState
.mouseFireSound
DB 1,$17,$80,$f0,$00,$c7
;----Penguin----------------------------------------------------------
PenguinInit:
ld hl,.penguinInitTable
jp StdInitFromTable
.penguinInitTable
DB 4 ;initial facing
DB 5 ;health
DB GROUP_MONSTERB ;group
DB 0 ;has bullet
PenguinCheck:
ld hl,.penguinCheckTable
jp StdCheckFromTable
.penguinCheckTable
DB 3 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW .penguinFireSound
DB 4 ;fire delay
DW TrackEnemyVectorToState
.penguinFireSound
DB 1,$2e,$c0,$f0,$00,$c6
;----BIOS-------------------------------------------------------------
BIOSInit:
ld hl,.BIOSInitTable
jp StdInitFromTable
.BIOSInitTable
DB 4 ;initial facing
DB 4 ;health
DB GROUP_MONSTERA ;group
DB 0 ;has bullet
BIOSCheck:
ld hl,.BIOSCheckTable
jp StdCheckFromTable
.BIOSCheckTable
DB 3 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW .BIOSFireSound
DB 4 ;fire delay
DW TrackEnemyVectorToState
.BIOSFireSound
DB 1,$01,$00,$f0,$00,$c4
;----Crouton Hulk-----------------------------------------------------
CroutonHulkInit:
ld hl,.croutonHulkInitTable
jp StdInitFromTable
.croutonHulkInitTable
DB 4 ;initial facing
DB 10 ;health
DB GROUP_MONSTERA ;group
DB 1 ;has bullet
DW classCroutonBullet ;associated bullet class ptr
DW CROUTONBULLET_CINDEX
CroutonHulkCheck:
ld hl,.croutonHulkCheckTable
jp StdCheckFromTable
.croutonHulkCheckTable
DB 4 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW hulkFireSound
DB 5 ;fire delay
DW TrackEnemyVectorToState
CroutonGruntInit:
ld hl,.croutonGruntInitTable
jp StdInitFromTable
.croutonGruntInitTable
DB 4 ;initial facing
DB 5 ;health
DB GROUP_MONSTERA ;group
DB 0 ;has bullet
;----Crouton Grunt----------------------------------------------------
CroutonGruntCheck:
ld hl,.croutonGruntCheckTable
jp StdCheckFromTable
.croutonGruntCheckTable
DB 4 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW gruntFireSound
DB 5 ;fire delay
DW TrackEnemyVectorToState
;----Wolf-------------------------------------------------------------
WolfSheepInit:
ld hl,.wolfSheepInitTable
jp StdInitFromTable
.wolfSheepInitTable
DB 4 ;initial facing
DB 3 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classWolf ;associated bullet class ptr
DW WOLF_CINDEX
WolfInit:
ld hl,.wolfInitTable
call StdInitFromTable
call LinkAssocToMe
jp ChangeMyClassToAssociatedAndRedraw
.wolfInitTable:
DB 4 ;initial facing
DB 3 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classWolfSheep ;associated bullet class ptr
DW SHEEP_CINDEX
WolfCheck:
call StdCheckDead
ret z
ld hl,.wolfCheckTable
call StdCheckFromTableNotDead
call GetAttackDelay
or a
jr z,.checkChangeToSheep
ld a,100 ;delay until I can change back
call SetMisc
ret
.checkChangeToSheep
;turn back into a sheep after bit
call GetMisc ;countdown until sheep
dec a
ld [hl],a
ret nz
jp ChangeMyClassToAssociatedAndRedraw
.wolfCheckTable:
DB 2 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW wolfFireSound
DB 6 ;fire delay
DW TrackEnemyVectorToState
WolfSheepCheck:
call StdCheckDead
ret z
ld hl,.wolfSheepCheckTable
call StdCheckFromTableNotDead
;turn into a wolf if I attacked somebody
call GetAttackDelay ;attacked this round?
or a
ret z
;change into wolf
ld a,100 ;delay until I can change back
call SetMisc
jp ChangeMyClassToAssociatedAndRedraw
.wolfSheepCheckTable:
DB 5 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW wolfFireSound
DB 6 ;fire delay
DW TrackEnemyVectorToState
wolfFireSound:
DB 1,$1d,$40,$f2,$00,$82
WolfSheepTakeDamage:
call StdTakeDamage
;change into wolf
ld a,100 ;delay until I can change back
call SetMisc
jp ChangeMyClassToAssociatedAndRedraw
;---------------------------------------------------------------------
; LinkAssocToMe
;---------------------------------------------------------------------
LinkAssocToMe:
push bc
ld b,c ;this->assoc->assoc = this
call GetAssociated
ld c,a
call SetAssociated
pop bc
ret
;----Snake------------------------------------------------------------
SnakeInit:
ld hl,.snakeInitTable
jp StdInitFromTable
.snakeInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_MONSTERC ;group
DB 0 ;has bullet
SnakeCheck:
push bc
ld bc,ITEM_SNAKEBITEKIT
call HasInventoryItem
pop bc
jr z,.checkNoKit
.checkWithKit
ld hl,.snakeCheckTable
jp StdCheckFromTable
.checkNoKit
ld hl,.snakeCheckTableNoKit
jp StdCheckFromTable
.snakeCheckTable
DB 3 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW .snakeFireSound
DB 4 ;fire delay
DW TrackEnemyVectorToState
.snakeCheckTableNoKit
DB 3 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 20 ;bullet damage
DW .snakeFireSound
DB 4 ;fire delay
DW TrackEnemyVectorToState
.snakeFireSound
DB 4,$00,$f3,$41,$80
;----Neanderthal------------------------------------------------------
NeanderthalInit:
ld hl,.neanderthalInitTable
call StdInitFromTable
ld a,4
jp SetMisc ;direction throwing enemy 4=none
.neanderthalInitTable
DB 4 ;initial facing
DB 6 ;health
DB GROUP_MONSTERD ;group
DB 0 ;has bullet
NeanderthalCheck:
ld hl,.neanderthalCheckTable
call StdCheckDead
ret z
call StdCheckTimeToMove
ret z
call .neanderthalCheckAttack
ret z
call StdMove
ret
.neanderthalCheckTable
DB 4 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW .neanderthalAttackSound
DB 20 ;fire delay
DW TrackEnemyVectorToState
.neanderthalCheckAttack
;can I attack yet?
push hl
call DecrementAttackDelay
pop hl
or a
jr nz,.attackOkay
inc hl
.didntFindEnemy
inc hl
inc hl
inc hl
inc hl
jr .skipAttack
.attackOkay
ld a,[hl+]
.meleeOnly
ld a,1
ld [losLimit],a
call LookForEnemyInLOS ;returns dir of enemy in b
or a
jr z,.didntFindEnemy
.foundEnemy
;Fire instead of moving
ld a,[curObjWidthHeight]
push af
ld a,[hl+] ;bullet damage
push hl
push af
ld a,[hl+] ;hl = fire sound
ld h,[hl]
ld l,a
pop af ;damage
call StdFireBullet ;b is direction to fire
pop hl
inc hl
inc hl
ld a,[hl+] ;delay
call SetAttackDelay
;throw enemy object away from us
push hl
ld a,[fireBulletLocation]
ld l,a
ld a,[fireBulletLocation+1]
ld h,a
call ThrowObjAtHLInDirB
pop hl
pop af
ld [curObjWidthHeight],a
;turn to face the direction we just fired
call GetFacing
and %11
cp b
jr z,.skipMove ;no need to turn
ld a,1
ld [moveAlignPrecision],a
call StandardValidateMoveAndRedraw
jr .skipMove
.skipAttack
ld a,1 ;return nz (go ahead and move)
or a
ret
.skipMove
xor a ;return z (skip move)
ret
.neanderthalAttackSound
DB 1,$79,$c0,$f3,$00,$c3
ThrowObjAtHLInDirB:
push bc
push de
push hl
ldio a,[curObjWidthHeight]
push af
ld a,MAPBANK
ldio [$ff70],a
ldio a,[firstMonster]
ld c,a
ld a,[hl]
cp c
jr c,.done ;no monster here
call EnsureTileIsHead
ld d,h
ld e,l
ld c,a
call GetFGAttributes
and FLAG_NOTHROW
jr nz,.done
call FindObject
call SetObjWidthHeight
call StandardValidateMoveAndRedraw
call StandardValidateMoveAndRedraw
call PointToSpecialFlags
set OBJBIT_THROWN,[hl]
;set timer to current-1 to ensure this moves next check
ld hl,OBJ_FRAME
add hl,de
ld a,[hl]
and %11100111
ld b,a
ld a,[objTimer60ths]
sub %00001000
and %00011000
or b
ld [hl+],a
ld [hl],1 ;can move next turn
.done
pop af
ldio [curObjWidthHeight],a
pop hl
pop de
pop bc
ret
;----Crow-------------------------------------------------------------
CrowInit:
ld hl,.crowInitTable
call StdInitFromTable
ld hl,0
call SetFoodIndexRange
ret
.crowInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_MONSTERC ;group
DB 0 ;has bullet
CrowCheck:
ld hl,.crowCheckTable
jp StdCheckFromTable
.crowCheckTable
DB 4 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW .crowSound
DB 20 ;fire delay
DW EatVectorToState
.crowSound
DB 1,$4c,$80,$f0,$00,$c5
;----Scarecrow--------------------------------------------------------
ScarecrowInit:
ld hl,.scarecrowInitTable
jp StdInitFromTable
.scarecrowInitTable
DB 1 ;initial facing
DB 20 ;health
DB GROUP_MONSTERN ;group
DB 0 ;has bullet
ScarecrowCheck:
ld hl,.crowCheckTable
jp StdCheckFromTable
.crowCheckTable
DB 0 ;move delay
DB 0 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW nullSound
DB 20 ;fire delay
DW 0
ScarecrowTakeDamage:
;call GetFacing
;xor %10
;call SetFacing
;ld b,METHOD_DRAW
;call CallMethod
jp StdTakeDamage2x2
;----Alligator--------------------------------------------------------
AlligatorInit:
ld hl,.alligatorInitTable
jp StdInitFromTable
.alligatorInitTable
DB 4 ;initial facing
DB 13 ;health
DB GROUP_MONSTERC ;group
DB 0 ;has bullet
AlligatorCheck:
call StdCheckDead
ret z
;save original facing
call GetFacing
and %00000011
push af
ld hl,.alligatorCheckTable
call StdCheckFromTableNotDead
;if facing changes set move delay to 10
call GetFacing
and %00000011
pop bc
cp b
ret z
ld a,10
call SetMoveDelay
ret
.alligatorCheckTable
DB 2 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW .alligatorAttackSound
DB 5 ;fire delay
DW TrackEnemyVectorToState
.alligatorAttackSound
DB 1,$d9,$00,$f0,$00,$c4
;----Scorpion---------------------------------------------------------
ScorpionInit:
ld hl,.scorpionInitTable
jp StdInitFromTable
.scorpionInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_MONSTERC
DB 0 ;has bullet
ScorpionCheck:
ld hl,.scorpionCheckTable
call StdCheckDead
ret z
call StdCheckTimeToMove
ret z
call .scorpionCheckAttack
ret z
call StdMove
ret
.scorpionCheckAttack
;can I attack yet?
push hl
call DecrementAttackDelay
pop hl
or a
jr nz,.attackOkay
inc hl
.didntFindEnemy
inc hl
inc hl
inc hl
inc hl
jr .skipAttack
.attackOkay
ld a,[hl+]
.meleeOnly
ld a,1
ld [losLimit],a
call LookForEnemyInLOS ;returns dir of enemy in b
or a
jr z,.didntFindEnemy
.foundEnemy
;Fire instead of moving
ld a,[curObjWidthHeight]
push af
ld a,[hl+] ;bullet damage
push hl
push af
ld a,[hl+] ;hl = fire sound
ld h,[hl]
ld l,a
pop af ;damage
call StdFireBullet ;b is direction to fire
pop hl
inc hl
inc hl
ld a,[hl+] ;delay
call SetAttackDelay
;freeze enemy
push bc
push de
push hl
ld a,[fireBulletLocation]
ld l,a
ld a,[fireBulletLocation+1]
ld h,a
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
call EnsureTileIsHead
ld d,h
ld e,l
ld c,a
call FindObject
;freeze the enemy for a bit
call GetHealth
or a
jr z,.afterFreeze
ld a,60
call SetMoveDelay
call GetHealth ;deal 1 point of damage
dec a ;(so can't get stuck with Haiku)
call SetHealth
.afterFreeze
pop hl
pop de
pop bc
pop af
ld [curObjWidthHeight],a
;turn to face the direction we just fired
call GetFacing
and %11
cp b
jr z,.skipMove ;no need to turn
ld a,1
ld [moveAlignPrecision],a
call StandardValidateMoveAndRedraw
jr .skipMove
.skipAttack
ld a,1 ;return nz (go ahead and move)
or a
ret
.skipMove
xor a ;return z (skip move)
ret
.scorpionCheckTable
DB 5 ;move delay
DB 1 ;attack type (0=none,1=melee,2=missile)
DB 1 ;bullet damage
DW scorpionFireSound
DB 15 ;fire delay
DW StdVectorToState
scorpionFireSound:
DB 1,$3b,$c0,$f0,$00,$c4
;----Bow--------------------------------------------------------------
BowInit:
ld hl,.bowInitTable
jp StdInitFromTable
.bowInitTable
DB 4 ;initial facing
DB 3 ;health
DB GROUP_MONSTERC
DB 1 ;has bullet
DW classArrowBullet
DW ARROWBULLET_CINDEX
BowCheck:
ld hl,.bowCheckTable
jp StdCheckFromTable
.bowCheckTable
DB 3 ;move delay
DB 2 ;attack type (0=none,1=melee,2=missile)
DB 2 ;bullet damage
DW bowFireSound
DB 8 ;fire delay
DW StdVectorToState
bowFireSound:
DB 1,$25,$00,$f0,$00,$c3
;----Cowboy-----------------------------------------------------------
CowboyInit:
ld hl,.cowboyInitTable
jp StdInitFromTable
.cowboyInitTable
DB 4 ;initial facing
DB 4 ;health
DB GROUP_MONSTERM ;friends
DB 1 ;has bullet
DW classCowboyBullet
DW COWBOYBULLET_CINDEX
CowboyCheck:
ld hl,.cowboyCheckTable
jp StdCheckFromTable
.cowboyCheckTable
DB 3 ;move delay
DB 2 ;attack type (0=none,1=melee,2=missile)
DB 1 ;bullet damage
DW cowboyFireSound
DB 6 ;fire delay
DW StdVectorToState
cowboyFireSound:
DB 4,$00,$f2,$42,$80
AngryCowboyCheck:
ld hl,.cowboyCheckTable
jp StdCheckFromTable
.cowboyCheckTable
DB 2 ;move delay
DB 2 ;attack type (0=none,1=melee,2=missile)
DB 1 ;bullet damage
DW cowboyFireSound
DB 6 ;fire delay
DW TrackEnemyVectorToState
;----Crouton Doctor / Guard-------------------------------------------
CroutonDoctorInit:
ld hl,.croutonDoctorInitTable
jp StdInitFromTable
.croutonDoctorInitTable
DB 4 ;initial facing
DB 3 ;health
DB GROUP_MONSTERA ;group
DB 1 ;has bullet
DW classCroutonBullet ;associated bullet class ptr
DW CROUTONBULLET_CINDEX
CroutonDoctorCheck:
ld hl,.croutonDoctorCheckTable
jp StdCheckFromTable
.croutonDoctorCheckTable
DB 4 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW guardFireSound
DB 6 ;fire delay
DW TrackEnemyVectorToState
;----Crouton Wizard---------------------------------------------------
CroutonWizardInit:
ld hl,.croutonWizardInitTable
jp StdInitFromTable
.croutonWizardInitTable
DB 4 ;initial facing
DB 3 ;health
DB GROUP_MONSTERA ;group
DB 1 ;has bullet
DW classWizardBullet ;associated bullet class ptr
DW WIZARDBULLET_CINDEX
CroutonWizardCheck:
ld hl,.croutonWizardCheckTable
jp StdCheckFromTable
.croutonWizardCheckTable
DB 4 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 0 ;bullet damage
DW .wizardFireSound
DB 6 ;fire delay
DW TrackEnemyVectorToState
.wizardFireSound
DB 1,$34,$40,$f6,$00,$81
;----Big Bee Hive-----------------------------------------------------
BigBeeHiveCheck:
;randomly create a bee every so often
ld a,127
call GetRandomNumMask
or a
jr nz,.afterCreateBee
ld a,[numFreeObjects]
cp (255-32)
jr c,.afterCreateBee
call FindEmptyLocationAround2x2
ld a,h
or a
jr z,.afterCreateBee
push bc
push de
ld bc,classBee
call FindClassIndex
or a
jr z,.afterCreateObject
ld c,a
call CreateInitAndDrawObject
.afterCreateObject
pop de
pop bc
.afterCreateBee
ld hl,.bigBeeHiveCheckTable
jp StdCheckFromTable
.bigBeeHiveCheckTable
DB 0 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW beeSound
DB 20 ;fire delay
DW 0
;----Sheep------------------------------------------------------------
SheepCheck:
call GetHealth
or a
jr nz,.afterChangeToDrumstick
call GetCurLocation
push hl
call StandardDie
pop hl
ld bc,classDrumstickBG
call FindClassIndex
push af
ld a,MAPBANK
ldio [$ff70],a
pop af
ld [hl],a
jp ResetMyBGSpecialFlags
.afterChangeToDrumstick
jp GenericCheck
;----Chicken----------------------------------------------------------
ChickenInit:
ld hl,.chickenInitTable
jp StdInitFromTable
.chickenInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_MONSTERB ;group
DB 1 ;has bullet
DW classEgg
DW EGG_CINDEX
ChickenCheck:
;lay egg?
ld a,255
call GetRandomNumMask
or a
jr nz,.afterLayEgg
ldio a,[updateTimer]
and %11
or a
jr nz,.afterLayEgg
ld a,[numFreeObjects]
cp 200
jr c,.afterLayEgg
push bc
call GetAssociated
ld c,a
call FindEmptyLocationAround1x1
or a
jr z,.afterCreateEgg
push de
call CreateInitAndDrawObject
pop de
.afterCreateEgg
pop bc
.afterLayEgg
ld hl,.chickenCheckTable
jp StdCheckFromTable
.chickenCheckTable
DB 5 ;move delay
DB 0 ;attack type (0=no attack,1=melee,2=missile)
DB 0 ;bullet damage
DW nullSound
DB 30 ;fire delay
DW StdVectorToState
;----Wisp-------------------------------------------------------------
WispInit:
ld hl,.wispInitTable
jp StdInitFromTable
.wispInitTable
DB 4 ;initial facing
DB 1 ;health
DB GROUP_MONSTERC ;group
DB 0 ;has bullet
WispCheck:
ld hl,.wispCheckTable
call StdCheckDead
ret z
call StdCheckTimeToMove
ret z
call .wispCheckAttack
ret z
call StdMove
ret
.wispCheckAttack
;can I attack yet?
push hl
call DecrementAttackDelay
pop hl
or a
jr nz,.attackOkay
inc hl
.didntFindEnemy
inc hl
inc hl
inc hl
inc hl
jp .skipAttack
.attackOkay
ld a,[hl+]
.meleeOnly
ld a,1
ld [losLimit],a
call LookForEnemyInLOS ;returns dir of enemy in b
or a
jr z,.didntFindEnemy
.foundEnemy
;Fire instead of moving
ld a,[curObjWidthHeight]
push af
ld a,[hl+] ;bullet damage
push hl
push af
ld a,[hl+] ;hl = fire sound
ld h,[hl]
ld l,a
pop af ;damage
call StdFireBullet ;b is direction to fire
pop hl
inc hl
inc hl
ld a,[hl+] ;delay
call SetAttackDelay
push bc
;exchange enemy with another randomly selected wisp
ld a,c
call CountNumObjects
dec a
jr z,.afterExchange
call GetRandomNumZeroToN
ld b,a
inc b
push bc ;save my class and object
push de
call GetFirst
dec b
jr z,.foundRemoteWisp
.findWisp
call GetNextObject
dec b
jr nz,.findWisp
.foundRemoteWisp
;save remote wisp's class and object
push bc
push de
call GetCurLocation
push hl
call .wispRemove
call GetFireTargetAsObject
call GetCurLocation
push hl
call .wispRemove
ld hl,sp+2 ;other object's location
ld a,[hl+]
ld h,[hl]
ld l,a
call SetCurLocation
ld b,METHOD_DRAW
call CallMethod
;reset camera if it was the hero that was moved
LDHL_CURHERODATA HERODATA_OBJ
ld a,[hl+]
cp e
jr nz,.afterResetCamera
ld a,[hl+]
cp d
jr nz,.afterResetCamera
call AdjustCameraToHero
call RestrictCameraToBounds
ld a,[desiredMapLeft]
ld [mapLeft],a
ld a,[desiredMapTop]
ld [mapTop],a
.afterResetCamera
pop hl
pop de ;first location(discard)
pop de ;first object
pop bc
call SetCurLocation
ld b,METHOD_DRAW
call CallMethod
.exchangeDone
pop de
pop bc
.afterExchange
pop bc
pop af
ld [curObjWidthHeight],a
;turn to face the direction we just fired
call GetFacing
and %11
cp b
jr z,.skipMove ;no need to turn
ld a,1
ld [moveAlignPrecision],a
call StandardValidateMoveAndRedraw
jr .skipMove
.skipAttack
ld a,1 ;return nz (go ahead and move)
or a
ret
.skipMove
xor a ;return z (skip move)
ret
.wispCheckTable
DB 3 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW .wispFireSound
DB 4 ;fire delay
DW StdVectorToState
.wispFireSound
DB 1,$75,$c0,$f0,$00,$c6
.wispRemove
call GetFGAttributes
and FLAG_2X2
swap a
ldio [curObjWidthHeight],a
call GetFacing
push bc
ld c,a
call RemoveFromMap
pop bc
call GetFacing
and %11111011 ;turn off split
jp SetFacing
;----GetFireTargetAsObject--------------------------------------------
GetFireTargetAsObject:
ld a,[fireBulletLocation]
ld l,a
ld a,[fireBulletLocation+1]
ld h,a
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
call EnsureTileIsHead
ld d,h
ld e,l
ld c,a
jp FindObject
;----Quatrain---------------------------------------------------------
QuatrainInit:
ld hl,.quatrainInitTable
jp StdInitFromTable
.quatrainInitTable
DB 4 ;initial facing
DB 10 ;health
DB GROUP_MONSTERA ;group
DB 0 ;has bullet
QuatrainCheck:
ld hl,.quatrainCheckTable
jp StdCheckFromTable
.quatrainCheckTable
DB 1 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW nullSound
DB 5 ;fire delay
DW TrackEnemyVectorToState
;----Crouton Goblin---------------------------------------------------
CroutonGoblinInit:
ld hl,.croutonGoblinInitTable
jp StdInitFromTable
.croutonGoblinInitTable
DB 4 ;initial facing
DB 1 ;health
DB GROUP_MONSTERA ;group
DB 0 ;has bullet
CroutonGoblinCheck:
ld hl,.croutonGoblinCheckTable
jp StdCheckFromTable
.croutonGoblinCheckTable
DB 2 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW goblinSound
DB 3 ;fire delay
DW TrackEnemyVectorToState
;----General Gyro-----------------------------------------------------
GeneralGyroInit:
ld hl,.gyroInitTable
jp StdInitFromTable
.gyroInitTable
DB 4 ;initial facing
DB 63 ;health (max)
DB GROUP_MONSTERA ;group
DB 0 ;has bullet
;----Crouton Artillery------------------------------------------------
CroutonArtilleryInit:
ld hl,.croutonArtilleryInitTable
jp StdInitFromTable
.croutonArtilleryInitTable
DB 4 ;initial facing
DB 10 ;health
DB GROUP_MONSTERA ;group
DB 1 ;has bullet
DW classRocketBullet ;associated bullet class ptr
DW CROUTONROCKET_CINDEX
CroutonArtilleryCheck:
call StdCheckDead
ret z
;save original facing
call GetFacing
and %00000011
push af
ld hl,.croutonArtilleryCheckTable
call StdCheckFromTableNotDead
;if facing changes set move delay to 15
call GetFacing
and %00000011
pop bc
cp b
ret z
ld a,15
call SetMoveDelay
ret
.croutonArtilleryCheckTable
DB 3 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 6 ;bullet damage
DW rocketFireSound
DB 10 ;fire delay
DW TrackEnemyVectorToState
;----Teleport Cube----------------------------------------------------
TeleportCubeInit:
ld hl,.cubeInitTable
call StdInitFromTable
jp LinkAssocToMe
.cubeInitTable
DB 1 ;initial facing
DB 2 ;health
DB GROUP_MONSTERA ;group
DB 1 ;has bullet
DW classTeleportCube2
DW TCUBE2_CINDEX
TeleportCubeCheck:
call GetCurLocation
push hl
call StdCheckDead
pop hl
jr nz,.tick
;died because of being shot (was timer up?)
push hl
call GetMisc
pop hl
cp 254
ret nz
;finished; resolve into one or more enemies
ld a,3
call GetRandomNumMask
cp 2
jr nc,.cluster
;one big enemy
or a
jr nz,.artillery
;create a hulk
ld bc,classCroutonHulk
jr .createSingle
.artillery
ld bc,classCroutonArtillery
.createSingle
call FindClassIndex
ret z
ld c,a
jp CreateInitAndDrawObject
.cluster
;create a cluster of grunts or goblins
and 1
jr nz,.goblins
ld bc,classCroutonGrunt
jr .createCluster
.goblins
;goblins
ld bc,classCroutonGoblin
.createCluster
call FindClassIndex
ret z
ld c,a
call CreateInitAndDrawObject
inc hl
call CreateInitAndDrawObject
ld d,0
ld a,[mapPitch]
ld e,a
add hl,de
call CreateInitAndDrawObject
dec hl
jp CreateInitAndDrawObject
.tick
call GetMisc
add 2
ld [hl],a
cp 254
jr nz,.notFinished
xor a
call SetHealth
ret
.notFinished
;determine how fast we're flashing
ld a,[hl]
cp 226
jr nc,.speed1
cp 200
jr nc,.speed2
cp 150
jr nc,.speed3
cp 100
jr nc,.speed4
.speed5
ldio a,[updateTimer]
and %11111
jr .checkFlash
.speed4
ldio a,[updateTimer]
and %1111
jr .checkFlash
.speed3
ldio a,[updateTimer]
and %111
jr .checkFlash
.speed2
ldio a,[updateTimer]
and %11
jr .checkFlash
.speed1
xor a
.checkFlash
ret nz
ld hl,.flashSound
call PlaySound
jp ChangeMyClassToAssociatedAndRedraw
.flashSound
DB 1,$35,$40,$f0,$00,$c4
TeleportCubeCheck2:
call StdCheckDead
ret z
jp ChangeMyClassToAssociatedAndRedraw
;----Dandelion Guard--------------------------------------------------
DandelionGuardInit:
ld hl,.dandelionGuardInitTable
jp StdInitFromTable
.dandelionGuardInitTable
DB 4 ;initial facing
DB 5 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classPansyBullet ;associated bullet class ptr
DW PANSYBULLET_CINDEX
DandelionGuardCheck:
ld hl,.dandelionGuardCheckTable
jp StdCheckFromTable
.dandelionGuardCheckTable
DB 3 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW .dandelionGuardFireSound
DB 8 ;fire delay
DW TrackEnemyVectorToState
.dandelionGuardFireSound
DB 1,$32,$80,$f0,$00,$c3
;----B12 Soldier------------------------------------------------------
B12SoldierInit:
ld hl,.b12SoldierInitTable
jp StdInitFromTable
.b12SoldierInitTable
DB 4 ;initial facing
DB 8 ;health
DB GROUP_MONSTERB ;group
DB 1 ;has bullet
DW classB12SoldierBullet ;associated bullet class ptr
DW B12SOLDIERBULLET_CINDEX
B12SoldierCheck:
ld hl,.b12SoldierCheckTable
jp StdCheckFromTable
.b12SoldierCheckTable
DB 3 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW baFireSound
DB 5 ;fire delay
DW TrackEnemyVectorToState
;----Big Spider-------------------------------------------------------
BigSpiderInit:
ld hl,.bigSpiderInitTable
jp StdInitFromTable
.bigSpiderInitTable
DB 4 ;initial facing
DB 9 ;health
DB GROUP_MONSTERE ;group
DB 0 ;has bullet
BigSpiderCheck:
ld hl,.bigSpiderCheckTable
jp StdCheckFromTable
.bigSpiderCheckTable
DB 12 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW .bigSpiderSound
DB 5 ;fire delay
DW StdVectorToState
.bigSpiderSound
DB $33,$80,$f0,$00,$c5
;----Little Spider----------------------------------------------------
LittleSpiderInit:
ld hl,.littleSpiderInitTable
jp StdInitFromTable
.littleSpiderInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_MONSTERE ;group
DB 0 ;has bullet
LittleSpiderCheck:
ld hl,.littleSpiderCheckTable
jp StdCheckFromTable
.littleSpiderCheckTable
DB 10 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW .littleSpiderSound
DB 5 ;fire delay
DW StdVectorToState
.littleSpiderSound
DB $33,$80,$f0,$60,$c5
;----Invisible Bat----------------------------------------------------
InvisibleBatCheck:
call StdCheckDead
ret z
ld hl,.invisibleBatCheckTable
call StdCheckFromTableNotDead
;make a noise every so often
ld hl,updateTimer
ld a,e
rrca
rrca
rrca
add [hl]
and %11111
cp %10000
jr nz,.checkAttack
ld hl,batFireSound
call PlaySound
.checkAttack
call GetAttackDelay ;attacked someone?
or a
ret z
call ChangeMyClassToAssociatedAndRedraw
ld a,50 ;delay until invisible
jp SetMisc
.invisibleBatCheckTable
DB 3 ;move delay
DB 1 ;attack type (0=none,1=melee,2=missile)
DB 1 ;bullet damage
DW batFireSound
DB 20 ;fire delay
DW TrackEnemyVectorToState
InvisibleBatTakeDamage:
call StdTakeDamage
call ChangeMyClassToAssociatedAndRedraw
ld a,50 ;delay until invisible
jp SetMisc
;----Slime------------------------------------------------------------
SlimeInit:
call GetCurLocation
ld a,MAPBANK
ldio [$ff70],a
xor a
ld [hl],a ;clear slime BG tile I'm on
ld hl,.slimeInitTable
jp StdInitFromTable
.slimeInitTable
DB 4 ;initial facing
DB 1 ;health
DB GROUP_MONSTERC
DB 0 ;has bullet
SlimeCheck:
ld hl,.slimeCheckTable
jp StdCheckFromTable
.slimeCheckTable
DB 4 ;move delay
DB 1 ;attack type (0=none,1=melee,2=missile)
DB 1 ;bullet damage
DW .slimeFireSound
DB 20 ;fire delay
DW TrackEnemyVectorToState
.slimeFireSound
DB 1,$35,$00,$f0,$00,$c7
;----Egg--------------------------------------------------------------
EggInit:
ld hl,.eggInitTable
call StdInitFromTable
ld a,255
jp SetMisc ;turns until hatch
.eggInitTable
DB 1 ;initial facing
DB 2 ;health
DB GROUP_MONSTERN
DB 1 ;has bullet
DW classChicken
DW CHICKEN_CINDEX
;----Monkey-----------------------------------------------------------
MonkeyInit:
push bc
push de
ld de,classSleepingMonkey
ld hl,MONKEY_CINDEX
ld a,1
call LoadAssociatedClass
pop de
pop bc
ld hl,.monkeyInitTable
jp StdInitFromTable
.monkeyInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_MONSTERD
DB 1 ;has bullet
DW classBananaBullet
DW BANANABULLET_CINDEX
MonkeyCheck:
ld hl,.monkeyCheckTable
jp StdCheckFromTable
.monkeyCheckTable
DB 3 ;move delay
DB 2 ;attack type (0=none,1=melee,2=missile)
DB 1 ;bullet damage
DW monkeyFireSound
DB 4 ;fire delay
DW TrackEnemyVectorToState
monkeyFireSound:
DB 1,$57,$2a,$f3,$10,$c7
;----Duke-------------------------------------------------------------
DukeInit:
ld hl,.dukeInitTable
jp StdInitFromTable
.dukeInitTable
DB 4 ;initial facing
DB 63 ;health (max)
DB GROUP_MONSTERD ;group
DB 1 ;has bullet
DW classBananaBullet
DW BANANABULLET_CINDEX
DukeCheck:
ld hl,.dukeCheckTable
jp StdCheckFromTable
.dukeCheckTable
DB 5 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 3 ;bullet damage
DW monkeyFireSound
DB 3 ;fire delay
DW StdVectorToState
;----Pig--------------------------------------------------------------
PigCheck:
call GetHealth
or a
jr nz,.afterPorkProducts
call GetCurLocation
push hl
call StandardDie
pop hl
ld bc,classPorkBG
call FindClassIndex
ld b,a
ld a,MAPBANK
ldio [$ff70],a
ld a,2
call GetRandomNumZeroToN
add b
ld [hl],a
call ResetMyBGSpecialFlags
ret
.afterPorkProducts
jp GenericCheck
EggCheck:
call GetHealth
or a
jr nz,.afterFried
call GetCurLocation
push hl
call StandardDie
pop hl
ld bc,classFriedEggBG
call FindClassIndex
push af
ld a,MAPBANK
ldio [$ff70],a
pop af
ld [hl],a
call ResetMyBGSpecialFlags
ret
.afterFried
call GetMisc
dec [hl]
jr nz,.notHatchedYet
ld hl,.eggHatchSound
call PlaySound
jp ChangeMyClassToAssociatedAndRedraw
.notHatchedYet
ld hl,.eggCheckTable
jp StdCheckFromTable
.eggCheckTable
DB 0 ;move delay
DB 0 ;attack type (0=none,1=melee,2=missile)
DB 0 ;bullet damage
DW nullSound
DB 20 ;fire delay
DW 0
.eggHatchSound
DB 4,$1b,$f0,$62,$c0
;----Crouton Blower---------------------------------------------------
BlowerInit:
ld hl,.blowerInitTable
jp StdInitFromTable
.blowerInitTable
DB 4 ;initial facing
DB 4 ;health
DB GROUP_MONSTERA
DB 0 ;has bullet
BlowerCheck:
call StdCheckDead
ret z
ld hl,.blowerCheckTable
call StdCheckFromTableNotDead
;handle 'firing' ourselves
;can we attack yet?
call DecrementAttackDelay
or a
ret z
push de
call GetFacing
push af
and %11
call GetLocInFront
pop af
rlca
and %110
push hl
ld l,a
ld a,(mapOffsetNorth & $ff)
add l
ld l,a
ld h,((mapOffsetNorth>>8)&$ff)
ld a,[hl+]
ld e,a
ld a,[hl]
ld d,a
pop hl
xor a
ld [losLimit],a
call ScanDirectionForEnemy ;returns dir of enemy in b
or a
jr z,.doneDE
;blow the enemy away from me
ld a,[fireBulletLocation] ;enemy's location
ld l,a
ld a,[fireBulletLocation+1]
ld h,a
pop de
call GetFacing
and %11
call ShiftObjectInDirection
ld a,3
call SetAttackDelay
ld hl,.blowerBlowSound
call PlaySound
ret
.doneDE pop de
ret
.blowerCheckTable
DB 4 ;move delay
DB 1 ;attack type (0=none,1=melee,2=missile)
DB 2 ;bullet damage
DW gruntFireSound
DB 5 ;fire delay
DW TrackEnemyVectorToState
.blowerBlowSound
DB 4,$00,$f5,$07,$80
;----Sleeping Monkey--------------------------------------------------
SleepingMonkeyInit:
ld hl,.sleepingMonkeyInitTable
jp StdInitFromTable
.sleepingMonkeyInitTable
DB 4 ;initial facing
DB 2 ;health (max)
DB GROUP_MONSTERD ;group
DB 1 ;has bullet
DW classMonkey
DW MONKEY_CINDEX
SleepingMonkeyCheck:
ld a,[guardAlarm]
or a
jr z,.check
call ChangeMyClassToAssociatedAndRedraw
ld de,classBananaBullet
ld hl,BANANABULLET_CINDEX
ld a,1
jp LoadAssociatedClass
.check
ld hl,.sleepingMonkeyCheckTable
jp StdCheckFromTable
.sleepingMonkeyCheckTable
DB 0 ;move delay
DB 0 ;attack type (0=no attack,1=melee,2=missile)
DB 0 ;bullet damage
DW monkeyFireSound
DB 3 ;fire delay
DW 0
;----Bell-------------------------------------------------------------
BellInit:
ld hl,.bellInitTable
call StdInitFromTable
jp LinkAssocToMe
.bellInitTable
DB 1 ;initial facing
DB 63 ;health (max)
DB GROUP_MONSTERN ;group
DB 1 ;has bullet
DW classRingingBell
DW RINGINGBELL_CINDEX
;----Banana Tree------------------------------------------------------
BananaTreeInit:
ld hl,.bananaTreeInitTable
jp StdInitFromTable
.bananaTreeInitTable
DB 1 ;initial facing
DB 6 ;health (max)
DB GROUP_MONSTERN ;group
DB 0 ;has bullet
BananaTreeCheck:
;regain 1 health every few seconds
ldio a,[updateTimer]
or a
jr nz,.check
call GetHealth
cp 6 ;at max?
jr nc,.check
inc a
call SetHealth
.check
jp DoNothingCheck
BananaTreeTakeDamage:
;create an adjacent banana that "fell off"
call FindEmptyLocationAround2x2
or a
jr z,.takeDamage
push bc
ld bc,classBananaBG
call FindClassIndex
push af
ld a,MAPBANK
ldio [$ff70],a
pop af
ld [hl],a
pop bc
call ResetMyBGSpecialFlags
.takeDamage
jp StdTakeDamage2x2
;----Hermit Crab No Shell---------------------------------------------
HermitNoShellInit:
ld hl,.hermitNoShellInitTable
call StdInitFromTable
;set misc to be class index of shell
ld bc,classHermitCrabShellBG
call FindClassIndex
jp SetMisc
.hermitNoShellInitTable
DB 4 ;initial facing
DB 3 ;health (max)
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classHermitInShell
DW HERMITINSHELL_CINDEX
HermitNoShellCheck:
;standing on shell?
call GetFacing
bit 7,a ;must be sprite
jr z,.notOnShell
call GetMisc
ld b,a
call GetCurLocation
ld a,TILESHADOWBANK
ldio [$ff70],a
ld a,[hl]
cp b
jr nz,.notOnShell
;get in shell
ld [hl],0 ;clear out shell
push bc
call GetFacing
ld c,a
call RemoveFromMap
pop bc
ld a,20
call SetHealth
call ChangeMyClassToAssociatedAndRedraw
ret
.notOnShell
ld hl,.hermitNoShellCheckTable
jp StdCheckFromTable
.hermitNoShellCheckTable
DB 5 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW crabAttackSound
DB 4 ;fire delay
DW StdVectorToState
crabAttackSound:
DB 1,$2c,$38,$f0,$00,$c6
;----Hermit Crab In Shell---------------------------------------------
HermitInShellCheck:
ld hl,.hermitInShellCheckTable
jp StdCheckFromTable
.hermitInShellCheckTable
DB 4 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW crabAttackSound
DB 4 ;fire delay
DW TrackEnemyVectorToState
;----Crab / Crab Burrowing -------------------------------------------
CrabInit:
ld hl,.crabInitTable
call StdInitFromTable
ld a,100 ;time till burrow
jp SetMisc
.crabInitTable
DB 4 ;initial facing
DB 3 ;health (max)
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classCrabBurrowing
DW CRABBURROWING_CINDEX
CrabCheck:
;can't burrow if sprite
call GetFacing
bit 7,a
jr nz,.notBurrowing
call GetMisc
dec [hl]
jr nz,.notBurrowing
;take another step if split tile
call MoveForwardIfSplit
jp ChangeMyClassToAssociatedAndRedraw
.notBurrowing
ld hl,.crabCheckTable
jp StdCheckFromTable
.crabCheckTable
DB 6 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 2 ;bullet damage
DW crabAttackSound
DB 1 ;fire delay
DW TrackEnemyVectorToState
CrabBurrowingInit:
ld hl,.crabBurrowingInitTable
call StdInitFromTable
xor a
call SetMisc
jp LinkAssocToMe
.crabBurrowingInitTable
DB 4 ;initial facing
DB 3 ;health (max)
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classCrab
DW CRAB_CINDEX
CrabBurrowingCheck:
;fully burrowed yet?
call GetMisc
cp 100
jr z,.burrowed
cp 5
jr z,.burrowed
inc [hl]
call GetFacing
ld c,a
jp RemoveFromMap
.burrowed
call GetMisc ;time to unburrow?
cp 100
jr nz,.notUnburrowing
call GetCurLocation
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
or a
ret nz ;can't unburrow when someone's on top
call GetFacing ;clear split bit
res 2,a
call SetFacing
jp ChangeMyClassToAssociatedAndRedraw
.notUnburrowing
;is an enemy on top of me?
call GetCurLocation
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
call IsMyEnemy
cp 1
ret nz
;flag to unburrow next time
ld a,100
jp SetMisc
;---------------------------------------------------------------------
;MoveForwardIfSplit
;---------------------------------------------------------------------
MoveForwardIfSplit:
call GetFacing
bit 2,a
ret z
and %11
ld b,a
jp StandardValidateMoveAndRedraw
;----UberMouse--------------------------------------------------------
UberMouseCheck:
ld a,63 ;can never die
call SetHealth
ld hl,.uberMouseCheckTable
jp StdCheckFromTable
.uberMouseCheckTable
DB 5 ;move delay
DB 1 ;attack type (0=no attack,1=melee,2=missile)
DB 5 ;bullet damage
DW .uberMouseFireSound
DB 2 ;fire delay
DW TrackEnemyVectorToState
.uberMouseFireSound
DB 1,$17,$00,$f0,$00,$c6
;----Turret-----------------------------------------------------------
TurretInit:
ld hl,.turretInitTable
jp StdInitFromTable
.turretInitTable
DB 4 ;initial facing
DB 20 ;health (max)
DB GROUP_MONSTERA ;group
DB 1 ;has bullet
DW classTurretBullet
DW TURRETBULLET_CINDEX
TurretCheck:
ld hl,.turretCheckTable
jp StdCheckFromTable
.turretCheckTable
DB 2 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW .turretFireSound
DB 1 ;fire delay
DW 0
.turretFireSound
DB 1,$3b,$80,$f3,$00,$83
;DB 1,$fa,$80,$f3,$00,$84
;----Pansy------------------------------------------------------------
PansyInit:
ld hl,.pansyInitTable
jp StdInitFromTable
.pansyInitTable
DB 4 ;initial facing
DB 2 ;health
DB GROUP_MONSTERC ;group
DB 1 ;has bullet
DW classPansyBullet ;associated bullet class ptr
DW PANSYBULLET_CINDEX
PansyCheck:
ld hl,.pansyCheckTable
jp StdCheckFromTable
.pansyCheckTable
DB 4 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW pansyFireSound
DB 10 ;fire delay
DW TrackEnemyVectorToState
HippiePansyCheck:
ld hl,.hippiePansyCheckTable
jp StdCheckFromTable
.hippiePansyCheckTable
DB 4 ;move delay
DB 2 ;attack type (0=no attack,1=melee,2=missile)
DB 1 ;bullet damage
DW pansyFireSound
DB 10 ;fire delay
DW EatVectorToState
;---------------------------------------------------------------------
; ActorCheck
;---------------------------------------------------------------------
ActorCheck:
push bc
push de
push hl
;am I dead?
call GetHealth
or a
jr nz,.checkTimeToMove
call StandardDie
jr .done
.checkTimeToMove
;time to move?
ld a,2
call TestMove
or a
jr z,.skipMove ;timer lsb==frame lsb, don't move yet
;xor a
ld a,1
ld [moveAlignPrecision],a
call ActorVectorToState
or a
jr z,.skipMove
call StandardValidateMoveAndRedraw
.skipMove
.done pop hl
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: LookForEnemyInLOS
; Arguments: c - class index of object
; de - this
; Alters: af,b
; Returns: a - 1=enemy spotted, 0=no enemy
; b - direction of enemy
; [fireBulletLocation]
; loc adj to shooter to place bullet
;---------------------------------------------------------------------
LookForEnemyInLOS:
push hl
;save my group and direction first
call GetGroup
ld [myGroup],a
call GetAttackDirState
or a
jr nz,.scanEast
;de = north offset
push de
ld a,DIR_NORTH
ld [myFacing],a
call GetLocInFront
ld a,[mapOffsetNorth] ;get North offset
ld e,a
ld a,[mapOffsetNorth+1]
ld d,a
call ScanDirectionForEnemy
or a
jr nz,.afterN2
ldio a,[curObjWidthHeight]
cp 2
jr z,.try2x2N
xor a
jr .afterN2
.try2x2N
inc hl ;try again to the side
call ScanDirectionForEnemy
.afterN2
pop de
or a
jr nz,.foundEnemyN
jp .advanceState ;found a wall
.foundEnemyN
ld b,DIR_NORTH ;found enemy
jp .saveEnemyLocation
.scanEast
;Attack Dir State says look east?
cp 1
jr nz,.scanSouth
;de = east offset
push de
ld a,DIR_EAST
ld [myFacing],a
call GetLocInFront
ld a,[mapOffsetEast] ;get East offset
ld e,a
ld a,[mapOffsetEast+1]
ld d,a
call ScanDirectionForEnemy
or a
jr nz,.afterE2
ldio a,[curObjWidthHeight]
cp 2
jr z,.try2x2E
xor a
jr .afterE2
.try2x2E
;try again to the side
ld a,[mapOffsetSouth]
add l
ld l,a
ld a,[mapOffsetSouth+1]
adc h
ld h,a
call ScanDirectionForEnemy
.afterE2
pop de
or a
jr z,.advanceState ;found a wall
ld b,DIR_EAST ;found enemy
jr .saveEnemyLocation
.scanSouth
;Attack Dir State says look south?
cp 2
jr nz,.scanWest
;de = south offset
push de
ld a,DIR_SOUTH
ld [myFacing],a
call GetLocInFront
ld a,[mapOffsetSouth] ;get South offset
ld e,a
ld a,[mapOffsetSouth+1]
ld d,a
call ScanDirectionForEnemy
or a
jr nz,.afterS2
ldio a,[curObjWidthHeight]
cp 2
jr z,.try2x2S
xor a
jr .afterS2
.try2x2S
inc hl ;try again to the side
call ScanDirectionForEnemy
.afterS2
pop de
or a
jr z,.scanWest ;found a wall
ld b,DIR_SOUTH ;found enemy
jr .saveEnemyLocation
.scanWest
;de = west offset
push de
ld a,DIR_WEST
ld [myFacing],a
call GetLocInFront
ld a,[mapOffsetWest] ;get West offset
ld e,a
ld a,[mapOffsetWest+1]
ld d,a
call ScanDirectionForEnemy
or a
jr nz,.afterW2
ldio a,[curObjWidthHeight]
cp 2
jr z,.try2x2W
xor a
jr .afterW2
.try2x2W
;try again to the side
ld a,[mapOffsetSouth]
add l
ld l,a
ld a,[mapOffsetSouth+1]
adc h
ld h,a
call ScanDirectionForEnemy
.afterW2
pop de
or a
jr z,.advanceState ;found a wall
ld b,DIR_WEST ;found enemy
.saveEnemyLocation
ld a,l
ld [fireBulletLocation],a
ld a,h
ld [fireBulletLocation+1],a
ld a,1
jr .done
.advanceState
;no enemies found, look next direction next time
call GetAttackDirState
inc a
call SetAttackDirState
xor a
.done
pop hl
ret
;---------------------------------------------------------------------
; Routine: ScanDirectionForEnemy
; Arguments: c - class index of scanning object
; de - offset to scan in
; hl - starting location for scan
; [losLimit] - 1=1 tile, 0=infinite
; Returns: a - 1=enemy found, 0=no enemy
; [fireBulletLocation] - location of enemy if found
; Alters: af
;---------------------------------------------------------------------
ScanDirectionForEnemy:
push bc
push hl
ld a,MAPBANK
ld [$ff70],a
ldio a,[firstMonster]
ld b,a
ld a,[losLimit]
cp 1
jr nz,.loop
;one time only
ld a,[hl]
or a
jr z,.done
cp b
jr c,.returnFalse
call IsMyEnemy
and 1 ;mask out & ignore bullets
jr .done
;infinite until hit wall
.loop ld a,[hl]
or a
jr z,.nextLocation
cp b
jr c,.foundWall
;might be an enemy
push af
ld a,l
ld [fireBulletLocation],a
ld a,h
ld [fireBulletLocation+1],a
pop af
call IsMyEnemy
cp 2
jr z,.restoreMapNextLocation ;is bullet, look past it
and 1
jr .done ;is creature
.restoreMapNextLocation
ld a,MAPBANK
ldio [$ff70],a
.nextLocation
add hl,de
jr .loop
.foundWall
;might be a shoot-over wall
push af
ld a,ZONEBANK
ldio [$ff70],a
pop af
bit 7,[hl] ;anything special here?
jr z,.returnFalse ;nope
call GetBGAttributes ;maybe...
and BG_FLAG_SHOOTOVER
jr z,.returnFalse ;still no
ld a,MAPBANK
ldio [$ff70],a
jr .nextLocation ;go back to looking
.returnFalse
xor a
.done
pop hl
pop bc
ret
;---------------------------------------------------------------------
; Routine: IsMyEnemy
; Arguments: a - class index of potential enemy
; c - class index of object
; hl - map location
; Returns: a - 0=no enemy, 1=is enemy, 2=no enemy but is bullet
; (bullet coming towards me = 1)
; Alters: af
; Description: Follows tail tiles back to head (if need be) & figures
; out if this index is friend or foe
;---------------------------------------------------------------------
IsMyEnemy:
push bc
push de
push hl
push af
ldio a,[firstMonster]
ld b,a
pop af
cp b
jr c,.notEnemy
call EnsureTileIsHead ;a = findHead(a)
ld c,a
ld d,h
ld e,l
call FindObject
call GetFGAttributes
and FLAG_ISBULLET
jr nz,.specialCaseIsBullet
call GetGroup
ld b,a
ld a,[myGroup]
ld c,a
call GetFOF
xor 1 ;reverse return value
jr .done
.specialCaseIsBullet
call GetFacing ;get bullets direction
add 2 ;reverse it
and %11
ld hl,myFacing
cp [hl] ;coming towards me if same dir
jr z,.isEnemy
;no enemy but is bullet
ld a,2
jr .done
.notEnemy
;not my enemy
xor a
jr .done
.isEnemy
ld a,1
.done
pop hl
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: EnsureTileIsHead
; Arguments: a - class index of tile (maybe adjoin ptr)
; hl - map location
; Returns: a - head of obj / class index
; hl - location of head
; Alters: af,hl
; Description: Follows tail tiles back to head (if need be)
;---------------------------------------------------------------------
EnsureTileIsHead::
push bc
push de
ld c,a
ld d,h
ld e,l
ld a,MAPBANK
ld [$ff70],a
.checkIfFoundHead
ld a,c
cp CLASS_ADJOIN_N
jr c,.foundHeadTile
jr z,.followTileToNorth
cp CLASS_ADJOIN_W
jr z,.followTileToWest
di
.error jr .error ;no classes should adjoin east or south
.followTileToNorth
ld a,[mapOffsetNorth]
ld l,a
ld a,[mapOffsetNorth+1]
ld h,a
add hl,de
ld d,h
ld e,l
ld c,[hl]
jr .checkIfFoundHead
.followTileToWest
dec de
ld a,[de]
ld c,a
jr .checkIfFoundHead
.foundHeadTile
ld h,d
ld l,e
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: StandardValidateMoveAndRedraw
; Arguments: b - direction to move
;---------------------------------------------------------------------
StandardValidateMoveAndRedraw:
ld a,b
and %11
ld b,a
call EnforceLegalMove
ld a,1
call CheckDestEmpty
or a
ret z
call Move
call StandardRedrawNoCheckSprite
ret
;---------------------------------------------------------------------
; Routine: PlayerValidateMoveAndRedraw
; Arguments: b - desired move dir
; Returns: a - 1 if bumping into monster
; 0 otherwise
; Description: Additional functionality of changing map if player
; hits a wall flagged as an exit
;---------------------------------------------------------------------
PlayerValidateMoveAndRedraw:
call EnforceLegalMove
ld a,1
call CheckDestEmpty
or a
jr nz,.move
;can't move. Bumping into exit?
ld a,4
call GetLocInFront
;can't be a monster
ld a,MAPBANK
ld [$ff70],a
ldio a,[firstMonster]
ld b,a
ld a,[hl]
cp b
jr c,.notAMonster
;return is monster unless it is a talker
call EnsureTileIsHead
ld b,a
ld a,[dialogBalloonClassIndex]
cp b
jr nz,.returnTrue
xor a
ret
.returnTrue
ld a,1
ret
.notAMonster
;save monster(?) index in b
;ld b,a
;switch to zone/exit map
ld a,ZONEBANK
ld [$ff70],a
;get & check exit at location in front
ld a,[hl]
and %01110000 ;clear off extraneous
xor %01110000 ;must be type "X"
;jr nz,.checkBumpIntoMonster
jr nz,.checkBumpIntoAttackable
;have an exit!
;save exit tile index
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
ld [exitTileIndex],a
call HandleExitFromMap
xor a
ret
.move
call Move
call StandardRedrawNoCheckSprite
xor a
ret
;ld a,MAPBANK
;ldio [$ff70],a
;ld a,[firstMonster]
;ld b,a
;ld a,[hl]
;cp b
;jr c,.checkBumpIntoAttackable
;ld a,1
;ret
.checkBumpIntoAttackable
ld a,[bgFlags]
and BG_FLAG_ATTACKABLE
ret z
ld a,1
ret
;---------------------------------------------------------------------
; Routines: StreamRedraw
; StreamCheck
; StreamDraw
; StreamDie
;---------------------------------------------------------------------
StreamRedraw:
push bc
push de
push hl
ld a,OBJBANK
ld [$ff70],a
xor a
ld [fgFlags],a
ld hl,OBJ_LIMIT ;get my color
add hl,de
ld b,[hl]
jp StreamDraw
StreamCheck:
;time to move?
ld a,1
call TestMove
or a
jr z,.streamDone ;timer lsb==frame lsb, don't move yet
call .streamMove
call .streamMove
call .streamMove
call StreamRedraw ;draw me please
.streamDone
ret
.streamMove
push bc
push hl
ldio a,[firstMonster]
ld b,a
ld a,4
call GetLocInFront ;4=in front, split included
or a
jr z,.keepGoing ;nothing in front
cp b ;is a monster or what?
jr c,.hitWall ;wall in front, bullet just dies
;object in front, hit it for damage but keep going next time
ld b,a ;monster index in b, loc in hl
ld a,1 ;one point of damage
ld [methodParamL],a
ld a,4 ;use direction of this object for expl
call HitObject
jr .done
.hitWall
call StreamDie
call GetCurLocation ;move obj over wall
call GetFacing
and %11
call AdvanceLocHLInDirection
call SetCurLocation
ld a,MAPBANK
ld [$ff70],a
xor a
ld [hl],a ;destroy bg tile at this loc
ld b,24 ;initial frame
call HitWall
ld hl,bigExplosionSound
call PlaySound
pop hl
pop bc
pop af ;return addr
ret
.keepGoing
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FRAME ;get current direction
add hl,de
ld a,[hl]
and %00000011 ;keep going same direction
ld b,a
call Move
;call StreamRedraw ;draw me please
.done
pop hl
pop bc
ret
StreamDraw:
jp StandardDraw
;call GetCurLocation
;call GetFacing
;add 2
;and %11 ;reverse facing
;call AdvanceLocHLInDirection ;location behind head
;call GetBaseTile
StreamDie:
ld a,5
ld [jiggleDuration],a
jp StandardDie
;---------------------------------------------------------------------
; Routine: BombLocation
; Arguments: b - damage
; hl - center of blast
; Returns: Nothing.
; Alters: af
; Description: Does 'b' damage in a cross shape spreading outward
; from center in a random radius of (2...b) horizontally
; and another random radius of (2...b) vertically.
;
; Uses $c000 as work RAM to collect locations and
; objects affected.
;---------------------------------------------------------------------
BombLocation:
push bc
push de
push hl
ld a,MAPBANK
ldio [$ff70],a
;save current object width & height
ldio a,[curObjWidthHeight]
push af
xor a ;number of objects found
ld [$c000],a
ld a,b
ld [fireBulletDamage],a
;limit b to 4 max
ld a,b
cp 5
jr c,.bOkay
ld b,4
.bOkay
push hl
;----left/right-----------------------------------------------
;get random radius 1...b
ld a,b
sub 2
call GetRandomNumZeroToN
inc a
inc a
ld c,a ;c is original desired number of explosions
;find left and right boundaries
ld de,$ffff
call .numTilesUntilWall
cp c
jr c,.leftSideOkay
jr z,.leftSideOkay
ld a,c ;clip
.leftSideOkay
push af
ld de,1
call .numTilesUntilWall
cp c
jr c,.rightSideOkay
jr z,.rightSideOkay
ld a,c ;clip
.rightSideOkay
dec a
ld c,a
pop af
push af
add c
ld c,a
pop af
cpl
inc a
inc a
add l
ld l,a
;hl is at left side, c indiates num tiles until right side
ld de,1
call .createExplosions
pop hl
;----up/down--------------------------------------------------
;get random radius 1...b
ld a,b
sub 2
call GetRandomNumZeroToN
inc a
inc a
ld c,a
;find top and bottom boundaries
ld a,[mapOffsetNorth]
ld e,a
ld a,[mapOffsetNorth+1]
ld d,a
call .numTilesUntilWall
cp c
jr c,.topSideOkay
jr z,.topSideOkay
ld a,c ;clip
.topSideOkay
ld b,c
dec a
ld c,a
or a
jr z,.topSideDone
push hl
.adjustTopHL
add hl,de
dec a
jr nz,.adjustTopHL
;hl is at top side, c indiates num tiles until bottom side
ld a,[mapOffsetSouth]
ld e,a
ld a,[mapOffsetSouth+1]
ld d,a
call .createExplosions
pop hl
.topSideDone
ld a,[mapOffsetSouth]
ld e,a
ld a,[mapOffsetSouth+1]
ld d,a
ld c,b
call .numTilesUntilWall
cp c
jr c,.bottomSideOkay
jr z,.bottomSideOkay
ld a,c ;clip
.bottomSideOkay
dec a
jr z,.bottomSideDone
ld c,a
add hl,de
;hl is at top side, c indiates num tiles until bottom side
call .createExplosions
.bottomSideDone
;loop through list of objects recorded as being in bomb
;blast and cause damage to each one
ld a,[$c000]
or a
jr z,.done
ld c,a
ld hl,$c001
.distributeDamageLoop
push bc
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl+]
ld e,a
ld a,[hl+]
ld d,a
ld a,[de] ;class index of target
ld c,a ;class index to look for
call FindObject
ld a,[fireBulletDamage]
ld [methodParamL],a
ld a,4
ld [fireBulletDirection],a
ld b,METHOD_TAKE_DAMAGE
call CallMethod
pop bc
dec c
jr nz,.distributeDamageLoop
;ld hl,bombSound
;call PlaySound
.done
;restore current object width and height
pop af
ldio [curObjWidthHeight],a
pop hl
pop de
pop bc
ret
.createExplosions
ld a,c
or a
ret z
push bc
push de
push hl
.createExplosionLoop
ld a,MAPBANK
ldio [$ff70],a
ldio a,[firstMonster]
ld b,a
ld a,[hl]
cp b
push de
push hl
jr c,.afterRecordObject
call EnsureTileIsHead
;add location to list of locations if not already there
call .isLocationRecorded
or a
jr nz,.afterRecordObject
;record the location
ld a,[$c000]
push af
sla a ;times two + 1
inc a
ld e,a
ld d,$c0 ;de = numObj*2 + 1
ld a,l
ld [de],a
inc de
ld a,h
ld [de],a
pop af
inc a
ld [$c000],a ;one more in the list
.afterRecordObject
pop hl
pop de
ld a,l
ld [bulletLocation],a
ld a,h
ld [bulletLocation+1],a
ld b,16
call CreateExplosion
add hl,de
dec c
jr nz,.createExplosionLoop
pop hl
pop de
pop bc
ret
.isLocationRecorded
;args: a - class
; hl - cur location
;returns: a - 1=in list, 0=not in list
push bc
push de
push hl
call EnsureTileIsHead
ld d,h
ld e,l
ld a,[$c000] ;num classes
or a
jr z,.inListDone ;no list - so not in list
ld c,a
ld hl,$c001
.testInListLoop
ld a,[hl+]
cp e
jr nz,.continueInListLoop
ld a,[hl]
cp d
jr nz,.continueInListLoop
ld a,1 ;is in list
jr .inListDone
.continueInListLoop
inc hl
dec c
jr nz,.testInListLoop
xor a
.inListDone
pop hl
pop de
pop bc
ret
.numTilesUntilWall
;takes a location (hl), an offset (de), and returns how
;many tiles (including the first) there are until a wall.
push bc
push hl
ld a,MAPBANK
ldio [$ff70],a
ldio a,[firstMonster]
ld b,a
ld c,0
.loop ld a,[hl]
or a
jr z,.keepCounting
cp b
jr c,.foundWall
.keepCounting
inc c
add hl,de
jr .loop
.foundWall
;keep going if shoot-over type
push af
ld a,ZONEBANK
ldio [$ff70],a
pop af
bit 7,[hl] ;special?
jr z,.foundWallDone
call GetBGAttributes
bit BG_BIT_SHOOTOVER,a
jr z,.foundWallDone
ld a,MAPBANK ;keep looking
ldio [$ff70],a
jr .keepCounting
.foundWallDone
ld a,c
pop hl
pop bc
ret
;---------------------------------------------------------------------
; Routine: FindEmptyLocationAround1x1
; Arguments: de - 1x1 object
; Returns: hl - empty location around object or $0000 if none
; a - 0 = no empty locations
; Alters: af,hl
;---------------------------------------------------------------------
FindEmptyLocationAround1x1Loc:
push bc
jr FindEmptyLocationAround1x1Common
FindEmptyLocationAround1x1:
push bc
;get my TL corner plus (-1,-1)
call GetCurLocation
FindEmptyLocationAround1x1Common:
call ConvertLocHLToXY
dec h
dec l
ld b,0
.outer
ld c,0
.inner
push hl
ld a,h
add b
ld h,a
ld a,l
add c
ld l,a
call ConvertXYToLocHL
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
or a
jr nz,.notEmpty
ld a,1
pop bc
jr .done
.notEmpty
pop hl
ld a,3
inc c
cp c
jr nz,.inner
inc b
cp b
jr nz,.outer
ld hl,0
xor a
.done
pop bc
ret
;---------------------------------------------------------------------
; Routine: FindEmptyLocationAround2x2
; Arguments: de - 2x2 object
; Returns: hl - empty location around object or $0000 if none
; a - 0 if none empty
; Alters: af,hl
;---------------------------------------------------------------------
FindEmptyLocationAround2x2:
push bc
;get my TL corner plus (-1,-1)
call GetCurLocation
call ConvertLocHLToXY
dec h
dec l
ld b,0
.outer
ld c,0
.inner
push hl
ld a,h
add b
ld h,a
ld a,l
add c
ld l,a
call ConvertXYToLocHL
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
or a
jr nz,.notEmpty
ld a,1
pop bc
jr .done
.notEmpty
pop hl
ld a,4
inc c
cp c
jr nz,.inner
inc b
cp b
jr nz,.outer
xor a
ld hl,0
.done
pop bc
ret
;---------------------------------------------------------------------
; Routine: GetCurLocation
; Arguments: de - object
; Returns: hl - current location
; Alters: af
;---------------------------------------------------------------------
GetCurLocation::
ld a,OBJBANK
ld [$ff70],a
ld a,[de]
ld l,a
inc de
ld a,[de]
ld h,a
dec de
ret
;---------------------------------------------------------------------
; Routine: SetCurLocation
;---------------------------------------------------------------------
SetCurLocation::
ld a,OBJBANK
ld [$ff70],a
ld a,l
ld [de],a
inc de
ld a,h
ld [de],a
dec de
ret
;---------------------------------------------------------------------
; Routine: GetFacing
; Returns: current facing + split
; Alters: af
;---------------------------------------------------------------------
GetFacing::
push hl
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FRAME
add hl,de
ld a,[hl]
pop hl
ret
;---------------------------------------------------------------------
; Routine: SetFacing
; Arguments: a - byte to set facing to
; Alters: af,hl
;---------------------------------------------------------------------
SetFacing::
push af
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_FRAME
add hl,de
pop af
ld [hl],a
ret
;---------------------------------------------------------------------
; Routine: AdvanceLocHLInDirection
; Arguments: a - direction to advance in
;---------------------------------------------------------------------
AdvanceLocHLInDirection:
bit 0,a
jr nz,.eastOrWest
push de
rlca
ld de,mapOffsetNorth ;de to correct map offset
add e
ld e,a
ld a,[de]
inc de
add l
ld l,a
ld a,[de]
adc h
ld h,a
pop de
ret
.eastOrWest
bit 1,a
jr nz,.west
inc hl
ret
.west dec hl
ret
;---------------------------------------------------------------------
; Routine: SetGroup
; Arguments: a - group to set to (see Object.asm for details)
; de - object
; Alters: af
; Returns: nothing
;---------------------------------------------------------------------
SetGroup::
push bc
push hl
ld b,a
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_GROUP
add hl,de
ld a,[hl]
and %11110000
or b
ld [hl],a
pop hl
pop bc
ret
;---------------------------------------------------------------------
; Routine: GetGroup
; Arguments: de - object
; Alters: af
; Returns: a - this object's group (see Object.asm for details)
;---------------------------------------------------------------------
GetGroup:
push hl
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_GROUP
add hl,de
ld a,[hl]
and %00001111
pop hl
ret
;---------------------------------------------------------------------
; Routine: GetActorDestZone
; Arguments: de - object
; Alters: af
; Returns: a - destination zone of DESTL/DESTH
;---------------------------------------------------------------------
GetActorDestZone:
push hl
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_DESTL
add hl,de
ld a,[hl+] ;get location in hl
ld h,[hl]
ld l,a
ld a,ZONEBANK
ld [$ff70],a
ld a,[hl]
and %1111
pop hl
ret
;---------------------------------------------------------------------
; Routine: SetActorDestLoc
; aka SetFoodIndexRange
; Arguments: de - object
; hl - location / food range h=high index, l=low
; Alters: af
; Returns: nothing
;---------------------------------------------------------------------
SetActorDestLoc::
SetFoodIndexRange::
push bc
push hl
ld b,h
ld c,l
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_DESTL
add hl,de
ld [hl],c
inc hl
ld [hl],b
xor a
call SetState
pop hl
pop bc
ret
;---------------------------------------------------------------------
; Routine: GetActorDestLoc
; Arguments: de - object
; Alters: af, hl
; Returns: hl - location
;---------------------------------------------------------------------
GetActorDestLoc:
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_DESTL
add hl,de
ld a,[hl+]
ld h,[hl]
ld l,a
ret
;---------------------------------------------------------------------
; Routine: GetDestL
; GetDestH
; Arguments: de - object
; Returns: a - contents of DESTL/DESTH
; Alters: af,hl
;---------------------------------------------------------------------
GetDestL::
ld a,OBJBANK
ldio [$ff70],a
ld hl,OBJ_DESTL
add hl,de
ld a,[hl]
ret
GetDestH::
ld a,OBJBANK
ldio [$ff70],a
ld hl,OBJ_DESTH
add hl,de
ld a,[hl]
ret
;---------------------------------------------------------------------
; Routine: SetDestL
; SetDestH
; Arguments: a - value to set to
; de - object
; Returns: Nothing.
; Alters: af,hl
;---------------------------------------------------------------------
SetDestL::
push af
ld a,OBJBANK
ldio [$ff70],a
pop af
ld hl,OBJ_DESTL
add hl,de
ld [hl],a
ret
SetDestH::
push af
ld a,OBJBANK
ldio [$ff70],a
pop af
ld hl,OBJ_DESTH
add hl,de
ld [hl],a
ret
;---------------------------------------------------------------------
; Routine: SetMisc
; GetMisc
; Arguments: a - value to set to (SetMisc)
; de - object
; Returns: a - retrieved value (GetMisc)
; Alters: af,hl
;---------------------------------------------------------------------
SetMisc::
push af
ld a,OBJBANK
ldio [$ff70],a
ld hl,OBJ_MISC
add hl,de
pop af
ld [hl],a
ret
GetMisc::
ld a,OBJBANK
ldio [$ff70],a
ld hl,OBJ_MISC
add hl,de
ld a,[hl]
ret
;---------------------------------------------------------------------
; Routine: SetSpriteLo
; Alters: af
; Arguments: a - loptr to sprite
; de - object
;---------------------------------------------------------------------
SetSpriteLo:
push hl
ld h,a
ld a,OBJBANK
ld [$ff70],a
ld a,h
ld hl,OBJ_SPRITELO
add hl,de
ld [hl],a
pop hl
ret
;---------------------------------------------------------------------
; Routine: GetSpriteLo
; Arguments: de - object
; Returns: a - loptr to sprite
; Alters: af
;---------------------------------------------------------------------
GetSpriteLo:
push hl
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_SPRITELO
add hl,de
ld a,[hl]
pop hl
ret
;---------------------------------------------------------------------
; Routine: GetSpritePtrInHL
; Arguments: de - object
; Returns: hl - loptr to sprite
; Alters: af
;---------------------------------------------------------------------
GetSpritePtrInHL:
call GetSpriteLo
ld l,a
ld h,((spriteOAMBuffer>>8) & $ff)
ret
;---------------------------------------------------------------------
; Routine: GetBulletDamage
; Returns: this.destL
; Alters: a,hl
;---------------------------------------------------------------------
GetBulletDamage:
ld a,OBJBANK
ld [$ff70],a
ld hl,OBJ_DESTL
add hl,de
ld a,[hl]
ret
;---------------------------------------------------------------------
; Routine: GetFGAttributes
; Arguments: c - class index
; Alters: af
; Returns: a - attributes for given class index
; [fgFlags] copy of attributes
;
; Returns full set of attributes including:
; [2:0] - color FLAG_PALETTE
; [4] - isBullet FLAG_ISBULLET
; [5] - is2x2 FLAG_2X2
; [6] - noRotate FLAG_NOROTATE
;---------------------------------------------------------------------
GetFGAttributes::
push hl
ld a,TILEINDEXBANK
ldio [$ff70],a
ld l,c
ld h,((fgAttributes>>8) & $ff)
ld a,[hl]
ld [fgFlags],a
pop hl
ret
;---------------------------------------------------------------------
; Routine: SetFGAttributes
; Arguments: a - new attributs
; c - class index
; Alters: af
;---------------------------------------------------------------------
SetFGAttributes::
push hl
push af
ld a,TILEINDEXBANK
ldio [$ff70],a
ld l,c
ld h,((fgAttributes>>8) & $ff)
pop af
ld [hl],a
pop hl
ret
;---------------------------------------------------------------------
; Routine: GetFGTileMapping
; Arguments: c - class index
; Returns: a - base fg tile for given class index
; Alters: af
;---------------------------------------------------------------------
GetFGTileMapping:
push hl
ld a,TILEINDEXBANK
ld [$ff70],a
ld l,c
ld h,((fgTileMap>>8) & $ff)
ld a,[hl]
pop hl
ret
;---------------------------------------------------------------------
; Routine: SetupHeroData
; Arguments: c - class index
; Returns: hl - ptr to hero0_data or hero1_data
; Alters: af,hl
;---------------------------------------------------------------------
SetupHeroData:
ld a,[hero0_index]
cp c
jr nz,.hero1
ld hl,hero0_data
ret
.hero1
ld hl,hero1_data
ret
;---------------------------------------------------------------------
; Routine: GetHeroData
; Arguments: a - data offset (e.g. HERODATA_HEALTH)
; hl - ptr to hero0_data or hero1_data
; Returns: a - 8-bit value
; Alters: af
;---------------------------------------------------------------------
GetHeroData:
push de
push hl
ld d,0
ld e,a
add hl,de
ld a,[hl]
pop hl
pop de
ret
;---------------------------------------------------------------------
; Routine: SetHeroData
; Arguments: a - data to set
; b - data offset (e.g. HERODATA_HEALTH)
; hl - ptr to hero0_data or hero1_data
; Returns: a - 8-bit value
; Alters: af
;---------------------------------------------------------------------
SetHeroData:
push de
push hl
ld d,0
ld e,b
add hl,de
ld [hl],a
pop hl
pop de
ret
;---------------------------------------------------------------------
; Routine: HealthSparks
; Arguments: a - cur health
; b - max health
; de - this
; Returns: Nothing.
; Alters: af, hl
; Description: Makes a spark every often if lower than half
; health, twice as often if lower than 1/4 health,
; like crazy if lower than 1/8 health or at 1
;---------------------------------------------------------------------
HealthSparks:
push bc
push de
srl b ;half max health
cp b
jr z,.atHalfHealth
jr nc,.done ;greater than half health
srl b ;1/4 max
cp b
jr z,.atQuarterHealth
jr nc,.atHalfHealth
srl b ;1/8 max
cp b
jr z,.atEighthHealth
jr nc,.atQuarterHealth
.atEighthHealth
;at 1/8 health
call GetState
add 1
call SetState
and %00000001
jr .spark
.atQuarterHealth
call GetState
add 1
call SetState
and %00000111
jr .spark
.atHalfHealth
call GetState
add 1
call SetState
and %00001111
.spark
or a
jr nz,.done
call GetFGAttributes
and %111
ld [bulletColor],a
call GetCurLocation
ld a,l
ld [bulletLocation],a
ld a,h
ld [bulletLocation+1],a
ld b,72 ;initial spark frame
call CreateExplosion
;hl points to explosion object
push de
call IndexToPointerDE
call GetSpriteLo
ld h,((spriteOAMBuffer>>8) & $ff)
ld l,a
pop de
;add +4 y if split north/south
push hl
push hl
call GetFacing
pop hl
bit 2,a
jr z,.afterSplit
bit 0,a
jr z,.splitNS
inc hl ;split e/w
.splitNS
ld a,[hl]
add 4
ld [hl],a
.afterSplit
pop hl
;offset by random +/- 0-3 pixels
ld a,%111
call GetRandomNumMask
add [hl] ;sprite y pos
sub 4
ld [hl+],a
ld a,%111
call GetRandomNumMask
add [hl] ;sprite x pos
sub 4
ld [hl],a
.done
pop de
pop bc
ret
;---------------------------------------------------------------------
; Routine: ShiftObjectInDirection
; Arguments: a - direction to shift object
; hl - location of object
; Alters: af, [curObjWidthHeight]
; Returns: Nothing.
;---------------------------------------------------------------------
ShiftObjectInDirection::
push bc
push de
push hl
ld b,a
ldio a,[curObjWidthHeight]
push af
ld a,MAPBANK
ldio [$ff70],a
ld a,[hl]
call EnsureTileIsHead
ld d,h
ld e,l
ld c,a
ld a,[hero0_index]
cp c
jr z,.isPlayer
ld a,[hero1_index]
cp c
jr z,.isPlayer
call FindObject
call SetObjWidthHeight
call StandardValidateMoveAndRedraw
pop af
ldio [curObjWidthHeight],a
pop hl
pop de
pop bc
ret
.isPlayer
call FindObject
call PlayerValidateMoveAndRedraw
pop af
ldio [curObjWidthHeight],a
pop hl
pop de
pop bc
ret
nullSound:
DB 0
;channel 1 effects
pansyFireSound:
DB 1,$72,$80,$f7,$00,$84
baFireSound:
DB 1,$3b,$40,$f3,$00,$84
bsFireSound:
DB 1,$4c,$40,$f3,$00,$87
bigLaserSound::
DB 1,$3d,$80,$f6,$00,$86
disappearSound::
DB 1,$72,$80,$f5,$00,$c2
goblinSound:
DB 1,$11,$80,$f0,$00,$c1
rocketFireSound:
DB 1,$25,$00,$f4,$00,$81
hulkFireSound:
DB 1,$31,$c0,$f0,$00,$c1
gruntFireSound:
DB 1,$21,$e0,$f8,$50,$80
haikuSound:
DB 1,$9c,$48,$f2,$d0,$c7
guardFireSound:
DB 1,$31,$80,$f0,$00,$c1
treeFireSound:
DB 1,$4d,$c0,$f0,$00,$c5
bushFireSound:
DB 1,$4d,$c0,$f0,$00,$c4
beeSound:
DB 1,$f7,$00,$f3,$00,$83
eatSound:
DB 1,$5a,$80,$f2,$00,$84
;low frogger 1,$23,$20,$af,$00,$81
;channel 4 effects
stdExplosionSound:
DB 4,$00,$c3,$44,$80
bigExplosionSound::
DB 4,$00,$f3,$81,$80
closeGateSound::
DB 4,$00,$f4,$4f,$80
bombSound::
DB 4,$00,$f6,$90,$80
;SECTION "AlignedClassTables",ROMX[$7F00],BANK[CLASSROM]
;---------------------------------------------------------------------
SECTION "AlignedClassTables",ROM0[$200]
;---------------------------------------------------------------------
stdStateTable:
;$7f00
DW SetupRandomMoveState, MoveToZone, TryRight, TryFwdAfterRight
DW TryLeft, TryFwdAfterLeft, RandomMove, MoveFwdThenState1
DW TryLeftFirst, TryFwdAfterLeftFirst, TryRightSecond
DW TryFwdAfterRightSecond, NoMove, NoMove, NoMove, NoMove
eatStateTable:
;$7f20
;DW EatOrTrack, MoveToZone, TryRight, TryFwdAfterRight
;DW TryLeft, TryFwdAfterLeft, RandomMove, MoveFwdThenState1
;DW TryLeftFirst, TryFwdAfterLeftFirst, TryRightSecond
;DW TryFwdAfterRightSecond, NoMove, NoMove, NoMove, NoMove
DW EatOrTrackState,EatOrTrackState,EatOrTrackState,EatOrTrackState
DW EatOrTrackState,EatOrTrackState,EatOrTrackState,EatOrTrackState
DW EatOrTrackState,EatOrTrackState,EatOrTrackState,EatOrTrackState
DW EatOrTrackState,EatOrTrackState,EatOrTrackState,EatOrTrackState
explosionFrameTable:
;$7f40
DB 0,8,0,8,0,0,0,0 ;pattern numbers
DB %00000000,%00000000,%01000000,%00100000 ;base attributes
DB %00000000,%01000000,%00100000,%01100000
trackEnemyStateTable:
;$7f50
DW SetupTrackEnemy, MoveToZone, TryRight, TryFwdAfterRight
DW TryLeft, TryFwdAfterLeft, RandomMove, MoveFwdThenState1
DW TryLeftFirst, TryFwdAfterLeftFirst, TryRightSecond
DW TryFwdAfterRightSecond, NoMove, NoMove, NoMove, NoMove
getLocSplitTable:
;$7f70
DB 0 ;%00 00 Facing: N Check: N
DB 0 ;%00 01 Facing: N Check: E
DB 1 ;%00 10 Facing: N Check: S
DB 0 ;%00 11 Facing: N Check: W
DB 0 ;%01 00 Facing: E Check: N
DB 1 ;%01 01 Facing: E Check: E
DB 0 ;%01 10 Facing: E Check: S
DB 0 ;%01 11 Facing: E Check: W
DB 0 ;%10 00 Facing: S Check: N
DB 0 ;%10 01 Facing: S Check: E
DB 1 ;%10 10 Facing: S Check: S
DB 0 ;%10 11 Facing: S Check: W
DB 0 ;%11 00 Facing: W Check: N
DB 1 ;%11 01 Facing: W Check: E
DB 0 ;%11 10 Facing: W Check: S
DB 0 ;%01 11 Facing: W Check: W
actorStateTable:
;$7f80
DW SetupMoveToLoc, MoveToZone, TryRight, TryFwdAfterRight
DW TryLeft, TryFwdAfterLeft, RandomMove, MoveFwdThenState1
DW TryLeftFirst, TryFwdAfterLeftFirst, TryRightSecond
DW TryFwdAfterRightSecond, NoMove, NoMove, NoMove, NoMove
fleeStateTable:
;$7fa0
DW ScardieFlee, MoveToZone, TryRight, TryFwdAfterRight
DW TryLeft, TryFwdAfterLeft, RandomMove, MoveFwdThenState1
DW TryLeftFirst, TryFwdAfterLeftFirst, TryRightSecond
DW TryFwdAfterRightSecond, NoMove, NoMove, NoMove, NoMove
ladyBulletStateTable:
;$7fc0
DW LadyBulletMove, MoveToZone, TryRight, TryFwdAfterRight
DW TryLeft, TryFwdAfterLeft, RandomMove, MoveFwdThenState1
DW TryLeftFirst, TryFwdAfterLeftFirst, TryRightSecond
DW TryFwdAfterRightSecond, NoMove, NoMove, NoMove, NoMove
;$7fe0