; Phantom Star ; by ; Joe Pemberton ; ; This source is public domain. Feel free to modify it or use it however you ; like, but please credit me. ; process_level: ld ix,(leveloffset) process_level_loop: ld a,(gameover) or a ret nz ;return if the game is over ld hl,levelend ;level end flag ld a,(hl) ;if the level is still ending or a ;wait for it jr z,process_level_noend ; dec (hl) ; cp 10 ret nc ;decrement the timer and return process_level_noend: ld bc,(syncmax-1) ;b = syncmax ld hl,synccnt ld a,(hl) inc (hl) sub b jr c,process_level_nosyncreset ld (hl),0 ;reset the synccnt process_level_nosyncreset: ld a,(syncflag) or a jr z,process_level_nosync ld a,(synccnt) ;a=cnt or a ret nz ;we're not sync'ed yet.. ld (syncflag),a ;now we are!! ret process_level_nosync: ld a,(timercntflag) or a jr z,process_level_cont ld hl,(timercnt) ld a,h or l jr z,process_level_reset_timer dec hl ld (timercnt),hl ret process_level_reset_timer: ld (timercntflag),a process_level_cont: ld a,(ewaitflag) or a jr z,process_level_cont2 ld a,(ewait) ld hl,numactualenemies cp (hl) ;check to see if we've met our goal ret c ;if there are still too many enemies, return xor a ; ld (ewaitflag),a ;wait no longer! process_level_cont2: ld de,(levelpointer) add ix,de ld l,(ix) ld h,0 add hl,hl ld de,level_jump_table add hl,de ld a,(hl) inc hl ld h,(hl) ld l,a ;hl = address ld bc,process_level_ret ;set this up for all ret's push bc ; ld bc,(levelpointer) ;for routines that need to know their origin jp (hl) ;'call' the routine process_level_ret: add ix,de ;de=return push ix pop hl ;hl = ix ld de,(levelpointer) ;de = levelpointer or a ;clear carry sbc hl,de ;hl = ix - levelpointer push hl pop ix ;ix = ix - levelpointer ld (leveloffset),ix jp process_level_loop level_var: level: .db 0 levelstring: .db 0,0,0,0 levelend: .db 0 gameover: .db 0 timercntflag: .db 0 timercnt: .dw 0 syncflag: .db 0 synccnt: .db 0 syncmax: .db 0 ewaitflag: .db 0 ewait: .db 0 swaitflag: .db 0 swait: .db 0 level_vars: lvar1: .db 0 lvar2: .db 0 lvar3: .db 0 lvar4: .db 0 lvar5: .db 0 lvar6: .db 0 lvar7: .db 0 lvar8: .db 0 level_var_end: level_jump_table: .dw _LE_NOTHING .dw _LE_SET_HEALTH .dw _LE_SET_SHOT_TYPE .dw _LE_SET_SHOT_TYPE_CUSTOM .dw _LE_SET_SHOT_RATE .dw _LE_SET_START_PATH .dw _LE_SET_START_PATH_C .dw _LE_SET_START_PATH_TIMER .dw _LE_SET_PATH .dw _LE_SET_PATH_CUSTOM .dw _LE_SET_PATH_TIMER .dw _LE_SET_SPRITE .dw _LE_SET_SPRITE_CUSTOM .dw _LE_SET_SPRITE_CNT .dw _LE_SET_SPRITE_CNT_VAR .dw _LE_SET_HEIGHT .dw _LE_SET_FLAG .dw _LE_INSTALL_ONE .dw _LE_INSTALL_ONE_VAR .dw _LE_INSTALL_ROW .dw _LG_SET_TIMER .dw _LG_WAIT_NUMENEMY .dw _LG_WAIT_NUMSHOTS .dw _L_END .dw _L_GAMEOVER .dw _LS_SET_VAR .dw _LS_VAR_SET_VAR .dw _LS_VAR_ADD .dw _LS_VAR_ADD_VAR .dw _LS_VAR_NEQ_GOTO .dw _LS_VAR_NEQ_VAR_GOTO .dw _LS_VAR_EQ_GOTO .dw _LS_VAR_EQ_VAR_GOTO .dw _LS_GOTO .dw _LS_SET_SYNC .dw _LS_SYNC .dw _LS_GET_NUMENEMY .dw _LS_GET_NUMBOSS .dw _LS_GET_SHIPX .dw _LS_GET_SHIPY .dw _LS_RAND .dw _LS_VAR_LT_GOTO .dw _LS_VAR_GT_GOTO _LE_NOTHING: ld de,1 ret ; byte _LE_SET_HEALTH: ld a,(ix+1) ;a = health ld (tempenemy+E_OFFSET_HEALTH),a ;set the health ld de,2 ;skip 2 bytes ahead ret ; byte _LE_SET_SHOT_TYPE: ld l,(ix+1) ld h,0 add hl,hl ld de,enemy_shotAI_table add hl,de ;hl->pointer ld e,(hl) inc hl ld d,(hl) ld (tempenemy+E_OFFSET_SHOTROUTINEPTR),de ld de,2 ret ; word _LE_SET_SHOT_TYPE_CUSTOM: ld l,(ix+1) ld h,(ix+2) add hl,bc ld (tempenemy+E_OFFSET_SHOTROUTINEPTR),hl ld de,3 ret ; byte (default is 30) _LE_SET_SHOT_RATE: ld a,(ix+1) ld (tempenemy+E_OFFSET_SHOTTIMERMAX),a ld de,2 ret ; byte, byte _LE_SET_START_PATH: ld a,(ix+2) ld (tempenemy+E_OFFSET_STARTPATHCNT),a ld l,(ix+1) ld h,0 add hl,hl ld de,enemy_startpath_table add hl,de ld e,(hl) inc hl ld d,(hl) ld (tempenemy+E_OFFSET_STARTPATHPTR),de ld de,3 ret ; word, byte _LE_SET_START_PATH_C: ld a,(ix+3) ld (tempenemy+E_OFFSET_STARTPATHCNT),a ld l,(ix+1) ld h,(ix+2) add hl,bc ld (tempenemy+E_OFFSET_STARTPATHPTR),hl ld de,4 ret ; byte _LE_SET_START_PATH_TIMER: ld a,(ix+1) ld (tempenemy+E_OFFSET_STARTPATHCNT),a ld de,2 ret ; byte _LE_SET_PATH: ld l,(ix+1) ld h,0 add hl,hl ;hl = pathID * 2 ld de,enemy_path_table add hl,de ;hl -> path pointer ld e,(hl) ; inc hl ; ld d,(hl) ;de -> path data ld a,(de) ;a = pathcntmax ld (tempenemy+E_OFFSET_PATHCNTMAX),a xor a ld (tempenemy+E_OFFSET_PATHCNT),a inc de ld (tempenemy+E_OFFSET_PATHPTR),de ld de,2 ret ; word _LE_SET_PATH_CUSTOM: ld l,(ix+1) ld h,(ix+2) add hl,bc ld a,(hl) ;a = pathcntmax ld (tempenemy+E_OFFSET_PATHCNTMAX),a xor a ld (tempenemy+E_OFFSET_PATHCNT),a inc hl ld (tempenemy+E_OFFSET_PATHPTR),hl ld de,3 ret ; byte pathcnt _LE_SET_PATH_TIMER: ld a,(ix+1) ld (tempenemy+E_OFFSET_PATHCNT),a ld de,2 ret ; byte _LE_SET_SPRITE: ld l,(ix+1) ld h,0 add hl,hl add hl,hl add hl,hl ;hl=hl*8 ld de,enemysprtable add hl,de ld (tempenemy+E_OFFSET_SPRITEPTR),hl ld de,2 ret ; word _LE_SET_SPRITE_CUSTOM: ld l,(ix+1) ld h,(ix+2) push bc ;save the offset add hl,bc ;fix the offset and make it into an address ld d,h ld e,l ;de->table ld bc,8 add hl,bc ;hl->table+8 ex de,hl ;de->table+8, hl->table ldir ;copy 8 bytes.. hl->table+8 pop bc ;bc = offset ld (tempenemy+E_OFFSET_SPRITEPTR),hl ld a,4 ;a = counter _LE_SET_SPR_C_LOOP: push af push hl ; ld a,(hl) ;a = LSB inc hl ; ld h,(hl) ;h = MSB ld l,a ;hl = offset add hl,bc ;hl = fixed pointer ex de,hl ;de = fixed pointer pop hl ;hl->LSB ld (hl),e ;save fixed LSB inc hl ; ld (hl),d ;save fixed MSB inc hl ; pop af dec a jr nz,_LE_SET_SPR_C_LOOP ld de,3 ret ; byte _LE_SET_SPRITE_CNT: ld a,(ix+1) ld (tempenemy+E_OFFSET_SPRITECNT),a ld de,2 ret ; byte _LE_SET_SPRITE_CNT_VAR: ld e,(ix+1) ld d,0 ld hl,level_vars add hl,de ld a,(hl) ld (tempenemy+E_OFFSET_SPRITECNT),a ld de,2 ret ; byte (default is 8) _LE_SET_HEIGHT: ld a,(ix+1) ld (tempenemy+E_OFFSET_HEIGHT),a ld de,2 ret ; byte (default is %00000000) _LE_SET_FLAG: ld a,(ix+1) ld (tempenemy+E_OFFSET_FLAG),a ld de,2 ret ; byte, byte y, x _LE_INSTALL_ONE: ld h,(ix+1) ld l,(ix+2) ld (tempenemy+E_OFFSET_X),hl ld bc,(tempenemy+E_OFFSET_SHOTTIMERMAX-1) ;b = shot timer max call myRandom ld (tempenemy+E_OFFSET_SHOTTIMER),a ld de,tempenemy call putenemy ld de,3 ret ;byte, byte _LE_INSTALL_ONE_VAR: ld e,(ix+1) ld d,0 ld hl,level_vars add hl,de ld a,(hl) ld (tempenemy+E_OFFSET_Y),a ld e,(ix+2) ld hl,level_vars add hl,de ld a,(hl) ld (tempenemy+E_OFFSET_X),a ld bc,(tempenemy+E_OFFSET_SHOTTIMERMAX-1) ;b = shot timer max call myRandom ld (tempenemy+E_OFFSET_SHOTTIMER),a ld de,tempenemy call putenemy ld de,3 ret ;flag(1), health(1), startpathcnt(1), startpathptr(2), pathcnt(1), pathcntmax(1), pathptr(2) ;x(1), y(1), height(1), spritecnt(1), spriteptr(2), shottimermax(1), shottimer(1), shotroutineptr(2) ; byte, byte, byte, byte, byte, byte ; (number, y, x, yinc, xinc, startpathtimer inc) _LE_INSTALL_ROW: ld a,(ix+1) or a ret z ld b,a ;b = counter ld h,(ix+2) ;h = y ld l,(ix+3) ;l = x ld (tempenemy+E_OFFSET_X),hl ;set x,y ld a,(tempenemy+E_OFFSET_STARTPATHCNT) push af _LE_INSTALL_ROW_loop: ld a,(tempenemy+E_OFFSET_SHOTTIMERMAX) ;a = shot timer max or a ;if the shot timer max is 0 jr z,_LE_INSTALL_ROW_skip ;shottimer is 0 push bc ;save the counter ld b,a ; call myRandom ;0 <= a < shot timer max pop bc ;restore the counter _LE_INSTALL_ROW_skip: ld (tempenemy+E_OFFSET_SHOTTIMER),a ;set the shot timer ld de,tempenemy call putenemy ld hl,tempenemy+E_OFFSET_Y ; ld a,(ix+4) ;a = yinc add a,(hl) ;a = new y ld (hl),a ;update the y coord dec hl ; ld a,(ix+5) ;a = xinc add a,(hl) ;a = new x ld (hl),a ;update the x coord ld hl,tempenemy+E_OFFSET_STARTPATHCNT ld a,(ix+6) add a,(hl) ld (hl),a djnz _LE_INSTALL_ROW_loop ld de,7 pop af ld (tempenemy+E_OFFSET_STARTPATHCNT),a ret ; Wait for N frames before continuing ; word _LG_SET_TIMER: ld l,(ix+1) ld h,(ix+2) ld (timercnt),hl ld a,1 ld (timercntflag),a ld de,3 ret ; Wait until the number of enemies is equal to or less than NUMENEMY ; byte _LG_WAIT_NUMENEMY: ld a,(ix+1) ld (ewait),a ld a,1 ld (ewaitflag),a ld de,2 ret ; byte _LG_WAIT_NUMSHOTS: ld a,(ix+1) ld (swait),a ld a,1 ld (swaitflag),a ld de,2 ret _L_END: ld a,20 ld (levelend),a ld hl,level inc (hl) ld c,(hl) call bintobcd ld hl,bcdstring ld de,levelstring ld bc,4 ldir ld de,1 ret _L_GAMEOVER: ld a,GAME_OVER_LENGTH ld (gameover),a ld de,1 ret ; byte, byte var, value _LS_SET_VAR: ld e,(ix+1) call getlvar ld a,(ix+2) ld (hl),a ld de,3 ret ; byte, byte var dest, var src _LS_VAR_SET_VAR: ld e,(ix+1) ld b,0 call getlvar ex de,hl ld c,(ix+2) ld hl,level_vars add hl,bc ld a,(hl) ld (de),a ld de,3 ret ; byte, byte var, value _LS_VAR_ADD: ld e,(ix+1) call getlvar ld a,(ix+2) add a,(hl) ld (hl),a ld de,3 ret ; byte, byte var dest, var src _LS_VAR_ADD_VAR: ld e,(ix+2) ld b,0 call getlvar ex de,hl ld c,(ix+1) ld hl,level_vars add hl,bc ld a,(de) add a,(hl) ld (hl),a ld de,3 ret ; byte, byte, word var, value, address _LS_VAR_NEQ_GOTO: ld e,(ix+1) call getlvar ld de,5 ld a,(ix+2) cp (hl) ret z jr goto_fin ; byte, byte, word var, var, address _LS_VAR_NEQ_VAR_GOTO: ld e,(ix+1) call getlvar ld a,(hl) ld e,(ix+2) ld hl,level_vars add hl,de ld de,5 cp (hl) ret z ;return if they're the same goto_fin: ld e,(ix+3) ld d,(ix+4) ld ix,0 add ix,de add ix,bc ld de,0 ret _LS_VAR_LT_GOTO: ld e,(ix+1) call getlvar ; hl->var ld de,5 ld a,(hl) ;a = var value cp (ix+2) ret nc jr goto_fin _LS_VAR_GT_GOTO: ld e,(ix+1) call getlvar ; hl->var ld de,5 ld a,(ix+2) ;a = value cp (hl) ret nc jr goto_fin ; byte, byte, word var, value, address _LS_VAR_EQ_GOTO: ld e,(ix+1) call getlvar ld de,5 ld a,(ix+2) cp (hl) ret nz jr goto_fin ; byte, byte, word var, var, address _LS_VAR_EQ_VAR_GOTO: ld e,(ix+1) call getlvar ld a,(hl) ld e,(ix+2) call getlvar ld de,5 cp (hl) ret nz ;return if they're different jr goto_fin ; word address _LS_GOTO: ld e,(ix+1) ld d,(ix+2) ld ix,0 add ix,de add ix,bc ld de,0 ret ; byte _LS_SET_SYNC: ld a,(ix+1) ;a = syncmax ld (syncmax),a dec a ld (synccnt),a ld de,2 ret _LS_SYNC: ld a,1 ld (syncflag),a ld de,1 ret ; byte _LS_GET_NUMENEMY: ld a,(numactualenemies) jr write_to_hl ; byte _LS_GET_NUMBOSS: ld hl,enemytable ld a,(numenemies) or a jr z,_LS_GET_NUMBOSS_SET ld b,a ;b = times to loop ld de,ENEMY_SIZE xor a _LS_GET_NUMBOSSL: bit 6,(hl) jr z,_LS_GET_NUMBOSS_NO inc a _LS_GET_NUMBOSS_NO: add hl,de djnz _LS_GET_NUMBOSSL _LS_GET_NUMBOSS_SET: write_to_hl: ld e,(ix+1) call getlvar ld (hl),a ld de,2 ret ; byte _LS_GET_SHIPX: ld a,(shipx) jr write_to_hl ; byte _LS_GET_SHIPY: ld a,(shipy) jr write_to_hl ; byte, byte, byte (var, floor, range) _LS_RAND: ld b,(ix+3) call myRandom add a,(ix+2) ld e,(ix+1) call getlvar ld (hl),a ld de,4 ret ;e = var ID getlvar: ld d,0 ld hl,level_vars add hl,de ret ;flag(1), health(1), startpathcnt(1), startpathptr(2), pathcnt(1), pathcntmax(1), pathptr(2) ;x(1), y(1), height(1), spritecnt(1), spriteptr(2), shottimermax(1), shottimer(1), shotroutineptr(2) tempenemy: .ds ENEMY_SIZE ;============= sprite data ============== shipsprtable: .dw explosionspr3 .dw explosionspr2 .dw explosionspr1 .dw explosionspr0 starspr: ;sprite for the stars .db %10000000 keyvar: .db 0 ;this byte is here for faster math ;(can be written over) .db %10000000 .db %10000000 shipspr: .db 7 .db %01111100 .db %11100000 .db %11110000 .db %10111111 .db %11110000 .db %11100000 .db %01111100 friendspr: .db 5 .db %11000000 .db %11100000 .db %11111100 .db %11100000 .db %11000000