**************************************************************************** **************************************************************************** ** ** Phoenix (Game saving) ** ** Copyright 2004 by Patrick Davidson. This software may be freely ** modified and/or copied with no restrictions. There is no warranty. ** ** by Patrick Davidson (pad@calc.org, http://pad.calc.org/) ** ** Last updated September 14, 2004 ** **************************************************************************** **************************************************************************** ******************************************** SEARCH FOR GAME TO RESTORE * This routine searches for a saved game in memory. In order to avoid * using any additional memory, Phoenix games are saved by placing them on * the end of the stack. As long as no other program overwrites this data, * the saved game can be restored. This routine first searches for the * signature 'PhnX' indicating the presence of a saved game, and then * checks if the version matches, and finally tests the checksum to ensure * the data hasn't been corrupted, and then restores the game data after * verifying its integrity. ******** restore_game: lea (a7),a4 ; Search for saved data loop_search: cmp.l #'PhnX',(a4) beq.s found_possible_saved_game loop_return: subq.w #2,a4 cmp.l #$120,a4 bgt.s loop_search bra Nothing_To_Restore ; Start a new game found_possible_saved_game: cmp.l #VERSION,4(a4) bne.s loop_return lea 8(a4),a3 ; Test checksum moveq #0,d0 move.w #(data_end-data_start)/2,d1 loop_checksum: add.w (a3)+,d0 dbra d1,loop_checksum tst.w d0 bne.s loop_return ******************************************** RESTORE SAVED GAME * Restore saved game. Since the full stack might extend over the save * data, the data must be copied elsewhere before it is restored. This is * done by copying the data to the LCD memory (only for a brief moment) and * then allocating space on the stack and storing it in its normal location. * After that, absolute references are relocated, and the game system is set * up and the game is started. ******** found_saved_game: move.w #$700,d0 ; Disable all interrupts trap #1 subq.l #2,a3 ; Copy the data to LCD_MEM lea LCD_MEM,a2 move.w #((data_end-data_start)/2)-1,d1 loop_restore: move.w -(a3),(a2)+ dbra d1,loop_restore clr.l -(a3) ; Erase signature lea -offset(a7),a7 ; Allocate variables on stack lea (a7),a5 ; Set pointer to variables lea data_start(a5),a3 ; Copy the data back move.w #((data_end-data_start)/2)-1,d1 loop_restore2: move.w -(a2),(a3)+ dbra d1,loop_restore2 lea _main(pc),a0 ; Relocate absolute references move.l a0,d0 add.l d0,xy_pointer(a5) bsr Load_Player lea $600000,a6 ; Allow relative port addressing bclr #2,1(a6) ; Allow writes to low memory move.w #$d1,d0 ; Set Int5 frequency to 30Hz bsr Set_Speed bsr Initialize_Stuff ; Set up initial screen move.l #trigger,($74).w ; Load custom int5 handler bsr Status_Prepare ; Fix status display bra Pre_Main_Loop ; Resume the game ******************************************** SAVE THE GAME * Saves the game. This is essentially done by leaving the data on the * stack. However, it will be moved to the lowest address to decrease the * chances it will be overwritten. Also, a signature, version number, and * checksum are stored to help identify and verify the data. ******** save_game: tst.b Game_Started(a5) ; Cancel save game if it's a beq.s exit_s ; false reading on title screen move.w #$700,d0 ; Deactivate interrupts trap #1 lea _main(pc),a0 ; Delocate absolute references move.l a0,d0 sub.l d0,xy_pointer(a5) lea (a5),a0 ; A0 -> Saving position moveq #0,d0 ; D0 = checksum move.l #'PhnX',(a0)+ ; Store signature move.l #VERSION,(a0)+ move.w #((data_end-data_start)/2)-1,d1 lea data_start(a5),a1 save_loop: ; Copy and sum data add.w (a1),d0 move.w (a1)+,(a0)+ dbra d1,save_loop neg.w d0 ; Store checksum move.w d0,(a0)+ bra Game_Over exit_s: rts ******************************************** MAIN PROGRAM BEGINS HERE Nothing_To_Restore: