World map continued
Extracting all “Map” symbols and putting valid Vectrex code around it – results in another very “easy” looking function:
(the calculated scale is due to using a BLOWUP of 4 – and a slight adjustment 🙂 )
So – by now we can:
- start the game
- build a character
- buy some equipment
- display a world map
Next thing will be:
- move around
- print status information
As “everyone” knows, printing text is “the worst thing” one can do on a Vectrex. Nonetheless we do HAVE to print something on the screen, at least two “lines”:
- The current player status (Gold, HitPoints, and Food)
- What is happening?
The “easy” way:
This “print”, when there is a worthwhile message to display, takes about 12000 cycles.
More than one third of all cycles we have available for the complete game display.
And this is already using an optimized print_Str_d, which uses only a 5 pixel high font. But for now… this must suffice – more optimization will be started, once the whole game is up and running.
Moving around… is pretty straight forward again.
We can reuse code done by Paul (or Richard) and just substitute the Vectrex’ input methods:
(The print_timed() function fills the message buffer that is displayed on the screen, later that was optimized some more.)
Being a little afraid of the dungeon… I next did the “easy” things like:
- entering town, and buying stuff
- entering the castle and receiving quests
I will not go further into that – since it is really more of the same. Parsing input, printing text on screen and doing while (1) loops to display a Vectrex-round.
It took a bit of experimenting and reading till I understood the drawing system of the dungeon.
In general the dungeon is drawn in slices (maximum depth 10):
Each color represents a dungeon slice. The bounds are defined by an outer rectangle (level 1: pink) and an inner rectangle (level 1: green).
Features are always drawn for one slice (like doors, ladders, monsters, traps etc). The original code draws all of these things dynamically and calculated with single “lines”.
So basically the complete dungeon is drawn in these slices (Loop variable “level”):
- DrawCalcRect() – creates the shown “outer” rectangle
- x, y are either 0, 1 or -1 and determine the direction you look at – so increasing the current position with those “moves”, you go one step further in your view direction (for the next level to draw)
- front, left, right are fairly self expanatory – these are the three tiles in front of the current “view” position
Within the DrawDungeon() – the “lines” are drawn – as an example the left and right walls:
Anyways – after making sure the math is save (sign wise and double, and long wise) and building a “dummy” HWLine() function… a dungeon is drawn:
The first simple implementation of HWLine():
(after doing a 0,0 correction
– each coordinate -128)
Some further math functions had to be removed:
- rand() function had to be “secured”
It always helped much to UNDERSTAND what was going on. Example:
The above code checks, whether a monster can attack, it can only attack if it is adjacent to the player and not diagonal. This can be reduced to:
Since the above version is basically Pythagoras, and checks if the hypotenuse is smaller than 2 (sqrt(2) < 1.3) – it is the same as checking that “no distance” is greater than abs(1) AND that “one distance” is zero.
And thus I got rid of two functions, that drove the “C” code crazy! POW() and SQRT().
Doors are actually drawn “more” complicated to place them in the middle and get the diagonals right:
But since the math worked ok and I am not optimizing yet… I left that alone as well.
(Actually I had to debug that for quite some time, since here a sign/unsign difference sneaked in using the 6809 gcc).
The above dungeon screen as shown refreshed in about 44000 cycles (12000 from the text output – but nonetheless over 30000 cycles for the few dungeon walls (depth levels: 3)).
In principle monsters are drawn like everything else.
But not in principle – monsters are different:
A monster is drawn with a “plot” function – seemingly a specialty of Apple II BASIC.
Plot is a function that draws a series of lines using dynamic parameters. e.g.:
Regardless of mighty Vide – this I could not convert directly with Vecci. This needed some manual labour:
- all signs must be “spaced”
- all fractions removed
- multiple plot entries must be seperated and absolut coordinates (the last plotted coordinates) added
- coordinates without offsets replaced with “0” (zero)
These are only a couple of replaces, easily done in a minute in any editor. For ten monsters perhaps 15-20 minutes “work”, easier than to program a parser, especially since we probably will never need it again.
This resulted in a “weird” list like:
_HPlot(y -23/d , 0, y -15/d , 0,
y -15/d , 0, y -15/d , x -15/d ,
y -15/d , x -15/d , y -8/d , x -30/d ,
y -8/d , x -30/d , y +8/d , x -30/d ,
y +8/d , x -30/d , y +15/d , x -15/d ,
y +15/d , x -15/d , y +15/d , 0,
y +15/d , 0, y +23/d ,0
_HPlot(0 , x -26/d , 0 , x -65/d , END , END);
_HPlot(y -2/d+ , x -38/d , y +2/d+ , x -38/d , END , END);
_HPlot(y -3/d+ , x -45/d , y +3/d+ , x -45/d , END , END);
_HPlot(y -5/d+ , x -53/d , y +5/d+ , x -53/d , END , END);
_HPlot(y -23/d , x -56/d , y -30/d , x -53/d ,
y -30/d , x -53/d , y -23/d , x -45/d
y -23/d , x -45/d , y -23/d , x -53/d ,
y -23/d , x -53/d , y -8/d , x -38/d , END , END);
_HPlot(y -15/d , x -45/d , y -8/d , x -60/d ,
y -8/d , x -60/d , y +8/d , x -60/d ,
y +8/d , x -60/d , y +15/d , x -45/d , END , END);
_HPlot(y +15/d , x -42/d , y +15/d , x -57/d , END , END);
_HPlot(y +12/d , x -45/d , y +20/d , x -45/d , END , END);
_HPlot(0 , x -75/d , y -5/d+ , x -80/d ,
y -5/d+ , x -80/d , y -8/d , x -75/d ,
y -8/d , x -75/d , y -5/d+ , x -65/d ,
y -5/d+ , x -65/d , y +5/d+ , x -65/d ,
y +5/d+ , x -65/d , y +5/d+ , x -68/d ,
y +5/d+ , x -68/d ,y -5/d+ , x -68/d ,
y -5/d+ , x -68/d , y -5/d+ , x -65/d , END , END);
_HPlot(y +5/d+ , x -65/d , y +8/d , x -75/d ,
y +8/d , x -75/d , y +5/d+ , x -80/d ,
y +5/d+ , x -80/d , y -5/d+ , x -80/d , END , END);
_HPlot(y -5/d+ , x -72/d , END , END);
_HPlot(y +5/d+ , x -72/d , END , END);
But Vecci can parse this!
Here a view of all monsters:
As you can see – some of the monsters have an exceptionly high vector count. The demon is drawn with over 90 vectors.
Every vectrex struggles with this many vectors drawn in one go – so I decided to forgo the “original” list variants of the BIOS and use a list type I “invented” – a synced list.
Synced lists have “synchronization” points during the draw, where the vectorbeam resets to zero and than moves to the last known location withing the “sprite” and than continues. The objects usually are drawn quite a lot cleaner and less shaky – but a little bit slower. But this was a sacrifice I had to make at this stage.
To be continued…