Jump to content

Recommended Posts

I have decided to start working on "Berylrogue" in TMS9900 assembly. I have recently developed a strong affinity for Roguelikes such as Rogue and Nethack... some very recognizable names... However, my favorites are the ones that are hard to find... Nearly-forgotten door games in nearly-forgotten BBSes. Thus is the setting for "Berylrogue."

 

Imagine you're sitting in a dark, wet basement of an abandoned warehouse... sitting in front of an old computer terminal. There is no sound but that of creaking pipes above you in the rafters of the basement... There is one flickering light hanging from the ceiling above your chair. There is one single phone cord coming out of the back of the terminal in front of you and running around the cracked paint of the corner to your left. As you sit, the tubes in the monitor warm up to a black screen which reads "Press Enter". You cautiously obey... the light above you flickers for one last time and you're surrounded in darkness... nothing to do and nowhere to go but into the mysterious and frightening depths of Berylrogue....

 

***

Check this picture out. I took this while playing NetHack on my iphone via a TelNet client.

 

7b91f17d.jpg

 

As you can see, this game starts inside one small room. As the player navigates the map, the map will expose itself a little at a time. This really adds to the mystery of the game... you don't know where the hidden elements reside on the map until you stumble across them in the dark. I like this concept alot... but I think it can be modified, improved. I know if any roguelike advocate hears someone say "We can improve on Rogue," they might have me strung up... so I hope nobody reads this post who loves roguelikes. =) hehehe

 

This was a mockup I did of the BerylRogue idea... this is not technically a "Roguelike" since there are character redefinitions and I don't use 100% ASCII characters.

 

rogueberyl.jpg

 

It was just a mockup, but I kind of like the idea of larger, more defined map dimensions and parameters. Nethack is great, but we'll try to make this unique... original. The concepts in this game are basically the same as in "Legend of Beryl Reichardt" except for a few things... graphics (obviously), number of "variables", number of players/enemies... little things like this. However, map data, scrolling, "variable" modification routines... All parallel for the most part. So anyway, I'll be posting assembly questions, answers, frustrations, elations, losses, gains, bumps and pains.... It is my first assembly project. I will certainly have much learning to do. If all goes as planned, we're talkin' cartridge release, 2011. Please keep me in your thoughts---and any advice you can give as I go forward will be greatly appreciated. I'm going Rogue, guys!!! Let's do it!

Share this post


Link to post
Share on other sites

So--the first thing I thought about is figuring out the best way to handle my numerous variables-- health, strength, experience, etc. Luckily, TMS9900 makes it easy to handle this kind of thing.

 

HTH DATA 20

STR DATA 10

EXP DATA 0

 

what this code segment does is sets 3 relocatable memory locations that contain the values for my variables. Let's say in the course of the game, I want to increase the value of EXP by one (meaning the experience of Beryl increases by 1) all you have to do is:

 

INC EXP

 

no label in the left column, so the program moves to the next field, the OpCode field. The computer sees INC in the opcode field and moves to the Operand field--- in the operand field, the computer reads "EXP" which is not a real memory location or a register, so it finds the label "EXP" and INCrements it by 1. It's really THAT simple

Share this post


Link to post
Share on other sites

There should be spaces before "INC" in that example... I'm on my iPhone---it didn't show up like I expected. There are spaces to the left of INC because it is an Opcode and not a label.

Share this post


Link to post
Share on other sites

If you're interested in seeing the wicked speed available in assembly, set up a loop. Of course, this is not a TRUE test of speed as a whole, but it will give you an idea about what I mean. I will be using the "." character to simulate a "space" in the source.

 

LP....LI.R5,>FFFF

