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
As always, please email me any question you might have.
ultima_revisited@yahoo.com
Joe
No comments:
Post a Comment