Tuesday, November 22, 2011

TUTORIAL #2 – MAIN PROGRAM



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.


As always, please email me any questions you might have.

ultima_revisited@yahoo.com

Joe




Thursday, November 17, 2011

TUTORIAL #1 - A tutorial on “TILE GRAPHICS” for Ultima 1!

Hello all,

I know it has been a long time since my last blog but helping take care of a new baby is ruff!  I still can't remember that last time I got a full 5 hours sleep!  So, to help those with Ultima 1 blog withdrawls I am giving a little taste of what I'm putting together as a tutorial, I will be posting the start of my tutorial just to give the die-hards something to chew on. 

Enjoy

Joe

TUTORIAL #1 - "TILE GRAPHICS FOR ULTIMA 1"

A tutorial covering the Assembly and Basic code for the Ultima 1 Revisited World Map movement program!



This is basically a tutorial on how to create the maps, tile graphics, and character movement for Ultima 1!
Hello all,
Today I will be presenting multiple tutorial pages on the assembly and Basic code for the ULTIMA 1 Revisited World Map Movement program. I will be showing header sections and subroutines of the programs; explaining how they function and how each variable works within the code. I will try to be as detailed and descriptive as possible but also keep the information understandable to those without an assembly background.
All the programming code can be entered into an original Apple IIe computer OR Apple IIe emulator application using the DOS TOOL KIT v1.0 (1980)(Apple).dsk program file. At the end of this tutorial I will be presenting instructions on what to do to run the assembler and entering code. For those who would like the .dsk image, please email me and I will send it to you. I’m a registered owner of the original version of DOS TOOL KIT v1.0.
I’m going to be showing the code in a top-down process where I will be talking about all the variables first, then presenting the main program and each subroutine one after the other. Last will be the data strings for the shapes and the map tile references.
DISCLAIMER: First, I am by no means an expert in Assembly programming. I would be hard pressed to even consider myself a novice. I’m just a guy who is learning assembly programming from the ground up and who wrote a program about Ultima 1 world map movement. I will be trying to explain how I wrote the code and how others can do the same. If you find any egregious errors or just simple spelling mistakes, please don’t feel you have to chastise me and run me over the coals just to let me know I’m an incompetent bone head, I already know this and you reiterating it would only be redundant! I would appreciate it though if you could point out these errors and I will update the tutorial accordingly. I am always open to comments and criticism. Please note that all programs can be written in many different ways and still get the same results. If anyone who goes through this tutorial finds a much cleaner, easier, and more practical way to write this program then please let me know and I will post it gladly. As I said before, I’m not an expert and with what I’ve learned so far this is what I was able to come up with.
Also, you should have your windows calculator open and set the view to programmer! You will be seeing a lot of values in HEX and the programmer calculator will let you convert these values into decimals. This way you will know what the real values are being used for simple counters or for use in adding and subtracting.
Enough of this talking, let’s get started!
The first part of this tutorial will cover the Assembly program and all its subroutines. The assembly code covers all the movement routines as well as the tiles/shapes and the data strings for the map. Once we have everything covered on the Assembly program we will go onto the Basic program. The basic program controls all the keystrokes that deal with the movement keys, the movement text, and the screen display for the command lines.
The file name I used for this program is U1AND2 to represent the first two map regions of the entire world map. Since the world map is made up of 4 separate map regions I wasn’t able to create one program small enough to cover movement through all four regions due to the 256 byte limitation in assembly. I had to separate the program into two world map movement programs. Even though each map region is 64 tiles by 64 tiles, there are ocean tiles surrounding the maps which must be present to allow movement around the map. When a character moves off the main map regions it will trigger the next program to open that has map regions 3 and 4. U1AND2 is the program for the first half of the world map and U3AND4 will be the second program and together they make up the entire Ultima 1 world map. These two programs are almost identical with only the tile reference data strings making up the differences.



PART #1 – DEFINING VARIABLES

When the program is first listed you will notice the following:



1   **ULTIMA 1 REVISTED ***



This is a comment line that gives the name of the program or other important information pertinent to the code below. This line starts with the * symbol. This symbol represents a REMARK in assembly code. Anytime you see this symbol it will be giving the reader information regarding the preceding subroutine or code. All comment lines are ignored by the assembly compiler.

2    ***

Again, this is a comment line that is for spacing and display only and will not be read by the compiler.

3                                  ORG    $6000

This line tells assembly which memory region the program will originate at. In the Apple II computer you have certain areas of memory that are free to place code in. These memory regions are mapped out throughout the entire 48K of memory on the computer. $6000 is HEX for 24576, which is the K memory value within the 48K of memory. This is where the program starts when it is loaded into memory.

4                                 JMP     BEGIN

This line tells the program to jump to the subroutine with the header titled BEGIN. You can’t use any name you desire, you must use a name that is not used by the assembler. Also, you can only use a name referenced once within the program as a header, but you can add a number to the end of the header and make it BEGIN1 or BEGIN33 and this is completely legal.

5    COLMADD         DS       1

These DS variables are defined variable strings with the size of one byte or more! This means that the since variable COLMADD, for "column add" is represented by a 1 byte memory region which can contain a value from 0 to 255. COLMADD is used to store the value which references the 20th tile set from the initial column value. On the world map the initial starting tile reference is created from a ROW and COLUMN value. These values tell the program where the upper left corner of the map will start from; example 20, 45. So if the initial column value was 45 then COLMADD would equal 65. This 65 is used to reference the last tile number that will be displayed on the screen, since only 20 tiles can be shown per line on the screen at one tile.

6   CHAR                   DS       1

This is the player Character reference variable. This variable holds the value for the type of tile or shape that will be shown on the screen representing the main character. It could hold the value that represents the horse tile or the land speeder tile or even the cart tile but normally it will be the main character tile.

7   TPCNT                  DS       1

This is a counter variable used within the LOADMAP subroutine which stands for "Temp Counter". It is used within a loop routine to count up to 20 for the number of tiles stored to be displayed on the each column of the screen.

8   TMAPCNT           DS       1

This is a counter variable used within the LOADSHP subroutine which stand for "Temp Map Counter". This is a temporary map counter variable and will be explained in more detail within the LOADSHP subroutine.

9   CHKER1               DS       1

This is a counter variable used within the MAIN PROGRAM subroutine and is part of an incremental counter with the LOADMAP subroutine to check when all 10 screen line of tiles have been stored in the MAPSTORE array. This variable will be explained in more detail within the MAIN PROGRAM subroutine.

10   STEPR1             DS       1

This is a counter variable used within the TILEPLC subroutine and is part of an incremental counter. This variable will be explained in more detail within the TILETLC subroutine.

11   HBYTE               DS       50

This variable stores the value of the "HIGH BYTE" of the data string for the shape/tiles references.

12   LBYTE                DS       50

This variable stores the value of the "LOW BYTE" of the data string for the shape/tiles references. Within each data string you can set a HEX value to reference a value for some part of the data, these two bytes that make up the HEX value can be separated and stored as individual bytes. This variable is used within the FRNTBYT subroutine and will be explained in more detail within that section. The value is defined as a 50 bytes array.

13   MAPROW        DS       50



This variable stores the value of the data string for the type of map shape reference value. This variable is used within the PREPROW subroutine and will be explained in more detail within that section. The values for HBYTE and LBYTE are taken from HEX value within this array. The value is defined as a 50 bytes array.

14   ROWFNL          DS       180

This variable "Row Final" stores the value from LBYTE and it represents the actual shape/tile reference # used on the map. This variable is used within the TILEPLC or "Tile Placement" subroutine and will be explained in more detail within that section. The value is defined as a 180 bytes array because it will tempararily hold each shape value of all the shapes of one horizontal line across the world map.

15   PREPMAP        DS       1

This variable is used to temporarily store the HEX value of the map section reference #. It is used within the PREMAP or "Pre Initial Map" subroutine and will be explained in more detail within that section. The value is defined as 1 byte.

16   BYTEA               DS       1

This variable is used as a loop counter to keep track of the 40 bytes that a referenced across the screen. As BYTEA increments by 1 then the next tile byte is referenced and displayed until BYTEA reaches 39.

17   LINEA                DS       1

This variable is used as a loop counter to keep track of the160 bytes lines that a referenced from line 0 to 159 down the screen. As LINEA increments by 1 then the next line byte is referenced and displayed until LINEA reaches 159.

18   COLUMN1       DS       1

This variable will store the starting value for the COLUMN where the top-left portion of the screen will begin based on the column value.  This location defines where the Ultima Character will start on the world map.

19   ROWNO           DS       1

This variable will stores the starting value for the ROW where the top-left portion of the screen will begin based on the row value.  This location defines where the Ultima Character will start on the world map.

20   MAPCOUNT    DS       1

This is a temporary map counter variable used within the LOADSHP subroutine.

21   STEPPB             DS       1

This variable is used in the LOADSHP subroutine and is used as a loop counter.

22   TCOUNT            DS       1

This is a temporary map counter variable used within the LOADSHP subroutine.

23   ROW                  DS       1

This variable stores the value of the initial ROWINIT value for the starting upper corner tile location and will change and update as the game progresses.

24   COLUMN          DS       1

This variable stores the value of the initial COLINIT value for the starting upper corner tile location and will change and update as the game progresses.

25   CHARCX            EQU    $FB

This variable stores the row/X location of the main character tile on the world map screen. This value is used to track when the character is over certain map location such as castles, town, transportation objects, etc…

26   CHARCY            EQU    $FC

This variable stores the column/Y location of the main character tile on the world map screen. This value is used to track when the character is over certain map location such as castles, town, transportation objects, etc…

27   ROWINIT          EQU    $EC

This variable stores the initial row value for the upper left corner starting location of the world map when the game starts. This value never changes.

28   COLINIT            EQU    $ED

This variable stores the initial column value for the upper left corner starting location of the world map when the game starts. This value never changes.

29    MAPSTORE     DS       200

This variable stores all 200 shape reference numbers for each of the 200 graphic tiles drawn on the screen.

30   TEMP                 DS       160

This variable as well as TEMP1 is used to temporarily store the 160 byte values for the first half of the tile shape for each graphic line from 0 to 159. Although there are 191 graphics lines on the screen, only 160 are drawn because the bottom of the screen is used for text! Each graphics tile in Ultima is based on a two bytes wide by two bytes high shape. The program draws each shape line by line or byte by byte from 0 to 159 then it move over one byte and draws the second half of the tiles line by line.

31   TEMP1             DS       160

This variable is used to temporarily store the second half of the bytes for each graphic tile.

32   GRAPHICS        EQU    $C050

This variable stores the HEX value used to reference the graphics mode. When the accumulator is stored with the HEX value $C050 the program knows to display the graphics mode as opposed to the text mode.

33   HIRES                 EQU    $C057

This variable stores the HEX value used to reference the Hi-Res graphics screen. When the accumulator is stored with the HEX value $C057 the program knows to display the Hi-Res graphics mode as opposed to the Low-Res graphics mode.

34   PAGE1               EQU    $C053

This variable stores the HEX value used to reference the Page 1 graphics screen. When the accumulator is stored with the HEX value $C053 the program knows to display the page 1 graphics screen.

35   PAGE2               EQU    $C055

This variable stores the HEX value used to reference the Page 1 graphics screen. When the accumulator is stored with the HEX value $C055 the program knows to display the page 2 graphics screen.



36   HIGH                  EQU    $1B

This variable is used as the HIGH BYTE value for the indirect indexed addressing to help reference the HI-Res page 1 graphics memory byte location on the screen. There are two Hi-Res graphics pages on the apple II that can be used to show images on the screen. This program only uses the Page 1 graphics screen, which references the first memory locations on line 0 as $2000 all the way too line 191 as $3FD0. The screen is 40 bytes wide. Since each memory location can be broken into two parts as in the case of $2000, which will be a 20 and 00! These values can be stored in data strings and referenced as a HIGH and LOW byte value. This address indexing makes it much easier to find and draw to specific memory location on the screen by referencing the HIGH and LOW byte of that location. These values will be read from a mapped data string and stored for reference by the program.

37   LOW                   EQU    $1A

This variable is used for the LOW byte value reference within the address indexing. The LOW and HIGH variable are used with Indirect Indexing for the MAPADR and SHAPE indexing.
It is always a good idea to keep your entire index of variables defined in the first part of your program. This makes for easy reference when you list the program because it will be the first part of your program to show up.

This is going to be a very long and thurough tutorial so I will take some time, please be patient and trust me when I say, "This tutorial will walk you through step-by-step the entire process of programming in Assembly the first two world maps, character movement with collision detection, and changing the different transportation devices for movement!"
Have fun and talk to you soon,

As always, please email me any question you might have.

ultima_revisited@yahoo.com

Joe