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

No comments:

Post a Comment