mirror of https://github.com/AbePralle/FGB.git
2264 lines
62 KiB
NASM
2264 lines
62 KiB
NASM
; Object.asm
|
|
; 1.2.2000 by Abe Pralle
|
|
; defines and handles the objects (data of classes) of FGB
|
|
|
|
;see Map.asm for location definitions of object RAM
|
|
|
|
;object data:
|
|
;each object is 16 bytes long
|
|
; Byte Name Description
|
|
; ---- ------ -------------------------------------------------------------
|
|
; 0 i_pos i index of left of object within map
|
|
; 1 j_pos j index of top of object within map
|
|
; 2 frame bits[2:0] - facing/frame of object. See (1) below.
|
|
; bits[4:3] - copy of timer's 2 LSB on upon last move
|
|
; bits[6:5] - index 0-3 on current path
|
|
; bit[7] - 1 if obj is currently a sprite, 0 if not
|
|
; 3 move Next move info
|
|
; bits[7:0] - counter 'till next move
|
|
; 4 limit Moves until AI switch + moves until fire again
|
|
; bits[3:0] - moveLimit. Decremented every move and
|
|
; sometimes used to switch states ("well this
|
|
; direction's not working").
|
|
; - Used as direction of fire by hero
|
|
; - Used as bullet color by bullet.
|
|
; bits[7-4] - special flags
|
|
; 7 = travel straight, speed=1 (OBJBIT_THROWN)
|
|
; 5 health Amount of health left
|
|
; bits[5:0] - Amount of health / hit points left
|
|
; bits[7:6] - desired direction. When the AI is sliding
|
|
; to the side looking for forward progress
|
|
; these bits tell the original direction.
|
|
; bits[7:6] - Fire timer. When not equal to classes
|
|
; 6 destzone bits [7:4] Destination zone (0-15) (no zone zero)
|
|
; [3:0] Number of dandelion puffs on me
|
|
; 7 misc bits[7:0] - Used for class-specific AI
|
|
; 8 state Current state of movement/ai
|
|
; bits[5:0] - state. Commonly:
|
|
; 0 - Reset. Figure out from scratch what
|
|
; to do.
|
|
; 1 - Move straightforwardly towards waypoint.
|
|
; 2 - Move up to "moveLimit" (see byte 4
|
|
; following) parallel to right of major
|
|
; axis, each time switching to state 3 to
|
|
; check for forward movement
|
|
; 3 - If can move forward along major axis do
|
|
; do and go back to state 1. If not go back
|
|
; to state 2.
|
|
; 4 - Same as (2) but moving left of major axis.
|
|
; 5 - Same as 3.
|
|
; 6 - Wander randomly.
|
|
; For heroes is spark timer
|
|
; bits[7:6] - attack dir state (direction to scan for
|
|
; attacking)
|
|
; 9 group bits[3:0] - group. Values:
|
|
; 0 - Free for all (shoot anything)
|
|
; 1 - Hero group
|
|
; 2-15 Monster A - Monster N
|
|
; 10 DESTL - actor dest low byte
|
|
; - eater low index
|
|
; - bullet damage
|
|
; - explosion initial frame
|
|
; 11 DESTH - actor dest high byte
|
|
; - eater high byte
|
|
; 12 SPRITELO - low ptr to sprite when obj is sprite
|
|
; 13 FIRETIMER - ticks before can fire again
|
|
; 14 unused
|
|
; 15 NEXT - index of next object or 0 for null
|
|
|
|
; (1) Frames have the following definitions:
|
|
; 0 (%000) - Facing north, frame0
|
|
; 1 (%001) - East, frame0
|
|
; 2 (%010) - South, frame0
|
|
; 3 (%011) - West, frame0
|
|
; 4 (%100) - Facing north, frame1 (top of two tiles)
|
|
; 5 (%101) - East, frame1 (left of two tiles)
|
|
; 6 (%110) - South, frame1 (top of two tiles)
|
|
; 7 (%111) - West, frame1 (left of two tiles)
|
|
|
|
; The object list works as follows:
|
|
; - All objects of the same class are stored as consecutive nodes in the
|
|
; linked list.
|
|
; - The following variables are used to keep track of the linked list:
|
|
; firstFree[1]: Index of first free object in objectExists[].
|
|
; node is linked to the next free node and so on (stored
|
|
; in bank0 instead of bank3 like the others)
|
|
; headTable[256]: Indices of head of list of a certain class. Every two
|
|
; bytes marks the start of a LowByte, HighByte address
|
|
; tailTable[256]: Indices of tail of list of a certain class.
|
|
|
|
INCLUDE "Source/Defs.inc"
|
|
INCLUDE "Source/Start.inc"
|
|
|
|
|
|
SECTION "ObjList",ROMX,BANK[CLASSROM]
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: AddObjectsToObjList
|
|
; Arguments: none
|
|
; Description: Parses through the map (just loaded) and creates an
|
|
; object for each creature and adds it to the objList.
|
|
;---------------------------------------------------------------------
|
|
AddObjectsToObjList::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
|
|
;initialize outer loop (b=0...mapHeight-1)
|
|
ld hl,map ;set hl to point to first tile in map
|
|
ld b,0
|
|
|
|
;initialize inner loop (c=0...mapWidth-1)
|
|
.outer ld c,0
|
|
ldio a,[firstMonster]
|
|
ld d,a
|
|
|
|
.inner ld a,MAPBANK ;switch to map RAM bank
|
|
ld [$ff00+$70],a
|
|
ld a,[hl] ;get a class index from map
|
|
cp d ;is it < first monster index?
|
|
jr c,.notAnObject
|
|
|
|
;create an object for d monsta
|
|
push bc
|
|
push de
|
|
;hl is ptr to location in map
|
|
ld c,a ;class index
|
|
call CreateObject ;returns de as ptr to object
|
|
pop de
|
|
pop bc
|
|
|
|
.notAnObject
|
|
;termination test for inner loop (is c==mapWidth?)
|
|
inc hl
|
|
inc c
|
|
ld a,[mapWidth]
|
|
cp c
|
|
jr nz,.inner
|
|
|
|
;skip excess width to make power of 2 pitch
|
|
ld a,[mapSkip]
|
|
ld d,0
|
|
ld e,a
|
|
add hl,de
|
|
|
|
;termination test for outer loop (is b==mapHeight?)
|
|
inc b
|
|
ld a,[mapHeight]
|
|
cp b
|
|
jr nz,.outer
|
|
|
|
;call the INIT method of each object
|
|
ld b,METHOD_INIT
|
|
call IterateAllLists
|
|
|
|
;call the DRAW method of each object
|
|
ld b,METHOD_DRAW
|
|
call IterateAllLists
|
|
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routines: PointerDEToIndex
|
|
; PointerHLToIndex
|
|
; Arguments: de/hl - pointer $d010-$dff0 to object
|
|
; Returns: a - index 1-255 of object
|
|
;---------------------------------------------------------------------
|
|
PointerDEToIndex::
|
|
push de
|
|
ld a,d
|
|
and %00001111
|
|
ld d,a
|
|
ld a,e
|
|
and %11110000
|
|
or d
|
|
swap a
|
|
pop de
|
|
ret
|
|
|
|
PointerHLToIndex::
|
|
push hl
|
|
ld a,h
|
|
and %00001111
|
|
ld h,a
|
|
ld a,l
|
|
and %11110000
|
|
or h
|
|
swap a
|
|
pop hl
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: ResetList
|
|
; Arguments: none
|
|
; Description: Sets all elements of headTable[] and tailTable[] to
|
|
; point to null. Sets up all 256 objExists flags to
|
|
; zero and [firstFreeObj] to 1. A few other misc things
|
|
;---------------------------------------------------------------------
|
|
ResetList::
|
|
push af
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
;Switch to the objectList RAM bank
|
|
ld a,OBJLISTBANK
|
|
ld [$ff00+$70],a
|
|
|
|
;Set object zero (which should never be accessed) to
|
|
;all-null to help ID infinite loops.
|
|
ld hl,objects
|
|
ld b,16
|
|
xor a
|
|
.setObjNullLoop
|
|
ld [hl+],a
|
|
dec b
|
|
jr nz,.setObjNullLoop
|
|
|
|
;Clear all elements of headTable[] and tailTable[] to
|
|
;point to null. tailTable[] follows headTable[] in memory so
|
|
;in total that's 512 bytes we need to set (or 256*2)
|
|
ld hl,headTable
|
|
xor a
|
|
ld c,0 ;e.g. counter of 256
|
|
|
|
.loop1 ld [hl+],a
|
|
ld [hl+],a
|
|
dec c
|
|
jr nz,.loop1
|
|
|
|
;Switch to the object RAM bank
|
|
ld a,OBJBANK
|
|
ld [$ff00+$70],a
|
|
|
|
;Set firstFreeObj to point to the first object, 1 ($d010)
|
|
ld a,1
|
|
ld [firstFreeObj],a
|
|
|
|
;255 objExists flags to zero
|
|
ld a,OBJLISTBANK
|
|
ld bc,255
|
|
ld d,0
|
|
ld hl,objExists+1
|
|
call MemSet
|
|
|
|
;set objExists[0] to 1 to prevent it from being allocated
|
|
ld a,1
|
|
ld [objExists],a
|
|
|
|
ld a,((objExists+1) & $ff)
|
|
ld [iterateNext],a
|
|
ld a,(((objExists+1)>>8) & $ff)
|
|
ld [iterateNext+1],a
|
|
|
|
ld a,255
|
|
ld [numFreeObjects],a
|
|
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
pop af
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: ClearFGBGFlags
|
|
; Arguments: None.
|
|
; Returns: Nothing.
|
|
; Alters: af
|
|
; Description: Clears bgAttributes and fgAttributes
|
|
;---------------------------------------------------------------------
|
|
ClearFGBGFlags::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
ld a,OBJLISTBANK
|
|
ld bc,256
|
|
ld d,0
|
|
ld hl,bgAttributes
|
|
call MemSet
|
|
|
|
ld a,OBJLISTBANK
|
|
ld bc,256
|
|
ld d,0
|
|
ld hl,fgAttributes
|
|
call MemSet
|
|
|
|
IF 0
|
|
;set all bgAttribute flags to zero
|
|
ld c,0
|
|
ld hl,bgAttributes
|
|
xor a
|
|
.bgAttrLoop
|
|
ld [hl+],a
|
|
dec c
|
|
jr nz,.bgAttrLoop
|
|
|
|
;set all fgAttribute flags to zero
|
|
ld c,0
|
|
ld hl,fgAttributes
|
|
xor a
|
|
.attrLoop
|
|
ld [hl+],a
|
|
dec c
|
|
jr nz,.attrLoop
|
|
ENDC
|
|
|
|
ld a,OBJLISTBANK
|
|
ld bc,256
|
|
ld d,0
|
|
ld hl,associatedIndex
|
|
call MemSet
|
|
|
|
ld a,OBJLISTBANK
|
|
ld bc,512
|
|
ld d,0
|
|
ld hl,classLookup
|
|
call MemSet
|
|
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: CreateObject
|
|
; Arguments: c - class index of object to create
|
|
; hl - ptr to location in map
|
|
; Returns: de - address of object
|
|
; Alters: af,de
|
|
; Description: Creates and adds the specified object into the list
|
|
; providing there's room. Equivalent to the following
|
|
; C code:
|
|
;
|
|
; if(!firstFreeObj) return 0;
|
|
; newObj = firstFreeObj;
|
|
; firstFreeObj = (next free obj index);
|
|
; if(!headTable[c]){
|
|
; headTable[c] = tailTable[c] = newObj;
|
|
; }else{
|
|
; tailTable[c]->nextItem = newObj;
|
|
; tailTable[c] = newObj;
|
|
; }
|
|
; return newObj;
|
|
;---------------------------------------------------------------------
|
|
CreateObject::
|
|
push af
|
|
push bc
|
|
push hl
|
|
|
|
ld a,OBJBANK ;switch in Object RAM
|
|
ld [$ff00+$70],a
|
|
|
|
;see if there's room for a new object
|
|
;if(!firstFreeObj) return 0;
|
|
ld a,[firstFreeObj]
|
|
or a ;check it out
|
|
jr nz,.freeNodeExists
|
|
|
|
ld de,0 ;return null
|
|
jp .doneHL
|
|
|
|
.freeNodeExists
|
|
push bc ;save class index for a bit
|
|
;newObj = firstFreeObj
|
|
;setup de to point to free node
|
|
ld [curObjIndex],a
|
|
call IndexToPointerDE ;de is now ptr to free node
|
|
|
|
;store location ptr (hl)
|
|
ld a,l
|
|
ld [de],a ;OBJ_IPOS
|
|
inc de
|
|
ld a,h
|
|
ld [de],a ;OBJ_JPOS
|
|
dec de
|
|
|
|
ld hl,numFreeObjects
|
|
dec [hl]
|
|
|
|
;firstFreeObj = (next free object index)
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
ld a,[firstFreeObj]
|
|
ld h,((objExists>>8) & $ff)
|
|
inc a
|
|
jr z,.foundNextFree ;no free objects
|
|
ld l,a
|
|
.lookAtNextObj
|
|
ld a,[hl+]
|
|
or a
|
|
jr nz,.thisObjNotFree
|
|
|
|
dec hl
|
|
ld a,l
|
|
jr .foundNextFree
|
|
|
|
.thisObjNotFree
|
|
ld a,l
|
|
or a
|
|
jr nz,.lookAtNextObj
|
|
;no free objects (1st is zero)
|
|
|
|
.foundNextFree
|
|
ld [firstFreeObj],a
|
|
|
|
;if(!headTable[c]){
|
|
ld h,((headTable>>8) & $ff)
|
|
ld l,c
|
|
ld a,[hl] ;get object index
|
|
or a
|
|
jr nz,.headExists
|
|
|
|
.noHead ;headTable[c] = curObjIndex
|
|
ld a,[curObjIndex]
|
|
ld [hl],a
|
|
|
|
;tailTable[c] = curObjIndex
|
|
ld h,((tailTable>>8) & $ff) ;hl is tailTable[c]
|
|
ld [hl],a
|
|
|
|
;switch in object RAM
|
|
ld a,OBJBANK
|
|
ld [$ff00+$70],a
|
|
|
|
jr .setNextToNull
|
|
|
|
.headExists
|
|
;oldTail = tailTable[c]
|
|
ld h,((tailTable>>8) & $ff)
|
|
ld a,[hl] ;old tail index
|
|
push de
|
|
call IndexToPointerDE
|
|
ld b,d
|
|
ld c,e ;bc = oldTail
|
|
pop de
|
|
|
|
;tailTable[c] = curObjIndex
|
|
ld a,[curObjIndex]
|
|
ld [hl],a
|
|
|
|
;switch in object RAM
|
|
ld a,OBJBANK
|
|
ld [$ff00+$70],a
|
|
|
|
;oldTail->nextItem = newObj
|
|
ld hl,OBJ_NEXT ;offset to get to nextItem
|
|
add hl,bc ;hl = &oldTail->nextItem
|
|
ld a,[curObjIndex]
|
|
ld [hl],a ;oldTail->nextItem = newObj
|
|
|
|
.setNextToNull
|
|
;newObj->nextItem = null
|
|
ld hl,OBJ_NEXT ;offset to get to nextItem low byte
|
|
add hl,de ;hl = &newObj->nextItem
|
|
xor a
|
|
ld [hl],a ;newObj->nextItem = null
|
|
|
|
;objExists[objectIndex] = 1;
|
|
ld a,OBJLISTBANK
|
|
ld [$ff00+$70],a
|
|
call GetObjectIndex ;sets up hl
|
|
ld a,1
|
|
ld [hl],a
|
|
|
|
;objClassLookup[objIndex] = classIndex
|
|
ld h,((objClassLookup>>8) & $ff)
|
|
pop bc ;get class lookup in c
|
|
ld [hl],c
|
|
|
|
.doneHL pop hl
|
|
;de is return value
|
|
pop bc
|
|
pop af
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: CreateInitAndDrawObject
|
|
; Arguments: c - class index to create
|
|
; hl - ptr to location in map
|
|
; Returns: de - address of object
|
|
; Alters: af,de
|
|
; Description: Creates and adds the specified object into the list
|
|
; providing there's room.
|
|
;---------------------------------------------------------------------
|
|
CreateInitAndDrawObject::
|
|
push bc
|
|
push hl
|
|
|
|
call CreateObject
|
|
ld a,d
|
|
or a
|
|
jr z,.done
|
|
|
|
ld b,METHOD_INIT
|
|
call CallMethod
|
|
ld b,METHOD_DRAW
|
|
call CallMethod
|
|
|
|
.done
|
|
pop hl
|
|
pop bc
|
|
ret
|
|
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: DeleteObject
|
|
; Arguments: c - class index of object to delete
|
|
; de - address of object
|
|
; Alters: af
|
|
; Description: Deletes the specified object from the class index's
|
|
; object list and returns it to the free node list.
|
|
; Equivalent to the following C code:
|
|
;
|
|
; //find the object
|
|
; prev = 0;
|
|
; for(cur=headTable[c]; cur; cur=cur->nextItem){
|
|
; if(cur==obj) break;
|
|
; prev = cur;
|
|
; }
|
|
; if(!cur) goto addToFreeList; //object not found
|
|
;
|
|
; //handle special cases of head and tail
|
|
; if(cur==headTable[c]){
|
|
; headTable[c] = cur->nextItem;
|
|
; }else{
|
|
; prev->nextItem = cur->nextItem;
|
|
; }
|
|
; if(cur==tailTable[c]){
|
|
; tailTable[c] = prev;
|
|
; }
|
|
;
|
|
; addToFreeList:
|
|
; firstFreeObj = min(firstFreeObj, curIndex);
|
|
; objExists[objIndex] = 0;
|
|
;---------------------------------------------------------------------
|
|
DeleteObject::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
ld hl,numFreeObjects
|
|
inc [hl]
|
|
|
|
;retrieve & save index of next object
|
|
ld a,OBJBANK
|
|
ld [$ff70],a
|
|
ld hl,OBJ_NEXT
|
|
add hl,de
|
|
ld a,[hl]
|
|
ld [nextObjIndex],a
|
|
|
|
;switch in objectList RAM
|
|
ld a,OBJLISTBANK
|
|
ld [$ff00+$70],a
|
|
|
|
;hl = &headTable[c]
|
|
ld h,((headTable>>8) & $ff)
|
|
ld l,c
|
|
|
|
;c = object index to remove
|
|
call PointerDEToIndex
|
|
ld [curObjIndex],a
|
|
ld c,a
|
|
;push de ;save original ptr to object
|
|
|
|
; prev = 0
|
|
; for(cur=headTable[c]; cur!=obj; cur=cur->nextItem){
|
|
; prev = cur;
|
|
; }
|
|
|
|
;b is prev index, a is cur index
|
|
ld b,0 ; prev = 0;
|
|
ld a,[hl] ; cur=headTable[c]
|
|
push hl ; save headTable
|
|
push hl ; save headTable again
|
|
|
|
push af
|
|
ld a,OBJBANK
|
|
ld [$ff70],a
|
|
pop af
|
|
|
|
;cur equal to desired?
|
|
.findIt
|
|
cp c
|
|
jr z,.foundIt
|
|
|
|
;prev = cur
|
|
ld b,a
|
|
|
|
;cur=cur->nextItem
|
|
call IndexToPointerHL
|
|
ld de,OBJ_NEXT
|
|
add hl,de
|
|
|
|
ld a,[hl]
|
|
jr .findIt
|
|
|
|
.foundIt
|
|
pop hl ;retrieve headTable[c]
|
|
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
;check value of prev to determine if cur is head or not
|
|
ld a,b
|
|
or a
|
|
|
|
;is head, set headTable[c] = cur->nextObj
|
|
jr z,.afterCheckHead
|
|
|
|
.notHead
|
|
;prev->nextObj = cur->nextObj
|
|
call IndexToPointerHL ;'a' is prevObj
|
|
ld de,OBJ_NEXT
|
|
add hl,de
|
|
ld a,OBJBANK
|
|
ld [$ff70],a
|
|
|
|
.afterCheckHead
|
|
ld a,[nextObjIndex]
|
|
ld [hl],a
|
|
|
|
;-------------------------check tail-----------------
|
|
; if(cur==tailTable[c]){
|
|
; tailTable[c] = prev;
|
|
; }
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
pop hl ;retrieve headTable[c]
|
|
ld h,((tailTable>>8) & $ff) ;make it tailTable[c]
|
|
|
|
ld a,c ;c is cur (found) obj
|
|
cp [hl]
|
|
jr nz,.afterCheckTail
|
|
|
|
ld [hl],b ;change tail = prev
|
|
|
|
.afterCheckTail
|
|
;objExists[objIndex] = 0;
|
|
ld h,((objExists>>8) & $ff) ;hl = &objExists[objIndex]
|
|
ld a,[curObjIndex]
|
|
ld l,a
|
|
xor a
|
|
ld [hl],a
|
|
|
|
;firstFreeObj = min(firstFreeObj, curObjIndex)
|
|
ld a,[firstFreeObj]
|
|
cp l ;compare to curObjIndex
|
|
jr c,.afterSetFirstFree ;no change
|
|
|
|
ld a,l
|
|
ld [firstFreeObj],a
|
|
|
|
.afterSetFirstFree
|
|
|
|
;pop de ;retrieve original pointer to object
|
|
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: IterateAllLists
|
|
; Arguments: b - offset of method to call on a given object
|
|
; Description: Loops through all the objects in each class calling a
|
|
; specified method on each. Makes use of the IterateList
|
|
; routine to do so.
|
|
;
|
|
; Equivalent to the following C code:
|
|
;
|
|
; void IterateAllLists(void *fnptr()){
|
|
; for(i=0; i<256; i++){
|
|
; IterateList(headTable[i],fnptr);
|
|
; }
|
|
; }
|
|
;
|
|
;---------------------------------------------------------------------
|
|
IterateAllLists::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
ld hl,headTable ;start of array of ptrs to heads of list
|
|
ld c,0 ;loop 0...numClasses - 1
|
|
|
|
.loop ld a,OBJLISTBANK ;switch in objectList RAM
|
|
ld [$ff00+$70],a
|
|
|
|
ld a,[hl+] ;de = headTable[i]
|
|
or a
|
|
jr z,.afterIterate
|
|
|
|
call IndexToPointerDE
|
|
call IterateList
|
|
|
|
.afterIterate
|
|
inc c
|
|
jr nz,.loop
|
|
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: IterateList
|
|
; Arguments: b - offset of method to call on a given object
|
|
; c - class index of object
|
|
; de - ptr to current object
|
|
; Description: Given a pointer to a list node (presumably the head),
|
|
; loops though all linked nodes calling a specified method
|
|
; on each object.
|
|
;
|
|
; Equivalent to the following C code:
|
|
;
|
|
; void IterateList(Node*cur, void *fnptr()){
|
|
; if(!cur) return;
|
|
; do{
|
|
; cur->fnptr(); //not really a C cmd I know!
|
|
; cur = cur->nextItem;
|
|
; }while(cur);
|
|
; }
|
|
;
|
|
;---------------------------------------------------------------------
|
|
IterateList::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
ldio a,[curObjWidthHeight]
|
|
push af
|
|
|
|
;pre-test curPtr to avoid unnecessary work if null
|
|
ld a,d ;test high byte of ptr
|
|
or a
|
|
jr z,.done
|
|
|
|
;save class index
|
|
ld a,c
|
|
ld [delTempL],a
|
|
ld a,b
|
|
ld [delTempH],a ;and method type
|
|
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
;convert offset into actual address of class method to call
|
|
ld a,b ;save function offset
|
|
ld b,0 ;clear high byte of bc
|
|
sla c ;shift c one left
|
|
rl b ;bit shifted out of c into b
|
|
ld hl,classLookup
|
|
add hl,bc ;hl is &classLookup[classIndex*2]
|
|
|
|
ld c,a ;method offset into c
|
|
ld a,[hl+]
|
|
ld b,a ;store LOW byte of addr in b
|
|
ld h,[hl] ;get high byte
|
|
ld l,b ;hl is now ptr to class
|
|
ld b,0 ;clear high byte of bc
|
|
add hl,bc ;hl is now ptr to ptr to class method
|
|
|
|
call GetMethodAddrFromPointer
|
|
|
|
.loop ;get ptr to next before calling method
|
|
ld a,OBJBANK ;switch in object RAM
|
|
ld [$ff00+$70],a
|
|
|
|
push hl
|
|
ld hl,OBJ_NEXT
|
|
add hl,de
|
|
ld a,[hl]
|
|
call IndexToPointerHL
|
|
ld b,h
|
|
ld c,l
|
|
pop hl
|
|
push bc ;save ptr to next on stack
|
|
|
|
push hl
|
|
ld bc,.returnAddress ;save return address on stack
|
|
push bc
|
|
ld a,[delTempL] ;class index into c
|
|
ld c,a
|
|
|
|
;----call super methods
|
|
push bc
|
|
push de
|
|
ld a,[delTempH] ;method index
|
|
cp METHOD_INIT
|
|
jr nz,.checkSuperDie
|
|
|
|
call SuperInit
|
|
jr .afterSuperDie
|
|
|
|
.checkSuperDie
|
|
cp METHOD_DIE
|
|
jr nz,.afterSuperDie
|
|
|
|
call SuperDie
|
|
|
|
.afterSuperDie
|
|
ld a,b
|
|
cp METHOD_CHECK
|
|
jr nz,.afterCheckIdle
|
|
ld a,[allIdle]
|
|
or a
|
|
jr z,.afterCheckIdle
|
|
;can't be explosion
|
|
pop de
|
|
pop bc
|
|
ld a,c
|
|
cp $ff
|
|
jr z,.returnAddress
|
|
jr .afterPopDEBC
|
|
.afterCheckIdle
|
|
|
|
pop de
|
|
pop bc
|
|
.afterPopDEBC
|
|
;---------
|
|
|
|
push hl
|
|
call SetObjWidthHeight
|
|
pop hl
|
|
jp hl ;start class method (de is cur)
|
|
.returnAddress
|
|
|
|
pop hl
|
|
pop de ;de = de->nextItem
|
|
ld a,d
|
|
or a ;we done?
|
|
jr nz,.loop
|
|
|
|
.done pop af
|
|
ldio [curObjWidthHeight],a
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: FindObject
|
|
; Arguments: c - class index of object to find
|
|
; de - location of object
|
|
; Returns: de - ptr to object
|
|
; a - non-zero if object was found
|
|
; Alters: af,de
|
|
; Description: Given a class and a location, finds the corresponding
|
|
; object.
|
|
; Note: Leaves the RAM bank set to OBJECT mem
|
|
;
|
|
; cur = headTable[c];
|
|
; while(cur){
|
|
; if(cur->loc == loc) return cur;
|
|
; cur = cur->nextItem;
|
|
; }
|
|
;---------------------------------------------------------------------
|
|
FindObject::
|
|
push bc
|
|
;de is return value
|
|
push hl
|
|
|
|
;find the head of the list
|
|
ld a,OBJLISTBANK ;switch in objectList RAM
|
|
ld [$ff00+$70],a
|
|
|
|
;find byte index into headTable array
|
|
ld h,((headTable>>8) & $ff)
|
|
ld l,c
|
|
ld a,[hl]
|
|
call IndexToPointerHL ;hl is head of list
|
|
|
|
ld bc,OBJ_NEXT-1 ;offset to add to hl during loop
|
|
|
|
;loop while our pointer is non-null
|
|
ld a,OBJBANK ;switch in object RAM
|
|
ld [$ff00+$70],a
|
|
|
|
.terminationTest
|
|
ld a,h ;high byte of ptr
|
|
or a ;null?
|
|
jr nz,.pointerOkay
|
|
|
|
.pointerNull
|
|
ld de,0 ;return null
|
|
jr .done
|
|
|
|
.pointerOkay
|
|
;test to see if object->loc == loc
|
|
ld a,[hl+] ;compare low byte
|
|
cp e
|
|
jr nz,.continue
|
|
ld a,[hl] ;compare high byte
|
|
cp d
|
|
jr nz,.continue
|
|
|
|
.foundMatch
|
|
dec hl
|
|
jr .returnMatch
|
|
|
|
.continue
|
|
add hl,bc ;add offset to get to nextItem
|
|
ld a,[hl]
|
|
call IndexToPointerHL ;cur = cur->nextItem
|
|
jr .terminationTest
|
|
|
|
.returnMatch
|
|
ld d,h
|
|
ld e,l
|
|
|
|
.done pop hl
|
|
;de is return value
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: CallMethod
|
|
; Arguments: b - offset of method to call
|
|
; c - class index of object
|
|
; de - ptr to object
|
|
; Returns: a - return value
|
|
; Alters: af
|
|
; Description: Calls the a class method passing in the location of an
|
|
; associated object.
|
|
; If calling Init or Die then calls SuperInit or
|
|
; or SuperDie first.
|
|
;---------------------------------------------------------------------
|
|
CallMethod::
|
|
ld a,b
|
|
cp METHOD_CHECK
|
|
jr nz,.afterCheckIdle
|
|
|
|
ld a,[allIdle]
|
|
or a
|
|
jr z,.afterCheckIdle
|
|
;can't be explosion
|
|
ld a,c
|
|
cp $ff
|
|
ret nz
|
|
|
|
.afterCheckIdle
|
|
push bc
|
|
push de
|
|
push hl
|
|
ldio a,[curObjWidthHeight]
|
|
push af
|
|
|
|
call SetObjWidthHeight
|
|
|
|
ld a,b
|
|
cp METHOD_INIT
|
|
jr nz,.checkSuperDie
|
|
|
|
call SuperInit
|
|
jr .afterSuperDie
|
|
|
|
.checkSuperDie
|
|
cp METHOD_DIE
|
|
jr nz,.afterSuperDie
|
|
|
|
call SuperDie
|
|
|
|
.afterSuperDie
|
|
;find the base address of class and add method offset
|
|
;get offset into classLookup
|
|
ld l,c
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
xor a
|
|
sla l
|
|
rla
|
|
add ((classLookup>>8) & $ff)
|
|
ld h,a ;hl is &classLookup[c]
|
|
ld a,[hl+]
|
|
add b ;add offset of method
|
|
ld h,[hl]
|
|
ld l,a ;hl is addr of class methods
|
|
ld a,0
|
|
adc h
|
|
ld h,a ;hl is addr of specific method
|
|
|
|
call GetMethodAddrFromPointer
|
|
|
|
ld a,c ;store class index in A temporarily
|
|
ld bc,.returnAddress ;save return address on stack
|
|
push bc
|
|
ld c,a ;class index into c
|
|
jp hl ;start class method (de is cur)
|
|
.returnAddress
|
|
|
|
.done
|
|
ld h,a ;save return value
|
|
pop af
|
|
ldio [curObjWidthHeight],a
|
|
ld a,h ;restore return value
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: SetObjWidthHeight
|
|
; Arguments: c - class index
|
|
; Returns: Nothing.
|
|
; Alters: af,hl
|
|
; Description: Sets up [curObjWidthHeight] with either 1 (for 1x1)
|
|
; or 2 (2x2)
|
|
;---------------------------------------------------------------------
|
|
SetObjWidthHeight::
|
|
;set the tile width and height to either 1x1 or 2x2
|
|
ld a,TILEINDEXBANK
|
|
ld [$ff70],a
|
|
ld h,((fgAttributes>>8) & $ff)
|
|
ld l,c
|
|
ld a,[hl]
|
|
rrca
|
|
swap a
|
|
and 1
|
|
inc a ;one or two
|
|
ldio [curObjWidthHeight],a
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetObjectIndex
|
|
; Arguments: de - ptr to object
|
|
; Returns: hl - &objExists[objIndex]
|
|
; Alters: af,hl
|
|
;---------------------------------------------------------------------
|
|
GetObjectIndex:
|
|
call PointerDEToIndex
|
|
ld h,((objExists>>8) & $ff)
|
|
ld l,a
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: IterateMaxObjects
|
|
; Arguments: b - offset of method to call on a given object
|
|
; c - max objects to iterate through
|
|
; Alters: af
|
|
; Description: Loops through the next 256 objects indices. If an
|
|
; object exists then the specified method is called on
|
|
; it and one is added to the maxObjects counter. When
|
|
; "maxObjects" have been handled the routine returns
|
|
; and picks up again next time where it left off. Each
|
|
; time the counter wraps around the object timers are
|
|
; incremented
|
|
;---------------------------------------------------------------------
|
|
IterateMaxObjects::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
ld a,OBJLISTBANK
|
|
ld [$ff00+$70],a
|
|
|
|
ld a,[iterateNext]
|
|
ld l,a
|
|
ld a,[iterateNext+1]
|
|
ld h,a
|
|
|
|
.outer ld e,0
|
|
|
|
.inner ld a,[hl+] ;pick up the next flag
|
|
|
|
or a ;non-zero?
|
|
jr z,.continue
|
|
|
|
;found an existing object
|
|
push de
|
|
push hl
|
|
|
|
dec hl ;go back to where we found it
|
|
|
|
;convert objIndex hl into objAddress de
|
|
ld a,l
|
|
call IndexToPointerDE
|
|
|
|
;get the class index
|
|
;hl = &objClassLookup[objIndex]
|
|
ld h,((objClassLookup>>8) & $ff)
|
|
ld a,[hl] ;what's the class index?
|
|
ld h,c ;stow c for a sec
|
|
ld c,a
|
|
|
|
call CallMethod
|
|
|
|
ld c,h ;retrieve c from storage
|
|
|
|
pop hl
|
|
pop de
|
|
dec c ;used one of our max checks
|
|
|
|
ld a,OBJLISTBANK ;be sure & point back to our
|
|
ld [$ff00+$70],a ;list RAM
|
|
|
|
.continue
|
|
;wrap around hl
|
|
ld a,h ;is hl < objExists + 256?
|
|
cp (((objExists>>8)&$ff)+1)
|
|
jr c,.hlOkay
|
|
|
|
ld hl,objExists+1 ;wrap around to beginning
|
|
call UpdateObjTimers ;update timers
|
|
|
|
.hlOkay
|
|
xor a
|
|
cp c
|
|
jr z,.skipUnused ;bust out if we've checked enough
|
|
|
|
dec e
|
|
jr nz,.inner
|
|
|
|
.skipUnused
|
|
|
|
.done
|
|
;save current value of hl
|
|
ld a,l
|
|
ld [iterateNext],a
|
|
ld a,h
|
|
ld [iterateNext+1],a
|
|
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: DeleteObjectsOfClass
|
|
; Arguments: bc - class to delete objects
|
|
; Alters: af
|
|
; Description:
|
|
;---------------------------------------------------------------------
|
|
DeleteObjectsOfClass::
|
|
push de
|
|
push hl
|
|
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
ld e,1
|
|
ld hl,classLookup+2
|
|
|
|
.loop ld a,[hl+]
|
|
cp c
|
|
jr nz,.afterCheck
|
|
ld a,[hl]
|
|
cp b
|
|
jr nz,.afterCheck
|
|
|
|
ld a,e
|
|
call DeleteObjectsOfClassIndex
|
|
|
|
.afterCheck
|
|
inc hl
|
|
inc e
|
|
jr nz,.loop
|
|
|
|
pop hl
|
|
pop de
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: DeleteObjectsOfClassIndex
|
|
; Arguments: a - class index to delete objects
|
|
; Alters: af,hl
|
|
; Description: Deletes all objects of the specified class index type
|
|
;---------------------------------------------------------------------
|
|
DeleteObjectsOfClassIndex::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
ld c,a ;class index in c
|
|
|
|
ld a,TILEINDEXBANK
|
|
ldio [$ff70],a
|
|
|
|
ld h,((headTable>>8) & $ff)
|
|
ld l,c
|
|
|
|
.loop ld a,[hl] ;get head object in de
|
|
or a
|
|
jr z,.done
|
|
call IndexToPointerDE
|
|
|
|
ld b,METHOD_DIE
|
|
call IterateList
|
|
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
.done
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetFirst
|
|
; Arguments: c - class index
|
|
; Returns: de - head of list or null
|
|
; a - null if no first object
|
|
; zflag - or a
|
|
; Alters: af,de
|
|
;---------------------------------------------------------------------
|
|
GetFirst::
|
|
call GetHead
|
|
call IndexToPointerDE
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetNextObject
|
|
; Arguments: de - current object
|
|
; Returns: a - null if no next object
|
|
; de - next object
|
|
; zflag - or a
|
|
; Alters: af,de
|
|
;---------------------------------------------------------------------
|
|
GetNextObject::
|
|
call GetNext
|
|
call IndexToPointerDE
|
|
ld a,d
|
|
or a
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetNext
|
|
; Arguments: de - current object
|
|
; Returns: a - index of next object or null
|
|
; Alters: af
|
|
;---------------------------------------------------------------------
|
|
GetNext::
|
|
push hl
|
|
|
|
ld a,OBJBANK
|
|
ld [$ff70],a
|
|
|
|
ld hl,OBJ_NEXT
|
|
add hl,de
|
|
ld a,[hl]
|
|
|
|
pop hl
|
|
or a
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: SetNext
|
|
; Arguments: a - index of next object
|
|
; de - current object
|
|
; Returns: Nothing.
|
|
; Alters: Nothing.
|
|
;---------------------------------------------------------------------
|
|
SetNext::
|
|
push hl
|
|
push af
|
|
ld a,OBJBANK
|
|
ldio [$ff70],a
|
|
pop af
|
|
|
|
ld hl,OBJ_NEXT
|
|
add hl,de
|
|
ld [hl],a
|
|
|
|
pop hl
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: SetHead
|
|
; Arguments: a - index to set head to
|
|
; c - class index
|
|
; Returns: None.
|
|
; Alters: af
|
|
;---------------------------------------------------------------------
|
|
SetHead::
|
|
push hl
|
|
push af
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
pop af
|
|
|
|
ld h,((headTable>>8) & $ff)
|
|
ld l,c
|
|
|
|
ld [hl],a
|
|
pop hl
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetHead
|
|
; Arguments: c - class index
|
|
; Returns: a - index of object at head or null if empty list
|
|
; Alters: af
|
|
;---------------------------------------------------------------------
|
|
GetHead::
|
|
push hl
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
ld h,((headTable>>8) & $ff)
|
|
ld l,c
|
|
|
|
ld a,[hl] ;get head object index
|
|
pop hl
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetTail
|
|
; Arguments: c - class index
|
|
; Returns: a - index of object at tail or null if empty list
|
|
; de - list
|
|
; Alters: af
|
|
;---------------------------------------------------------------------
|
|
GetTail::
|
|
push hl
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
ld h,((tailTable>>8) & $ff)
|
|
ld l,c
|
|
|
|
ld a,[hl] ;get tail object index
|
|
pop hl
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: SetTail
|
|
; Arguments: a - index to set head to
|
|
; c - class index
|
|
; Returns: Nothing.
|
|
; Alters: Nothing.
|
|
;---------------------------------------------------------------------
|
|
SetTail::
|
|
push hl
|
|
push af
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
pop af
|
|
|
|
ld h,((tailTable>>8) & $ff)
|
|
ld l,c
|
|
|
|
ld [hl],a
|
|
pop hl
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetNumObjects
|
|
; Arguments: c - class index
|
|
; Returns: a - object count for class
|
|
; zflag - or a
|
|
; Alters: af
|
|
;---------------------------------------------------------------------
|
|
GetNumObjects::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
ld b,0
|
|
call GetFirst
|
|
jr z,.countFinished
|
|
|
|
.getNext
|
|
inc b
|
|
call GetNextObject
|
|
jr z,.countFinished
|
|
jr .getNext
|
|
|
|
.countFinished
|
|
ld a,b
|
|
or a
|
|
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetAssociated
|
|
; Arguments: c - class index
|
|
; Returns: a - associated class index
|
|
; Alters: af
|
|
;---------------------------------------------------------------------
|
|
GetAssociated::
|
|
push hl
|
|
ld a,TILEINDEXBANK
|
|
ld [$ff70],a
|
|
ld h,((associatedIndex>>8)&$ff)
|
|
ld l,c
|
|
ld a,[hl]
|
|
pop hl
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
SECTION "ObjListHome",ROM0
|
|
;---------------------------------------------------------------------
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: InitFOF
|
|
; Arguments: none
|
|
; Returns: nothing
|
|
; Alters: af
|
|
; Description: Initializes the Friend Or Foe Table so that each group
|
|
; is friends only with itself except for:
|
|
; - FFA group friends with no one (not even selves)
|
|
; - MONSTERM/N (groups M&N) set to friends with all
|
|
; but FFA
|
|
; - MONSTERB set to friends with hero
|
|
;---------------------------------------------------------------------
|
|
InitFOF::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
ld c,0 ;loop 256 times
|
|
ld hl,FOFTable
|
|
xor a
|
|
|
|
.loop1 ld [hl+],a
|
|
dec c
|
|
jr nz,.loop1
|
|
|
|
ld hl,FOFTable+17
|
|
ld c,15
|
|
ld a,1
|
|
ld de,16 ;offset
|
|
|
|
.loop2 ld [hl+],a
|
|
add hl,de
|
|
dec c
|
|
jr nz,.loop2
|
|
|
|
;set monster N to be friends with all but FFA
|
|
;row
|
|
ld hl,FOFTable+30 ;row 2, second to last column
|
|
ld c,15 ;set next 15 rows
|
|
.loop30 ld [hl],a
|
|
add hl,de
|
|
dec c
|
|
jr nz,.loop30
|
|
|
|
;column
|
|
ld hl,FOFTable+(14*16)+1
|
|
ld c,15
|
|
.loop40 ld [hl+],a
|
|
dec c
|
|
jr nz,.loop40
|
|
|
|
;set monster N to be friends with all but FFA
|
|
;row
|
|
ld hl,FOFTable+31 ;row 2, last column
|
|
ld c,15 ;set next 15 rows
|
|
.loop3 ld [hl],a
|
|
add hl,de
|
|
dec c
|
|
jr nz,.loop3
|
|
|
|
;column
|
|
ld hl,FOFTable+(15*16)+1
|
|
ld c,15
|
|
.loop4 ld [hl+],a
|
|
dec c
|
|
jr nz,.loop4
|
|
|
|
ld a,1
|
|
ld b,GROUP_HERO
|
|
ld c,GROUP_MONSTERB
|
|
call SetFOF
|
|
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: SetFOF
|
|
; Arguments: a - value to set to (0=enemies or 1=friends)
|
|
; b - group 1
|
|
; c - group 2
|
|
; Returns: nothing
|
|
; Alters: af
|
|
; Description: Sets an entry in the FOF table
|
|
;---------------------------------------------------------------------
|
|
SetFOF::
|
|
push hl
|
|
|
|
;combine b and c in l
|
|
push af
|
|
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
ld a,b
|
|
swap a
|
|
or c
|
|
ld l,a
|
|
ld h,((FOFTable>>8) & $ff)
|
|
pop af
|
|
|
|
;set the one entry
|
|
ld [hl],a
|
|
|
|
;set the reverse entry
|
|
swap l
|
|
ld [hl],a
|
|
|
|
pop hl
|
|
ret
|
|
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetFOF
|
|
; Arguments: b - group 1
|
|
; c - group 2
|
|
; Returns: a - 1=friend, 0=foe
|
|
; Alters: af
|
|
; Description: Sets an entry in the FOF table
|
|
;---------------------------------------------------------------------
|
|
GetFOF::
|
|
push hl
|
|
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
ld a,b
|
|
swap a
|
|
or c
|
|
ld l,a
|
|
ld h,((FOFTable>>8) & $ff)
|
|
|
|
ld a,[hl]
|
|
|
|
pop hl
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: LinkRemakeLists
|
|
; Arguments: None.
|
|
; Alters: af
|
|
; Returns: Nothing.
|
|
; Description: Initializes some values.
|
|
; objTimerBase = 0
|
|
; objTimer60ths = 0
|
|
; heroTimerBase = 0
|
|
; heroTimer60ths = 0
|
|
; oamFindPos = 0
|
|
; baMoved = 0
|
|
; bsMoved = 0
|
|
; iterateNext = objExists + 1
|
|
;
|
|
; Remakes the tailTable.
|
|
; Waits for a VBLANK
|
|
; Resets $ff+vblankTimer to zero
|
|
; Resets updateTimer to zero
|
|
;---------------------------------------------------------------------
|
|
LinkRemakeLists::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
;initialize some values
|
|
xor a
|
|
ld [objTimerBase],a
|
|
ld [objTimer60ths],a
|
|
ld [heroTimerBase],a
|
|
ld [heroTimer60ths],a
|
|
ld [oamFindPos],a
|
|
ld [baMoved],a
|
|
ld [bsMoved],a
|
|
ld de,objExists+1
|
|
ld hl,iterateNext
|
|
ld [hl],e
|
|
inc hl
|
|
ld [hl],d
|
|
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
;----remake tailTable-----------------------------------------
|
|
;first go through and zero out contents of tailTable
|
|
ld hl,tailTable
|
|
ld c,0 ;loop 256 times
|
|
xor a
|
|
.zeroTailTable
|
|
ld [hl+],a
|
|
dec c
|
|
jr nz,.zeroTailTable
|
|
|
|
;start at the head of each list and follow each link until
|
|
;a null link is found. That will be the tail.
|
|
ld de,headTable
|
|
.getNextListHead
|
|
ld a,[de]
|
|
or a ;this linked list null?
|
|
jr z,.afterMakeTail
|
|
|
|
ld b,a
|
|
ld a,OBJBANK
|
|
ld [$ff70],a
|
|
ld a,b ;index of object
|
|
ld bc,OBJ_NEXT
|
|
.followLink
|
|
call IndexToPointerHL ;convert into object pointer
|
|
add hl,bc ;set HL to point to link
|
|
ld a,[hl] ;get link
|
|
or a
|
|
jr nz,.followLink
|
|
|
|
;HL is the tail + OBJ_NEXT
|
|
;convert HL to obj index and use that to set up
|
|
;entry into tailTable
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
ld a,l ;align hl on 16-byte boundary
|
|
and %11110000
|
|
ld l,a
|
|
call PointerHLToIndex
|
|
ld d,((tailTable>>8) & $ff) ;de is &tailTable[class]
|
|
ld [de],a
|
|
ld d,((headTable>>8) & $ff) ;de is &headTable[class]
|
|
|
|
.afterMakeTail
|
|
inc de
|
|
ld a,e
|
|
or a
|
|
jr nz,.getNextListHead
|
|
|
|
xor a
|
|
ldio [vblankTimer],a
|
|
ldio [updateTimer],a
|
|
|
|
;count the number of free objects
|
|
ld c,$ff
|
|
ld hl,objExists+1
|
|
.countFree
|
|
ld a,[hl+]
|
|
or a
|
|
jr z,.countContinue
|
|
dec c
|
|
.countContinue
|
|
ld a,h
|
|
cp $d5
|
|
jr nz,.countFree
|
|
ld a,c
|
|
ld [numFreeObjects],a
|
|
|
|
call SetBGSpecialFlags
|
|
|
|
ld b,METHOD_DRAW
|
|
call IterateAllLists
|
|
|
|
call ClearBackBuffer
|
|
|
|
call RestrictCameraToBounds
|
|
call ScrollToCamera
|
|
call DrawMapToBackBuffer
|
|
|
|
;turn on sound master control
|
|
ld a,$80
|
|
ld [$ff26],a
|
|
|
|
ld a,$ff
|
|
ld [$ff24],a ;full volume both channels
|
|
ld [$ff25],a ;all sounds to both channels
|
|
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetClass
|
|
; Arguments: de - current object
|
|
; Returns: c - class index of object
|
|
; Alters: af,c
|
|
;---------------------------------------------------------------------
|
|
GetClass::
|
|
push hl
|
|
ld a,OBJLISTBANK
|
|
ldio [$ff70],a
|
|
call PointerDEToIndex
|
|
ld h,((objClassLookup>>8) & $ff)
|
|
ld l,a
|
|
ld c,[hl] ;obj class
|
|
pop hl
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: InstanceOf
|
|
; Arguments: c - class index of object
|
|
; hl - class (e.g. classWallCreature)
|
|
; Returns: a - 1 if this instanceof, 0 if not instanceof
|
|
; Alters: af,hl
|
|
;---------------------------------------------------------------------
|
|
InstanceOf::
|
|
push de
|
|
ld d,h
|
|
ld e,l
|
|
call GetClassMethodTable
|
|
ld a,d
|
|
cp h
|
|
jr nz,.false
|
|
ld a,e
|
|
cp l
|
|
jr nz,.false
|
|
ld a,1
|
|
pop de
|
|
ret
|
|
.false
|
|
pop de
|
|
xor a
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetClassMethodTable
|
|
; Arguments: c - class index of object
|
|
; Returns: hl - ptr to method vector table
|
|
; Alters: af,hl
|
|
;---------------------------------------------------------------------
|
|
GetClassMethodTable::
|
|
ld a,OBJLISTBANK
|
|
ldio [$ff70],a
|
|
|
|
ld h,0
|
|
ld l,c
|
|
sla l
|
|
rl h
|
|
push bc
|
|
ld bc,classLookup
|
|
add hl,bc
|
|
pop bc
|
|
|
|
ld a,[hl+]
|
|
ld h,[hl]
|
|
ld l,a
|
|
ret
|
|
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetFGMapping
|
|
; Arguments: c - class index
|
|
; Returns: a - tile index mapped to class
|
|
; Alters: af, hl
|
|
;---------------------------------------------------------------------
|
|
GetFGMapping::
|
|
ld a,TILEINDEXBANK
|
|
ldio [$ff70],a
|
|
ld h,((fgTileMap>>8) & $ff)
|
|
ld l,c
|
|
ld a,[hl]
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: SetFGMapping
|
|
; Arguments: a - tile index to set to
|
|
; c - class index
|
|
; Returns: Nothing.
|
|
; Alters: af, hl
|
|
;---------------------------------------------------------------------
|
|
SetFGMapping::
|
|
push af
|
|
ld a,TILEINDEXBANK
|
|
ldio [$ff70],a
|
|
pop af
|
|
ld h,((fgTileMap>>8) & $ff)
|
|
ld l,c
|
|
ld [hl],a
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: GetBGMapping
|
|
; Arguments: c - class index
|
|
; Returns: a - tile index mapped to class
|
|
; Alters: af, hl
|
|
;---------------------------------------------------------------------
|
|
GetBGMapping::
|
|
ld a,TILEINDEXBANK
|
|
ldio [$ff70],a
|
|
ld h,((bgTileMap>>8) & $ff)
|
|
ld l,c
|
|
ld a,[hl]
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: SetBGMapping
|
|
; Arguments: a - tile index to set to
|
|
; c - class index
|
|
; Returns: Nothing.
|
|
; Alters: af, hl
|
|
;---------------------------------------------------------------------
|
|
SetBGMapping::
|
|
push af
|
|
ld a,TILEINDEXBANK
|
|
ldio [$ff70],a
|
|
pop af
|
|
ld h,((bgTileMap>>8) & $ff)
|
|
ld l,c
|
|
ld [hl],a
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: CheckEachHero
|
|
; Arguments: a - skip hero1 if hero0 return true (1=yes, 0=no)
|
|
; hl - routine to call
|
|
; Returns: a - 1 or 0 result of last function called
|
|
; Alters: all
|
|
; Description: loads {A} with hero0_index and then hero1_index,
|
|
; calling the routine pointer with each.
|
|
;---------------------------------------------------------------------
|
|
CheckEachHero::
|
|
push af
|
|
|
|
ld a,[hero0_index]
|
|
or a
|
|
jr z,.checkHero1
|
|
push hl
|
|
ld de,.returnPoint0
|
|
push de ;return address
|
|
jp hl
|
|
.returnPoint0
|
|
pop hl
|
|
or a
|
|
jr z,.checkHero1
|
|
|
|
;second is optional
|
|
pop af
|
|
or a
|
|
ret nz ;optional okay
|
|
|
|
push af
|
|
.checkHero1
|
|
pop af
|
|
ld a,[hero1_index]
|
|
or a
|
|
ret z
|
|
|
|
ld de,.returnAddress1
|
|
push de
|
|
jp hl ;will return to my parent
|
|
.returnAddress1
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: RemoveHero
|
|
; Arguments: c - hero class index
|
|
; Returns: Nothing.
|
|
; Alters: af
|
|
; Description: Saving heroes current health etc into heroX_data.
|
|
; If its health is zero:
|
|
; - restores health to full (incorrect)
|
|
; - changes map to [respawnMap] if local hero, leaves
|
|
; map be if remote hero.
|
|
; Does nothing if class index is null.
|
|
; Removes the hero from the map.
|
|
; If local, sets [heroesPresent] to zero. If remote
|
|
; then remote hero flag is removed by RemoveRemoteHero
|
|
;---------------------------------------------------------------------
|
|
RemoveHero::
|
|
ld a,c
|
|
or a
|
|
ret z
|
|
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
call GetFirst ;get the hero object in de
|
|
call GetHealth
|
|
or a
|
|
jr nz,.afterDeath
|
|
|
|
IF INFINITEHEALTH==0
|
|
;----dead, create an explosion----
|
|
call GetFGAttributes
|
|
and %111 ;isolate color
|
|
ld [bulletColor],a
|
|
call GetCurLocation
|
|
ld a,l
|
|
ld [bulletLocation],a
|
|
ld a,h
|
|
ld [bulletLocation+1],a
|
|
ld b,16 ;initial frame
|
|
call CreateExplosion
|
|
ENDC
|
|
|
|
.afterDeath
|
|
ld a,[hero0_index]
|
|
cp c
|
|
jr nz,.handleHero1
|
|
|
|
;----hero 0 (local)-----
|
|
call GetPuffCount
|
|
ld [hero0_puffCount],a
|
|
call GetHealth
|
|
ld [hero0_health],a
|
|
ld b,a
|
|
ld hl,hero0_data
|
|
ld a,[amLinkMaster]
|
|
or a
|
|
jr z,.removeRemote
|
|
jr .removeLocal
|
|
|
|
.handleHero1
|
|
;----hero 1 (remote)----
|
|
call GetPuffCount
|
|
ld [hero1_puffCount],a
|
|
call GetHealth
|
|
ld [hero1_health],a
|
|
ld b,a
|
|
ld hl,hero1_data
|
|
ld a,[amLinkMaster]
|
|
or a
|
|
jr z,.removeLocal
|
|
jr .removeRemote
|
|
|
|
.removeLocal
|
|
push bc
|
|
push hl
|
|
call GetFacing
|
|
ld c,a
|
|
call RemoveFromMap
|
|
xor a
|
|
ld [heroesPresent],a
|
|
pop hl
|
|
pop bc
|
|
|
|
push bc
|
|
push de
|
|
push hl
|
|
ld de,classDoNothing
|
|
call GetClassMethodTable
|
|
ld b,h
|
|
ld c,l
|
|
call ChangeClass
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
|
|
ld a,b
|
|
or a
|
|
jr nz,.done ;wasn't dying, just leaving
|
|
|
|
IF INFINITEHEALTH==0
|
|
;pause for a second
|
|
ld a,30
|
|
call Delay
|
|
|
|
;fade to black
|
|
;ld a,30
|
|
;call SetupFadeToBlack
|
|
;call WaitFade
|
|
|
|
;----respawn at the appropriate map----
|
|
ld de,HERODATA_ENTERDIR
|
|
add hl,de
|
|
ld a,EXIT_D
|
|
ld [hl],a
|
|
|
|
call UpdateState
|
|
|
|
ld hl,$1500
|
|
ld a,l
|
|
ld [curLevelIndex],a
|
|
ld a,h
|
|
ld [curLevelIndex+1],a
|
|
ld a,1
|
|
ld [timeToChangeLevel],a
|
|
ENDC
|
|
jr .done
|
|
|
|
.removeRemote
|
|
call RemoveRemoteHero
|
|
|
|
.done
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: CallBGAction
|
|
; Arguments: a - action type (BGACTION_HIT)
|
|
; c - class
|
|
; hl - map location of bg tile
|
|
; Returns: 'a' zflag from action + a's zflag, normally:
|
|
; 0 - no explosion
|
|
; non-zero - explosion
|
|
; Alters: af
|
|
; Description:
|
|
;---------------------------------------------------------------------
|
|
CallBGAction::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
;ensure class IS a bg class
|
|
ld d,a
|
|
ldio a,[firstMonster]
|
|
ld e,a
|
|
ld a,c
|
|
or a
|
|
jr z,.returnAddress ;null tile
|
|
cp e
|
|
jr nc,.returnAddress ;is a monster (myself?)
|
|
ld a,d
|
|
|
|
;save return address on stack
|
|
ld de,.returnAddress
|
|
push de
|
|
|
|
;get tile class in c
|
|
push af
|
|
|
|
push hl
|
|
call GetClassMethodTable
|
|
ld d,h
|
|
ld e,l
|
|
pop hl
|
|
pop af
|
|
push de ;addr of method on stack
|
|
|
|
ret ;call method
|
|
|
|
.returnAddress
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
or a
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: ChangeMyClass
|
|
; ChangeMyClassAndRedraw
|
|
; ChangeMyClassToAssociatedAndRedraw
|
|
; Arguments: a - new class type
|
|
; c - old class type
|
|
; de - this
|
|
; Returns: c - new class type
|
|
; Alters: af,c
|
|
; Description: Changes this object from the old to new class type.
|
|
;---------------------------------------------------------------------
|
|
ChangeMyClassToAssociatedAndRedraw::
|
|
call GetAssociated
|
|
jp ChangeMyClassAndRedraw
|
|
|
|
ChangeMyClassAndRedraw::
|
|
call ChangeMyClass
|
|
ld b,METHOD_DRAW
|
|
jp CallMethod
|
|
|
|
ChangeMyClass::
|
|
push af
|
|
call RemoveObjectFromList
|
|
pop af
|
|
ld c,a
|
|
call AddObjectToList
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: RemoveObjectFromList
|
|
; Arguments: c - class type
|
|
; de - this
|
|
; Returns: Nothing.
|
|
; Alters: af
|
|
; Description: Removes the object from its class's linked list but
|
|
; does not delete it.
|
|
;---------------------------------------------------------------------
|
|
RemoveObjectFromList::
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
call PointerDEToIndex
|
|
ld b,a
|
|
|
|
;head of list?
|
|
call GetHead
|
|
cp b
|
|
jr nz,.notHead
|
|
|
|
;make next item new head of list
|
|
call IndexToPointerDE
|
|
call GetNext
|
|
call SetHead
|
|
jr .done
|
|
|
|
.notHead
|
|
.search
|
|
;search through list for item that points to that to remove
|
|
call IndexToPointerDE
|
|
call GetNext
|
|
cp b
|
|
jr nz,.search
|
|
|
|
.foundPrevious
|
|
;set prev->next = prev->next->next
|
|
call PointerDEToIndex
|
|
push af ;save index of prev
|
|
ld a,b ;get searchObj
|
|
call IndexToPointerDE
|
|
call GetNext ;searchObj->next
|
|
ld b,a
|
|
pop af
|
|
call IndexToPointerDE ;prev = searchObj->next
|
|
ld a,b
|
|
call SetNext
|
|
|
|
;if next is null then removed obj was tail. Reset tail
|
|
;to prev
|
|
;ld b,a redundant; A already == B
|
|
or a
|
|
jr nz,.done
|
|
|
|
call PointerDEToIndex
|
|
call SetTail
|
|
|
|
.done
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: AddObjectToList
|
|
; Arguments: c - class type
|
|
; de - this
|
|
; Returns: Nothing.
|
|
; Alters: af
|
|
; Description:
|
|
;---------------------------------------------------------------------
|
|
AddObjectToList::
|
|
push de
|
|
|
|
xor a
|
|
call SetNext ;obj->next = null in all cases
|
|
|
|
call PointerDEToIndex
|
|
|
|
push af
|
|
|
|
;objClassLookup[objIndex] = classIndex
|
|
ld d,((objClassLookup>>8) & $ff)
|
|
ld e,a
|
|
ld a,OBJLISTBANK
|
|
ldio [$ff70],a
|
|
ld a,c
|
|
ld [de],a
|
|
|
|
;head == null?
|
|
call GetHead
|
|
or a
|
|
jr nz,.addToTail
|
|
|
|
.addToHead
|
|
pop af
|
|
call SetHead
|
|
call SetTail
|
|
pop de
|
|
ret
|
|
|
|
.addToTail
|
|
call GetTail
|
|
call IndexToPointerDE
|
|
pop af
|
|
|
|
call SetNext
|
|
call SetTail
|
|
|
|
pop de
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: SetAssociated
|
|
; Arguments: b - class to associate
|
|
; c - current class
|
|
; Alters: af
|
|
;---------------------------------------------------------------------
|
|
SetAssociated::
|
|
push hl
|
|
ld a,OBJLISTBANK
|
|
ld [$ff70],a
|
|
|
|
ld h,((associatedIndex>>8)&$ff)
|
|
ld l,c
|
|
ld [hl],b
|
|
pop hl
|
|
ret
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: CountNumObjects
|
|
; Arguments: a - class index to count
|
|
; Returns: a - number of objects of this class
|
|
; Alters: af
|
|
;---------------------------------------------------------------------
|
|
CountNumObjects::
|
|
push bc
|
|
push de
|
|
|
|
ld c,a
|
|
|
|
ld b,0
|
|
call GetFirst
|
|
or a
|
|
jr z,.done
|
|
|
|
inc b
|
|
|
|
.loop call GetNextObject
|
|
or a
|
|
jr z,.done
|
|
inc b
|
|
jr .loop
|
|
|
|
.done ld a,b
|
|
pop de
|
|
pop bc
|
|
ret
|
|
|
|
|
|
;---------------------------------------------------------------------
|
|
; Routine: ClassIndexIsHeroType
|
|
; Arguments: a - hero flag e.g. HERO_BS_FLAG
|
|
; c - class index
|
|
; Returns: a - 1 if matches
|
|
; zflag - or a
|
|
; Alters: af
|
|
;---------------------------------------------------------------------
|
|
ClassIndexIsHeroType::
|
|
push bc
|
|
ld b,a
|
|
|
|
ld a,[hero0_index]
|
|
cp c
|
|
jr nz,.checkingHero1
|
|
|
|
.checkingHero0
|
|
ld a,[hero0_type]
|
|
jr .checkType
|
|
|
|
.checkingHero1
|
|
ld a,[hero1_type]
|
|
.checkType
|
|
cp b
|
|
jr nz,.returnFalse
|
|
|
|
ld a,1 ;return true
|
|
or a
|
|
pop bc
|
|
ret
|
|
|
|
.returnFalse
|
|
xor a
|
|
pop bc
|
|
ret
|
|
|