(this makes LP a label, then Loads the value "FFFF" into Register #5. In decimal, that value is 65535.

 

......DEC R5

(this subtracts "1" from the value in register #5)

 

......JNE LP

(this compares the value of R5 to zero, if it's not, it jumps back to the label "LP"... JNE means (J)ump if (N)ot (E)qual. So/-- if you run this, it takes literally less than a second. Now, create a loop in XB. To make it fair, make it a "3000" loop.

 

100 FOR LP=1 TO 3000 :: NEXT LP

 

it takes twice as long.

 

Of course, this is not an apples to apples comparison, but if you need a delay loop in Asm, you usually need to nest a loop to give yourself enough time. Creating the nested loop is very similar to how you do it in XB. Just use 2 registers, Load >FFFF into one (inner loop), 8 into another (outer loop) with JNE instructions to return to the label which either loads

or decreases the values. I will type code for this when I'm not on my iPhone. Sucks.

Share this post


Link to post
Share on other sites

If you wanna have some fun, try

setting up an XB loop that loops >FFFF times. :) make it an even playing field. Do it, type RUN, and go get yourself a sandwich. When you get back to your terminal, finish the sandwich, pour a nice cup of tea, and check your stopwatch when it stops executing and gives you a **READY** prompt. :). And report back!

Share this post


Link to post
Share on other sites

You can use the "code" tags in your posts to make sure code is displayed as intended. The tags follow HTML convention, but instead of < and >, use [ and ]. The open code tag is [ followed by the word "code" and a close ]. The close tag is the same but the open [ is followed by / then "code" then ].

The code tag
   lets you keep
       your indentation
   and
such, and even does syntax highlighting (but
I think the default is C or something.)

* Your example:
      LI  R5,>FFFF
LP     DEC R5
      JNE LP

 

......JNE LP

(this compares the value of R5 to zero, if it's not, it jumps back to the label "LP"... JNE means (J)ump if (N)ot (E)qual. So/-- if you run this, it takes literally less than a second. Now, create a loop in XB. To make it fair, make it a "3000" loop.

 

Actually, it is the DEC instruction that does the compare to zero. The jump instructions only check the status of certain flags in the Status Register and jump (or not) accordingly. Many, but not all, of the 9900 instructions have this automatic "compare the result to zero" after each instruction is executed. You can check the E/A manual or the 9900 Data Manual to see which instructions compare the result to zero.

 

Of course, this is not an apples to apples comparison, but if you need a delay loop in Asm, you usually need to nest a loop to give yourself enough time.

 

Delay loops are sometimes necessary, but using them to control game speed is the wrong way and a bad practice (IMO). A delay loop binds you to the speed of the CPU and your program will not run correctly if run on emulators that can over-clock (like Classic99) or on real over-clocked hardware. Usually if you need a delay of some sort, it is best to use the VDP interrupt (this gives you a "tick" 60 times a second) or a timer via the 9901 (I know, the 9901 is a pain in the ass.)

 

Matthew

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for the info Matthew!!! Yea, you're right... I was using CI with INC preceding JNE before and CI is obviously the compare command there. The immediate compare to zero--- handy feature!

Share this post


Link to post
Share on other sites

In Lottrup's book he likes to count "up" instead of "down". On most CPU's, counting down is better because most CPU's (at least the ones I have dealt with) do some sort of compare to zero. For example:

 

      LI  R2,32
LP01   DEC R2
      JNE LP01

- vs -
      CLR R2
LP01   INC R2
      CI  R2,32
      JNE LP01

 

Counting down is faster and shorter, and you can usually count down vs. counting up. Until I understood how the automatic "compare the result to zero" worked, statements like this always confused me:

 

      MOV R2,R3
      JNE SOMEWHERE

 

I learned with Lottrup counting up so I only thought you could use a jump instruction after a compare (C, CB, or CI) instruction. Now I know, and so do you. :-)

 

Matthew

Edited by matthew180

Share this post


Link to post
Share on other sites

My first assembly screen draw for Berylrogue. I haven't re-defined characters or set colors yet, just drew the screen. =)

 

  	DEF  START
  	REF  VMBW
START
  	LI   R0,0
  	LI   R1,MAPDAT
  	LI   R2,768
  	BLWP @VMBW
LP
  	LIMI 2
  	JMP LP

MAPDAT DATA >2020,>4245,>5259,>4C20	;
  	DATA >2048,>5020,>3335,>2020	;
  	DATA >2020,>2020,>4C49,>5645	;
  	DATA >5320,>3220,>2020,>2020	;
* -- Map Row 1 --
  	DATA >2020,>2020,>2020,>2020	;
  	DATA >2A20,>202A,>2020,>2020	;
  	DATA >2020,>2020,>2020,>2A20	;
  	DATA >2020,>202A,>2020,>202A	;
* -- Map Row 2 --
  	DATA >2020,>2020,>2020,>2020	;
  	DATA >2A20,>202A,>2020,>2020	;
  	DATA >2020,>2020,>2020,>2A20	;
  	DATA >2020,>202A,>2020,>202A	;
* -- Map Row 3 --
  	DATA >2020,>2020,>2020,>2020	;
  	DATA >2A20,>202A,>2020,>2020	;
  	DATA >2020,>2020,>2020,>2A20	;
  	DATA >2020,>202A,>2020,>202A	;
* -- Map Row 4 --
  	DATA >2020,>2020,>2020,>2020	;
  	DATA >2A20,>202A,>2A2A,>2A2A	;
  	DATA >2A2A,>2020,>2020,>2A2A	;
  	DATA >2A2A,>2A2A,>2020,>202A	;
* -- Map Row 5 --
  	DATA >2020,>2020,>2020,>2020	;
  	DATA >2A20,>2020,>2020,>2020	;
  	DATA >202A,>2A2A,>2A2A,>2A20	;
  	DATA >2A20,>2A2A,>2020,>202A	;
* -- Map Row 6 --
  	DATA >2A2A,>2A2A,>2020,>2020	;
  	DATA >2A20,>2020,>2020,>2020	;
  	DATA >2020,>2020,>2020,>2A2A	;
  	DATA >202A,>202A,>2020,>202A	;
* -- Map Row 7 --
  	DATA >2020,>202A,>2020,>2020	;
  	DATA >2A20,>2020,>2020,>2020	;
  	DATA >2020,>2020,>2020,>2A20	;
  	DATA >2A20,>2A2A,>2020,>202A	;
* -- Map Row 8 --
  	DATA >2020,>202A,>2020,>2020	;
  	DATA >2A20,>202A,>2A2A,>2A2A	;
  	DATA >2020,>2020,>2020,>2A2A	;
  	DATA >202A,>202A,>2020,>202A	;
* -- Map Row 9 --
  	DATA >2020,>202A,>2020,>2020	;
  	DATA >2A20,>202A,>2020,>202A	;
  	DATA >2A2A,>2A2A,>2020,>2A20	;
  	DATA >2A20,>2A2A,>2020,>202A	;
* -- Map Row 10 --
  	DATA >2023,>202A,>2020,>2020	;
  	DATA >2A20,>202A,>2020,>2020	;
  	DATA >2020,>202A,>2020,>2A2A	;
  	DATA >202A,>202A,>2020,>202A	;
* -- Map Row 11 --
  	DATA >2020,>202A,>2A2A,>2A2A	;
  	DATA >2A20,>202A,>2020,>2020	;
  	DATA >2020,>202A,>2020,>2A20	;
  	DATA >2A20,>2A2A,>2020,>202A	;
* -- Map Row 12 --
  	DATA >2020,>2020,>2020,>2020	;
  	DATA >2020,>202A,>2020,>2020	;
  	DATA >2020,>202A,>2020,>2A2A	;
  	DATA >202A,>202A,>2020,>202A	;
* -- Map Row 13 --
  	DATA >2023,>2020,>2020,>2020	;
  	DATA >2020,>202A,>2020,>2020	;
  	DATA >2020,>202A,>2020,>2A20	;
  	DATA >2A20,>2A2A,>2020,>202A	;
* -- Map Row 14 --
  	DATA >2020,>202A,>2A2A,>2A2A	;
  	DATA >2A23,>202A,>2020,>2020	;
  	DATA >2020,>202A,>2020,>2A2A	;
  	DATA >2A2A,>2A2A,>2020,>202A	;
* -- Map Row 15 --
  	DATA >2020,>202A,>2020,>2020	;
  	DATA >2A20,>202A,>2020,>2020	;
  	DATA >2020,>202A,>2020,>2020	;
  	DATA >2020,>2020,>2020,>202A	;
* -- Map Row 16 --
  	DATA >2023,>202A,>2020,>2020	;
  	DATA >2A20,>202A,>2A2A,>2A20	;
  	DATA >2020,>202A,>2020,>2020	;
  	DATA >2020,>2020,>2020,>202A	;
* -- Map Row 17 --
  	DATA >2020,>202A,>2020,>2020	;
  	DATA >2A20,>2020,>2020,>2A20	;
  	DATA >2020,>202A,>2A2A,>2A2A	;
  	DATA >2A2A,>2A2A,>2020,>202A	;
* -- Map Row 18 --
  	DATA >2020,>202A,>2020,>2020	;
  	DATA >2A20,>2020,>2020,>2A20	;
  	DATA >2020,>2020,>2A2A,>2A2A	;
  	DATA >2A2A,>2A2A,>2020,>202A	;
* -- Map Row 19 --
  	DATA >2A2A,>2A2A,>2020,>2020	;
  	DATA >2A2A,>2A2A,>2A20,>2A20	;
  	DATA >2020,>2020,>2A20,>2020	;
  	DATA >2020,>2020,>2020,>2A2A	;
* -- Map Row 20 --
  	DATA >2020,>2020,>2020,>2020	;
  	DATA >2020,>2020,>2A20,>2A20	;
  	DATA >2020,>2020,>2A20,>2020	;
  	DATA >2020,>2020,>2020,>2A20	;
* -- Map Row 21 --
  	DATA >2020,>2020,>2020,>2020	;
  	DATA >2020,>2020,>2A20,>2A20	;
  	DATA >2020,>2020,>2A20,>2023	;
  	DATA >2020,>2020,>2020,>2A20	;
* -- Map Row 22 --
  	DATA >2020,>2020,>2020,>2020	;
  	DATA >2020,>2020,>2A20,>2A20	;
  	DATA >2020,>2020,>2A20,>2020	;
  	DATA >2020,>2020,>2020,>2A20	;
* -- Map Row 23 --
  	DATA >2020,>2020,>2020,>2020	;
  	DATA >2020,>2020,>2A20,>2A20	;
  	DATA >2020,>2020,>2A2A,>2A2A	;
  	DATA >2A2A,>2A2A,>2A2A,>2A20	;
  	END 

Edited by Opry99er

Share this post


Link to post
Share on other sites

I've attached a zipfile containing my source code and the compiled object file. To run it and see the extreme speed of assembly, drop SCR/O into DSK1, start Classic99 with the Editor Assembler module...

 

1) Type "3" for the LOAD AND RUN option

