cursorLogic.asm - RLH-2110/gbCalc GitHub Wiki
Table of Contents
Overview
CursorArray
CursorHandler
wCursorState vs wCursorPos
Routines
CursotSetPosition
Overview
This file determines the actions of the buttons on the current cursor position, like what to do to when moving left and right or pressing up and down.
It also handles positioning the cursor graphics.
CursorArray
At the start of the file, we create a jump table and a table to index into the jump table. This will be used to determine what we do on certain actions.
;indexes for the cursor array
CursorArray::
dw .cs0, .cs1, .cs2, .cs3, .cs4
;tilemap offset, inc routine, dec routine, left routine, right routine
.cs0:
dw screen + $102, CursorSignToggle, CursorSignToggle, CursorWrapToRight, CursorRight
.cs1:
dw screen + $103, CursorNumberInc, CursorNumberDec, CursorNumberLeft, CursorNumberRight
.cs2:
dw screen + $109, CursorOperatorInc, CursorOperatorDec, CursorLeft, CursorRight
.cs3:
dw screen + $10B, CursorSignToggle, CursorSignToggle, CursorLeft, CursorRight
.cs4:
dw screen + $10C, CursorNumberInc, CursorNumberDec, CursorNumberLeft, CursorNumberRight
Here is the same table as a graphic:
CursorHandler
This routine jumps to the right routine based on the lookup table, the current cursor position, and the value of e (e = what action to do)
here is the head of the routine:
; this subroutine jumps to a subroutine defined in an array thats indexed by the cursor state and the A register
; E: function selector
CursorHandler::
push af
push hl
push bc
push de
; note:
; [CursorArray+CursorState]->CursorData
; [CursorData-+offset]->functionPointer
And here we get the new base pointer that points into the right part of the table based onto the cursor address:
ld hl,CursorArray ; base adress
;bc = wCursorState (used as an offset)
ld b, 0
ld a,[wCursorState]
ld c,a
add hl,bc ; combine base adress with the offset
add hl,bc ; do it twice, since the data is 2 byte big
; get pointer to new base adress
ld c,[hl] ;load lower part of the new base adress
inc hl
ld b,[hl] ;load upper part
Here is an example with the previous graphic:
After that, we save the tile map address of where the cursor is into BC
;transfer to hl
ld h,b
ld l,c
;load tilemap adress into bc
ld c,[hl] ; load lower part
inc hl
ld b,[hl] ; load upper part
dec hl
push bc ; save tilemap address
Now we index into our selected part of the jump table
ld d,0
; e * 2 (since the data is 2 bytes long)
SLA e
add hl,de ; apply offset parameter to new base adress
; get the pointer thats behind the new adress
ld c,[hl] ;load lower part of the pointer
inc hl
ld b,[hl] ;load upper part
;transfer to hl
ld h,b
ld l,c
;HL now contains the pointer.
Here is another example graphic:
here is the rest of the routine, it saved the tile map address of the cursor position into DE and then calls the routine in our jump table.
;get the tilemap adress into de
pop de
;call the function
ld bc,.CursorHanlderReturnAdress
push bc ; push return adress onto the stack
jp hl ; call the function pased on the pointer we got
.CursorHanlderReturnAdress
pop de
pop bc
pop hl
pop af
ret
wCursorState vs wCursorPos
wCursorState keeps track on what element the cursor is, like the first sign, the first number, the operator, ...
However, it does not keep track where the cursor is within a number. It can tell you its number0, but not where in number0
wCursorPos tells you where the cursor is inside a number, but it does not tell you what number it is in. It's just an offset from the start of the number.
Routines
Here I list all the routines. All of them except all registers to be free of use.
DE contains the current screen position of the cursor.
You will often see these routines incrementing the contains of HL, which modifies the tile on screen.
The user input is in fact saved in Video RAM and is only later copied into work ram after we need to do something with the input.
You can see the routines in the file, I just provide an example and then list what routines exist.
This routine flips the sign
; DE: tilemap adress
;! assumes that all registers are free to use. !
CursorSignToggle:
;load offset io the tile with the number into hl
ld h,d
ld l,e
; if it is '+'
ld a,[hl]
cp a,tile_add
jr z,.setMinus ; set it to minus
;else set it to plus
ld [hl],tile_add
call validateInput
ret
.setMinus
ld [hl],tile_sub
call validateInput
ret
These routines increment/decrement a digit and wraps around if it over/underflows.
It needs to apply the wCursorPos to the tile map location of the cursor.
CursorNumberInc
CursorNumberDec
these routines increment and decrement the Operator and wrap around on over/underflows
CursorOperatorInc
CursorOperatorDec
These are simple cursor movement routines for everything that's not a number
CursorLeft
CursorRight
There, set the position to the left or the right
CursorWrapToLeft
( unused )
CursorWrapToRight
These routines move the cursor within the number, and if it goes out of the number, it goes to the previous/next cursor state
CursorNumberLeft
CursorNumberRight
CursotSetPosition
This routine removes the old cursor graphics and draws the new ones.
Here is the head of the routine:
; BC: old cursor pos
; DE: old cursor state (D is expected to be zero)
; wCursorState: new cursor pos
CursotSetPosition:
push hl
push af
; note:
; [CursorArray+CursorState]->CursorData
; [CursorData+0] = normal cursor pos
; normal cursor pos + cursor pos = actually cursor pos
We then get the row for the old cursor state to get the old tile map offset
ld hl,CursorArray ; base adress
sla e
add hl,de ; apply offset
; get the adress we point at.
ld e,[hl]
inc hl
ld d,[hl]
; load adress into hl
ld h,d
ld l,e
; now load the old default cursor pos
ld e,[hl]
inc hl
ld d,[hl]
Here is a graphic:
Note: since we address the first element, we don't need to apply any more offsets, so we can just load the old tile map offset into DE.
We then add the old cursor position to the old cursor tile map offset and save the result into HL
; add the old cursor pos
ld a, d
add a,b
ld d,a
ld a, e
add a,c
ld e,a
;load into HL
ld h,d
ld l,e
now we remove the old cursor graphics
; HL and DL = the adress of the old cursor pos in the tilemap
ld bc,cursorOffset ; bc = offset of how much the cursor grapics are away from the cursor position
; remove the lower cursor grapic
add HL,bc ; apply offset to put hl at the adress of the upper lower grapic
ld [hl],tile_empty ; set tile to nothing
;restet hl to cursor position
ld h,d
ld l,e
; remove the upper cursor grapic
; substact bc and hl (apply offset to put hl at the adress of the upper cursor grapic)
ld a,l
sub a,c
ld l,a
ld a,h
sbc a,b ; sub with carry!
ld h,a
; set tile to nothing
ld [hl],tile_empty
Now the old graphics have been removed, and we can add the new ones.
But first we need to load the new tile map offset and apply the number position!
; DE = wCursorState
ld d,0
ld a,[wCursorState]
ld e,a
ld hl,CursorArray ; base adress
sla e
add hl,de ; apply offset
; get the adress we point at.
ld e,[hl]
inc hl
ld d,[hl]
; load adress into hl
ld h,d
ld l,e
; now load the old default cursor pos
ld e,[hl]
inc hl
ld d,[hl]
; add the new cursor pos
ld b,e
ld a,[wCursorPos]
add a,b
ld e,a
;load into HL
ld h,d
ld l,e
Now we draw the graphics onto the new position
; HL and DL = the adress of the new cursor pos in the tilemap
ld bc,cursorOffset ; bc = offset of how much the cursor grapics are away from the cursor position
; add the lower cursor grapic
add HL,bc ; apply offset to put hl at the adress of the upper lower grapic
ld [hl],lower_cursor
;restet hl to cursor position
ld h,d
ld l,e
; add the upper cursor grapic
; substact bc and hl (apply offset to put hl at the adress of the upper cursor grapic)
ld a,l
sub a,c
ld l,a
ld a,h
sbc a,b ; sub with carry!
ld h,a
ld [hl], upper_cursor
pop af
pop hl
ret