I will be going through the Main Program subroutine line-by-line
and explaining what each line of code is doing and how it affects the outcome
of the program.
38 *********************************************
This is just a comment line
breaker and helps to space out each subroutine or section of code.
39 *****
MAIN PROGRAM *************
This is the main comment line
telling the reader where the starting section of code begins for the main
program. Remember; an * is what
represents a comment field.
40 BEGIN JSR PGM
Lines 40 thru 82 consist of
the main subroutine, and the header name of this subroutine is called
BEGIN. For the program to jump to
specific subroutines within the program it needs to see the header name. Line 40 is where the program starts and goes
from line to line in a top-down fashion telling the program to “[J]ump to [S]ub[R]outine” with the header PGM. Once the subroutine PGM finishes it will
return back to this line and continue down the rest of the program. Subroutine PGM is where the screen is blanked out and cleared of text and
graphics. PGM will be explained in more detail later in the blog.
41 JSR INITIAL
After subroutine PGM
completes and returns, line 41 tells the program to “[J]ump
to [S]ub[R]outine”
to the subroutine with the header INITIAL. Subroutine INITIAL is where all starting variables for the map, character, and
tiles graphics are initialized to a value of [0] or predetermined values. INITIAL
will be explained in more detail later in the blog.
42 START8 JSR PREMAP
After subroutine INITIAL
completes and returns, line 42 tells the program to “[J]ump
to [S]ub[R]outine”
to the subroutine with the header PREMAP. Line 42 also has a header name so it can also
be referenced and can be called to run just line BEGIN was. When the game starts and your character is
placed on the world map this region is defined ahead of time by a ROW and
COLUMN value. Subroutine PREMAP helps define where the ULTIMA 1 world
map will start from based on the row number it see, which is predefined in the
INITIAL subroutine when the program starts.
The world map is made up of 84 ROWS from top to bottom. This row number is used in PREMAP to search
through the map address for certain values to obtain the starting map corner
location. Subroutine PREMAP will be explained in more detail
later in the blog. START8 is a
subroutine within BEGIN that is used when after the main program starts and all
variables have been initialized for the first time, once the ULTIMA map needs
to be redrawn again you can’t have the program call BEGIN or it would reset
everything, so START8 let you redraw the map but with updated character
movements and current variable.
43 JSR PREPROW
After subroutine PREMAP
completes and returns, line 43 tells the program to “[J]ump
to [S]ub[R]outine”
to the subroutine with the header PREPROW. Since we know the world map is 84 rows deep,
it is also made up of numerous columns. Also, because memory usage is critical
on the APPLE computer I had to figure out a way to compress the map data that
would be read to figure out the number of columns and tiles which make up the
entire world map width. PREPMAP is used
to obtain the specific number of data strings which are represented in each
separate map row. Subroutine PREPROW will be explained in more
detail later in the blog.
44 JSR FRNTBYT
After subroutine PREMAP
completes and returns, line 44 tells the program to “[J]ump
to [S]ub[R]outine”
to the subroutine with the header FRNTBYT. FRNTBYT is used to help uncompress the map
data so it can read a HIGH byte and a LOW byte to figure out the number and
type of tile which is used in the given ROW of the world map. Subroutine FRNTBYT will be explained in more detail later in the blog.
45 JSR TILEPLC
After subroutine FNRTBYT
completes and returns, line 45 tells the program to “[J]ump
to [S]ub[R]outine”
to the subroutine with the header TILEPLC. Earlier
in my BLOG I explained how since I was trying to save memory by compressing the
map data, I had to come up with a way to compress the way the number of tiles
and type of tiles that were being used on each row of the world map. This compression process uses a number of
subroutines to help uncompress the map data and put the number of tile and type
of tiles in temporary storage memory regions.
The subroutine TILEPLC uses the HIGH and LOW byte values found in
FRNTBYT and breaks it down so it counts out each tile type on the world map row
and stores it in an array variable. This
array stores each map tile from the starting row and column up to the next 20
tiles because the screen only represents 20 graphic tiles at a time. Subroutine TILEPLC will be explained in more detail later in the blog.
46 LDA #$00
After subroutine TILEPLC
completes and returns, line 46 is used to “[L]oa[D] the [A]ccumulator”
or register A with the HEX value of zero!
So you could think of it as [A] holding the value of [0].
On the Apple 6502, there are
six instructions that load and store
the registers.
These are:
LDA v Load the A register with v
LDX v Load the X register with v
LDY v Load the Y register with v
STA v Store the A register with v
STX v Store the Y register with v
STY v Store the Y register with v
Here LD stands for “LOAD”; ST
stands for “STORE”; and v can be and cell in the main memory.
47 INC ROWNO
Line 47 is used to “[INC]rement” whatever value is in ROWNO by 1! This is to get ready to help draw the next
row of graphics tile on the screen.
There are six instructions on the 6502 which increment and
decrement:
INC v increment v
DEC v decrement v
INX Increment the X register
DEX Decrement
the X register
INY Increment
the Y register
DEY Decrement
the Y register
Here v can be any cell in the
main memory, as before. Note that we
cannot increment or decrement, the A register!!!
48 JSR LOADMAP
Line 48 tells the program to
“[J]ump to the [S]ub[R]outine” with the header LOADMAP. This subroutine take the [20] row tiles that
will be displayed on the screen and stores them into a MAPSTORE array, to be
used after all 200 tiles have been stored and are ready for the screen.
Subroutine LOADMAP will be explained
in more detail later in the blog.
49 INC CHKER1
Line 49 is used to “[INC]rement” whatever value is in CHKER1 by 1! This
variable is part of an incremental counter within the LOADMAP subroutine to
check when all ten screen line of tiles have been stored in the MAPSTORE array.
50 LDA CHKER1
Line 50 is used to “[L]oa[D] the [A]ccumulator” or register A with the value from CHKER1
after it has been incremented in line 49.
51 CMP #$0A
Once the value of CHKER1 is
loaded into register A, Line 51 is used to “[C]o[MP]are” what is in register A to the HEX value of $0A
or 10. The value of 10 is the number of
horizontal line on the screen that will hold graphic tiles.
52 BLT
START8
Line 52 is used to “[B]ranch on [L]ess [T]han”, which means that as long as the value in
register A is less than [<] 10 it will continue to call the subroutine with
the header START8. Once the value of A
is greater than [>] 10 it will bypass line 52 and continue to line 53.
53 LDA #$00
Line 53 is used to “[L]oa[D] the [A]ccumulator” with the HEX value of zero! So you could think of it as [A] holding the
value of [0].
54 STA CHKER1
Line 54 is used to “[ST]ore the [A]ccumulator” which has the value of zero into the
variable CHKER1. So the variable CHKER1
will equal zero after line 54 completes.
55 JSR CHARTILE
Line 55 tells the program to
“[J]ump to the [S]ub[R]outine” with the header CHARTILE. This subroutine is used to load the type of
character graphic tile that will be displayed on the screen, such as the fighter,
the horse, the cart, etc… Subroutine CHARTILE will be explained in more
detail later in the blog.
56 LDX #$00
Line 56 is used to “[L]oa[D] the [X] register” with the HEX value of zero! So you could think of it as [x] holding the
value of [0].
57 STX MAPCOUNT
Line 57 is used to “[ST]ore the [X] register”
which holds the HEX value of zero into the variable MAPCOUNT! Remember that MAPCOUNT is going to be used as
a step counter in another subroutine. So
you could think of it as, variable MAPCOUNT is equal to the value of [0].
58 START1
JSR LOADSHP
Line 58 tells the program to
“[J]ump to the [S]ub[R]outine” with the header LOADSHP. Line 58 also has a header name so it can also
be referenced and can be called to run just line START8 was. Subroutine LOADSHP takes each map address stored into MAPSTORE which represent
a single graphic tile and start to recreate the tile from individual bytes and
once it creates the entire shape it then draws it to the screen from top to
bottom and left to right! Subroutine LOADSHP will be explained in more
detail later in the blog. START1 is a SUB-subroutine
OR “a subroutine within a subroutine” which is also within the BEGIN subroutine
that is used to load each shape into a tile graphic and draw it to the screen
for each of the 20 graphics tiles shown across the screen. START1 is part of a loop that when it finishes
drawing the 20 tiles it continues on to the rest of the main subroutine.
59 JSR DRAW
Line 59 tells the program to
“[J]ump to the [S]ub[R]outine” with the header DRAW. This subroutine is used to DRAW the actual
graphic tile to the screen. Since each
graphic tile in Ultima is made up of two bytes wide and two byte deep, the DRAW
subroutine draws the two byte right next to each other one line at a time until
it draws the entire column of 10 tiles or 160 graphic lines down the screen. Subroutine DRAW will be explained in more detail later in the blog.
60 INC LINEA
Line 60 is used to “[INC]rement” whatever value is in LINEA by 1! This
variable LINEA is part of an incremental counter within the START1 SUB-subroutine
of the subroutine BEGIN that counts up to 20 to check for each ROW of graphic
tiles on the screen as the DRAW subroutine is called. Once LINEA reaches a certain value the counter
check will be completed and the next statement will be bypassed.
61 LDA LINEA
Line 61 is used to “[L]oa[D] the [A]ccumulator” with the value that is in variable LINEA! So you could think of it as [A] holding the
value of variable LINEA.
62 CMP #$14
Once the value of LINEA is
loaded into register A, Line 62 is used to “[C]o[MP]are” what is in register A to the HEX value of $14
or 20. The value of 20 is the number of
horizontal lines the graphics tiles, which are two bytes high, are drawn on. Remember, a graphic tile is 2x2 bytes, so it
is two bytes high and there are 10 graphic tiles that run from the top of the
screen down to the bottom of the screen.
63 BLT
START1
Line 63 is used to “[B]ranch on [L]ess [T]han”, which means that as long as the value in
register A is less than [<] 20 “in this case” it will continue to call the
subroutine with the header START1. Once
the value of A is greater than [>] 20 it will bypass line 63 and continue to
line 64.
64 RTS
Line 64 is used to “[R]e[T]urn from [S]ubroutine”, which means that everything in this
subroutine has completed and will be returned back the statement line which
called it. In this case, this means
since this is the Main Program Subroutine “BEGIN”, this return statement will END
the program altogether.
Joe
Great to see this! If you ever turn this into a large article, feel free to submit it to http://codex.ultimaaiera.com
ReplyDeleteWe already have fairly detailed tech documents on several of the Ultima games, and we'd love one more!
http://codex.ultimaaiera.com/wiki/Template:Internal