2) When it asks for object file, type "DSK1.SCR/O"

3) It will ask for another object file... just hit "enter"

4) When it asks for program name, type "START"

5) hit one last enter.

SCREEN.zip

Share this post


Link to post
Share on other sites

One thing, Owen...

 

Roguelike games are categorized as having one particular element... procedurally generated layouts. Using a data map for testing is fine, but you'll also want to investigate random map generation.

 

You can look at Dark Maze to see an example of one at work. It works like this:

 

- Plot a number of chambers on the screen

- Each are 3x3 blocks in size of empty space

- Store the center location of each into a stack for later calculation

- It's okay if they overlap, but they should stay within the boundaries

- For each chamber, plot four hallways in all cardinal directions away from the center

- If it encounters a boundary, change to a random direction

- Periodically, change to another direction

- When it encounters an empty space that's not the original chamber, end that direction for that chamber

- Random directions should use some intelligence, if it doubles back on itself it will end prematurely

 

Maze generation is actually fun and helps you learn how to craft algorithms. You also start figuring out what all those logic classes are really useful for... for example, with my first version of Dark Maze, the double-back feature meant that it could create chambers that are potentially not connected to others at all. That was a hole in my design I had to fix to make it work properly.

 

Adamantyr

Share this post


Link to post
Share on other sites

