+++ /dev/null
-#define ACTION_ATTACK_SPRITE1 0xA0
-#define UNIT_ACTION_ATTACK_ANIM_LEN 16
-
- ; sets up default actions for a new game
- ; for button A and button B
-actions_new_game_init:
- ; write default action ptrs
- ld hl, action_btna
-
- ; default A button action
- ld a, st_action_attack_init HI
- ld [hl+], a
- ld a, st_action_attack_init LO
- ld [hl+], a
-
- ; default B button action
- ld a, st_action_attack_init HI
- ld [hl+], a
- ld a, st_action_attack_init LO
- ld [hl+], a
-
- ret
-
- ; handles an assinged action
- ; a player can assign any in-game action to either A or B
- ; inputs:
- ; hl: action ptr (usually action btna or action btnb)
- ; returns:
- ; bc: next state
-unit_handle_assigned_action:
- ; load state ptr for action
- ld a, [hl+]
- ld b, a
- ld a, [hl]
- ld c, a
- ret
-
- ; generic direction picker
- ; press B to abort
- ; press keyopad to pick direction
- ; inputs:
- ; de: unit
- ; bc: next success state
- ; returns:
- ; bc: null if no press
- ; bc: unit_switch_to_active -> B pressed
- ; bc: bc input -> direction pressed
- ; act_rt_action_dat1: writes pressed bit BTNUP, BTNDOWN, BTNLEFT, BTNRIGHT
- ; act_rt_action_dat2: set to 0
-unit_action_pick_direction:
- ld hl, act_rt_action_dat1
- add hl, de ; hl = act_rt_action
-
- ; save next state
- push bc
-
- ; b to abort
- ld b, BTNB
- input_just
- pop bc ; need to pop in case of jp
- jp nz, unit_switch_to_active
-
- push bc ; save again..
-
-
- ld b, BTNUP
- input_just
- jr nz, @direction_pressed REL
-
- ld b, BTNDOWN
- input_just
- jr nz, @direction_pressed REL
-
- ld b, BTNLEFT
- input_just
- jr nz, @direction_pressed REL
-
- ld b, BTNRIGHT
- input_just
- jr nz, @direction_pressed REL
-
- pop bc ; remove from stack
-
- ldnull bc
- ret
-@direction_pressed:
- ld a, b
- ld [hl+], a ; write pressed button to action dat
- xor a, a
- ; clear dat2
- ld [hl], a
-
- call ui_status_line_clear
-
- ; should contain next state
- pop bc
- ret
-
-
- ; get the attack location
- ; input:
- ; de: actor
- ; returns:
- ; bc: tile position
-unit_attack_get_attack_tile:
- ; get location
- call unit_get_pos
-
- ld hl, act_rt_action_dat1
- add hl, de ; hl = dat1
-
- ; determine where to draw animation
- ld a, [hl] ; a = direction pressed
- cp a, DIRUP
- jr nz, @not_up REL
- dec b ; y--
-@not_up:
-
- cp a, DIRDOWN
- jr nz, @not_down REL
- inc b ; y++
-@not_down:
-
- cp a, DIRLEFT
- jr nz, @not_left REL
- dec c ; x--
-@not_left:
-
- cp a, DIRRIGHT
- jr nz, @not_right REL
- inc c ; x++
-@not_right:
- ret
-
- ; rests for a turn healing the unit
- ; and skipping the turn
- ; inputs:
- ; de: actor
-unit_action_rest:
- ld a, 1
- call stat_heal_by
- push af
- call ui_redraw_player
- call ui_request_redraw
-
- ld hl, STR_HEALDED_FOR
- pop af
- call ui_draw_status_stat
- ldnull bc
- ret
-
- ; rest action skips a turn
-st_action_rest:
- st_def 0x00, unit_action_rest, st_unit_delay_to_active_template
+++ /dev/null
-str_am_attack:
-.str "attack"
-.db 0
-
-str_am_shoot:
-.str "shoot"
-.db 0
-
-str_am_rest:
-.str "rest"
-.db 0
-
-str_am_pick_up:
-.str "pick up"
-.db 0
-
- ; label
-action_menu_str_table:
- dw str_am_attack
- dw str_am_pick_up
- dw str_am_shoot
- dw str_am_rest
-action_menu_str_table_end:
-
- ; map to actions
-action_menu_action_table:
- dw st_action_attack_init
- dw st_action_attack_init
- dw st_action_shoot_init
- dw st_action_rest
-action_menu_action_table_end:
-
-#define ACTION_MENU_STR_TABLE_LEN (action_menu_str_table_end - action_menu_str_table) / 2
-
- ; game state for action menu selector
- ; the action menu allows the player to select
- ; any action the character can perform
- ; it also allows binding an action to the B button
- ; by pressing select
- ; inputs:
- ; de: state
- ; returns:
- ; bc: next state
-update_action_menu:
- ; exit menu on b button press
- ld b, BTNB
- input_just
- jr z, @notb REL
- ld bc, st_update_game
- ret
-@notb:
-
- ; on up enter debug mode
- ld b, BTNUP
- input_just
- jr z, @notup REL
- ; load debug menu
- call debug_menu_init
- ldnull bc
- ret
-@notup:
-
- ; update menu
- ld a, [action_menu_cursor]
- ld hl, action_menu_str_table
- ld b, ACTION_MENU_STR_TABLE_LEN
- call select_menu_update
- ld [action_menu_cursor], a
-
- ; did the player select an action?
- ld a, b
- cp a, BTNA
- jr nz, @no_action_selected REL
- ; if selection was made
- ; return to game state
- ; and run action for player
-
- ; load action into player
- ld a, [action_menu_cursor]
- add a, a
- ld d, 0
- ld e, a
- ld hl, action_menu_action_table
- add hl, de ; hl = action selected
-
- ld a, [hl+]
- ld e, a
- ld a, [hl]
- ld d, a
-
- ; de = action state ptr
- ld hl, player_unit
- ld bc, st_size
- call memcpy
-
- ld bc, st_update_game
- ret
-@no_action_selected:
-
-
- ldnull bc
- ret
-
- ; transitions from the current state
- ; to action menu
-action_menu_init:
- ld hl, game_mode
- ld de, st_next
- add hl, de
- ; write st_update_action_menu to st_next
- ld a, st_update_action_menu LO
- ld [hl+], a
- ld a, st_update_action_menu HI
- ld [hl], a
-
- ; draw the initial status line
- ld a, [action_menu_cursor]
- ld b, ACTION_MENU_STR_TABLE_LEN
- ld hl, action_menu_str_table
- call select_menu_draw_status
-
- ret
-
+++ /dev/null
-#include "unit_demo.s"
-
-; actor table:
-; an actor table is a list of actors
-; that can either be loaded into the active table directly
-; or it can be used as a template for placing new actors
-; that are valid for this map.
-; to use as a template use the actors but move the position
-; as needed and setting act_loot_table_dat.
-
-floor_1_actor_table:
-map_c_actor_table:
-.db 7 ; size
-dw unit_demo_guard
-dw unit_demo_guard
-dw unit_demo_guard
-dw unit_demo_hazmat
-dw unit_demo_hazmat
-dw unit_demo_dog
-dw unit_demo_dog
-dw unit_demo_dog
-dw unit_demo_dog
-dw unit_demo_guard
-dw unit_demo_guard
-dw unit_demo_guard
-dw unit_demo_guard
-dw unit_demo_guard
-dw unit_demo_guard
-dw unit_demo_guard
-dw unit_demo_guard
-dw unit_demo_guard
-
-; actor tables for each floor
-floor_actor_tables:
-dw floor_1_actor_table
+++ /dev/null
- ; init the actor saves
- ; sets everything to 0xFF
-act_save_init:
- ld hl, act_sg
- ld bc, act_sg_end - act_sg
- ld d, ACT_SG_DEFAULT_VALUE
- call memset
- ret
-
- ; loads current start of save game slot
- ; based on the current map seed index
- ; inputs:
- ; a: map cursor
- ; returns:
- ; bc: act save game slot
-act_sg_load_current_slot:
- ld hl, act_sg
- ; no need to loop if a is 0
- cp a, 0
- jr z, @done REL
- ld de, act_sg_size * UNITS_MAX
-
- ; add sg size for every index offset
-@loop:
- add hl, de
- dec a
- jr nz, @loop REL
-@done:
- push hl
- pop bc ; we want return value in bc
-
- ret
-
- ; stores actor save game
- ; based on the current map's seed offset
- ; skipped if [map_header] is NULL
-act_sg_store:
- ; check if map header is NULL
- ld a, [map_header]
- ld b, a
- ld a, [map_header+1]
- or a, b
- ret z
-
- ld a, [player_map_cursor_prev]
- call act_sg_load_current_slot
-
- ld hl, p0_units
-.rep i, UNITS_MAX, 1, call act_sg_store_single
-
- ret
-
- ; stores data from a single actor into
- ; the save slot
- ; inputs:
- ; bc: act save game slot
- ; hl: actor
- ; returns:
- ; hl: next actor
- ; bc: next slot
-act_sg_store_single:
- ; store type
- push hl
- ld de, act_type
- add hl, de
- ld a, [hl]
- ld [bc], a
- inc bc
- pop hl
-
- push hl
- ; store flags
- ld de, act_flags
- add hl, de
- ld a, [hl]
- ld [bc], a
- inc bc
- pop hl
-
- push hl
-
- ; store y pos
- ld de, act_pos_y
- add hl, de
- ld a, [hl+]
- ld [bc], a
- inc bc
-
- ; store x pos
- ld a, [hl]
- ld [bc], a
- inc bc
-
- pop hl
-
- ; store p0
- push hl
- ld de, act_p0
- add hl, de
- ld a, [hl]
- ld [bc], a
- inc bc
- pop hl
-
- ; store hp
- push hl
- ld de, act_hp
- add hl, de
-
- ld a, [hl]
- ld [bc], a
- inc bc
- pop hl
-
- ; sotre mp
- push hl
- ld de, act_mp
- add hl, de
-
- ld a, [hl]
- ld [bc], a
- inc bc
- pop hl
-
- ; advance to next actor
- ld de, act_size
- add hl, de
-
- ret
-
- ; restores actor save game based on
- ; current map's seed offset
-act_sg_restore:
- ld a, [player_map_cursor]
- call act_sg_load_current_slot
- ; skip over player
-.rep i, act_sg_size, 1, inc bc
- ld hl, p0_units+act_size
-.rep i, UNITS_MAX-1, 1, call act_sg_restore_single
- ret
-
- ; restores a single entry of actor data
- ; skips restore if pos y is 0xFF
- ; inputs:
- ; bc: act save game slot
- ; hl: actor
- ; returns:
- ; hl: next actor
- ; bc: next slot
-act_sg_restore_single:
- inc bc ; bc = position y
- ld a, [bc]
- dec bc
- cp a, 0xFF
- jp z, @skip ; skip if 0xFF
-
- ; load type
- push hl
- ld de, act_type
- add hl, de
- ld a, [bc]
- ld [hl], a
- inc bc
- pop hl
-
- push hl
- ; load flags
- ld de, act_flags
- add hl, de
- ld a, [bc]
- ld [hl], a
- inc bc
- pop hl
-
- push hl
- ; load positions
- ld de, act_pos_y
- add hl, de
- ld a, [bc]
- ld [hl+], a
- inc bc
-
- ld a, [bc]
- ld [hl], a
- inc bc
-
- pop hl
-
- push hl
- ; load p0
- ld de, act_p0
- add hl, de
-
- ld a, [bc]
- ld [hl], a
- inc bc
-
- pop hl
-
- ; load hp
- push hl
- ld de, act_hp
- add hl, de
-
- ld a, [bc]
- ld [hl], a
- inc bc
-
- pop hl
-
- ; load mp
- push hl
- ld de, act_mp
- add hl, de
-
- ld a, [bc]
- ld [hl], a
- inc bc
- pop hl
-
- ld de, act_size
- add hl, de ; next actor
- ret
-
-@skip:
- ; move to next item and ret
-.rep i, act_sg_size, 1, inc bc
- ld de, act_size
- add hl, de
- ret
+++ /dev/null
-#define ATTACK_ANIM_LEN 32
-
-player_anim_table:
- anim_header 32, player_anim_table_f2
- anim_ent 0, 8, 0x8C, OAM_FXFLIP
- anim_ent 0, 0, 0x8E, OAM_FXFLIP
- anim_ent 0, 0, 0x00, 0
-
-player_anim_table_f2:
- anim_header 32, player_anim_table
- anim_ent 1, 8, 0x8C, OAM_FXFLIP
- anim_ent 1, 0, 0x8E, OAM_FXFLIP
- anim_ent 0, 0, 0x00, 0
-
-player_anim_table_attack_up:
- anim_header ATTACK_ANIM_LEN, player_anim_table
- anim_ent 1, 8, 0x8C, OAM_FXFLIP
- anim_ent 1, 0, 0x8E, OAM_FXFLIP
- anim_ent -12, 0, ACTION_ATTACK_SPRITE1, 0
-
-player_anim_table_attack_down:
- anim_header ATTACK_ANIM_LEN, player_anim_table
- anim_ent 1, 8, 0x8C, OAM_FXFLIP
- anim_ent 1, 0, 0x8E, OAM_FXFLIP
- anim_ent 12, 0, ACTION_ATTACK_SPRITE1, 0
-
-player_anim_table_attack_left:
- anim_header ATTACK_ANIM_LEN, player_anim_table
- anim_ent 1, 8, 0x8C, OAM_FXFLIP
- anim_ent 1, 0, 0x8E, OAM_FXFLIP
- anim_ent 0, -12, ACTION_ATTACK_SPRITE1, 0
-
-player_anim_table_attack_right:
- anim_header ATTACK_ANIM_LEN, player_anim_table
- anim_ent 1, 8, 0x8C, OAM_FXFLIP
- anim_ent 1, 0, 0x8E, OAM_FXFLIP
- anim_ent 0, 12, ACTION_ATTACK_SPRITE1, 0
-
- ; table that maps actor type to
- ; a list of animations
-anim_actor_table:
- dw NULL
- dw anim_list_player
- dw anim_list_guard
- dw anim_list_dog
- dw anim_list_hazmat
-
-
-anim_list_player:
- ; IDLE_NEUTRAL
- dw player_anim_table
- ; ATTACK LEFT
- dw player_anim_table_attack_left
- ; ATTACK RIGHT
- dw player_anim_table_attack_right
- ; ATTACK_UP
- dw player_anim_table_attack_up
- ; ATTACK_DOWN
- dw player_anim_table_attack_down
-
-anim_list_guard:
- ; IDLE NEUTRAL
- dw unit_demo_guard_anim_table
- ; ATTACK LEFT
- dw unit_demo_guard_attack_left
- ; ATTACK RIGHT
- dw unit_demo_guard_attack_right
- ; ATTACK UP
- dw unit_demo_guard_attack_up
- ; ATTACK DOWN
- dw unit_demo_guard_attack_down
-
-anim_list_dog:
- ; idle neutral
- dw unit_demo_dog_anim_table
- ; attack left
- dw unit_demo_dog_attack_left
- ; attack right
- dw unit_demo_dog_attack_right
- ; attack up
- dw unit_demo_dog_attack_up
- ; attack down
- dw unit_demo_dog_attack_down
-
-anim_list_hazmat:
- ; idle
- dw unit_demo_hazmat_anim_table
- ; attack left
- dw unit_demo_hazmat_attack_left
- ; attack right
- dw unit_demo_hazmat_attack_right
- ; attack up
- dw unit_demo_hazmat_attack_up
- ; attack down
- dw unit_demo_hazmat_attack_down
-
-
- ; translates tile to screen
- ; inputs:
- ; $1: Y/X offset
- ; $2: register containing scroll
- ; a: tile position
-#macro tile_to_scrn
- add a, $1
- sub a, $2
-#endmacro
-
- ; loads an animation for the current acotr
- ; based on its type
- ; and the requested animation entry
- ; inputs:
- ; de: actor
- ; b: the animation
- ; writes:
- ; new animation into selected actor
-anim_load_type:
- push de ; save actor
-
- ; 1) load animation list based on type
- ld hl, act_type
- add hl, de
- ld a, [hl] ; a = actor type
- sla a ; * 2 to use as ptr offset
- ld d, 0
- ld e, a
- ld hl, anim_actor_table
- add hl, de
-
- ld a, [hl+]
- ld d, a
- ld a, [hl+]
- ld h, a
- ld l, d
-
- ; 2) load animation table based on requested animation
-
- sla b ; * 2 to get offset
- ld d, 0
- ld e, b
- add hl, de ; get animation ptr
-
- ld a, [hl+]
- ld c, a
- ld a, [hl+]
- ld b, a
-
- ; bc = animation ptr
-
- ; 3) write animation to animation entry
- pop de ; restore actor
-
- ; write anim table
- ld hl, act_anim_table
- add hl, de
- ld a, c
- ld [hl+], a
- ld a, b
- ld [hl], a
- ret
-
- ; performs no drawing
-unit_nop_draw:
- ldnull bc
- ret
-
-
- ; calls unit's draw function
- ; inputs:
- ; hl: actor ptr
-unit_update_draw:
- push hl
- ld de, act_draw
- add hl, de
- ; hl = draw ptr
- ld a, [hl+]
- ld e, a
- ld a, [hl]
- ld d, a
- ; de = draw function
- push de
- pop hl ; hl = draw function
- pop de ; de = actor
- call_hl
- ret
-
- ; gets the left tile offset
- ; for object 1
- ; based on the y flip of oam
- ; inputs:
- ; a: oam flags
- ; returns:
- ; a: x-offset
-get_left_tile_offset1:
- and a, OAM_FXFLIP
- jr z, @not_set REL
- ld a, 8
- ret
-@not_set:
- xor a, a
- ret
-
- ; gets the left tile offset
- ; for object 2
- ; based on the y flip of oam
- ; inputs:
- ; a: oam flags
- ; returns:
- ; a: x-offset
-get_left_tile_offset2:
- and a, OAM_FXFLIP
- jr z, @not_set REL
- xor a, a
- ret
-@not_set:
- ld a, 8
- ret
-
- ; draws a unit's animation table
- ; draws all 3 tables based on animation timer
- ; and animation max value (first item in table)
- ; inputs
- ; de: actor
-unit_draw:
- ; load anim entries
- ld hl, act_anim_table
- add hl, de ; hl = entry 1
- ld a, [hl+]
- push af
- ld a, [hl]
- ld h, a
- pop af
- ld l, a
- push hl
- pop bc
-
- ; bc = animation header
- push bc ; save header for later
- inc bc
- inc bc
- inc bc ; go past header
-
- ; bc = anim talbe entry
- call unit_draw_obj
- call unit_draw_obj
- call unit_draw_obj
-
- ; process header
- pop bc
-
- ld hl, act_rt_anim_timer
- add hl, de ; hl = animation timer
- ld a, [hl]
- inc a
- ld [hl], a ; timer++
-
- push de
- ld d, a ; d = current timer
- ld a, [bc] ; a = expected timer
- cp a, d ; next frame?
- pop de
- jr nc, @no_new_frame REL
-
- ; if new frame: clear timer
- xor a, a
- ld [hl], a ; clear timer
-
- inc bc ; bc = next animation ptr
- ; load next table
- ld hl, act_anim_table
- add hl, de
- ld a, [bc]
- ld [hl+], a
- inc bc
- ld a, [bc]
- ld [hl], a
-@no_new_frame:
- ret
-
- ; draws a single object
- ; in the current animation table
- ; inputs:
- ; de: actor
- ; bc: anim table entry
- ; returns:
- ; bc: next entry
-unit_draw_obj:
-#define TMP_SCROLL_Y scratch
-#define TMP_SCROLL_X scratch+1
-#define TMP_A scratch+2
- ; skip if tile is 0x00
- inc bc
- inc bc
- ld a, [bc]
- dec bc
- dec bc
- cp a, 0
- jp z, @skip_ent
-
- push de
-
- ; hl = pos y
- ld hl, act_pos_y
- add hl, de
- push hl
- pop de ; de = pos y
-
- push bc
- push de
-
- call load_scroll
- ld a, b
- ld [TMP_SCROLL_Y], a
- ld a, c
- ld [TMP_SCROLL_X], a
-
- call load_unit_obj
-
- pop de
-
- ; set y position
- ld a, [TMP_SCROLL_Y]
- ld b, a ; b = y scroll
- ld a, [de]
- tile_to_scrn OBJ_OFF_Y, b ; scroll offset
- ld [TMP_A], a
-
- ; apply anim entry y offset
- pop bc
- ld a, [bc]
- push bc
- ld b, a
- ld a, [TMP_A]
- add a, b ; a += y offset
- ; write result to obj
- ld [hl+], a
-
-
- ; set x position
- inc de
- ld a, [TMP_SCROLL_X]
- ld c, a ; c = scroll x
- ld a, [de]
- tile_to_scrn OBJ_OFF_X, c
- ld [TMP_A], a
-
- ; apply anim entry x offset
- pop bc
- inc bc ; next entry
- ld a, [bc]
- push bc
- ld b, a
- ld a, [TMP_A]
- add a, b ; a += x offset
- ; write result to obj
- ld [hl+], a
-
- pop bc
- inc bc ; bc = tile index
- ; write tile from table
- ld a, [bc]
- ld [hl+], a
-
- ; write flags
- inc bc
- ld a, [bc]
- ld [hl+], a
- inc bc
-
- pop de
- ret
-@skip_ent:
- inc bc
- inc bc
- inc bc
- inc bc
- ret
-#undefine TMP_SCROLL_Y
-#undefine TMP_SCROLL_X
-#undefine TMP_A
+++ /dev/null
-; melee attack action
-
-
- ; picks a direction for an attack
- ; inputs:
- ; de: unit
- ; returns:
- ; bc: next action
-unit_action_attack_pick_direction_init:
- ; draw question to status line
- ld hl, STR_ATTACK_DIRECTION
- ld de, UI_STATUS_LINE
- call puts
-
- call ui_request_redraw
-
- ldnull bc
- ret
-
- ; reads player direction inputs to pick a direction
- ; inputs:
- ; de: unit
- ; returns:
- ; bc: next action
-unit_action_attack_pick_direction:
- ld bc, st_action_attack_damage_actor
- jp unit_action_pick_direction
-
- ; decides which animation to load
- ; based on units action dat 1 direction
- ; inputs:
- ; de: actor
-unit_action_attack_decide_animation:
- ld hl, act_rt_action_dat1
- add hl, de
-
- ld a, [hl]
- cp a, DIRUP
- jr nz, @notup REL
- ld b, ANIM_T_ATTACK_UP
- call anim_load_type
- ret
-@notup:
-
- cp a, DIRDOWN
- jr nz, @notdown REL
- ld b, ANIM_T_ATTACK_DOWN
- call anim_load_type
- ret
-@notdown:
-
- cp a, DIRLEFT
- jr nz, @notleft REL
- ld b, ANIM_T_ATTACK_LEFT
- call anim_load_type
- ret
-@notleft:
-
- cp a, DIRRIGHT
- jr nz, @notright REL
- ld b, ANIM_T_ATTACK_RIGHT
- call anim_load_type
-@notright:
- ret
-
- ; performs an attack
- ; based on the units rt_action tmp value
- ; inputs:
- ; de: unit
- ; returns:
- ; bc: next action
-unit_action_attack_finish:
-
- ; unset flag
- ld a, [gpf_attack_ongoing]
- dec a
- ld [gpf_attack_ongoing], a
-
- ldnull bc
- ret
-
- ; performs damage calculations based on the attacked location
- ; inputs:
- ; de: unit
- ; returns:
- ; bc: new state
-unit_action_attack_damage_calc:
- ; play animation
- push de
- call unit_action_attack_decide_animation
- call play_attack_noise
- pop de
-
- ; set flag
- ld a, [gpf_attack_ongoing]
- inc a
- ld [gpf_attack_ongoing], a
-
- ; calculate damage
- push de
- call unit_attack_get_attack_tile
- call unit_find_at
-
- ld a, h
- or a, l
- pop de
- jp z, @miss ; no unit found
-
-
- push hl
- pop bc
- ; de = attacker
- ; bc = attacked unit
- push hl
- call stat_calc_physical_damage_vs
- pop hl
-
- ld hl, STR_HIT_FOR
- call ui_draw_status_stat
- call ui_redraw_player
-
- ldnull bc
- ret
-@miss:
- ld hl, STR_MISS
- ld de, UI_STATUS_LINE
- call puts
- call ui_request_redraw
- ldnull bc
- ret
-
- ; default attack state
-st_action_attack_init:
- st_def 0x00, unit_action_attack_pick_direction_init, st_action_attack_pick_direction
-st_action_attack_pick_direction:
- st_def 0x00, unit_action_attack_pick_direction, st_action_attack_pick_direction
-st_action_attack_direction_picked:
- st_def ATTACK_ANIM_LEN, unit_action_attack_finish, st_unit_delay_to_active_fast
-st_action_attack_damage_actor:
- st_def 0x00, unit_action_attack_damage_calc, st_action_attack_direction_picked
+++ /dev/null
- ; inputs:
- ; de: source actor
- ; bc: target coordinates
-battle_attack:
- call unit_find_at
- ret
-
-; this is a helper file for a debug menu
-
-strz str_dbg_new_game, "RELOAD"
-
-str_dbg_clear_actors:
-.str "CLEAR ACTORS"
-.db 0
-
-debug_menu_str_table:
- dw str_dbg_new_game
- dw str_dbg_clear_actors
-debug_menu_str_table_end:
-
-#define DEBUG_MENU_STR_TABLE_LEN (debug_menu_str_table_end - debug_menu_str_table) / 2
-
-; debug routines:
-; get jumped to directly
-; return:
-; bc: new game state
-debug_menu_action_table:
- dw debug_fn_new_game
- dw debug_fn_clear_actors
-debug_menu_action_table_end:
-
- ; updates the debug menu
- ; inputs:
- ; de: state
- ; returns:
- ; bc: next state
-update_debug_menu:
- ; exit debug menu on b press
- ld b, BTNB
- input_just
- jr z, @notb REL
- ld bc, st_update_game
- ret
-@notb:
-
- ; update menu
- ld a, [debug_menu_cursor]
- ld hl, debug_menu_str_table
- ld b, DEBUG_MENU_STR_TABLE_LEN
- call select_menu_update
- ld [debug_menu_cursor], a
-
- ; did the player select an action?
- ld a, b
- cp a, BTNA
- jr nz, @no_action_selected REL
-
- ; load ptr from action table
- ; into hl and call it
- ld a, [debug_menu_cursor]
- add a, a ; * 2 for offset
- ld hl, debug_menu_action_table
- ld d, 0
- ld e, a
- add hl, de
-
- ld a, [hl+]
- ld d, a
- ld a, [hl]
- ld h, a
- ld l, d
-
- ; jp to selected routine
- jp hl
-@no_action_selected:
-
- ldnull bc
- ret
-
-debug_menu_init:
- ld hl, game_mode
- ld de, st_next
- add hl, de
- ; write st_update_debug_menu to std_Next
- ld a, st_update_debug_menu LO
- ld [hl+], a
- ld a, st_update_debug_menu HI
- ld [hl], a
-
- ; draw initial status line
- ld a, [debug_menu_cursor]
- ld b, DEBUG_MENU_STR_TABLE_LEN
- ld hl, debug_menu_str_table
- call select_menu_draw_status
- ret
-
- ; debug new game routine
- ; but load with a known hard-coded seed
- ; returns:
- ; bc: new state
-debug_fn_new_game:
- ; ld a, 15
- ; ld [srand], a
- ; ld [srand+1], a
-
- call new_game_init
- ld bc, st_update_game
- ret
-
-debug_fn_clear_actors:
- ld bc, st_update_game
- ret
-
-
.section defs
-#define FLOOR_W 4
-#define FLOOR_H 4
-#define FLOOR_MAP_COUNT (FLOOR_W * FLOOR_H)
-
#define UI_STATUS_LINE shadow_ui+1
.def int OAMDMAFN = 0xFF80
#define WRAM 0xC000
#define WRAMLEN 0xFFF
-#define STAT_MAX 255
-
-; game speed defs
-#define GAME_SPEED_SLOW 128
-#define GAME_SPEED_NORMAL 235
-#define GAME_SPEED_FAST 255
-
#define GAME_SPEED_DEFAULT GAME_SPEED_NORMAL
#define NULL 0
-#define UNITS_MAX 20
-#define UNITS_SPAWN_MIN 2
-#define UNITS_SPAWN_MASK 3
+#define ACTS_MAX 32
#define STACK_BEGIN 0xDFFF
-#define TILE_SIZE 8
-#define MAP_W 16
-.def int MAP_W_DEF = MAP_W
-#define MAP_H 16
-#define MAP_SIZE (MAP_W * MAP_H)
-
-#define VIEW_PORT_TILES_W 6
-#define VIEW_PORT_TILES_H 6
-
; seed for the rng
; 8 bit signed int
#define RAND_MAGIC 0x1B
#define UI_TILE_WIDTH 32
#define UI_TILE_HEIGHT 4
-#define BG_WIDTH 32
-#define BG_SHADOW_HEIGHT 4
-
- ; defines end of scroll location
-#define CURSOR_MIN_X 0
-#define CURSOR_MAX_X 0xF8
-#define CURSOR_MIN_Y 0
-#define CURSOR_MAX_Y 0xB8
-
-#define REDRAW_TILES_PER_FRAME 4
-
-
-
- ; draw flags
-.se 1
- ; if set to 1, return
- ; an invalid object from soam
- ; when units want to draw
-.de DRAWF_SKIP_UNIT_OBJS, 1
-
-
- ; gameplay flags
-.se 1
- ; if this is set units do not update
- ; but draw calls still happen
- ; this is useful when waiting for an animation
-.de GPF_PAUSE_UPDATE, 1
- ; set if the player has taken their turn
- ; this will allow all other units to
- ; perform their update
-.de GPF_PLAYER_TURN_TAKEN, 2
-
- ; cell flags
-.se 1
-.de CF_COLLISION, 1
- ; exit flag
- ; flags this tile as a valid exit
- ; must be at the edge of the map
- ; TODO: maybe add a special exit as a default
-.de CF_EXIT, 2
-.de CF_DOOR, 4
- ; if this flag is set do not
- ; set object priority bit
- ; so that objects are behind the tile
-.de CF_COVERED, 8
-
- ; player special flags
- ; set if player is currently on a covered tile.
- ; this can be used for drawing units that
- ; are inside
-.def int PLAYERSF_CF_COVERED = CF_COVERED
-
- ; cells struct
-.se 0
-.de c_tile, 1
-.de c_flags, 1
-.de c_size, 0
-
- ; state struct
- ; states are intended to
- ; be used as part of a larger
- ; struct
- ; e.g. player state
-.se 0
- ; time until next state
-.de st_time, 1
- ; state routine (LE)
- ; it can return 0000 in hl
- ; or a new state address in hl (LE)
- ; if bc is not 0000 after
- ; the calling state's address
- ; will be set to bc immediatly
- ; inputs for all state routines:
- ; de: state pointer
-.de st_routine, 2
- ; next state (LE)
-.de st_next, 2
-.de st_size, 0
-
-
- ; stats struct
- ; this tracks the current value. most real values
- ; are calculated
- ; e.g. stat_calc_str with actor as input
-#define stat_size 1
-
- ; status effect
-.se 0
-.de effect_type, 1
-.de effect_dat, 1
-.de effect_size, 0
-
; actor type enum
.se 0
.de ACT_T_GUARD, 1
.de ACT_T_DOG, 1
.de ACT_T_HAZMAT, 1
-
- ; actor struct (unit's are instances of actors)
- ; actor structs are basically just states
- ; to define an actor the following macros must be used in order
- ; st_def
+
+ ; actor struct
; act_def
- ; act_stat_def1
- ; act_stat_def2
- ; act_st_def
- ; act_def_meta
.se 0
- ; copy of current state
-.de act_state, st_size
.de act_type, 1
.de act_flags, 1
-.de act_pos_y, 1 ; y/x tile position
+.de act_pos_y, 1 ; y/x position
.de act_pos_x, 1
; custom parameter
.de act_p0, 1
- ; actor runtime values
-
- ; last collision tile position
-.de act_rt_collision_pos_y, 1
-.de act_rt_collision_pos_x, 1
- ; last collision flags
-.de act_rt_collision_cf, 1
- ; last collision with actor
- ; set during unit_collision_woth_any_other
-.de act_rt_collided_with, 2
-
- ; temporary buffer for any action picked
-.de act_rt_action_dat1, 1
-.de act_rt_action_dat2, 1
-
- ; generic timer
- ; can be used for animations or other relevant timers
- ; state switching may change this value.
-.de act_rt_timer, 1
-
- ; animation frame timer
-.de act_rt_anim_timer, 1
-
- ; stats1
-.de act_level, 1
-.de act_hp, stat_size
-.de act_mp, stat_size
-.de act_ac, stat_size
-
- ; stats2
-
-.de act_str, stat_size
-.de act_int, stat_size
-.de act_dex, stat_size
-.de act_vit, stat_size
-
- ; actor states
- ; used for state switching
- ; set to 0000 to disable the state
-.de act_st_active, 2
-.de act_st_idle, 2
-
- ; ptr to function for drawing the actor
- ; called after state update
- ; replace in state code if drawing needs to be
- ; changed at runtime
- ; inputs:
- ; de: actor
- ; returns:
- ; bc: null
-.de act_draw, 2
-.de act_anim_table, 2
+ ; stats
+.de act_hp, 1
+.de act_ac, 1
.de act_size, 0
- ; actor save game data
- ; if pos y and x is 0xFF
- ; it is not restored
-.se 0
-.de act_sg_type, 1
-.de act_sg_flags, 1
-.de act_sg_pos_y, 1
-.de act_sg_pos_x, 1
-.de act_sg_p0, 1
-.de act_sg_hp, 1
-.de act_sg_mana, 1
-.de act_sg_size, 0
-
-#define ACT_SG_DEFAULT_VALUE 0xFF
-
-#define MAP_BG_TILE_OFFSET 0
-#define MAP_BG_FLAGS_OFFSET 1
-
-#define MAP_NAME_LEN 8
-
- ; map flags1
-.se 1
- ; disables random generation
-.de MAPF1_NO_RAND, 1
; map header struct
.se 0
-.de map_flags_1, 1
-.de map_flags_2, 1
-.de map_flags_3, 1
-.de map_flags_4, 1
+.de map_flags, 1
; 8 bytes reserved for map names
; map_name in map properties
-.de map_name, MAP_NAME_LEN
.de map_bg_ptr, 2
-.de map_tile_flags_ptr, 2
- ; ptr to mape state to be loaded
- ; maps to map property state_ptr
-.de map_state_ptr, 2
- ; ptr to actor table
- ; an actor table is a single byte for number of actors
- ; followed by a list of pointers to actor
- ; templates
- ; maps to map property actor_table_ptr
-.de map_actor_table_ptr, 2
+
+ ; ptr to map objects list
+.de map_objs_ptr, 2
; pointers to tile banks to be loaded
; maps to map property tile_bank0, tile_bank1, tile_bank2, tile_bank3
; note that tile_bank1 and tile_bank2 are 128 bytes each
.de map_tile_bank3_ptr, 2
.de map_header_size, 0
- ; map actor table struct
-.se 0
-.de map_actor_table_len, 1
- ; list of be pointers to actors
-.de map_actor_table_act_ptrs, 0
-
-
- ; map exit table entry struct
-.se 0
-.de exit_flags, 1
- ; if this is != 0
- ; the exit will only trigger
- ; if the input specified is pressed
-.de exit_required_input, 1
-.de exit_goto_y, 1
-.de exit_goto_x, 1
- ; pointer to new map struct
-.de exit_to, 2
-.de exit_size, 0
-
- ; object animation struct
- ; simple call in update code
- ; with a single state
- ; intended for use with short-term map animations
- ; e.g. door opening
-.se 0
-.de obja_st, st_size
-.de obja_flags, 1
-.de obja_pos_y, 1
-.de obja_pos_x, 1
-.de obja_dat, 1
- ; time in frames
-.de obja_timer, 1
-.de obja_size, 0
-
-
- ; action struct
-.se 0
-.de action_st_action_ptr, 2
-.de action_size, 0
-
- ; animation header
-.se 0
-.de anim_header_frame_time, 1
-.de anim_header_next, 2
-
-; animation entry struct
-; start with a header
-; an animation table *always* has
-; 3 entries
-; if the tile is 0x00 the entry is not rendered
-.se 0
-.de anim_ent_y_offset, 1
-.de anim_ent_x_offset, 1
-.de anim_ent_oam_tile, 1
-.de anim_ent_oam_flags, 1
-.de anim_ent_size, 0
-
-; animation types
-.se 0
-.de ANIM_T_IDLE_NEUTRAL, 1
-.de ANIM_T_ATTACK_LEFT, 1
-.de ANIM_T_ATTACK_RIGHT, 1
-.de ANIM_T_ATTACK_UP, 1
-.de ANIM_T_ATTACK_DOWN, 1
-
-
-; special text commands
-
-; consumes the command
-; and interprets the next
-; byte as a number
-#define TEXT_NUMBER 0x80
-
- ; constants
-
#define DISTANCE_BGTA 1
#define DISTANCE_AGTB 0
+++ /dev/null
- ; updates a unit's status effects
- ; inputs:
- ; de: unit
-effects_unit_update:
- ret
-
- ; adds a new effect to a unit
- ; if no effect slot is available
- ; the new effect is dropped
- ; inputs:
- ; de: unit
- ; a: effect type
- ; b: effect dat
-effect_add:
- ret
-
- ; updates a single status effect
- ; inputs:
- ; de: unit
- ; hl: effect
-effect_update:
- ret
--- /dev/null
+ ; sets the state routine
+ ; inputs:
+ ; hl: new state
+game_set_state:
+ ld a, l
+ ld [game_state], a
+ ld a, h
+ ld [game_state+1], a
+ ret
.endscope
#endmacro
-
- ; adjust player scroll
- ; inputs:
- ; $1: add/sub
- ; $2: scroll_move_y/x
- ; uses: a
- ; skipped if z flag is 1
-#macro cursor_adjust_scroll
-.beginscope
- ld a, [$2]
- $1 a, 1
- ld [$2], a
-.endscope
-#endmacro
-
- ; move cursor
- ; inputs:
- ; $1: cursor_move_y/x -> move
- ; $2: cursor_move_y/x -> clear
- ; $2: NEGATE/1
-#macro cursor_move_direction
- xor a, a
- ld [$2], a
- ld a, CURSOR_MOVE_SPEED * $3
- ld [$1], a
-#endmacro
-
- ; defines a state
- ; to be used by actors
- ; inputs:
- ; $1 timer
- ; $2 routine
- ; $3 next
-#macro st_def
- .db $1
- dw $2
- dw $3
-#endmacro
-
- ; defines actor meta data call for actor
- ; inputs:
- ; $1: draw call
- ; $2: animation header ptr
-#macro act_def_meta
- dw $1
- dw $2
-#endmacro
-
- ; define an actor without state
- ; to define an actor call
- ; st_def and act_def
- ; inputs:
- ; $1 type
- ; $2 flags
- ; $3 y pos
- ; $4 x pos
- ; $5 custom p0 value
-#macro act_def
- .db $1 ; type
- .db $2 ; flags
- .db $3 ; y pos
- .db $4 ; x pos
- .db $5 ; p0
-
- ; act rt pos y, pos x, collision cf
- .db 0, 0, 0
- ; act_rt_collided_with
- dw 0
- ; act_rt_action_dat1/2
- .db 0, 0
-
- ; rt timer
- .db 0
- ; rt animation timer
- .db 0
-#endmacro
-
- ; defines an actor's stats (1/2)
- ; $1 level
- ; $2 health points
- ; $3 mana points
- ; $5 armor
-#macro act_stat_def1
- .db $1 ; level
- .db $2 ; hp hp max
- .db $3 ; mp mp max
- .db $4 ; ac
-#endmacro
-
- ; $1 str
- ; $2 int
- ; $3 dex
- ; $4 vit
-#macro act_stat_def2
- .db $1 ; str
- .db $2 ; int
- .db $3 ; dex
- .db $4 ; vit
-#endmacro
-
- ; defines actor state callbacks
- ; inputs:
- ; $1: st_active
- ; $2: st_idle
-#macro act_st_def
- dw $1
- dw $2
-#endmacro
-
- ; defines an exit table entry
- ; inputs:
- ; $1: flags
- ; $2: required input/0
- ; $3: goto y
- ; $4: goto x
- ; $5: map header pointer
-#macro exit_def
- .db $1
- .db $2
- .db $3
- .db $4
- dw $5
-#endmacro
-
- ; loads NULL into a 16 bit register
- ; inputs:
- ; $1: register
-#macro ldnull
- ld $1, 0
-#endmacro
-
- ; creates a NUL terminated string
- ; inputs:
- ; $1: string
-#macro strt
- .str $1
- .db 0
-#endmacro
; calls rst 0x08
#macro call_hl
ld b, a
#endmacro
- ; animation header
- ; inputs:
- ; $1: frame time
- ; $2: next frame ptr
-#macro anim_header
- .db $1
- dw $2
-#endmacro
-
- ; animation entry
- ; inputs:
- ; $1: y offset
- ; $2: x offset
- ; $3: tile
- ; $4: oam flags
-#macro anim_ent
- .db $1
- .db $2
- .db $3
- .db $4
-#endmacro
-
; defines a 0-terminated stirng
; inpputs:
; $1: label name
#include "sys.s"
#include "input.s"
#include "player.s"
-#include "unit_cpu.s"
#include "update.s"
#include "ui.s"
#include "audio.s"
#include "map.s"
#include "math.s"
+#include "game.s"
-#include "animation.s"
-#include "roompatterns.s"
-#include "mapgen.s"
-#include "state.s"
#include "tiles.inc"
-#include "unit.s"
-#include "effect.s"
#include "text.s"
-#include "stats.s"
-#include "actortables.s"
-#include "exittables.s"
#include "demos.s"
-#include "mainmenu.s"
-#include "actsave.s"
-#include "objanim.s"
-#include "battle.s"
-#include "action.s"
-#include "attack.s"
-#include "shoot.s"
-#include "action_menu.s"
-#include "select_menu.s"
#include "debug.s"
; fill bank
+++ /dev/null
-#define MAIN_MENU_FILE_1_OFFSET 128+2
-
-#define MENU_CURSOR_TILE 0xF5
-#define MENU_CURSOR_TILE_REVERSE 0xF5+3
-
-
- ; location table for cursor
- ; y positon
-main_menu_cursor_locations_y:
-.db 40, 48, 56, 72
-
-#define MAIN_MENU_CURSOR_MAX 3
-
- ; fixed x position
-#define main_menu_cursor_x 16
-
- ; update main menu state
- ; handles cursor sprite drawing
- ; handles file/new game selection
-main_menu_update:
- call rand
-
- ; clear oam
- call shadow_oam_clear
-
- ; ensure the cursor is capped to MAX
- ld a, [menu_cursor_index]
- and a, MAIN_MENU_CURSOR_MAX
- ld [menu_cursor_index], a
-
- ; draw cursor as sprite
- ld d, 0
- ld a, [menu_cursor_index]
- ld e, a ; de = cursor location offset
- ld hl, main_menu_cursor_locations_y
- add hl, de
- ld a, [hl] ; a = y position
-
- ld hl, shadow_oam
- ld [hl+], a ; write y
-
- ld a, main_menu_cursor_x
- ld [hl+], a ; write x
-
- ; write tile
- ld a, MENU_CURSOR_TILE
- ld [hl+], a
-
- xor a, a
- ld [hl], a ; write flags
-
-
- ld b, BTNSTART | BTNA ; b = button mask
- input_just
- jr z, @no_new_game REL
- ld bc, st_init_new_game
- ret
-@no_new_game:
-
- ld b, BTNDOWN
- input_held
- jr z, @not_down REL
-
- ; cursor++
- ld a, [menu_cursor_index]
- inc a
- ld [menu_cursor_index], a
- ld bc, st_main_menu_delay
- ret
-@not_down:
-
-
- ld b, BTNUP
- input_held
- jr z, @not_up REL
-
- ; cursor--
- ld a, [menu_cursor_index]
- dec a
- ld [menu_cursor_index], a
- ld bc, st_main_menu_delay
- ret
-@not_up:
-
- ldnull bc
- ret
-
- ; inits main menu
- ; draws the menu screen to SCRN0
- ; disables lcd and interrupts while it is
- ; loading
-main_menu_init:
- call next_vblank_wait
- call lcd_off
-
- ; set up palettes
- ; for main menu
- ld a, 0b11000000
- ld [RBGP], a
-
- ld a, 0b11000000
- ld [ROBP0], a
-
- ld a, 0b11000000
- ld [ROBP1], a
-
- call unit_load_default_player
-
- ; load tile banks of default map
- ld hl, map_c_header
- call map_tile_banks_load
-
-
- ld hl, STR_FILE1
- ld de, SCRN0+MAIN_MENU_FILE_1_OFFSET
- call puts
-
- ld hl, STR_FILE2
- ld de, SCRN0+MAIN_MENU_FILE_1_OFFSET+32
- call puts
-
- ld hl, STR_FILE3
- ld de, SCRN0+MAIN_MENU_FILE_1_OFFSET+64
- call puts
-
- ld hl, STR_DELETE
- ld de, SCRN0+MAIN_MENU_FILE_1_OFFSET+128
- call puts
-
- ; hide window
- ld a, 144
- ld [RWY], a
- ld [RWX], a
-
- ; set cursor index to 0
- xor a, a
- ld [menu_cursor_index], a
-
- call lcd_on
- ldnull bc
- ret
-
-st_main_menu_update:
- st_def 0x00, main_menu_update, st_main_menu_update
-
-st_main_menu_delay:
- st_def 16, st_null_fn, st_main_menu_update
-
-st_main_menu_init:
- st_def 0x00, main_menu_init, st_main_menu_update
-
- ; disables the lcd
- ; call before map_load
-map_load_start:
- ; disable interruts
- ; wait for next blank
- ; disable lcd
- call disableinterrutpts
- call next_vblank_wait
- call lcd_off
-
- xor a, a
- ld [gpf_attack_ongoing], a
- ret
-
- ; draws the map
- ; enables the lcd
- ; call after map_load
-map_load_end:
- call map_draw_all
-
- ; restore lcd and interrupts
- call lcd_on
- call vblank_wait
- call enableinterrupts
- ret
-
- ; loads a new map
- ; inputs:
- ; hl: map ptr
- ; disables and enables interrupts
- ; and lcd
- ; TODO: do not touch lcd or interrupts if
- ; they were not enabled!
-map_load:
- ; backup the map header
- ld a, l
- ld [map_header], a
- ld a, h
- ld [map_header+1], a
-
-
- push hl
- call map_draw_area_title
- pop hl
-
- push hl
- call map_tiles_load
-
- pop hl
- push hl
- call map_state_load
- pop hl
-
- push hl
- call map_actors_load
- pop hl
-
- push hl
- call map_tile_banks_load
- pop hl
-
- ret
-
- ; draws map title to UI
- ; inputs:
- ; hl: map_ptr
-map_draw_area_title:
- ld de, map_name
- add hl, de ; hl = map_name ptr
-
- ld b, MAP_NAME_LEN
- ld de, shadow_ui+1
-@loop:
- ld a, [hl+]
- add a, FONT_OFFSET
- ld [de], a
- inc de
- dec b
- jr nz, @loop REL
-
- ; draw player map cursor number
- ld a, [player_map_cursor]
- add a, FONT_OFFSET+1
- ld [de], a
-
- call ui_request_redraw
-
- ret
-
- ; same as map_get_tile
- ; but also divides the b/c input by 16
-map_get_tile_div16:
- div16 b
- div16 c
-
- ; gets the tile at a y/x position
- ; inputs:
- ; b/c: y/x tile position
- ; returns:
- ; a: flags
- ; b: tile index
- ; hl: ptr to tile index
-map_get_tile:
- ; current map
- ld hl, map
- ld d, 0
- ld e, MAP_W * c_size
-
- ld a, b
- cp a, 0
- jr z, @skip_y REL
-
- ; calculate y offset
-@y_loop:
- add hl, de
- dec b
- jr nz, @y_loop REL
-@skip_y:
-
- ; add x offset
- ld e, c
- ; add x offset c_size times
-.rep i, c_size, 1, add hl, de
- ; hl should now be the correct tile
-
-
- ; load values
- ld a, [hl+] ; tile index
- ld b, a
- ld a, [hl] ; tile flags
-
- dec hl
-
- ret
-
- ; loads map tiles
- ; inputs:
- ; hl: map header
-map_tiles_load:
- ; first clear
- push_all
-
- ld hl, map
- ld bc, map_end - map
- ld d, 0
- call memset
-
- pop_all
-
- ; load bg ptr
- push hl
- ld de, map_bg_ptr
- add hl, de ; hl = bg_ptr
- ld a, [hl+]
- ld d, a
- ld a, [hl+]
- ld h, a
- ld l, d
- ; hl = bg ptr
-
- ld de, MAP_BG_TILE_OFFSET ; 0 offset for bg
- call tile_map_compressed_load
- pop hl
-
- ; load tile flags ptr
- ld de, map_tile_flags_ptr
- add hl, de ; hl = bg_ptr
- ld a, [hl+]
- ld d, a
- ld a, [hl+]
- ld h, a
- ld l, d
- ; hl = bg ptr
-
- ld de, MAP_BG_FLAGS_OFFSET
- call tile_map_compressed_load
- ret
-
- ; loads compressed data into the map buffer
- ; this can either be tiles or flags
- ; based on its offset and the compressed ptr
- ;
- ; map compression:
- ; maps are using a simple RLE
- ; 1 byte of length, 1 byte of data
- ; the data is terminated with a 0x00 length byte
- ; inputs:
- ; hl: compressed map data
- ; de: target offset (usually 0/1)
-tile_map_compressed_load:
- push hl
- pop bc ; bc = map ptr
-
- ld hl, map
- add hl, de ; + offset
- ; bc = destination
- ; hl = rle encoded data
-
-@decompress_loop:
- ; load run length
- ld a, [bc]
- cp a, 0
- ret z ; if run length == 0 exit
- ld d, a ; d = copy coutner
-
- inc bc
- ld a, [bc] ; load data
- inc bc
-
-@copy_loop:
- ld [hl+], a
- inc hl ; hl++ to skip over unneeded byte
-
- dec d
- jr nz, @copy_loop REL
-
- ; again
- jr @decompress_loop REL
-
- ; loads a map's state
- ; inputs:
- ; hl: map ptr
-map_state_load:
- ld de, map_state_ptr
- add hl, de ; hl = state ptr ptr
-
- ld a, [hl+]
- ld e, a
- ld a, [hl]
- ld d, a
- ; de = state ptr
- ld hl, map_st
- ld bc, st_size
- call memcpy
-
- ret
-
- ; loads a map's actor table
- ; starting at p0_actors+1 (0 is reserved for player)
- ; inputs:
- ; hl: map ptr
-map_actors_load:
- ; first clear actor table except player
- push hl
- ld hl, p0_units + act_size
- ld bc, act_size * (UNITS_MAX - 1)
- ld d, 0
- call memset
- pop hl
-
- ld de, map_actor_table_ptr
- add hl, de ; hl = actor table ptr
-
- ld a, [hl+]
- ld e, a
- ld a, [hl]
- ld d, a
- ; de = actor table
-
- ; load actor count
- ld a, [de]
- cp a, 0
- jp z, @skip ; do not load if ptr is 0
- inc de ; de = first actor ptr
-
- ; load starting at slot 1
- ; hl = dst
- ld hl, p0_units + act_size
- @loop:
- ; load next actor
- push af
- push hl
-
- ; load ptr
- ld a, [de]
- ld b, a
- inc de
- ld a, [de]
- inc de
- ; save de for now
- ; de = next ptr
- push de
-
- ; set src ptr
- ld e, b
- ld d, a
- ; de = str ptr
- ; hl = dst already
- ld bc, act_size
- call memcpy
-
-
- ; copy
-
- pop de
- pop hl
- push de
- ; move to next actor destination
- ld de, act_size
- add hl, de
- pop de
-
- pop af
- ; i--
- dec a
- jr nz, @loop REL
-
-@skip:
- ; hand over control to a unit
- ld de, player_unit
- call unit_wake_up
- ret
-
- ; loads map tilesets
- ; inputs:
- ; hl: map ptr
-map_tile_banks_load:
- ld de, map_tile_bank0_ptr
- add hl, de ; hl = bank0 ptr
-
- ; load ptr
- ld a, [hl+]
- ld e, a
- ld a, [hl+]
- ld d, a
- push hl
- call tiles_load_bank8000
-
- pop hl
- ld a, [hl+]
- ld e, a
- ld a, [hl+]
- ld d, a
- push hl
- call tiles_load_bank8800
-
- pop hl
- ld a, [hl+]
- ld e, a
- ld a, [hl+]
- ld d, a
- push hl
- call tiles_load_bank8C00
-
- pop hl
- ld a, [hl+]
- ld e, a
- ld a, [hl+]
- ld d, a
- call tiles_load_bank9000
-
- ret
-
- ; draws all cells currently loaded to the screen
- ; only call during blank!
-map_draw_all:
-#define TMP_TILE_COUNT scratch
-#define TMP_TILE_OFFSET scratch+1
-
- ; de = loop counter
- ld de, MAP_SIZE
- ld bc, SCRN0
-
- ; clear tile count
- xor a, a
- ld [TMP_TILE_COUNT], a
- ; set a tile offset
- ld [TMP_TILE_OFFSET], a
-
- ld hl, map
- ; hl = c_tile
-
- ; load row 1
- call map_draw_rows
-
- ld de, MAP_SIZE
- ld bc, SCRN0+32
- ; clear tile count
- xor a, a
- ld [TMP_TILE_COUNT], a
- ; set a tile offset
- ld a, 16
- ld [TMP_TILE_OFFSET], a
- ld hl, map
- call map_draw_rows
-
- ret
-
- ; draws 2 2x2 rows of tiles to shadow_bg
- ; map size is equal to 2 rows
- ; inputs:
- ; a: row offset
-map_draw_shadow2:
- ld hl, map
- ld de, MAP_W * c_size
-
- ; calculate what row to draw
-@offset_loop:
- cp a, 0
- jr z, @offset_done REL
- ; go down a row
- add hl, de
- dec a
- jr @offset_loop REL
-@offset_done:
-
- push hl ; save map ptr
-
- ; row 1
- ld de, MAP_W * 2
- ld bc, shadow_bg
- xor a, a
- ld [TMP_TILE_COUNT], a
- ld [TMP_TILE_OFFSET], a
-
- call map_draw_rows
-
- ; row 2
- pop hl ; resotre map ptr
-
- ld de, MAP_W * 2
- ld bc, shadow_bg+32
- xor a, a
- ld [TMP_TILE_COUNT], a
- ld a, 16
- ld [TMP_TILE_OFFSET], a
-
- call map_draw_rows
-
- ret
-
-
- ; requests a full map redraw
- ; always draws to SCRN0
- ; redraws one set of shadow tiles to SCRN0 + a * MAP_W
- ; inputs:
- ; a: row to begin drawing at
-map_request_redraw_at:
- push af ; save y for after
- call map_draw_shadow2
- pop af
-
- ld hl, SCRN0
- ; a = y position
- call map_request_redraw2
- ret
-
- ; requests a map redraw
- ; this will set up redraw_bg
- ; redraw_shadow and redraw steps for 4 rows of tiles
- ; inputs:
- ; hl: bg target ptr
- ; a: row offset (a*2*32 + hl)
-map_request_redraw2:
- ; adjust screen target position by row offset
- ld de, 32
- add a, a
-@row_offset_calc:
- cp a, 0
- jr z, @row_offset_done REL
- add hl, de
- dec a
- jr @row_offset_calc REL
-@row_offset_done:
-
- ; write bg target
- ld a, h
- ld [redraw_bg], a
- ld a, l
- ld [redraw_bg+1], a
-
- ; load tiles to write
- ld de, shadow_bg
- ld a, d
- ld [redraw_shadow], a
- ld a, e
- ld [redraw_shadow+1], a
-
- ; steps of 5 * 16
- ld a, BG_WIDTH * BG_SHADOW_HEIGHT / REDRAW_TILES_PER_FRAME
- ld [redraw_steps], a
- ret
-
-
- ; draws a map rows
- ; either top or bottom rows of a 2x2 tile
- ; inputs:
- ; hl: map ptr
- ; bc: SCRN start
- ; de: MAP_SIZE
- ; [TMP_TILE_COUNT]: 0
- ; [TMP_TILE_OFFSET]: 0 or 16
-map_draw_rows:
-@loop:
- push de
- ; load row 1
- ld a, [hl] ; load tile
- ld d, a
- ld a, [TMP_TILE_OFFSET]
- add a, d ; tile + tile offset
-
- ld [bc], a ; draw
- inc bc ; bc++
- inc a ; move one tile over
- ld [bc], a ; draw
- inc bc ; bc++
-
- ; count tiles drawn
- ld a, [TMP_TILE_COUNT]
- inc a
- cp a, MAP_W ; map size
- ; bc + 32 to go to next row if edge is reached
- jr nz, @no_advance REL
-
- push hl
- ld hl, 32
- add hl, bc
- push hl
- pop bc ; bc = next row
-
- pop hl
-
- ; clear map tile counter
- xor a, a
-@no_advance:
- ld [TMP_TILE_COUNT], a
-
- ld de, c_size
- add hl, de ; next cell
- pop de
-
- dec de ; de--
-
- ; check if de is 0
- ld a, d
- or a, e
- cp a, 0
- jr nz, @loop REL
-
- ret
-#undefine TMP_TILE_COUNT
-#undefine TMP_TILE_OFFSET
-
- ; empty actor table
-map_actor_table_null:
-.db 0
-
-st_map_null:
- st_def 0, map_null_state, st_map_null
-
- ; null state
-map_null_state:
- ldnull bc
- ret
-
-; template maps
-; maps can be loaded directly
-
-#include "map_c.s"
-#include "map_ce.s"
-#include "map_cw.s"
-
-#include "map_te.s"
-#include "map_tc.s"
-#include "map_tw.s"
-
-#include "map_be.s"
-#include "map_bc.s"
-#include "map_bw.s"
-
+++ /dev/null
-
- ; initial map setup
- ; seeds the floor
- ; loads a random map from the map table
- ; clears act_save
- ; also places initial door locations
-mapgen_init:
- ; disable act sg
- ld a, [mapgen_flags]
- or a, MAPGEN_F_NO_ACT_SG
- ld [mapgen_flags], a
-
- call act_save_init
- call mapgen_seed
- call mapgen_make_doors
- call mapgen_select_player_spawn
-
- ; re-enable act sg
- xor a, a
- ld [mapgen_flags], a
- ret
-
- ; selects a room pattern table
- ; returns:
- ; hl: pattern table
- ; a: size
-mapgen_select_pattern_table:
- ; TODO: select different tables based on floor
- ld hl, room_patterns_floor1
- ld a, ((room_patterns_floor1_end - room_patterns_floor1) / 2) - 1
- ret
-
- ; selects a map from the tables based on the current floor
- ; and the current cursor seed
- ; returns:
- ; hl: map pointer
-mapgen_select_map:
- call mapgen_select_pattern_table
- push hl
-
- ld b, a
- call rand
- and a, b ; cap rand to table size
-
- pop hl
-
- add a, a ; * 2 because its a 2-byte table
-
- ld b, 0
- ld c, a
- add hl, bc
-
- ; load table ptr
- ld a, [hl+]
- ld c, a
- ld a, [hl]
- ld b, a
-
- ld l, c
- ld h, b
-
-
- ret
-
-
- ; generates a new set of seeds
- ; and places them into map_seeds
-mapgen_seed:
- ld hl, map_seeds
- ; 2 bytes per seed
- ld b, FLOOR_MAP_COUNT*2
-
-@loop:
- push hl
- call rand
- pop hl
- ld [hl+], a
- dec b
- jr nz, @loop REL
-
-
- ret
-
- ; loads the current seed based on player map cursor
- ; returns:
- ; de: the seed
-mapgen_load_seed:
- ld a, [player_map_cursor]
- add a, a ; * 2 because it is a 2-byte table
- ld d, 0
- ld e, a
- ld hl, map_seeds
- add hl, de
- ; hl = seeds+offset
- ld a, [hl+]
- ld d, a
- ld a, [hl]
- ld e, a ; de = seed
- ret
-
- ; places a rectangular room
- ; into the currently loaded map
- ; 1) selects a random map to draw
- ; 2) places doors
- ; 3) places actors
- ; 4) reloads actor sg
- ; 5) draws map
- ; preserves:
- ; srand
-mapgen:
- call map_load_start
-
- ld a, [mapgen_flags]
- and a, MAPGEN_F_NO_ACT_SG
- call z, act_sg_store
-
- ; load seed
- ; and back it up
- ld a, [srand]
- ld b, a
- ld a, [srand+1]
- ld c, a
- push bc
-
-
- call mapgen_load_seed
-
- ; load seed param
- ld a, e
- ld [srand+1], a
- ld a, d
- ld [srand], a
-
- call mapgen_select_map
- call map_load
- ld hl, map
-
- call mapgen_draw_doors
-
- call mapgen_place_actors
-
-
- ; restore seed
- pop bc
- ld a, c
- ld [srand+1], a
- ld b, a
- ld [srand], a
-
- ld a, [mapgen_flags]
- and a, MAPGEN_F_NO_ACT_SG
- call z, act_sg_restore
-
- call map_load_end
-
- ret
-
- ; generates door locations for each map
- ; starts at location 3/3 and moves one door at a time
- ; avoids placing doors at the edge.
- ; stops after plaving at least N doors
-mapgen_make_doors:
- ld b, 0
- ld c, 0 ; bc = y/x position
- ; start current ptr at 1/1 as well
- ld hl, map_doors_location
-
- ; set map cursor
- ld a, 0
- ld [player_map_cursor], a
-
- ; select how many doors we want
- push bc
- push hl
- call rand
- add a, 24 ; at least N doors
- and a, (FLOOR_MAP_COUNT * 2) - 1
-
- pop hl
- pop bc
-
-@loop:
- push af
- push hl
- push bc
-
- ; select a random location
-
- call rand
- and a, 3
-
- pop bc
- pop hl
-
- call make_door
- call make_opp_door
-
- pop af
- dec a
- jr nz, @loop REL
- ret
-
- ; creates the counterpart to
- ; a recently created door
- ; inputs:
- ; a: 1 = UP, 2 = DOWN, 3 = LEFT, 0 = RIGHT
- ; [hl]: current door ptr
- ; returns:
- ; [hl]: ord new door
-make_opp_door:
- cp a, 0
- jp z, @right
- cp a, 1
- jp z, @up
- cp a, 2
- jp z, @down
- cp a, 3
- jp z, @left
-
-@right:
- ld a, [hl]
- or a, DIRLEFT
- ld [hl], a
- ret
-@up:
- ld a, [hl]
- or a, DIRDOWN
- ld [hl], a
- ret
-@down:
- ld a, [hl]
- or a, DIRUP
- ld [hl], a
- ret
-@left:
- ld a, [hl]
- or a, DIRRIGHT
- ld [hl], a
- ret
-
- ; creates a single door
- ; based on the random selection
- ; inputs:
- ; a: 1 = UP, 2 = DOWN, 3 = LEFT, 0 = RIGHT
- ; bc: current coordinate
- ; hl: current ptr
- ; returns:
- ; a: door direction -> door placed
- ; [hl]: ors new door bit
- ; bc: if door placed moves coordinates
- ; hl: if door placed moves ptr
-make_door:
- push af
- cp a, 0
- jp z, @right
-
- cp a, 1
- jp z, @up
-
- cp a, 2
- jp z, @down
-
- cp a, 3
- jp z, @left
-
-@try_again:
- pop af
- inc a
- and a, 3
- jp make_door
-@left:
-
- ; can we even place it?
- ld a, c
- cp a, 0
- jp z, @try_again
-
- ; is this door already set?
- ; ld a, [hl]
- ; and a, DIRLEFT
- ; jp nz, @try_again
-
- ; we can!
- ld a, [hl]
- or a, DIRLEFT
- ld [hl], a
-
- dec c ; x--
- dec hl ; hl--
-
- pop af
- ret
-@right:
- ld a, c
- cp a, FLOOR_W-1
- jp z, @try_again
-
- ; ld a, [hl]
- ; and a, DIRRIGHT
- ; jp nz, @try_again
-
- ld a, [hl]
- or a, DIRRIGHT
- ld [hl], a
-
- inc c ; x++
- inc hl ; hl++
-
- pop af
- ret
-@up:
-
- ld a, b
- cp a, 0
- jp z, @try_again
-
- ; ld a, [hl]
- ; and a, DIRUP
- ; jp nz, @try_again
-
- ld a, [hl]
- or a, DIRUP
- ld [hl], a
-
- dec b ; y--
-
- ; move hl up one row
-.rep i, FLOOR_W, 1, dec hl
-
- pop af
- ret
-@down:
-
- ld a, b
- cp a, FLOOR_H-1
- jp z, @try_again
-
- ; ld a, [hl]
- ; and a, DIRDOWN
- ; jp nz, @try_again
-
- ld a, [hl]
- or a, DIRDOWN
- ld [hl], a
-
- inc b ; y++
-
- ; move hl one row down
-.rep i, FLOOR_W, 1, inc hl
-
- pop af
- ret
-
- ; loads the current player map cursor
- ; and draws the required doors
- ; inputs:
- ; hl: [map]
- ; preserves: hl
-mapgen_draw_doors:
- push hl
- ld hl, map_doors_location
- ld a, [player_map_cursor]
- ld e, a
- ld d, 0
- add hl, de ; hl = door entry
-
- ld a, [hl] ; a = door pattern
- pop hl ; hl = map
- ld b, a ; b = door pattern backup
-
- and a, DIRUP
- jr z, @no_door_up REL
- push hl
- ld de, 7*c_size ; move over 7 tiles
- add hl, de
- ld a, DOOR_TILE_TOP
- ld [hl+], a
- ld a, CF_DOOR | CF_COLLISION | CF_EXIT
- ld [hl], a
- pop hl
-@no_door_up:
-
- ld a, b
- and a, DIRDOWN
- jr z, @no_door_down REL
- push hl
- ld de, 7*c_size + MAP_W * (MAP_H - 1) * c_size
- add hl, de
- ld a, DOOR_TILE_BOTTOM
- ld [hl+], a
- ld a, CF_DOOR | CF_COLLISION | CF_EXIT
- ld [hl], a
- pop hl
-@no_door_down:
-
- ld a, b
- and a, DIRLEFT
- jr z, @no_door_left REL
- push hl
- ld de, 7 * MAP_W * c_size
- add hl, de
- ld a, DOOR_TILE_LEFT
- ld [hl+], a
- ld a, CF_DOOR | CF_COLLISION | CF_EXIT
- ld [hl], a
- pop hl
-@no_door_left:
-
- ld a, b
- and a, DIRRIGHT
- jr z, @no_door_right REL
- push hl
- ld de, 7 * MAP_W * c_size + (MAP_W - 1) * c_size
- add hl, de
- ld a, DOOR_TILE_RIGHT
- ld [hl+], a
- ld a, CF_DOOR | CF_COLLISION | CF_EXIT
- ld [hl], a
- pop hl
-@no_door_right:
-
- ; check if player is on top of a door
- ; if so remove it and mark as an exit instead
- ld de, player_unit
- call unit_get_pos
- call map_get_tile
-
- ld a, b
- cp a, DOOR_TILE_LEFT
- jr z, @door_tile REL
- cp a, DOOR_TILE_RIGHT
- jr z, @door_tile REL
- cp a, DOOR_TILE_TOP
- jr z, @door_tile REL
- cp a, DOOR_TILE_BOTTOM
- jr z, @door_tile REL
-
- ret
-
-@door_tile:
- xor a, a
- ld [hl+], a ; clear tile
-
- ld a, [hl] ; clear collision and door flags
- and a, CF_EXIT
- ld [hl], a
- ret
-
- ; places actors from a valid actor table
- ; from the current floor value. This will overwrite the
- ; header loaded by map_load. Preserves player entry.
- ; the length of the actor table must be maskable
- ; inputs:
- ; a loaded map
-mapgen_place_actors:
- ; clear everything past player
- ld hl, p0_units + act_size
- ld bc, (UNITS_MAX - 1) * act_size
- ld d, 0
- call memset
-
-
- ; load floor actor tables
- ld hl, floor_actor_tables
- ld d, 0
- ld a, [floor]
- ld e, a
- add hl, de
- ; hl = floor actor table ptr
-
- ; load actor table ptr
- ld a, [hl+]
- ld b, a
- ld a, [hl+]
- ; hl = map header actor table ptr
- ld h, a
- ld l, b
-
- ld a, [hl+]
- ld c, a
- cp a, 0
- ret z ; if length is 0 we bail
- ; c = actor table length
- ; hl = actor entries
-
- ; load actor table starting after plater
- ld de, p0_units + act_size
- ; de = actor table
-
- ; b = loop counter
- ld b, UNITS_MAX - 1
- push hl
- call rand
- and a, UNITS_SPAWN_MASK
- add a, UNITS_SPAWN_MIN
- ld b, a
- ; b = units to spawn, at least 4 but might be more
- pop hl
-@spawn_another:
- push bc
- push de
- push hl
- call rand
- pop hl
- pop de
- pop bc
-
- ; mask the rand result
- and a, c
-
- ; now we know which actor to pick
- add a, a ; * 2 because the table is a ptr table
-
- push hl
- push bc
- push de
-
- ld d, 0
- ld e, a
- add hl, de
- ; hl = actor picked ptr
- ld a, [hl+]
- ld e, a
- ld a, [hl+]
- ld d, a
- ; de = actor picked = src
-
-
- pop hl ; hl = actor table dst
- push hl ; re-push for pop de later
- ld bc, act_size
- call memcpy
-
- pop de
- pop bc
- pop hl
-
- ; move to next actor table entry
- push hl
- call mapgen_unit_randomize_position
- ld hl, act_size
- add hl, de
- push hl
- pop de ; de = next entry
- pop hl
-
- dec b
- jp nz, @spawn_another
-
- ret
-
- ; randomizes (or reloads from sram)
- ; an actors position
- ; inputs:
- ; de: actor table entry
- ; preserves all registers
-mapgen_unit_randomize_position:
- push_all
- ld hl, act_pos_y
- add hl, de ; hl = y pos
-@retry:
-
- ; select position
- push hl
- call rand
- and a, MAP_H - 1
- ld b, a
- call rand
- and a, MAP_W - 1
- ld c, a
- ; bc = y/x
-
- ; check if tile is OK to spawn on
- push bc
- call map_get_tile
- cp a, 0x00 ; check flags
- pop bc
- pop hl
- ; if collision flag is set try again
- jr nz, @retry REL
-
- push bc
- push hl
- ; check if this tile already had an actor
- call unit_find_at
- ld a, h
- or a, l
- pop hl
- pop bc
- cp a, 0
- jr nz, @retry REL
-
- ; write y and x positions
- ld a, b
- mul16 a
- ld [hl+], a
-
- ld a, c
- mul16 a
- ld [hl], a
-
- pop_all
- ret
-
- ; selects player spawn room
- ; selects a random room that has an exit and
- ; sets the map cursor
- ; then places the player on a tile without flags
- ; calls mapgen after player is placed to make the map
-mapgen_select_player_spawn:
- call rand
- and a, FLOOR_MAP_COUNT-1
- ld hl, map_doors_location
- ld d, 0
- ld e, a
- add hl, de
- ; check if the selected room has doors (is not 0)
-
- ld a, [hl]
- cp a, 0
- jr z, mapgen_select_player_spawn REL
-
- ; write selected room
- ld a, e
- ld [player_map_cursor], a
-
- call mapgen
-
-@try_placement_again:
- call rand
- and a, MAP_H-1
- ld b, a ; y pos
- call rand
- and a, MAP_W-1
- ld c, a ; x pos
-
- ; get tile data
- push bc
- call map_get_tile
- cp a, 0x00 ; we want no flags here
- pop bc
- jr nz, @try_placement_again REL
-
- push bc
- ; test if a unit is here
- call unit_find_at
- ld a, h
- or a, l
- pop bc
-
- jp nz, @try_placement_again
- ; otherwise write position
- ld hl, player_unit
- ld de, act_pos_y
- add hl, de
- ld a, b
- mul16 a
- ld [hl+], a ; write y
-
- ld a, c
- mul16 a
- ld [hl], a ; write x
-
- ld de, player_unit
- call unit_scroll_center
-
- ret
; set up mbc1
call mbc1_init
- ; load initial game state
- ld de, st_main_menu_init
- ld hl, game_mode
- ld bc, st_size
- call memcpy
-
- ; copy delay to active template to wram
- ld de, st_unit_delay_to_active_template
- ld hl, st_unit_delay_to_active
- ld bc, st_size
- call memcpy
-
- call objanim_init
-
- ; set up default game speed
- ld a, GAME_SPEED_DEFAULT
- ld [game_speed], a
-
; load a demo
; ld hl, demo_inputs1
; call load_demo_ptr
+ ; set initial game state ptr
+ ld hl, update_game
+ call game_set_state
+
ret
; copies memory from one location to another
+++ /dev/null
-#define DOOR_SPRITE_TILE 0x80
-
- ; sets up object animation state
-objanim_init:
- ld de, st_null
- ld hl, objanim
- ld bc, st_size
- call memcpy
-
- ret
-
- ; sets objanim to display a door
- ; opening animation.
- ; decides which animation to play based on the tile inex
- ; supplied.
- ; inputs:
- ; a: tile flags
- ; b: tile index
- ; de: actor
-objanim_door_open:
- push de
- push bc
-
- ; set up the correct state based on tile index
- ld a, b ; a = tile index
- cp a, DOOR_TILE_TOP
- jr nz, @not_top REL
-
- ld de, st_objanim_door_open_up
- ld hl, objanim
- ld bc, st_size
- call memcpy
- jp @done
-@not_top:
-
- cp a, DOOR_TILE_LEFT
- jr nz, @not_left REL
-
- ld de, st_objanim_door_open_left
- ld hl, objanim
- ld bc, st_size
- call memcpy
- jp @done
-@not_left:
-
- cp a, DOOR_TILE_RIGHT
- jr nz, @not_right REL
- ld de, st_objanim_door_open_right
- ld hl, objanim
- ld bc, st_size
- call memcpy
- jp @done
-@not_right:
-
- ; default to down
- ld de, st_objanim_door_open_down
- ld hl, objanim
- ld bc, st_size
- call memcpy
-
-@done:
-
- pop bc
- pop de
-
- ld hl, act_rt_collision_pos_y
- add hl, de ; hl = col pos y
-
- ; clear flags
- ld de, objanim+obja_flags
- xor a, a
- ld [de], a
- inc de ; de = y pos
-
- ld a, [hl+]
- ld [de], a
- inc de ; de = x pos
-
- ld a, [hl]
- ld [de], a
- inc de ; de = dat
-
- ; dat = tile index
- ld a, b
- ld [de], a
- inc de ; de = timer
-
- ; clear frame counter
- xor a, a
- ld [de], a
-
- ; set gameplay flag to pause object updates
- ld a, [gameplay_flags]
- or a, GPF_PAUSE_UPDATE
- ld [gameplay_flags], a
-
- ret
-
- ; down animation
-objanim_door_open_down_fn:
- ld a, [objanim+obja_timer] ; read timer before calling handler
- push af
- call objanim_door_open_generic_fn
-
- pop af
- push bc ; save next state
- ; hl = oam ptr
- inc hl ; skip obj1 y
-
- ; adjust x position based on timer
- ; offset position by counter
- sra a
- ld b, a
- ld a, [hl]
- sub a, b
- ; wirte adjusted obj1 x
- ld [hl+], a ; hl = obj1 tile
-
- inc hl ; skip obj1 tile
- inc hl ; skip obj1 flags
- inc hl ; skip obj2 y
-
- ; hl = obj2 x
- ld a, [hl]
- add a, b
- ; write adjusted obj2 x
- ld [hl+], a
-
- pop bc ; restore next state
- ret
-
-objanim_door_open_up_fn:
- ld a, [objanim+obja_timer] ; read timer before calling handler
- push af
- call objanim_door_open_generic_fn
-
- pop af
- push bc ; save next state
- ; hl = oam ptr
- inc hl ; skip obj1 y
-
- ; adjust x position based on timer
- ; offset position by counter
- sra a
- ld b, a
- ld a, [hl]
- sub a, b
- ; wirte adjusted obj1 x
- ld [hl+], a ; hl = obj1 tile
-
- inc hl ; skip obj1 tile
- ld a, OAM_FYFLIP
- ld [hl+], a ; write obj1 flag and ++
- inc hl ; skip obj2 y
-
- ; hl = obj2 x
- ld a, [hl]
- add a, b
- ; write adjusted obj2 x
- ld [hl+], a
-
- inc hl ; skip obj2 tile
- ld a, OAM_FYFLIP ; write obj2 flag
- ld [hl], a
-
- pop bc ; restore next state
-
- ret
-
-objanim_door_open_left_fn:
- ld a, [objanim+obja_timer] ; read timer before calling handler
- push af
- call objanim_door_open_generic_fn
-
- pop af
- push bc ; save next state
- ; hl = oam ptr
-
- ; adjust x position based on timer
- ; offset position by counter
- ld b, a
- ld a, [hl]
- sub a, b
- ; wirte adjusted obj1 y
- ld [hl+], a ; hl = obj1 tile
- inc hl ; skip obj1 x
-
- ; adjust tile by 4 (next tile) and ++
- ld a, DOOR_SPRITE_TILE + 4
- ld [hl+], a
-
- xor a, a
- ld [hl+], a ; write obj1 flag and ++
-
- ; hl = obj2 y
- ld a, [hl]
- sub a, b
- ; write adjusted obj2 y
- ld [hl+], a
- inc hl ; skip obj2 x
-
- ; adjust tile by 4 (next tile) and ++
- ld a, DOOR_SPRITE_TILE + 6
- ld [hl+], a
-
- xor a, a
- ld [hl], a
-
- pop bc ; restore next state
- ret
-
-objanim_door_open_right_fn:
- ld a, [objanim+obja_timer] ; read timer before calling handler
- push af
- call objanim_door_open_generic_fn
-
- pop af
- push bc ; save next state
- ; hl = oam ptr
-
- ; adjust x position based on timer
- ; offset position by counter
- ld b, a
- ld a, [hl]
- sub a, b
- ; wirte adjusted obj1 y
- ld [hl+], a ; hl = obj1 tile
- inc hl ; skip obj1 x
-
- ; adjust tile by 4 (next tile) and ++
- ld a, DOOR_SPRITE_TILE + 6
- ld [hl+], a
-
- ld a, OAM_FXFLIP
- ld [hl+], a ; write obj1 flag and ++
-
- ; hl = obj2 y
- ld a, [hl]
- sub a, b
- ; write adjusted obj2 y
- ld [hl+], a
- inc hl ; skip obj2 x
-
- ; adjust tile by 4 (next tile) and ++
- ld a, DOOR_SPRITE_TILE + 4
- ld [hl+], a
-
- ld a, OAM_FXFLIP
- ld [hl], a
-
- pop bc ; restore next state
- ret
-
- ; state function for door opening animation
- ; is called by more specific functions that take this base setup
- ; and set the right tiles and animations after
- ; inputs:
- ; de: objanim
- ; returns:
- ; hl: first object used
- ; the objects are guaranteed to be consecutive
- ; and 2 objects will have been reserved
- ; bc: next state
-objanim_door_open_generic_fn:
-#define TMP_Y, scratch
-#define TMP_X, scratch+1
-
- call load_unit_obj
- push hl
- ld de, objanim+st_size
- call load_scroll
-
- ; hl = oam ptr
- ; de = anim flags
-
- ; set first object
- inc de ; skip flags
- ld a, [de] ; a = y position
- inc de ; de = x postion
- tile_to_scrn OBJ_OFF_Y, b
- ld [hl+], a
- ld [TMP_Y], a
-
- ld a, [de] ; a = x position
- tile_to_scrn OBJ_OFF_X, c
- ld [TMP_X], a
- ld [hl+], a
-
-
- ; door tile
- ld a, DOOR_SPRITE_TILE
- ld [hl+], a
-
- xor a, a
- ld [hl+], a ; no flags
-
-
- ; set up second object
- call load_unit_obj
-
- ; set y pos
- ld a, [TMP_Y]
- ld [hl+], a
-
- ; set x pos
- ld a, [TMP_X]
- add a, 8 ; move over a tile
- ld [hl+], a
-
- ; tile
- ld a, DOOR_SPRITE_TILE+2
- ld [hl+], a
-
- ; flags
- xor a, a
- ld [hl], a
-
- pop hl ; restore object ptr used == return value
- ; check if we are done
- ld a, [objanim+obja_timer]
- inc a
- ld [objanim+obja_timer], a ; frame counter++
- cp a, 0x10 ; end frame?
- jr z, @timer_done REL
-
- ldnull bc
- ret
-@timer_done:
- call door_open_done
-#undefine TMP_X
-#undefine TMP_Y
-
- ; completes the door opening animation
-door_open_done:
- ; unset pause object update
- ld a, [gameplay_flags]
- and a, ~GPF_PAUSE_UPDATE & 0xFF
- ld [gameplay_flags], a
-
- ld bc, st_null
- ret
-
-st_objanim_door_open_down:
- st_def 0x00, objanim_door_open_down_fn, st_objanim_door_open_down
-
-st_objanim_door_open_up:
- st_def 0x00, objanim_door_open_up_fn, st_objanim_door_open_up
-
-st_objanim_door_open_left:
- st_def 0x00, objanim_door_open_left_fn, st_objanim_door_open_left
-
-st_objanim_door_open_right:
- st_def 0x00, objanim_door_open_right_fn, st_objanim_door_open_right
-.def int CURSOR_TILE = 0x04
-
- ; loads the default player unit
- ; and hands over control
-unit_load_default_player:
- ld de, unit_player
- ld hl, p0_units
- ld bc, act_size
- call memcpy
-
- ret
-
-unit_player_init:
- ldnull bc
- ret
-
- ; inputs
- ; de: actor
-unit_player_update:
- ; check if player flag is set
- ; if so return early
- ldnull bc
- ld a, [gameplay_flags]
- and a, GPF_PLAYER_TURN_TAKEN
- ret nz
-
- ; check if an attack is ongoing
- ld a, [gpf_attack_ongoing]
- cp a, 0
- ret nz
-
- ; check if the player is currently
- ; on a convered tile or not
- push de
-
- ; first read the current tile
- call unit_get_pos
- call map_get_tile_div16
- push af ; store for later use
-
- ; a = tile flags
- and a, CF_COVERED
- ld b, a
- ld a, [player_rt_special_flags]
- ld c, a ; remove door might needs this in c
- and a, (~CF_COVERED) & 0xFF
- or a, b
- ld [player_rt_special_flags], a
- pop af ; get back a for next check
- pop de
-
- ; hl should still be tile ptr here
-
- ; check for exit flags
- push de
- call unit_check_exit_hit
- pop de
-
- push de
- call unit_scroll_center
- pop de
-
- push de
- call unit_handle_inputs
- pop de
-
- push de
- push bc
- ; test last collision flags
- push de
- ld hl, act_rt_collision_cf
- add hl, de
- ld a, [hl]
- pop de
- and a, CF_DOOR
- call nz, unit_player_remove_door
- pop bc
- pop de
-
- ret
-
- ; removes the door tile the player is currently
- ; standing on
- ; inputs:
- ; de: actor
-unit_player_remove_door:
- ; get tile of last collision
- push de
- ld hl, act_rt_collision_pos_y
- add hl, de
- ld a, [hl+] ; load y
- ld b, a
- ld a, [hl+] ; load x
- ld c, a
- xor a, a
- ld [hl], a ; clear cf
- call map_get_tile_div16
- pop de
-
- ; schedule animation
- push_all
- call objanim_door_open
- call play_door_open_noise
- pop_all
-
- ; remove door tile, door flag
- ; and redraw map
- ld a, 0x00 ; floor tile
- ; clear map
- ld [hl+], a
-
- ; clear all flags but exit
- ld a, [hl]
- and a, CF_EXIT
- ld [hl], a
-
- ld hl, act_rt_collision_pos_y
- add hl, de
- ld a, [hl] ; load y offset
- div16 a
-
- ; if y is at bottom of map go back up a tile...
- cp a, MAP_H-1 ;
- jr nz, @not_end_of_map REL
- dec a
-@not_end_of_map:
- call map_request_redraw_at
-
- ret
-
- ; checks the current tile
- ; and checks for exit flags
- ; if an exit flag is set, checks if
- ; the player is in position y == 0
- ; y == MAP_H-1, x == 0 or x == MAP_W-1
- ; to determine where to take the player
- ; the direction moving the player oob must be pressed to move the player
- ; inputs:
- ; de: actor
-unit_check_exit_hit:
- push de
- ld hl, act_pos_y
- add hl, de ; hl = actor_y
-
- ld a, [hl+]
- ld b, a ; b = y pos
- ld a, [hl] ; hl = x pos
- ld c, a ; c = x pos
-
- call map_get_tile_div16
- ; a = flags
- ld b, a ; b = flags for later use
- and a, CF_EXIT
- pop de
- ret z ; if not we bail
-
- ; now it's time to look up
- ; the exit's position
- ; de = actor
- ld hl, act_pos_y
- add hl, de
- ; hl = act_pos_y
-
- ld a, [hl]
- div16 a
- cp a, 0 ; top
- jp z, unit_exit_top
-
- ld a, [hl+]
- div16 a
- cp a, MAP_H-1
- jp z, unit_exit_bottom
-
- ld a, [hl] ; hl = x pos
- div16 a
- cp a, 0
- jp z, unit_exit_left
-
- ld a, [hl]
- div16 a
- cp a, MAP_W-1
- jp z, unit_exit_right
-
-
- ; performs the map load
-unit_map_load:
- ; fade out
- call video_fade_out
-
-
- ; generate new map
- call mapgen
-
- ; hl = player
- ld hl, player_unit
- ld de, act_pos_y
- add hl, de ; hl = y pos
-
-
- ; scroll to player's position
- ld de, player_unit
- call unit_scroll_center
- call next_vblank_wait
- call scroll_write
-
- ; fade back in
- ld a, [shadow_bpg]
- call video_fade_in
-
- ret
-
- ; performs a top exit
- ; adjusts player cursor
- ; and units position
- ; checks if input is held, -> calls unit_load_map
- ; inputs:
- ; de: unit
- ; preserves:
- ; hl, de
-unit_exit_top:
- ld b, BTNUP
- input_held
- ret z
-
- ld hl, act_pos_y
- add hl, de
-
- ; move player down
- ld a, MAP_H-2
- mul16 a
- ld [hl], a
-
- ld a, [player_map_cursor]
- ; cursor needs to go 1 row up
- sub a, FLOOR_W
- ld [player_map_cursor], a
-
- call unit_map_load
- ret
-
- ; performs bottom exit
- ; same as exit top
- ; inputs:
- ; de; unit
- ; preserves:
- ; hl, de
-unit_exit_bottom:
- ld b, BTNDOWN
- input_held
- ret z
-
- ld hl, act_pos_y
- add hl, de
-
- ; move player up
- ld a, 1
- mul16 a
- ld [hl], a
-
- ld a, [player_map_cursor]
- ; go down a row
- add a, FLOOR_W
- ld [player_map_cursor], a
-
- call unit_map_load
- ret
-
- ; performs a right exit
- ; same as exit top
- ; inputs:
- ; de: unit
-unit_exit_right:
- ld b, BTNRIGHT
- input_held
- ret z
-
- ld hl, act_pos_x
- add hl, de
-
- ; move player left
- ld a, 1
- mul16 a
- ld [hl], a
-
- ld a, [player_map_cursor]
- ; go right one row
- inc a
- ld [player_map_cursor], a
-
- call unit_map_load
- ret
-
- ; performs a left exit
- ; same as exit top
- ; inputs:
- ; de: unit
-unit_exit_left:
- ld b, BTNLEFT
- input_held
- ret z
-
- ld hl, act_pos_x
- add hl, de
-
- ; move player right
- ld a, MAP_W-2
- mul16 a
- ld [hl], a
-
- ld a, [player_map_cursor]
- ; go left one row
- dec a
- ld [player_map_cursor], a
-
- call unit_map_load
- ret
-
-
- ; player attack state
- ; inputs:
- ; de: actor
- ; returns:
- ; bc: next state
-unit_player_attack:
- ldnull bc
- ret
-
-#define player_draw unit_draw
-
-unit_player:
- st_def 0x00, unit_player_init, st_unit_idle
- act_def ACT_T_PLAYER, 0, 2, 2, 0
- act_stat_def1 1, 3, 1, 1
- act_stat_def2 1, 1, 90, 1
- act_st_def st_unit_player_update, st_unit_idle
- act_def_meta player_draw, player_anim_table
-
-st_unit_player_update:
- st_def 0x00, unit_player_update, st_unit_player_update
-
-st_unit_player_attack:
- st_def 0x00, unit_player_attack, st_unit_player_attack
ld a, [srand]
ret
-
- ; rolls a d16
- ; returns a number between
- ; 0 and 15
- ; returns:
- ; [d16]: last roll
- ; a: d16 roll
- ; preserves registers other than af
-roll_d16:
- push hl
-
- call rand
- and a, 0x0F
- ld [d16], a
-
- pop hl
- ret
-
+++ /dev/null
-#define DOOR_TILE_TOP 0x2E
-#define DOOR_TILE_BOTTOM 0x0E
-#define DOOR_TILE_LEFT 0x0C
-#define DOOR_TILE_RIGHT 0x2C
-
- ; table of possible maps
- ; must be divisible by 2 in size
-
-room_patterns_floor1:
- dw map_c_header
- dw map_ce_header
- dw map_cw_header
- dw map_be_header
- dw map_bc_header
- dw map_bw_header
- dw map_te_header
- dw map_tc_header
-room_patterns_floor1_end:
-
-
+++ /dev/null
-#define SELECT_MENU_DELAY_FRAMES 10
-
- ; a select menu is any menu that allows the player to select
- ; a range of values
- ; writes current string to status line and requests an update
- ; if the direction keys are pressed
- ; inputs:
- ; hl: string ptr table
- ; b: table length
- ; a: current slection value
- ; returns:
- ; a: selection value
- ; b: button pressed
-select_menu_update:
- push af
-
- ; check if delay timer is active
- ld a, [select_menu_delay]
- cp a, 0
- jr z, @not_delay REL
- dec a
- ld [select_menu_delay], a
- jp @no_select
-@not_delay:
-
- ; save table length
- pop af
- push af
- push bc
-
- cp a, 0
- jr z, @notleft REL
-
- ld b, BTNLEFT
- input_held
- jr z, @notleft REL
- ld a, SELECT_MENU_DELAY_FRAMES
- ld [select_menu_delay], a
- pop bc
- pop af
- dec a
- call select_menu_draw_status
- ld b, BTNLEFT
- ret
-@notleft:
-
- pop bc ; get back table length
- ld c, b ; store table length in c
- pop af
- push af
- dec b ; length - 1
- cp a, b
- jr z, @notright REL ; is a > b
-
- ld b, BTNRIGHT
- input_held
- jr z, @notright REL
- ld a, SELECT_MENU_DELAY_FRAMES
- ld [select_menu_delay], a
- pop af
- inc a
- ld b, c ; table length = c
- call select_menu_draw_status
- ld b, BTNRIGHT
- ret
-@notright:
-
-@no_select:
-
- ; A button to select action
- ld b, BTNA
- input_just
- jr z, @nota REL
- pop af
- ld b, BTNA
- ret
-@nota:
-
- ; TODO: SELECT to assign to B
- pop af ; pop original input for a
- ld b, 0 ; clear b return value
- ret
-
- ; draws a status text for the current selection
- ; inputs:
- ; hl: string ptr table
- ; a: selection
- ; b: string table length
- ; preserves:
- ; af
-select_menu_draw_status:
- push af
- push bc
-
- push hl
- push af
- call ui_clear_status_line
-
- pop af
- push af
- ; check if left arrow needs to be drawn (a != 0)
- cp a, 0
- jr z, @no_left_arrow REL
- ; write cursor tile
- ld de, UI_STATUS_LINE
- ld a, MENU_CURSOR_TILE_REVERSE
- ld [de], a
-@no_left_arrow:
-
- pop af
- pop hl
-
- add a, a ; * 2 for table offset
- ld d, 0
- ld e, a
- add hl, de ; hl = string ptr
-
- ld a, [hl+]
- ld d, a
- ld a, [hl]
- ; hl = the string
- ld h, a
- ld l, d
-
- ld de, UI_STATUS_LINE+1
- call puts
- push de
- call ui_request_redraw
- pop de
- ; de = tile after string
-
- pop bc
- pop af
-
- push af
- ; check if right arrow needs to be drawn (a != b-1)
- dec b
- cp a, b
- jr z, @no_right_arrow REL
- ; write cursor tile
- ld a, MENU_CURSOR_TILE
- ld [de], a
-@no_right_arrow:
- pop af
- ret
+++ /dev/null
-; shoot (ranged attack) actions
-; cast a ray in direction
-; hit first actor found
-; and attacking actor plays a small shoot animation
-
-unit_action_shoot_pick_direction_init:
- ld hl, STR_ATTACK_DIRECTION
- ld de, UI_STATUS_LINE
- call puts
- call ui_request_redraw
- ldnull bc
- ret
-
-unit_action_shoot_pick_direction:
- ld bc, st_unit_delay_to_active_template
- jp unit_action_pick_direction
-
-st_action_shoot_init:
- st_def 0x00, unit_action_shoot_pick_direction_init, st_action_shoot_pick_direction
-st_action_shoot_pick_direction:
- st_def 0x00, unit_action_shoot_pick_direction, st_action_shoot_pick_direction
+++ /dev/null
- ; updates the state of an actor
- ; inputs:
- ; de: actor
-st_update:
- push de
-
- inc de
- ld a, [de]
- ld l, a
- inc de
- ld a, [de]
- ld h, a
- ; hl = function ptr
-
- dec de
- dec de ; de = timer
- ld a, [de] ; a = timer
- cp a, 0
- ; if timer is 0 update state
- jr z, @update REL
-
- ; otherwise timer--
- dec a
- ld [de], a
-
- pop de
- ret
-@update:
- ; de = actor ptr
- pop de
- push de
- call_hl
-
- pop hl ; hl = original actor ptr = dst
-
- ; if routine returns
- ; a new ptr in bc
- ; set state to this pointer
- ; otherwise use state's next
- ld a, b
- or a, c
- cp a, 0
- jr z, @set_next_state_default REL
-
- ; hl = actor ptr
-
- ; set returned state
- push bc
- pop de ; de = src
-
- ld bc, st_size
- call memcpy
- ret
-@set_next_state_default:
-
- ; set default state
- ; hl = actor ptr
- push hl
-
- inc hl
- inc hl
- inc hl
- ; hl = st_next
- ld a, [hl+]
- ld e, a
- ld a, [hl]
- ld d, a ; de = next state ptr
-
- pop hl
-
- ld bc, st_size
- call memcpy
- ret
-
- ; null state
- ; do nothing and return
-st_null_fn:
- ldnull bc
- ret
-
-st_null:
- st_def 0xFF, st_null_fn, st_null
-
-
+++ /dev/null
- ; main stats:
- ; str: increases heavy weapon damage
- ; increases heavy weapon speed
- ; int: increases mana and spell damage
- ; increases spell speed
- ; dex: increases ranged/short weapon damage
- ; increases ranged/short weapon speed
- ; decreses time between moves and attack speed
- ; vit: increases health
- ; increases hit chance
-
- ; calculated stats based on gear/other stats:
- ; hit: increases chance to hit
- ; resistances: decrease how long a dot lasts and how much damage
- ; is taken.
- ; fire, lightning, poison resistance and magic resitance
- ; health
- ; mana
- ; ac: armor value
-
- ; calculates the real strength stat
- ; inputs:
- ; de: actor
- ; returns:
- ; a: str value
-stat_calc_str:
- ld hl, act_str
- add hl, de
- ld a, [hl]
- ret
-
- ; calculates hp
- ; inputs:
- ; de: actor
- ; returns:
- ; a: hp
-stat_calc_hp:
- ld hl, act_hp
- add hl, de
- ld a, [hl]
- ret
-
- ; calculates mp
- ; inputs:
- ; de: actor
- ; returns:
- ; a: mp
-stat_calc_mp:
- ld hl, act_mp
- add hl, de
- ld a, [hl]
- ret
-
- ; calculates weapon damage
- ; inputs:
- ; de actor
- ; returns:
- ; a: raw weapon damage
-stat_calc_weapon_damage:
- ; TODO: 1 is fist stat...
- ld a, 1
- ret
-
- ; calculates ac
- ; inputs:
- ; de: actor
- ; returns:
- ; a: ac
-stat_calc_ac:
- ld hl, act_ac
- add hl, de
- ld a, [hl]
- ret
-
- ; calculates max hp based
- ; inputs:
- ; deL actor
- ; returns:
- ; a: max hp
-stat_calc_hp_max:
- ld hl, act_vit
- add hl, de
- ld a, [hl]
- add a, 2 ; base health
- ret
-
- ; calculates mp max
- ; inputs:
- ; de: actor
- ; returns:
- ; a: mp max
-stat_calc_mp_max:
- ; TODO calculate properly
- ld a, 255
- ret
-
- ; calculates physical damage of
- ; one actor agains another
- ; formula:
- ; physical damage = (weapon damage a1 + strength a1 / 8) - (ac a2 / 2)
- ; inputs:
- ; de: actor1
- ; bc: actor2
- ; returns:
- ; sub damage from actor2
- ; a: damage
-stat_calc_physical_damage_vs:
- ; actor 1
- push bc
-
- call stat_calc_weapon_damage
- ; a = damage
- ld b, a ; b = weapon damage
-
- ; weapon damage + strenth / 8
- call stat_calc_str
- sra a ; / 2
- sra a ; / 4
- sra a ; / 8
- add a, b
- ld b, a ; b = real damage
-
- ; actor 2
-
- pop de ; de = actor2 now
- ; damage - ac/2
- call stat_calc_ac
- sra a
- sub_ba
- jp c, @no_damage
-
- ; b = damage to apply
-
- ; apply damage
-
- ld hl, act_hp
- add hl, de
- ; hl = act2 hp
- ld a, [hl]
- sub a, b
- jp c, @dead
-
- ; write new hp
- ld [hl], a
-
- ; a = damage dealt
- ld a, b
-
- ret
-@no_damage:
- xor a, a
- ret
-@dead:
- xor a, a
- ld [hl], a ; write 0 hp
- ld a, b ; a = damage dealt
- ret
-
- ; heals the actor by N
- ; does not overheal
- ; inputs:
- ; de: actor
- ; a: amount
- ; returns:
- ; a: actual heal amount
-stat_heal_by:
- push af ; push original a value
- ld b, a ; b = amount to heal by
- ld hl, act_hp
- add hl, de
- ld a, [hl] ; a = current hp
- add a, b ; a = new hp
-
- push hl
- push af
- call stat_calc_hp_max
- ld b, a ; b = max hp
- pop af
- pop hl
-
- cp a, b
- ; a > b? (max > new value)
- jr nc, @overheal REL
- ld [hl], a ; write new value
- pop af ; return input value
- ret
-@overheal:
- ; set to max
- ld a, b
- ld [hl], a ; write max into hp
- pop af
- xor a, a ; no healing was done
- ret
-
- ; calculates the real speed state
- ; inputs:
- ; de: actor
- ; returns:
- ; a: speed stat
-stat_calc_speed:
- ld a, [game_speed]
- ret
; increments unit sprite
; returns;
; hl: current unit sprite
-load_unit_obj:
- ld a, [draw_flags]
- and a, DRAWF_SKIP_UNIT_OBJS
- jr nz, @load_unit_empty REL
-
- ld a, [unit_sprite]
+load_oam_obj:
+ ld a, [current_oam_obj]
ld d, 0
; next object
add a, oamsize
- ld [unit_sprite], a
+ ld [current_oam_obj], a
ret
-@load_unit_empty:
- ld hl, empty_oam
- ret
; resets unit obj
-reset_unit_obj:
+reset_oam_obj:
xor a, a
- ld [unit_sprite], a
+ ld [current_oam_obj], a
ret
; writes default vblank jmp vector
ld a, 0xD9 ; reti
ld [hl], a
ret
+
; inits UI
ui_init:
- ; fill shadow UI with default tile
- ld hl, shadow_ui
- ld bc, UI_TILE_WIDTH * UI_TILE_HEIGHT
- ld d, UI_WINDOW_BACKGROUND
- call memset
- call ui_redraw_hp
- call ui_redraw_mp
-
- call ui_request_redraw
- ret
-
- ; redraws player stats
- ; preserves all
-ui_redraw_player:
- push_all
- call ui_redraw_hp
- pop_all
- ret
-
- ; updates HP UI
-ui_redraw_hp:
- ld hl, STR_HP
- ld de, UI_STATUS_LINE+32
- call puts
-
- push de
- ld de, player_unit
- call stat_calc_hp
- pop de
-
- call putn
-
- ; print /
- ld hl, STR_SLASH
- call puts
-
- ; print max hp
- push de
- ld de, player_unit
- call stat_calc_hp_max
- pop de
-
- call putn
-
- ret
-
- ; updates MP UI
-ui_redraw_mp:
- ld hl, STR_MP
- ld de, UI_STATUS_LINE+64
- call puts
-
- push de
- ld de, player_unit
- call stat_calc_mp
- pop de
-
- call putn
-
- ; print /
- ld hl, STR_SLASH
- call puts
-
- ; print max mp
- push de
- ld de, player_unit
- call stat_calc_mp_max
- pop de
- call putn
- ret
-
- ; clears the status line
- ; and requests a UI redraw
-ui_status_line_clear:
- ld hl, STR_STATUS_CLEAR
- ld de, UI_STATUS_LINE
- call puts
- jp ui_request_redraw
-
- ; requests a redraw
- ; this will set up redraw_bg
- ; redraw_shadow and redraw_steps
-ui_request_redraw:
- ld hl, SCRN1
- ld a, h
- ld [redraw_bg], a
- ld a, l
- ld [redraw_bg+1], a
-
- ld de, shadow_ui
- ld a, d
- ld [redraw_shadow], a
- ld a, e
- ld [redraw_shadow+1], a
-
- ; steps of 5 * 16
- ld a, UI_TILE_WIDTH * UI_TILE_HEIGHT / REDRAW_TILES_PER_FRAME
- ld [redraw_steps], a
ret
-
-
- ; draw a string and a number
- ; as a status line
- ; inputs:
- ; hl: text ptr
- ; a: value to display
-ui_draw_status_stat:
- push af
- ld de, UI_STATUS_LINE
- call puts
- pop af
-
- call putn
- call ui_request_redraw
-
- ret
-
- ; clears the UI status line
-ui_clear_status_line:
- ld de, UI_STATUS_LINE
- ld hl, ui_str_clear
- jp puts
-
+++ /dev/null
- ; runs state for each unit
- ; does not update if actor is ACT_T_NULL
- ; inputs:
- ; hl: unit table (p0/p1)
-units_update:
-
- ; loop counter
- ld a, UNITS_MAX
-
-@loop:
- push af ; store loop counter
-
- push hl
- ld de, act_type
- add hl, de ; hl = act_type
-
- ; a = type
- ld a, [hl]
- pop hl ; restore hl
- cp a, ACT_T_NULL ; do not update type NULL
- jr z, @skip REL
-
- ; save hl again
- ; hl = act_state state machine
- push hl
- push hl
- pop de ; need hl in de for parameter
- ld a, [gameplay_flags]
- and a, GPF_PAUSE_UPDATE
- call z, st_update
-
- pop hl
-
- push hl
- call unit_update_draw
- pop hl
-@skip:
- ; next actor
- ld de, act_size
- add hl, de
-
- ; a--
- pop af
- dec a
- jr nz, @loop REL
-
- ret
-
- ; sets player turn taken flag
-unit_set_player_turn_taken:
- ld a, [gameplay_flags]
- or a, GPF_PLAYER_TURN_TAKEN
- ld [gameplay_flags], a
- ret
-
- ; clears player turn taken flag
-unit_clear_player_turn_taken:
- ld a, [gameplay_flags]
- and a, ~GPF_PLAYER_TURN_TAKEN & 0xFF
- ld [gameplay_flags], a
- ret
-
- ; generic unit input handler
- ; inputs:
- ; de: actor
- ; hl: action table
- ; a: remaining moves
- ; returns:
- ; bc: next state
-unit_handle_inputs:
- ; push next state to the stack for now
- ld bc, NULL
- push bc
-
-
- ld b, BTNA
- input_just
- ld hl, action_btna
- jr z, @nota REL
- pop bc
- call unit_handle_assigned_action
- push bc ; bc = next state
-@nota:
-
- ld b, BTNSELECT
- input_just
- jr z, @notselect REL
- call action_menu_init
-@notselect:
-
- ld b, BTNUP
- input_held
- jr z, @notup REL
-
- push de
- push hl
- call unit_try_move_up
- pop hl
- pop de
-
- call unit_set_player_turn_taken
- pop bc
- ld bc, st_unit_delay_to_active
- push bc
-@notup:
-
- ld b, BTNDOWN
- input_held
- jr z, @notdown REL
-
- push de
- push hl
- call unit_try_move_down
- pop hl
- pop de
-
- call unit_set_player_turn_taken
- pop bc
- ld bc, st_unit_delay_to_active
- push bc
-@notdown:
-
- ld b, BTNLEFT
- input_held
- jr z, @notleft REL
-
- push de
- push hl
- call unit_try_move_left
- pop hl
- pop de
-
- call unit_set_player_turn_taken
- pop bc
- ld bc, st_unit_delay_to_active
- push bc
-@notleft:
-
- ld b, BTNRIGHT
- input_held
- jr z, @notright REL
-
- call unit_try_move_right
-
- call unit_set_player_turn_taken
- pop bc
- ld bc, st_unit_delay_to_active
- push bc
-@notright:
-
- pop bc
- ret
-
- ; performs a generic collision test
- ; before a move is attempted
- ; ret on nz
- ; inputs:
- ; $1: register containing coordinate
- ; $2: change in register (e.g. +16/-16)
- ; $3: collision mask for tile
- ; de: actor
- ; returns:
- ; unit_test_collision_cf_flags: 0 if not collided with a tile
- ; FLAGS if collided
- ; _pox_y/x: set to input acot y and x
-#macro unit_test_collision
- ; perform tile collision check
- push de
- call unit_get_pos
-
- ld a, $1
- add a, ($2 & 0xFF)
- ld $1, a
-
- ; write y and x pos
- ld hl, act_rt_collision_pos_y
- add hl, de ; de = collision vars y pos
- ld a, b
- ld [hl+], a ; write y
- ld a, c
- ld [hl+], a ; write x
-
- push bc
- push hl ; save hl = rt cf value
- call map_get_tile_div16
- ; set flags result
- pop hl
- ld [hl], a ; store last cf
- and a, $3
- pop bc
- pop de
- ret nz
-
- push de
- call unit_collides_with_any_other
- ; TODO: write collided unit here as well
- and a, $2
- pop de
- ret nz
-#endmacro
-
- ; tests a tile position for collision with
- ; any other actor. Skips actors of type 0
- ; inputs:
- ; b/c: y/x tile positon to test
- ; de : current actor
- ; returns:
- ; a = CF_COLLISION if collision occured
- ; sets act_rt_collided_with
-unit_collides_with_any_other:
-#define scratch_loop_i scratch
- ld hl, p0_units
- ld a, UNITS_MAX ; loop counter
-
-@loop:
- ld [scratch_loop_i], a
- push de ; save current actor on stack
- push bc
-
- ; skip act type == 0
- push de
- push hl
- ld de, act_type
- add hl, de ; hl = actor type
- ; skip if type is 0
- ld a, [hl]
- cp a, 0
- pop hl
- pop de
- jr z, @skip REL
-
- ; check if actor is current actor
- ld a, h
- cp a, e
- jr nz, @no_skip REL
- ld a, l
- cp a, d
- jr z, @skip REL
-@no_skip:
-
- push hl
- ld de, act_pos_y
- add hl, de ; hl = pos_y of current actor
-
- ld a, [hl+] ; a = y
- cp a, b
- ; a != b -> no collision
- jr nz, @no_collision REL
-
- ld a, [hl] ; a = x
- cp a, c
- ; a != c -> no collision
- jr z, @collision REL
-@no_collision:
- pop hl
-
-@skip:
- ld de, act_size
- add hl, de ; move to next actor
-
- ld a, [scratch_loop_i]
- dec a
-
- pop bc
- pop de
- jp nz, @loop
-
- ; if we get here
- ; no collision occured
- ld a, 0
- ret
-@collision:
- pop hl
- pop bc
- pop de
- ; set de to hl's current collider actor
- ld bc, act_rt_collided_with
- add hl, bc
- ld a, e
- ld [hl+], a
- ld a, d
- ld [hl], a
-
- ; if we get here clean up the stack
- ; and set the CF_COLLISION flag
- ld a, CF_COLLISION
- ret
-#undefine scratch_loop_i
-
-
- ; moves a unit up
- ; moves are aborted
- ; if no more initiative is left
- ; a wall is hit, another unit is hit
- ; or the edge of the map is hit
- ; inputs:
- ; de: actor
- ; updates:
- ; actor initiative based on tile flags
- ; actor position
-unit_try_move_up:
- ; y - 1
- unit_test_collision b, -16 & 0xFF, CF_COLLISION
-
- push de
- ld hl, act_pos_y
- add hl, de
- ; hl = actor y
- ld a, [hl]
- cp a, 0 ; upper bound
-
- pop de
- ret z
-
- sub a, 16
- ld [hl], a
-
- call play_walk_noise
-
- ret
-
-unit_try_move_down:
- ; y + 1
- unit_test_collision b, 16, CF_COLLISION
-
- ld hl, act_pos_y
- add hl, de
- ; hl = actor y
- ld a, [hl]
- cp a, MAP_H - 1 ; lower bound
- ret z
-
- add a, 16
- ld [hl], a
-
- call play_walk_noise
-
- ret
-
-unit_try_move_left:
- ; x - 1
- unit_test_collision c, -16 & 0xFF, CF_COLLISION
-
- ld hl, act_pos_x
- add hl, de
- ; hl = actor x
- ld a, [hl]
- cp a, 0 ; left bound
- ret z
-
- sub a, 16
- ld [hl], a
-
- call play_walk_noise
-
- ret
-
-unit_try_move_right:
- ; x + 1
- unit_test_collision c, 16, CF_COLLISION
-
- ld hl, act_pos_x
- add hl, de
- ; hl = actor x
- ld a, [hl]
- cp a, MAP_W - 1 ; right bound
- ret z
-
- add a, 16
- ld [hl], a
-
- call play_walk_noise
-
- ret
-
-
- ; centers the current scroll on the selected unit
- ; snaps to corners of the map
- ; inputs:
- ; de: actor
-unit_scroll_center:
- ld hl, act_pos_y
- add hl, de
- ; hl = pos y
-
- ; y position scroll
- ld a, [hl+]
- div16 a
-
- ; max y
- cp a, 0x0E
- jr c, @not_max_y REL
- ld a, 0x0E
-@not_max_y:
-
- ; min y
- cp a, 0x05
- jr nc, @not_min_y REL
- ld a, 0x05
-@not_min_y:
- ; adjust scroll
- sub a, (MAP_H - VIEW_PORT_TILES_H) / 2
- mul16 a
- ld [scroll_y], a
-
- ; x position scroll
- ld a, [hl]
- div16 a
-
- ; max x
- cp a, 0x0B
- jr c, @not_max_x REL
- ld a, 0x0B
-@not_max_x:
-
- ; min x
- cp a, 0x05
- jr nc, @not_min_x REL
- ld a, 0x05
-@not_min_x:
-
- sub a, (MAP_W - VIEW_PORT_TILES_W) / 2
-
- mul16 a
- ld [scroll_x], a
-
-
- ret
-
- ; switches a unit to active state
- ; inputs:
- ; de: unit
- ; returns:
- ; bc: new state
-unit_switch_to_active:
- ld hl, act_st_active
- add hl, de ; hl = st_active ptr
- ld a, [hl+]
- ld c, a
- ld a, [hl]
- ld b, a
- ; bc = next active state
-
- ret
-
- ; forces a unit into an active state
- ; inputs:
- ; de: unit
-unit_wake_up:
- push de
- call unit_switch_to_active
- ; bc = active state
- push bc
- pop de ; de = new state
- pop hl ; unit ptr
- ld bc, st_size
- call memcpy
- ret
-
- ; switches the current unit to idle
- ; sets moves to 0
- ; inputs:
- ; de: unit
- ; returns:
- ; bc: new state
-unit_switch_to_idle:
- ld hl, act_st_idle
- add hl, de ; hl = st_idle ptr
- ld a, [hl+]
- ld c, a
- ld a, [hl]
- ld b, a
- ret
-
- ; forces a unit to go into idle state
- ; inputs:
- ; de: unit
-unit_sleep:
- push de
- call unit_switch_to_idle
- ; bc = active state
- push bc
- pop de ; de = new state
- pop hl ; unit ptr
- ld bc, st_size
- call memcpy
- ret
-
- ; called before switching to active
- ; this call also checks if the unit may need to
- ; hand over control to a new unit
- ; this is done when moves are 0
- ; if the player unit is here we set the turn as finished
- ; inputs:
- ; de: unit
-unit_delay_to_active:
- ; check if de is player
- ; if so set turn as finished
- ld a, player_unit LO
- cp a, e
- jr nz, @not_player REL
- ld a, player_unit HI
- cp a, d
- jr nz, @not_player REL
-
- call unit_set_player_turn_taken
-
-@not_player:
- ; do not proceed if an attack animation is ongoing
- ld a, [gpf_attack_ongoing]
- cp a, 0
- jr nz, @delay_again REL
-
- ldnull bc
- ret
-@delay_again:
- ld bc, st_unit_delay_to_active_fast
- ret
-
- ; inputs
- ; de: actor
-unit_idle:
- ldnull bc
- ret
-
- ; pauses object redraws
- ; until unpause is called
-unit_pause_objs:
- ld a, [draw_flags]
- or a, DRAWF_SKIP_UNIT_OBJS
- ld [draw_flags], a
- ret
-
- ; resumes obj updates
-unit_resume_objs:
- ld a, [draw_flags]
- and a, ~DRAWF_SKIP_UNIT_OBJS & 0xFF
- ld [draw_flags], a
- ret
-
-
- ; gets the tile value at the current unit's position
- ; inputs:
- ; de: unit
- ; returns:
- ; bc: y/x
-unit_get_pos:
- ld hl, act_pos_y
- add hl, de ; hl = pos y
- ld a, [hl+]
- ld b, a ; b = y
- ld a, [hl]
- ld c, a ; c = x
- ret
-
- ; TODO:
- ; returns:
- ; hl: inventory ptr
- ; a: inventory length
-unit_get_inventory:
- ret
-
- ; TODO:
- ; returns:
- ; hl: equipment ptr
- ; a: equipment length
-unit_get_equipment:
- ret
-
- ; sets a draw routine for a unit
- ; inputs:
- ; de: unit
- ; bc: draw routine
-unit_set_draw:
- ld hl, act_draw
- add hl, de
- ; hl = draw ptr
- ld a, c
- ld [hl+], a
- ld a, b
- ld [hl], a
- ret
-
- ; finds a unit at a specific location
- ; inputs:
- ; bc: y/x
- ; returns:
- ; hl: unit ptr or NULL if not found
-unit_find_at:
- ld hl, p0_units
-
- ; a = loop counter
- ld a, UNITS_MAX
-
-@loop:
- push af
- push hl
-
- push hl
- ; do not find type null
- ld de, act_type
- add hl, de
- ld a, [hl]
- pop hl
- cp a, 0
- jr z, @no_match REL
-
- ld de, act_pos_y
- add hl, de
- ; hl = y pos
-
- ; check if positions match
- ld a, [hl+]
- cp a, b ; does y match?
- jr nz, @no_match REL
-
- ld a, [hl]
- cp a, c ; does x match?
- jp z, @found
-
-@no_match:
- pop hl ; back to start
- pop af ; restore loop counter
- ; next unit
- ld de, act_size
- add hl, de
- dec a
- jp nz, @loop
-
- ldnull hl
- ret
-
-@found:
- pop hl ; hl = start of found act
- pop af ; af was also saved so we need to pop
- ret
-
-st_unit_idle:
- st_def 0x00, unit_idle, st_unit_idle
-
- ; template for st_unit_delay_to_active
- ; in wram
-st_unit_delay_to_active_template:
- st_def 8, unit_delay_to_active, st_unit_switch_to_active
-
-st_unit_delay_to_active_fast:
- st_def 0, unit_delay_to_active, st_unit_switch_to_active
-
-st_unit_switch_to_active:
- st_def 0, unit_switch_to_active, st_unit_switch_to_active
+++ /dev/null
-#define UNIT_SCAN_RANGE_Y MAP_H/4
-#define UNIT_SCAN_RANGE_X MAP_W/4
-
- ; checks if the unit is dead
- ; if so sets type to 0
- ; inputs:
- ; de: actor
- ; returns:
- ; z-flag if dead
-unit_cpu_check_dead:
- ld hl, act_hp
- add hl, de
- ld a, [hl]
- cp a, 0
- ret nz ; not dead
- push af
-
- ld a, ACT_T_NULL
- ld hl, act_type
- add hl, de
- ld [hl], a ; set type to NULL
-
- pop af
- ret
-
- ; handles cpu inputs
- ; chaser CPU script
- ; inputs:
- ; de: actor
- ; returns:
- ; bc: next state
-unit_handle_cpu_inputs:
-#define MOVE_MADE scratch
-
- ; check if dead
- ; if so set type to 0
- call unit_cpu_check_dead
- ldnull bc
- ret z
-
- ; check if player has taken turn
- ; if not exit
- ldnull bc
- ld a, [gameplay_flags]
- and a, GPF_PLAYER_TURN_TAKEN
- ret z
-
- ; if rand is > 127 we do not
- ; attack no matter what
- call rand
- cp a, 127
- jr c, @skip_attack REL
-
- ; attempt an attack
- ; and jump to move made if attack was performed
- call unit_cpu_attack_player
- cp a, 0
- jp nz, @attack_started
-
-@skip_attack:
- ; clear move made buffer
- xor a, a
- ld [MOVE_MADE], a
-
- ; there's a change the
- ; unit will just move randomly anyway
- call rand
- and a, 0x2
- cp a, 0
- jp z, @random_move
-
- ; otherwise follow player
-
- ; check y position
- ; and follow player in y direction if player is in range
- ld hl, player_unit+act_pos_y
- ld a, [hl]
- ld b, a ; b = player y pos
- push de
- ld hl, act_pos_y
- add hl, de
- ld a, [hl] ; a = act y pos
- call distance
- pop de
-
- ; are we in scan range?
- cp a, UNIT_SCAN_RANGE_Y
- jr nc, @not_in_y_range REL
- cp a, 0
- jr z, @not_in_y_range REL
-
- ; which direction?
- ld a, c
- cp a, DISTANCE_BGTA
- push af
- call nz, unit_try_move_up
- pop af
- call z, unit_try_move_down
- ld a, 1
- ld [MOVE_MADE], a
-@not_in_y_range:
-
- ; check x position
- ; and follow player in x direction if player is in range
- ld hl, player_unit+act_pos_x
- ld a, [hl]
- ld b, a ; b = player x pos
- push de
- ld hl, act_pos_x
- add hl, de
- ld a, [hl] ; a = act x pos
- call distance
- pop de
-
- ; are we in scan range?
- cp a, UNIT_SCAN_RANGE_X
- jr nc, @not_in_x_range REL
- cp a, 0
- jr z, @not_in_x_range REL
-
- ; which direction?
- ld a, c
- cp a, DISTANCE_BGTA
- push af
- call nz, unit_try_move_left
- pop af
- call z, unit_try_move_right
- ld a, 1
- ld [MOVE_MADE], a
-@not_in_x_range:
-@random_move:
-
- ; call random move if move was not made
- ld a, [MOVE_MADE]
- cp a, 0
- call z, unit_cpu_random_move
-
-@move_made:
- ld bc, st_unit_delay_to_active
- ret
-@attack_started:
- ld bc, st_action_attack_damage_actor
- ret
-#undefine MOVE_MADE
-
- ; loads attack runtime ptr and clears values
- ; inputs
- ; de: actor
- ; returns:
- ; hl: act_rt_action_dat1
- ; preserves: af
-unit_cpu_load_and_clear_attack_rt_dat:
- ; hl = rt action dat 1
- ld hl, act_rt_action_dat1
- add hl, de
-
- push af
- inc hl ; rt action dat 2
- ; clear attack frame timer
- xor a, a
- ld [hl], a
- dec hl ; back to dat 1
- pop af
- ret
-
- ; performs an attack
- ; in the direction of the player
- ; checks if player is on tile next to current unit
- ; inputs:
- ; de: actors
- ; returns:
- ; a: 1 attack performed
- ; a: 0 no attack
-unit_cpu_attack_player:
- ; first check if x == x player
- ld hl, act_pos_x
- add hl, de
- ld a, [hl]
- ld b, a ; b = act x
-
- ld hl, player_unit+act_pos_x
- ld a, [hl]
-
- ; they need to be equal to be in range
- cp a, b
- jr nz, @not_in_y_range REL
-
- ; now check y position distance
- ld hl, act_pos_y
- add hl, de
-
- ld a, [hl] ; a = current unit y
- ld b, a ; move to b
-
- ld hl, player_unit+act_pos_y
- ld a, [hl] ; a = player y
-
- call unit_cpu_load_and_clear_attack_rt_dat
-
-
- ; check y distance
- call distance
- cp a, 1
- jr nz, @not_in_y_range REL
- ld a, c ; find out which direction
- cp a, DISTANCE_AGTB
- ; jump up or down
- jp nz, @attack_up
- jp @attack_down
-
-@not_in_y_range:
-
- ; check x distance
- ; first check if y == y player
- ld hl, act_pos_y
- add hl, de
- ld a, [hl]
- ld b, a ; b = act y
-
- ld hl, player_unit+act_pos_y
- ld a, [hl]
-
- cp a, b
- jr nz, @not_in_x_range REL
-
- ; now check x position distance
- ld hl, act_pos_x
- add hl, de
- ld a, [hl] ; a = current unit x
- ld b, a ; move to b
-
- ld hl, player_unit+act_pos_x
- ld a, [hl] ; a = player_x
-
- call unit_cpu_load_and_clear_attack_rt_dat
-
- ; check x distance
- call distance
- cp a, 1
- jr nz, @not_in_x_range REL
- ld a, c ; find out which direction
- cp a, DISTANCE_AGTB
- ; jump left or right
- jp nz, @attack_left
- jp @attack_right
-@not_in_x_range:
-
- ld a, 0 ; no attack
- ret
-
-@attack_up:
- ; write direction values
- ld a, DIRUP
- ld [hl], a
- ld a, 1 ; attack
- ret
-
-@attack_down:
- ld a, DIRDOWN
- ld [hl], a
- ld a, 1 ; attack
- ret
-
-@attack_left:
- ld a, DIRLEFT
- ld [hl], a
- ld a, 1 ; attack
- ret
-
-@attack_right:
- ld a, DIRRIGHT
- ld [hl], a
- ld a, 1 ; attack
- ret
-
-
- ; moves actor into a random direction
- ; inputs:
- ; de: actor
-unit_cpu_random_move:
- ; pick where to go
- call roll_d16
- and a, 3 ; 0-3
- ; 0 == left
- cp a, 0
- call z, unit_try_move_left
-
- ; 1 == right
- cp a, 1
- call z, unit_try_move_right
-
- ; 2 == up
- cp a, 2
- call z, unit_try_move_up
-
- ; 3 == down
- cp a, 3
- call z, unit_try_move_down
-
- ret
-
- ; attack state for demo units
- ; inputs:
- ; de: actor ptr
- ; returns:
- ; bc: next state
-unit_demo_1_cpu_update_attack:
- ldnull bc
- ret
+++ /dev/null
-unit_demo_guard_anim_table:
- anim_header 0, unit_demo_guard_anim_table
- anim_ent 0, 0, 0x88, 0
- anim_ent 0, 8, 0x8A, 0
- anim_ent 0, 0, 0x00, 0
-
-unit_demo_guard_attack_up:
- anim_header ATTACK_ANIM_LEN, unit_demo_guard_anim_table
- anim_ent 0, 0, 0x88, 0
- anim_ent 0, 8, 0x8A, 0
- anim_ent -12, 0, ACTION_ATTACK_SPRITE1, 0
-
-unit_demo_guard_attack_down:
- anim_header ATTACK_ANIM_LEN, unit_demo_guard_anim_table
- anim_ent 0, 0, 0x88, 0
- anim_ent 0, 8, 0x8A, 0
- anim_ent 12, 0, ACTION_ATTACK_SPRITE1, 0
-
-unit_demo_guard_attack_left:
- anim_header ATTACK_ANIM_LEN, unit_demo_guard_anim_table
- anim_ent 0, 0, 0x88, 0
- anim_ent 0, 8, 0x8A, 0
- anim_ent 0, -12, ACTION_ATTACK_SPRITE1, 0
-
-
-unit_demo_guard_attack_right:
- anim_header ATTACK_ANIM_LEN, unit_demo_guard_anim_table
- anim_ent 0, 0, 0x88, 0
- anim_ent 0, 8, 0x8A, 0
- anim_ent 0, 12, ACTION_ATTACK_SPRITE1, 0
-
-unit_demo_dog_anim_table:
- anim_header 0, unit_demo_dog_anim_table
- anim_ent 0, 0, 0x90, 0
- anim_ent 0, 8, 0x92, 0
- anim_ent 0, 0, 0x00, 0
-
-unit_demo_dog_attack_up:
- anim_header ATTACK_ANIM_LEN, unit_demo_dog_anim_table
- anim_ent 0, 0, 0x90, 0
- anim_ent 0, 8, 0x92, 0
- anim_ent -12, 0, ACTION_ATTACK_SPRITE1, 0
-
-unit_demo_dog_attack_down:
- anim_header ATTACK_ANIM_LEN, unit_demo_dog_anim_table
- anim_ent 0, 0, 0x90, 0
- anim_ent 0, 8, 0x92, 0
- anim_ent 12, 0, ACTION_ATTACK_SPRITE1, 0
-
-unit_demo_dog_attack_left:
- anim_header ATTACK_ANIM_LEN, unit_demo_dog_anim_table
- anim_ent 0, 0, 0x90, 0
- anim_ent 0, 8, 0x92, 0
- anim_ent 0, -12, ACTION_ATTACK_SPRITE1, 0
-
-
-unit_demo_dog_attack_right:
- anim_header ATTACK_ANIM_LEN, unit_demo_dog_anim_table
- anim_ent 0, 0, 0x90, 0
- anim_ent 0, 8, 0x92, 0
- anim_ent 0, 12, ACTION_ATTACK_SPRITE1, 0
-
-unit_demo_hazmat_anim_table:
- anim_header 0, unit_demo_hazmat_anim_table
- anim_ent 0, 0, 0x94, 0
- anim_ent 0, 8, 0x96, 0
- anim_ent 0, 0, 0x00, 0
-
-unit_demo_hazmat_attack_up:
- anim_header ATTACK_ANIM_LEN, unit_demo_hazmat_anim_table
- anim_ent 0, 0, 0x94, 0
- anim_ent 0, 8, 0x96, 0
- anim_ent -12, 0, ACTION_ATTACK_SPRITE1, 0
-
-unit_demo_hazmat_attack_down:
- anim_header ATTACK_ANIM_LEN, unit_demo_hazmat_anim_table
- anim_ent 0, 0, 0x94, 0
- anim_ent 0, 8, 0x96, 0
- anim_ent 12, 0, ACTION_ATTACK_SPRITE1, 0
-
-unit_demo_hazmat_attack_left:
- anim_header ATTACK_ANIM_LEN, unit_demo_hazmat_anim_table
- anim_ent 0, 0, 0x94, 0
- anim_ent 0, 8, 0x96, 0
- anim_ent 0, -12, ACTION_ATTACK_SPRITE1, 0
-
-unit_demo_hazmat_attack_right:
- anim_header ATTACK_ANIM_LEN, unit_demo_hazmat_anim_table
- anim_ent 0, 0, 0x94, 0
- anim_ent 0, 8, 0x96, 0
- anim_ent 0, 12, ACTION_ATTACK_SPRITE1, 0
-
-unit_demo_1_init:
- ldnull bc
- ret
-
- ; cpu controllerd unit update
-unit_demo_1_cpu_update:
- push de
- call unit_handle_cpu_inputs
- pop de
-
- ret
-
-unit_demo_1_cpu_update_idle:
- ldnull bc
- ret
-
-unit_demo_guard:
- st_def 0x00, unit_demo_1_init, st_unit_demo_1_cpu_update
- act_def ACT_T_GUARD, 0, 9, 9, 0
- act_stat_def1 1, 3, 1, 1
- act_stat_def2 1, 1, 32, 1
- act_st_def st_unit_demo_1_cpu_update, st_unit_idle
- act_def_meta unit_draw, unit_demo_guard_anim_table
-
-unit_demo_dog:
- st_def 0x00, unit_demo_1_init, st_unit_demo_1_cpu_update
- act_def ACT_T_DOG, 0, 9, 9, 0
- act_stat_def1 1, 2, 1, 1
- act_stat_def2 1, 1, 32, 1
- act_st_def st_unit_demo_1_cpu_update, st_unit_idle
- act_def_meta unit_draw, unit_demo_dog_anim_table
-
-
-unit_demo_hazmat:
- st_def 0x00, unit_demo_1_init, st_unit_demo_1_cpu_update
- act_def ACT_T_HAZMAT, 0, 9, 9, 0
- act_stat_def1 1, 1, 1, 1
- act_stat_def2 1, 1, 32, 1
- act_st_def st_unit_demo_1_cpu_update, st_unit_idle
- act_def_meta unit_draw, unit_demo_hazmat_anim_table
-
-
-st_unit_demo_1_cpu_update:
- st_def 0x00, unit_demo_1_cpu_update, st_unit_demo_1_cpu_update
-
-st_unit_demo_1_cpu_update_idle:
- st_def 0x00, unit_demo_1_cpu_update_idle, st_unit_demo_1_cpu_update_idle
-
update_game_over:
- ldnull bc
ret
update_game:
; tick rng every frame
call rand
- ; clear turn taken flag
- call unit_clear_player_turn_taken
-
; clear oam
call shadow_oam_clear
-
- ; update map state
- ld de, map_st
- call st_update
-
- ld hl, p0_units
- call units_update
-
- ; play obj animation
- ld de, objanim
- call st_update
-
- ld a, [player_map_cursor]
- ld [player_map_cursor_prev], a
-
- ldnull bc
- ret
-
-update_pause:
- ldnull bc
+
ret
; called after vblank
ld [frame_count], a
; reset objects
- call reset_unit_obj
-
- ld de, game_mode
- jp st_update
-
- ; sets up a new game
- ; loads default player
- ; fades out the screen
- ; loads default map
-new_game_init:
- call video_fade_out
-
- call shadow_oam_clear
-
- call ui_init
-
- call unit_load_default_player
- call actions_new_game_init
-
- ; init initial map
+ call reset_oam_obj
+
+ ; load current sate routine
+ ld a, [game_state]
+ ld l, a
+ ld a, [game_state+1]
+ ld h, a
+ jp hl
- call mapgen_init
-
- call game_init
-
- ld a, BGP
- ld [shadow_bpg], a
- call video_fade_in
ret
-
- ; geric game init call
- ; sets up window
- ; inits UI
-game_init:
- ; set up UI
- ld a, WINDOW_Y
- ld [RWY], a
- ld a, WINDOW_X
- ld [RWX], a
-
- ; set up palettes for
- ; gameplay
- ld a, BGP
- ld [RBGP], a
- ld [shadow_bpg], a
-
- ld a, 0b11100100
- ld [ROBP0], a
- ld [shadow_robp0], a
-
- ld a, 0b11011000
- ld [ROBP1], a
- ld [shadow_robp1], a
-
- ldnull bc
- ret
-
-
-st_init_new_game:
- st_def 0x00, new_game_init, st_update_game
-
-st_update_game:
- st_def 0x00, update_game, st_update_game
-st_update_pause:
- st_def 0x00, update_pause, st_update_pause
-st_update_game_over:
- st_def 0x00, update_game_over, st_update_game_over
-
-st_update_action_menu:
- st_def 0x00, update_action_menu, st_update_action_menu
-
-st_update_debug_menu:
- st_def 0x00, update_debug_menu, st_update_debug_menu
or a, LCDCF_OBJON
ld [RLCD], a
- ; check ui update
- call redraw_vblank
-
; dma previous frame's oam
call OAMDMAFN
; get inputs
call poll_inputs
- call video_swap_tile_bank_player_indoors
-
ld a, 1
ld [frame_ready], a
pop_all
ret
- ; swaps tilebank if the player is currently
- ; inside a room
- ; sets LCDC_TILE_BANK if player is inside
- ; unsets it otherwise
-video_swap_tile_bank_player_indoors:
- ld a, [player_rt_special_flags]
- and a, CF_COVERED
- jr nz, @not_covered REL
-
- ld a, [RLCD]
- ; set bit
- or a, LCDCF_TILE_BANK
- ld [RLCD], a
-
- ret
-@not_covered:
- ld a, [RLCD]
- ; unset bit
- and a, (~LCDCF_TILE_BANK) & 0xFF
- ld [RLCD], a
-
- ret
-
; swaps the current tilebank by setting/unsetting
; LCDC_TILE_BANK
video_swap_tile_bank:
#undefine video_fade_set_bgp
-#macro redraw_vblank_write
- ld a, [de]
- inc de
- ld [hl+], a
-#endmacro
- ; redraws a BG step in vblank
-redraw_vblank:
- ld a, [redraw_steps]
- ; no more steps we bail
- cp a, 0
- ret z
-
- ; steps--
- dec a
- ld [redraw_steps], a
-
- ; load bg ptr
- ld a, [redraw_bg]
- ld h, a
- ld a, [redraw_bg+1]
- ld l, a
-
- ; load source address
- ld a, [redraw_shadow]
- ld d, a
- ld a, [redraw_shadow+1]
- ld e, a
-
- ; write data
- ; in an unrolled loop
- redraw_vblank_write
- redraw_vblank_write
- redraw_vblank_write
- redraw_vblank_write
-
- ; lastly store current ptr state again
-
-
- ld a, d
- ld [redraw_shadow], a
- ld a, e
- ld [redraw_shadow+1], a
-
- ld a, h
- ld [redraw_bg], a
- ld a, l
- ld [redraw_bg+1], a
-
- ret
-#undefine redraw_vblank_write
-
-
; loads tilesets
; inputs:
shadow_oam: .adv OBJSMAX * oamsize
shadow_oam_end:
- ; temporary variables
- ; that can be used by any routine
- ; as storage
-scratch: .adv 16
-
frame_ready: .adv 1
frame_count: .adv 1
- ; current sprite
-unit_sprite: .adv 1
+current_oam_obj: .adv 1
; current frame's inputs
curr_inputs: .adv 1
; previous frame's inputs
prev_inputs: .adv 1
-
-game_mode: .adv st_size
; used by video fade out and fade in
shadow_bpg: .adv 1
; shadow version of IE
shadow_ie: .adv 1
+
+ ; game state routine ptr
+game_state: .adv 2
; self modifying code
; the vblank interrupt jumps here
; if set to NULL do not read from this address
demo_inputs: .adv 2
- ; menu cursor can be used by any in-game menu
-menu_cursor_index: .adv 1
-
-draw_flags: .adv 1
-gameplay_flags: .adv 1
-
- ; special flags that are set by the player unit
-player_rt_special_flags: .adv 1
-
- ; shadow UI is a buffer for drawing the UI
- ; this UI is then re-drawn on request in vblank
-shadow_ui: .adv UI_TILE_WIDTH * UI_TILE_HEIGHT
-
- ; shadow bg
- ; 4 rows of tiles that can be updated
- ; the same way shadow_ui can be redrawn
- ; draw new tiles here
- ; and queue up a redraw for the desired amount of rows
- ; at the desired location
-shadow_bg: .adv BG_WIDTH * BG_SHADOW_HEIGHT
-
-; redraw BG address
-redraw_bg: .adv 2
-; redraw shadow address
-redraw_shadow: .adv 2
-; remaining redraw steps
-redraw_steps: .adv 1
-
-action_menu_cursor: .adv 1
-debug_menu_cursor: .adv 1
-
- ; simple menu delay timer
-select_menu_delay: .adv 1
-
; dummy oam
; same memory as empty_unit
empty_oam: .adv oamsize
- ; > 0 if an actor has an ongoing attack
- ; used to delay other actors during the animation
-gpf_attack_ongoing: .adv 1
-
- ; mapgen flags
-mapgen_flags: .adv 1
-
-
- ; can be used for custom state transtions
- ; simple write state info to this location
- ; and return st_custom
-st_custom: .adv st_size
- ; it is common for delay to active to have a custom
- ; timer to simulate movement speed
- ; this is a valid delay state and should only be written to
- ; to change its timer
-st_unit_delay_to_active: .adv st_size
; scroll location
scroll_y: .adv 1
scroll_x: .adv 1
-
- ; +/-1 for each time the cursor moves
- ; allows us to move scroll when needed
-scroll_move_y: .adv 1
-scroll_move_x: .adv 1
- ; state for object animation
-objanim: .adv obja_size
-
- ; game state
- ; this region holds the entire game state
- ; everything thats needed for a savme game should be
- ; contained here
-state:
; 16 bit srand seed
; seed must never be 0
srand: .adv 2
- ; game speed variable
- ; this controls how fast the
- ; game runs
-game_speed: .adv 1
-
- ; last d16 result
-d16: .adv 1
-
-
- ; the current floor
-floor: .adv 1
-
-
-
- ; player speciifc data
-
- ; player inventory data
-player_inventory:
- ; TODO: add data here
-
- ; player equipment
- ; pointers to items
- ; stores all items equiped
- ; for player actors there are 6 eqipment slots
- ; for all other actors there is no equipment
-player_equipment:
-player_eq_head: .adv 2
-player_eq_body: .adv 2
-player_eq_hand1: .adv 2
-player_eq_hand2: .adv 2
-player_eq_ring: .adv 2
-player_eq_amulet: .adv 2
; units
; player_unit (unit 0) is reserved
player_unit: .adv 0
-p0_units: .adv act_size * UNITS_MAX
-
- ;
- ; floor data
- ;
-
- ; cursor into the floor's map tables (e.g. seeds)
- ; go up: dec by FLOOR_W
- ; go down: inc by FLOOR_W
- ; go left: dec
- ; go right: inc
-player_map_cursor: .adv 1
- ; the previous frame's map cursor
-player_map_cursor_prev: .adv 1
-
- ; one byte per map
- ; indicating where doors should be placed
- ; DIRUP, DIRDOWN, DIRLEFT, DIRRIGHT bits
- ; this links all maps in a floor
-map_doors_location: .adv FLOOR_MAP_COUNT
-
- ; list of seeds used
- ; for the current maps
- ; fill using mapgen_seed
- ; the seeds will be accessed via the map's
- ; seed index
-map_seeds: .adv FLOOR_MAP_COUNT * 2
+actors: .adv act_size * ACTS_MAX
- ; map tiles and collision data
-map: .adv c_size * MAP_SIZE
-map_end:
-
- ; mape state machine
-map_st: .adv st_size
- ; ptr to the last map header used
-map_header: .adv 2
+map_current_page: .adv 1
- ; actor savegame data;
- ; store actor data here on map load
- ; and re-load on map restore
- ; if pos y and pos x are both 0xFF do not restore
-act_sg: .adv act_sg_size * UNITS_MAX * FLOOR_MAP_COUNT
-act_sg_end:
-
-; buttton-assigned actions
-action_btna: .adv action_size
-action_btnb: .adv action_size
-
state_end: