castleraider

changeset 323:e4cdff52b4a0

Moved some routines to the loader where they are copied down into working memory, ready to be used by the game itself. This frees up memory in the main game code and also makes them available for use in both the loader and the game. Ensured that temporary files are deleted as they are used or after the game has been built.
author David Boddie <david@boddie.org.uk>
date Sat Oct 04 20:48:08 2014 +0200
parents 6f53862eb4f7
children 5ecff9e25e1c
files build.py code.oph ending.oph loader.oph
diffstat 4 files changed, 203 insertions(+), 102 deletions(-) [+]
line diff
     1.1 --- a/build.py	Sat Oct 04 01:13:43 2014 +0200
     1.2 +++ b/build.py	Sat Oct 04 20:48:08 2014 +0200
     1.3 @@ -76,6 +76,16 @@
     1.4      
     1.5      return data_oph, text_length
     1.6  
     1.7 +def encode_data(bytes):
     1.8 +
     1.9 +    data = []
    1.10 +    i = 0
    1.11 +    while i < len(bytes):
    1.12 +    
    1.13 +        data.append(".byte " + ",".join(map(lambda x: "$%02x" % ord(x), bytes[i:i+24])))
    1.14 +        i += 24
    1.15 +    
    1.16 +    return "\n".join(data)
    1.17  
    1.18  tiles = map(lambda tile: makelevels.tile_ref[tile], makelevels.tile_order)
    1.19  
    1.20 @@ -89,6 +99,135 @@
    1.21  
    1.22  life_sprites = ["images/life1.png", "images/life2.png"]
    1.23  
    1.24 +title_data_oph_routines = [
    1.25 +("print_title_text", """
    1.26 +
    1.27 +    ldx #[%(in_game_title_text_length)i - 1]
    1.28 +    title_text_loop:
    1.29 +        lda $%(in_game_title_text_address)x,x
    1.30 +        jsr $ffee
    1.31 +        dex
    1.32 +        bpl title_text_loop
    1.33 +
    1.34 +    clc
    1.35 +    rts
    1.36 +"""),
    1.37 +("print_game_over_text", """
    1.38 +
    1.39 +    ldx #[%(in_game_game_over_text_length)i - 1]
    1.40 +    game_over_text_loop:
    1.41 +        lda $%(in_game_game_over_text_address)x,x
    1.42 +        jsr $ffee
    1.43 +        dex
    1.44 +        bpl game_over_text_loop
    1.45 +
    1.46 +    clc
    1.47 +    rts
    1.48 +""")]
    1.49 +
    1.50 +def encode_in_game_data(in_game_data_address):
    1.51 +
    1.52 +    # Encode the in-game title data.
    1.53 +    title_data_oph = ""
    1.54 +    
    1.55 +    title_rows = 0
    1.56 +    for line in open("title.txt").readlines():
    1.57 +    
    1.58 +        line = line.rstrip("\n")
    1.59 +        title_data_oph += ".byte "
    1.60 +        
    1.61 +        for i in range(0, 40, 4):
    1.62 +        
    1.63 +            byte = 0
    1.64 +            shift = 0
    1.65 +            for char in line[i:i + 4]:
    1.66 +                byte = byte | (".@#+".index(char) << shift)
    1.67 +                shift += 2
    1.68 +            
    1.69 +            title_data_oph += "$%02x" % byte
    1.70 +            if i < 36:
    1.71 +                title_data_oph += ", "
    1.72 +        
    1.73 +        title_data_oph += "\n"
    1.74 +        title_rows += 1
    1.75 +    
    1.76 +    title_data_oph += "\n"
    1.77 +    
    1.78 +    title_text = [(26, 31, 3, 6, 17, 3, "Retro Software"),
    1.79 +                      (31, 6, 8, "presents"),
    1.80 +                      (31, 2, 27, 17, 2, "Press ", 17, 3, "SPACE/FIRE"),
    1.81 +                      (31, 6, 29, 17, 2, "to play")]
    1.82 +    
    1.83 +    title_data, in_game_title_text_length = encode_text(title_text)
    1.84 +    title_data_oph += title_data
    1.85 +    title_data_oph += '\n'
    1.86 +    
    1.87 +    game_over_text = [(26, 31, 1, 16, 17, 3, "Your quest is over"),
    1.88 +                          (31, 4, 29, 17, 1, "Press  SPACE")]
    1.89 +    
    1.90 +    game_over_data, in_game_game_over_text_length = encode_text(game_over_text)
    1.91 +    title_data_oph += game_over_data
    1.92 +    title_data_oph += '\n'
    1.93 +    
    1.94 +    in_game_title_text_address = in_game_data_address + (title_rows * 10)
    1.95 +    in_game_game_over_text_address = in_game_title_text_address + in_game_title_text_length
    1.96 +    in_game_title_routines_address = in_game_game_over_text_address + in_game_game_over_text_length
    1.97 +    
    1.98 +    labels = (
    1.99 +        ".alias title_data_address              $%(title_data_address)x\n"
   1.100 +        ".alias title_rows                      %(title_rows)i\n"
   1.101 +        ".alias in_game_title_text_address      $%(in_game_title_text_address)x\n"
   1.102 +        ".alias in_game_title_text_length       %(in_game_title_text_length)i\n"
   1.103 +        ".alias in_game_game_over_text_address  $%(in_game_game_over_text_address)x\n"
   1.104 +        ".alias in_game_game_over_text_length   %(in_game_game_over_text_length)i\n"
   1.105 +        ".alias in_game_completion_address      $%(in_game_completion_address)x\n"
   1.106 +    )
   1.107 +    
   1.108 +    details = {
   1.109 +        "title_data_address": in_game_data_address,
   1.110 +        "title_rows": title_rows,
   1.111 +        "in_game_title_text_address": in_game_title_text_address,
   1.112 +        "in_game_title_text_length": in_game_title_text_length,
   1.113 +        "in_game_game_over_text_address": in_game_game_over_text_address,
   1.114 +        "in_game_game_over_text_length": in_game_game_over_text_length,
   1.115 +        }
   1.116 +    
   1.117 +    routine_address = in_game_title_routines_address
   1.118 +    for name, routine in title_data_oph_routines:
   1.119 +    
   1.120 +        routine = name + ":" + (routine % details)
   1.121 +        open("temp.oph", "w").write(routine)
   1.122 +        system("ophis temp.oph -o TEMP")
   1.123 +        
   1.124 +        # Include the routine in the title data file.
   1.125 +        title_data_oph += routine + "\n"
   1.126 +        
   1.127 +        # Add the run-time address to the constants.
   1.128 +        labels += ".alias " + name + "_address" + (" $%0x\n" % routine_address)
   1.129 +        details[name + "_address"] = routine_address
   1.130 +        
   1.131 +        # Update the routine address.
   1.132 +        routine_address += os.stat("TEMP")[stat.ST_SIZE]
   1.133 +        
   1.134 +        os.remove("temp.oph")
   1.135 +        os.remove("TEMP")
   1.136 +    
   1.137 +    # The completion code is stored after the title routines.
   1.138 +    details["in_game_completion_address"] = routine_address
   1.139 +    
   1.140 +    ending = open("ending.oph").read()
   1.141 +    ending = ending % {"in_game_completion_address": routine_address}
   1.142 +    open("temp.oph", "w").write(ending)
   1.143 +    
   1.144 +    system("ophis temp.oph -o TEMP")
   1.145 +    ending = open("TEMP").read()
   1.146 +    os.remove("temp.oph")
   1.147 +    os.remove("TEMP")
   1.148 +    title_data_oph += encode_data(ending)
   1.149 +    
   1.150 +    open("title-data-and-ending.oph", "w").write(title_data_oph)
   1.151 +    
   1.152 +    return labels, details
   1.153  
   1.154  if __name__ == "__main__":
   1.155  
   1.156 @@ -112,57 +251,6 @@
   1.157      else:
   1.158          level_file = sys.argv[4]
   1.159      
   1.160 -    # Encode the in-game title data.
   1.161 -    title_data_oph = "title_data:\n"
   1.162 -    
   1.163 -    title_rows = 0
   1.164 -    for line in open("title.txt").readlines():
   1.165 -    
   1.166 -        line = line.rstrip("\n")
   1.167 -        title_data_oph += ".byte "
   1.168 -        
   1.169 -        for i in range(0, 40, 4):
   1.170 -        
   1.171 -            byte = 0
   1.172 -            shift = 0
   1.173 -            for char in line[i:i + 4]:
   1.174 -                byte = byte | (".@#+".index(char) << shift)
   1.175 -                shift += 2
   1.176 -            
   1.177 -            title_data_oph += "$%02x" % byte
   1.178 -            if i < 36:
   1.179 -                title_data_oph += ", "
   1.180 -        
   1.181 -        title_data_oph += "\n"
   1.182 -        title_rows += 1
   1.183 -    
   1.184 -    title_data_oph += (
   1.185 -        "\n"
   1.186 -        "title_end:\n"
   1.187 -        ".alias title_length [title_end - title_data]\n"
   1.188 -        "\n"
   1.189 -        )
   1.190 -    
   1.191 -    title_text = [(26, 31, 3, 6, 17, 3, "Retro Software"),
   1.192 -                      (31, 6, 8, "presents"),
   1.193 -                      (31, 2, 27, 17, 2, "Press ", 17, 3, "SPACE/FIRE"),
   1.194 -                      (31, 6, 29, 17, 2, "to play")]
   1.195 -    
   1.196 -    title_data_oph += 'game_title_text:\n'
   1.197 -    title_data, in_game_title_text_length = encode_text(title_text)
   1.198 -    title_data_oph += title_data
   1.199 -    title_data_oph += 'game_title_text_end:\n'
   1.200 -    
   1.201 -    game_over_text = [(26, 31, 1, 16, 17, 3, "Your quest is over"),
   1.202 -                          (31, 4, 29, 17, 1, "Press  SPACE")]
   1.203 -    
   1.204 -    title_data_oph += 'game_over_text:\n'
   1.205 -    game_over_data, in_game_game_over_text_length = encode_text(game_over_text)
   1.206 -    title_data_oph += game_over_data
   1.207 -    title_data_oph += 'game_over_text_end:\n'
   1.208 -    
   1.209 -    open("title-data.oph", "w").write(title_data_oph)
   1.210 -    
   1.211      # Memory map
   1.212      memory_map = {
   1.213          "working area": 0xb00,
   1.214 @@ -238,11 +326,8 @@
   1.215      # data - this is done in the loader.
   1.216      title_data_address = initial_row_offsets + 0x10
   1.217      
   1.218 -    in_game_title_text_address = title_data_address + (title_rows * 10)
   1.219 -    in_game_game_over_text_address = in_game_title_text_address + in_game_title_text_length
   1.220 -    in_game_completion_address = in_game_game_over_text_address + in_game_game_over_text_length
   1.221 -    
   1.222 -    working_end = in_game_completion_address
   1.223 +    in_game_data_labels, in_game_data_details = encode_in_game_data(title_data_address)
   1.224 +    working_end = in_game_data_details["in_game_completion_address"]
   1.225      
   1.226      # Permanent data
   1.227      
   1.228 @@ -551,19 +636,7 @@
   1.229               monster_right_offset,
   1.230               monster_right_max_offset)
   1.231      
   1.232 -    constants_oph += (
   1.233 -        ".alias title_data_address              $%x\n"
   1.234 -        ".alias title_rows                      %i\n"
   1.235 -        ".alias in_game_title_text_address      $%x\n"
   1.236 -        ".alias in_game_title_text_length       %i\n"
   1.237 -        ".alias in_game_game_over_text_address  $%x\n"
   1.238 -        ".alias in_game_game_over_text_length   %i\n"
   1.239 -        ".alias in_game_total_text_length       %i\n"
   1.240 -        "\n"
   1.241 -        ) % (title_data_address, title_rows,
   1.242 -             in_game_title_text_address, in_game_title_text_length,
   1.243 -             in_game_game_over_text_address, in_game_game_over_text_length,
   1.244 -             in_game_title_text_length + in_game_game_over_text_length)
   1.245 +    constants_oph += (in_game_data_labels % in_game_data_details) + "\n"
   1.246      
   1.247      scenery_rows = 16
   1.248      extra_rows = 7
   1.249 @@ -620,6 +693,7 @@
   1.250      
   1.251      system("ophis code.oph -o CODE")
   1.252      code = open("CODE").read()
   1.253 +    os.remove("CODE")
   1.254      
   1.255      loader_start = 0x3500
   1.256      
   1.257 @@ -662,6 +736,7 @@
   1.258      
   1.259      system("ophis loader.oph -o LOADER")
   1.260      loader_code = open("LOADER").read() + markers + title_data
   1.261 +    os.remove("LOADER")
   1.262      
   1.263      bootloader_start = 0xe00
   1.264      bootloader_code = ("\r\x00\x0a\x0d*FX 229,1"
   1.265 @@ -683,14 +758,20 @@
   1.266      #    uncompressed = c.uncompress(compressed)
   1.267      #    print info[0], len(data), len(compressed), data == uncompressed
   1.268      
   1.269 -    loader_size = os.stat("LOADER")[stat.ST_SIZE]
   1.270 +    loader_size = len(loader_code)
   1.271      print
   1.272      print "%i bytes (%04x) of loader code" % (loader_size, loader_size)
   1.273      
   1.274 -    code_size = os.stat("CODE")[stat.ST_SIZE]
   1.275 +    code_size = len(code)
   1.276      print "%i bytes (%04x) of code" % (code_size, code_size)
   1.277      print
   1.278      
   1.279 +    # Calculate the amount of space used for the loader.
   1.280 +    
   1.281 +    loader_finish = loader_start + loader_size
   1.282 +    print "LOADER runs from %04x to %04x" % (loader_start, loader_finish)
   1.283 +    print
   1.284 +    
   1.285      # Calculate the amount of working space used.
   1.286      
   1.287      print "Working data area runs from 0b00 to %04x (%i bytes free)" % (working_end, 0xd00 - working_end)
   1.288 @@ -812,5 +893,12 @@
   1.289          print
   1.290          print "Written", out_file
   1.291      
   1.292 +    # Remove temporary files.
   1.293 +    os.remove("bank_routines.oph")
   1.294 +    os.remove("constants.oph")
   1.295 +    os.remove("loader-constants.oph")
   1.296 +    os.remove("screen.oph")
   1.297 +    os.remove("title-data-and-ending.oph")
   1.298 +    
   1.299      # Exit
   1.300      sys.exit()
     2.1 --- a/code.oph	Sat Oct 04 01:13:43 2014 +0200
     2.2 +++ b/code.oph	Sat Oct 04 20:48:08 2014 +0200
     2.3 @@ -30,12 +30,7 @@
     2.4      jsr show_bank2          ; Show bank 2 since this is where the output of OS
     2.5                              ; calls will appear.
     2.6  
     2.7 -    ldx #[in_game_title_text_length - 1]
     2.8 -    title_text_loop:
     2.9 -        lda in_game_title_text_address,x
    2.10 -        jsr $ffee
    2.11 -        dex
    2.12 -        bpl title_text_loop
    2.13 +    jsr print_title_text_address
    2.14  
    2.15      ; Wait for the SPACE key or fire button to be pressed.
    2.16      main_start_wait_loop:
    2.17 @@ -194,7 +189,7 @@
    2.18              cmp #finish_scroll_offset_high
    2.19              bne main_loop_check_monsters
    2.20  
    2.21 -            jmp game_completed
    2.22 +            jsr in_game_completion_address
    2.23  
    2.24          main_loop_check_monsters:
    2.25          jsr check_player_monsters
    2.26 @@ -250,12 +245,7 @@
    2.27      jsr show_bank2          ; Show bank 2 since this is where the output of OS
    2.28                              ; calls will appear.
    2.29  
    2.30 -    ldx #[in_game_game_over_text_length - 1]
    2.31 -    game_over_text_loop:
    2.32 -        lda in_game_game_over_text_address,x
    2.33 -        jsr $ffee
    2.34 -        dex
    2.35 -        bpl game_over_text_loop
    2.36 +    jsr print_game_over_text_address
    2.37  
    2.38      lda #157        ; (SPACE)
    2.39      jsr wait_for_key
    2.40 @@ -1099,14 +1089,6 @@
    2.41      sec
    2.42      rts
    2.43  
    2.44 -game_completed:
    2.45 -
    2.46 -    ; Do something to indicate the game has been completed.
    2.47 -    ; Check whether the player found the treasures.
    2.48 -
    2.49 -    clc
    2.50 -    rts
    2.51 -
    2.52  .include "screen.oph"
    2.53  .include "plotting.oph"
    2.54  .include "scrolling.oph"
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/ending.oph	Sat Oct 04 20:48:08 2014 +0200
     3.3 @@ -0,0 +1,28 @@
     3.4 +; Copyright (C) 2014 David Boddie <david@boddie.org.uk>
     3.5 +;
     3.6 +; This program is free software: you can redistribute it and/or modify
     3.7 +; it under the terms of the GNU General Public License as published by
     3.8 +; the Free Software Foundation, either version 3 of the License, or
     3.9 +; (at your option) any later version.
    3.10 +;
    3.11 +; This program is distributed in the hope that it will be useful,
    3.12 +; but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.13 +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.14 +; GNU General Public License for more details.
    3.15 +;
    3.16 +; You should have received a copy of the GNU General Public License
    3.17 +; along with this program.  If not, see <http://www.gnu.org/licenses/>.
    3.18 +
    3.19 +; The following line contains a placeholder address that the build script
    3.20 +; calculates and fills in.
    3.21 +.org $%(in_game_completion_address)x
    3.22 +
    3.23 +game_completed:
    3.24 +
    3.25 +    ; Do something to indicate the game has been completed.
    3.26 +    ; Check whether the player found the treasures.
    3.27 +
    3.28 +    jmp game_completed
    3.29 +
    3.30 +    clc
    3.31 +    rts
     4.1 --- a/loader.oph	Sat Oct 04 01:13:43 2014 +0200
     4.2 +++ b/loader.oph	Sat Oct 04 20:48:08 2014 +0200
     4.3 @@ -117,12 +117,12 @@
     4.4      jsr tab_x_y
     4.5  
     4.6      ldx #0
     4.7 -    title_text_loop:
     4.8 +    loader_title_text_loop:
     4.9          lda title_text,x
    4.10          jsr $ffee
    4.11          inx
    4.12          cpx #[title_text_end - title_text]
    4.13 -        bne title_text_loop
    4.14 +        bne loader_title_text_loop
    4.15  
    4.16      ; Define ENVELOPEs.
    4.17      lda #0
    4.18 @@ -490,12 +490,9 @@
    4.19  
    4.20  move_title_data:
    4.21  
    4.22 -    ldx #0
    4.23 -    ldy #0
    4.24 -
    4.25 -    lda #<title_data
    4.26 +    lda #<in_game_data_start
    4.27      sta $70
    4.28 -    lda #>title_data
    4.29 +    lda #>in_game_data_start
    4.30      sta $71
    4.31  
    4.32      lda #<title_data_address
    4.33 @@ -503,6 +500,7 @@
    4.34      lda #>title_data_address
    4.35      sta $73
    4.36  
    4.37 +    ldy #0
    4.38      move_title_data_loop:
    4.39  
    4.40          clc
    4.41 @@ -525,14 +523,19 @@
    4.42          sta $73
    4.43          clc
    4.44  
    4.45 -        inx
    4.46 -        cpx #[title_length + in_game_total_text_length]
    4.47 +        lda $70
    4.48 +        cmp #<in_game_data_end
    4.49 +        bne move_title_data_loop
    4.50 +        lda $71
    4.51 +        cmp #>in_game_data_end
    4.52          bne move_title_data_loop
    4.53  
    4.54      clc
    4.55      rts
    4.56  
    4.57 -.include "title-data.oph"
    4.58 +in_game_data_start:
    4.59 +.include "title-data-and-ending.oph"
    4.60 +in_game_data_end:
    4.61  
    4.62  ; Flag drawing routines
    4.63