Yea man... I've played nethack and Dark Maze quite a bit. Dark Maze is actually part of my inspiration here. And as far as the random map generation... yep... Pretty

much as you described it--- that seems pretty uniform in Roguelikes. Another thing I plan to do is make this game "optionally Roguelike." Meaning I will design graphics for each of the used ASCII characters in the roguelike. If you select "Dungeon-mode" at the beginning, it's the graphical

game. If you select "Rogue-mode," it simply will not access the routine which redefines those ASCII characters. Instead of a wall in "Dungeon-mode," it will be a "#" in "Rogue-mode."

Edited by Opry99er

Share this post


Link to post
Share on other sites

There is a very primitive Rogue-like game called robotfindskitten in the TI Basic section of the Gameshelf website :)

Share this post


Link to post
Share on other sites

I've got some level generating code I came up with a while back for a roguelike board I was on. You're welcome to look through that if you're interested Owen, though it's more fun coming up with your own. :) I'm actually very happy with the random board generator in Helm Of Wooldridge, I think it's pretty decent for a short XB prog. Anyway, let me know if you want to see the code, or if you just need basic tips and tricks for making your own.

Share this post


Link to post
Share on other sites

Walid-- thanks for the heads up on the game!! I'll take a look.

 

Codex--- your level generation in Beryl is great. I also liked the level generation in FlyGuy as well. I will study these and learn what I can. In the mean time, I will continue studying the rudiments of this language.

Share this post


Link to post
Share on other sites

ROBOTFINDSKITTEN.... How cool is that?!?

 

Walid... How many languages in the universe have you used for writing games? It seems that BASIC, XB, Assembly are all in your wheelhouse. I imagine Forth and Pascal? =)

 

RFK.jpg

 

Thanks for the game, Walid. I'm playing it behind the Atariage window. =)

Share this post


Link to post
Share on other sites

I opened this up in notepad and the format was not wordwrapped... Or, rather, there was no definition of lines.. it all just runs together. I do not have any other assembler other than the EA cart on classic99... I was planning on copying and pasting. Should I try opening this in a different application?

Share this post


Link to post
Share on other sites

You should check out the XB version to understand how the algorithm works, and this is a good site for mazes in general:

 

http://www.astrolog.org/labyrnth/algrithm.htm

 

Also, a really good website on generating ToD style dungeons, and that all the dungeon generator pages out there ripped off, is this:

 

http://web.archive.org/web/20080715113228/http://www.aarg.net/~minam/dungeon_design.html

 

Unfortunately the original site seems to be gone, so you have to use the "way back" machine to view the page. I don't know what happened to Jamis Buck's Dungeon Generator website.

 

Matthew

Share this post


Link to post
Share on other sites

I opened this up in notepad and the format was not wordwrapped... Or, rather, there was no definition of lines.. it all just runs together. I do not have any other assembler other than the EA cart on classic99... I was planning on copying and pasting. Should I try opening this in a different application?

 

You really need to get a decent programmer's editor. By default I save my code in unix format (LF end of line instead of the "DOS" CRLF that notepad only reads.) At the very least try Notepad++ at:

 

http://notepad-plus.sourceforge.net/uk/site.htm

 

You should embrace syntax highlighting. Also, TextPad is, IMO the best text editor available on Windows. Also, if you can get past the configuration, Eclipse is a serious programmer's IDE. Anyway, drop notepad and get into something that will help you write code easier.

 

Matthew

Share this post


Link to post
Share on other sites

Is that what you are modeling BerylRogue on? Interesting. There is no scrolling, which makes the game a lot less complicated. Also, the levels could be generated on the fly right after you take the portal, and depending on how you generate each level, you may not need to store each map between levels (thinking of the way Codex randomly created the original FlyGuy levels.) You have to stock each room though, and make each level progressively harder, so you still have a lot of book keeping and balancing to do.

 

Matthew

Share this post


Link to post
Share on other sites

This is not a model "per-se" for Berylrogue--- but it is giving me some ideas. I want to have a "map" feature too. Click "M" and a screen will pop up showing the revealed map. I should start focusing on actual gameplay here soon--- but I'm still working on learning KSCAN stuff and getting my head around assembly graphics. :)

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...