Difference between revisions of "Roguelike Magazine Issue 2"
(archived part two.) |
|||
Line 1: | Line 1: | ||
This is second issue of the [[Roguelike Magazine]], copied from [http://magazine.rogueforge.net/rtm_issue2_20070402.html here] to preserve it. All articles written by [[Mario Donick]]. | This is second issue of the [[Roguelike Magazine]], copied from [http://magazine.rogueforge.net/rtm_issue2_20070402.html here] to preserve it. All articles written by [[Mario Donick]], unless noted otherwise. | ||
= Intro. = | = Intro. = | ||
Line 111: | Line 111: | ||
No. | No. | ||
'''And a rather dumb question: A clich? | '''And a rather dumb question: A clich???? says that finnish people are always sad and therefore drink much beer. Is this true and influences this your art?''' | ||
I don’t drink alcohol at all, but it’s true that finns are sad and depressed people. Maybe I should drink beer a lot, too. | I don’t drink alcohol at all, but it’s true that finns are sad and depressed people. Maybe I should drink beer a lot, too. | ||
Line 352: | Line 352: | ||
==A Virtual Console Window== | ==A Virtual Console Window== | ||
The x- and y-coordinates used in the function call (here 15 and 10) refer to a matrix in which every cell contains one letter or tile at a time. It works like the 80? | The x- and y-coordinates used in the function call (here 15 and 10) refer to a matrix in which every cell contains one letter or tile at a time. It works like the 80????25-matrix of a console, but the actual size of every cell depends on the size of the tiles you wish to use (in fact, the cell size is the same as the size of your tiles). The total number of lines and rows in this »virtual console« depends on the width and height of your game’s main window. | ||
If your window size was 640? | If your window size was 640????480 and your tiles had a size of 32????32 (like in the example source), you would get a »resolution« of 20????15. If your window size was 800????600 and your tiles were 32????32, the available size was 25????18. And if your window size was 800????600, but your tiles had a size of 10????20 (as seen in LambdaRogue), the resulting space was 80????30. | ||
==The Console Part== | ==The Console Part== | ||
Line 446: | Line 446: | ||
Finally, I want to address an issue related to window- and tile sizes. The basics were already covered above, but out of these basics a problem is born which can lead to strange results if not handled properly. | Finally, I want to address an issue related to window- and tile sizes. The basics were already covered above, but out of these basics a problem is born which can lead to strange results if not handled properly. | ||
You probably want to use a standard resolution, e.g. 800? | You probably want to use a standard resolution, e.g. 800????600, for the SDL mode of your game. If you now use the described functions to output text, chars or tiles, all will work fine until you accidently use a coordinate out of range. | ||
This can happen very easily if the SDL window offers more rows or columns than the console mode. If you don’t think about this and e.g. use a CharXY(20,27,'T'), in a 80? | This can happen very easily if the SDL window offers more rows or columns than the console mode. If you don’t think about this and e.g. use a CharXY(20,27,'T'), in a 80????25 console your game will crash with an access violation. | ||
To avoid this, you have several options. You could just stop to use rows greater than 25, but in SDL mode this would cause a fairly large amount of unused space (perhaps this could be filled by a nice background texture). | To avoid this, you have several options. You could just stop to use rows greater than 25, but in SDL mode this would cause a fairly large amount of unused space (perhaps this could be filled by a nice background texture). | ||
Line 457: | Line 457: | ||
Window Size Optimal Tile Size | Window Size Optimal Tile Size | ||
640? | 640????480 8????19 | ||
800? | 800????600 10????24 | ||
1024? | 1024????768 12????30 | ||
These sizes, of course, are very uncommon. Most available tilesets come in squared sizes and editing them would need as much work as creating a completely new tileset. However, if you don’t want to use graphics, but use a virtual (SDL) console, you only need tiles with letters, ciphers and special chars. Such tiles can easily be created with every graphics editor. Just open a new file in your desired size, select a font and adjust the size of the font to make all characters fit into the center of your file. Create all files you need and copy them into one single bitmap. This bitmap is your tileset. | These sizes, of course, are very uncommon. Most available tilesets come in squared sizes and editing them would need as much work as creating a completely new tileset. However, if you don’t want to use graphics, but use a virtual (SDL) console, you only need tiles with letters, ciphers and special chars. Such tiles can easily be created with every graphics editor. Just open a new file in your desired size, select a font and adjust the size of the font to make all characters fit into the center of your file. Create all files you need and copy them into one single bitmap. This bitmap is your tileset. |
Revision as of 12:04, 22 August 2008
This is second issue of the Roguelike Magazine, copied from here to preserve it. All articles written by Mario Donick, unless noted otherwise.
Intro.
The Infinite Deadline Problem
First of all, welcome to the second issue of Roguelike. The magazine. I know it’s late. I also know it contains only four of the planned articles, and even this was only possible with Glenn R. Whichman’s article about JavaScript as language for roguelikes.
Well, usually I tend to excuse myself again and again for not meeting deadlines, but of course I know that everybody in the roguelike scene tends to not even giving deadlines. So I will adopt this behavior for RTM ;-)
The problem with this is that the concept of a magazine requires to meet deadlines. It’s neither a piece of software (or, to be more precise, a computer program) nor a blog, it’s a thing which is expected to return on a regular basis. The question is how wide this basis should be. One month? Did not work. Two months? Might be possible (and when RTM started, I even scheduled RTM #2 for May, not for April … ). However, three months would be the most realistic cycle.
And this produces another problem (but at least one I was always aware of): Reviews. If RTM is only published four times a year, writing reviews of games which are in development is rather useless. By the time the review is written, a new release could be already out, with issues fixed still mentioned in the review. The reviews could of course contain the version number of the tested game, but critical reviews might produce negative effects on games which already have been improved. Especially readers who don’t visit r.g.r.d regularly and don’t know about the fast update cycles of many roguelikes might get a wrong impression.
A Concept
So what to do to make my life easier, but keep RTM interesting?
Step one: Continue publishing interviews and writing theoretical articles (e.g. the – in this issue absent, sry again – series Aesthetics in Roguelikes or the articles about languages and coding).
Step two: Cover new roguelikes which are in alpha or early-beta stage only with summaries, but not with complete reviews. The last 7DRL contest showed me that it’s just not possible for me to play them with the effort needed to write accurate reviews.
Step three: Review only roguelikes which can be expected to be fun for other people than the developers on r.g.r.d – this does not mean I don’t respect the efforts of developing new games and concepts, but reviews in RTM will be more useful if they cover games which offer a wider range of gameplay (e.g. a minimal length; things to discover etc.) also for players still not so affine to roguelikes, and many alpha/beta-projects (and most 7DRLs) don’t fulfill this requirement.
So this is the plan and it allows me to ignore most of the infinite [release]-messages, taking pressure from me, while it also admits me to have a look at older roguelikes – so don’t be surprised if there was a YANAIM (Yet Another Nethack Article In Media) in RTM some day ;-)
7DRL contest 2007.
Hive Awakening
Ever watched Star Trek? If so, you might know the, mostly evil, cyborg species Borg (»Sounds Swedish.«). By default, they know no individualism. Instead they live as collective on gigantic cubic or spherical space ships and want to assimilate everything and everybody into their collective. The collective is controlled by a queen, who does the same as the queen in a bee hive. Therefore the shared consciousness of the Borg drones is called hive mind. (Of course, Star Trek hasn’t invented the concept of group mind. See the english Wikipedia article for a rather complete list of shared consciousness in science fiction).
In certain episodes of Star Trek, single members of the collective get separated and have to survive on their own. Usually they just have to wait for rescue or, if rescue is unlikely, they have to destroy themselves. However sometimes, these drones get aware of their individuality – and like it. Reason enough for the queen to eliminate these broken parts of the collective.
So, now read the last two paragraphs again, but replace Borg with Bot and Queen with Hive Control. Then you know what the background story of the Gero Kunter’s 7DRL Hive Awakening (site) is all about.
Resistance Is NOT Futile
In Hive Awakening, you take control of one of the bots with self consciousness. In order to ensure your survival, you have to find an hive interface and use it to reprogram the hive control.
After the game has told you about your quest, it asks you to enter a handle, i.e. a name for your avatar. By default it suggests 5DRL which is not only a side blow on the needed development time of Hive Control, but reminds also of famous robots like R2D2 or C3PO. After entering the handle, you are presented the dungeon view.
This view looks very clear. The @ is highlighted by the cursor. Walls look turquoise. The lines at the bottom present some status values, and the advice to press ? to get a list of available keys should be taken serious. In general, the player is not overburdened by too many things at a time and his eyes and mind can adopt to the atmosphere of the game without stress.
To the atmosphere just mentioned count the names of the status values, too. Instead of HP, you have to care about the structure of your avatar. Other values are weight, engine and speed. Although it seems natural to have such denotations in a game where your avatar is a robot, it’s worth to notice.
Having a look at the key commands shows us that movement is controlled either by the number pad or by vi keys. Cursor keys don’t work. Instead you get an invalid key message. Laptop users who aren’t familiar with vi movement are forced to learn it (which, of course, wouldn’t be bad at all), because even using laptop’s virtual number pad (activated by pressing the Fn key together with a letter key) doesn’t work. The only alternative to vi keys is using NumLock, but then 15 of the letter keys (i.e. the i key which is for example necessary to enter portals to the next level) are not usable. Although the game is just a 7DRL, these issues are rather annoying.
Configure Yourself
Anyway, once basic movement works for everybody, the game will soon show its qualities. One of these is the equipment system. Your avatar is provided with several sockets which can hold different modules. Now some modules need more than one socket to be equipped. In such a case, you need to connect the sockets with a socket link. While you start with only two sockets available, you will find modules that add more sockets to the bot. However, the more equipment you have installed, the more energy is needed. More energy is produced by better engine cores.
In many roguelikes, your health regenerates over time. This is possible in Hive Awakening, too – but only with the right modules equipped. Although restorators, reconstructors and regenerators are available, you have to decide if you want to use one of these or if a weapon would do a better job for you. You can also equip different shells. These tools increase the maximum structure and therefore help to stay alive.
The described system reminds me of several battlemech inspired games (anybody here to write a »Front Mission RL«?) and once you have understood the concept, it works very well. It contains a strong tactical component and much of the game’s fun is created by that.
The First Minutes
You start with two sockets, a drill, a restorator and a protium core. At the moment, you can’t equip all three items at one time, so you have to decide which is less important. In principle, this is the decision between an active and defensive gaming strategy. If you enable the restorator instead of the drill, you will survive much easier, but can’t do harm to the enemies. The other way around you do harm, but will be destroyed rather soon. The third alternative is to deactivate the core, but this only works as long as you don’t need power for additional equipment. As items are richly available (too richly, i.e. repetitive sometimes), the power core will be needed soon.
Once you have discovered the first level, you surely want to go further. For doing so, you need to find the security interface of the level and deactivate it. Otherwise, the portal to the next area will be protected by a force field and can’t be entered.
After some time you will have collected lots of items and parts that can be used to enhance your bot. As stated before, this can only be done with modules that add new sockets, and finding these socket forks requires some patience. Once you have one or two of them, the equipment system finally becomes useful.
Summary
Hive Awakening could become a great game if the author spent some time on it. The equipment system allows very deep tactical gameplay and the atmosphere is quite dense, thanks to the terms, the colors and the dungeon layout – all three aspects fit the background story well. Though the story itself is not new, Hive Awakening is (as far as I know) the first computer game to put you in the role of an artificial life form that just wants to survive.
People.
Paul Pekkarinen / Krice
This column is dedicated to you, the roguelike community. Its purpose is to introduce single individuals and their personal view on the RL scene. We start with Paul Pekkarinen, also known as Krice. Thanks for taking time to answer my questions.
Where are you at the moment, how was the day until now and how’s the weather?
I live in a small village located at central Finland. The day was sunny and clear, +10 celcius degrees warm. Some spots of snow still on ground, but they are quickly disappearing.
What do you like most on the roguelike genre? Do you have a favorite RL?
I like role playing of course and replay value from randomness. My favourite RL is Nethack.
Do you believe that role playing can be done better in roguelikes or in more classical RPGs?
I think role playing experience could be made deeper but at the same time non-restrictive. The restrictions come from balancing between character classes. I don’t believe in those restrictions.
You are developing the roguelike Kaduria. Its website states the game will be finished in 2 years. This statement is sarcasm, isn’t it? How is the state of re-coding so far?
It’s very good, because it’s mostly object oriented now and much easier to maintain.
When will you release a new public version?
It’s hard to say. It depends on so many things that are still unfinished.
When and why did you start to develop Kaduria?
I guess the project has seen several starts so to speak. In general the project began at 1995 and the reason I started to make it was just to create something like Nethack, but with easier gameplay. The newest start was a couple of months ago when I installed Visual C++. It's a great developing tool! I never realized how much it would matter to have a proper developing tool.
Do you speak of the latest version? I agree that Visual »whatever« 2005 is the best IDE Microsoft has yet released, and indeed one of the best tools in general.
Yes.
Do you have any advice for new developers who just start a RL?
Learn good programming skills. It took me really long time to realize that I was a poor programmer. I try to be a better one each time I write code.
If one has a look at Kriceland, your personal website, one gets to know you as damn creative person. Your output seems to be very high; just two days ago, for instance, you uploaded another of your several guitar music mp3s (which are actually rather good). Additionally, you draw, you paint, you write. So – where does this need for total expression arise from?
I would say I’m an artistic kind of person. When you are an artist you don’t have a choice, you must create stuff all the time.
Is programming Kaduria art, too? Could the game be seen the same way one could watch your drawings or read your texts?
No.
And a rather dumb question: A clich???? says that finnish people are always sad and therefore drink much beer. Is this true and influences this your art?
I don’t drink alcohol at all, but it’s true that finns are sad and depressed people. Maybe I should drink beer a lot, too.
By reading some of your postings on r.g.r.d, not much leads to the finding that »Krice« is active on so many different fields. Instead one gets the impression you wish to behave as troll, or as a person who enjoys to neglect many things going on in r.g.r.d.!?
I’m a half-troll.
How do you see the roguelike community, in relation to creativity, individuality or self-awareness?
It’s important to know there are people like you. Even guys like me feel somehow connected to that bunch of people who share the same dreams. The most important thing in life is to realize you are not alone.
Why did you change your real name to Krice on r.g.r.d?
I believe Google Groups asked for a nickname and began to use that for newsgroup posts.
You once stated that there is a lack of innovation in new RLs. Which topic should be covered?
The secret of a good game is small things done right. It’s all in the details and in the way of always trying to make something better than what already exists.
What does »Kitara, hevi ja naiset« (the title of your blog at blogspot.com) mean? What is your blog all about?
It means »Guitar, heavy (music) and women« and it’s about those three things. I also have a personal web diary, but I wanted to talk more about guitars and playing them etc. and of course about women. Or in my case lack of them.
What do you do in »real life«, when not being creative?
Not much. I’m all creative person. I work as computer assistant for six hours per day, but I call that »a distraction« which sadly takes six hours away from all the fun of making roguelikes. Occasionally I go to gym and pump iron. It’s good to have some physical activity so your brains can rest for a while.
Roguelike Languages.
JavaScript
(by Glenn R. Wichman).
The column »Roguelike Languages« introduces several well-known or not-so-well-known programming languages in which somebody can write a roguelike. It is assumed that you already have some basic knowledge about programming techniques.
Introduction
JavaScript is a language specifically designed for dynamically controlling elements in an HTML document. When you move your mouse over an image on a browser page, and the image changes, you are seeing JavaScript at work. Although it may not be the first language you would think of for writing something as complex as a roguelike game, JavaScript is a surprisingly versatile language, and it does offer some unique advantages.
As the name implies, it is a scripting language; it is not compiled to machine code, rather the source is interpreted by the JavaScript interpreter each time your program is run. Its name would also imply that it is somehow related to Java, but this is not the case. JavaScript is no more related to Java than csh is to C. That being said, there are things about JavaScript which will look very familar to the Java programmer. The syntax of the language is similar to Java, C or C++. JavaScript's String, Math, and Date objects have similar behavior to the equivalent Java classes.
Netscape/Mozilla’s JavaScript and Microsoft’s JScript are technically two different dialects of a language called ECMAScript, but it is safe to just treat them as a single language.
JavaScript is a Turing-complete programming language. It is a loosely typed or »duck typed« language. Variable types are not declared, but are set by implication based on the value that is assigned to the variable. If you assign a value of a different type to an existing variable, that variable’s type will change accordingly. The types are number, string, object (which includes arrays and maps), and function.
The syntax of the language allows for procedural or object-oriented programming, or a combination of both. Although you can create objects in JavaScript, many of the facilities normally associated with OOP are not supported by the language. There is no direct syntax for such things as inheritance, method overloading, method overriding, etc. That being said, the language is flexible enough that you can achieve the equivalent functionality without much difficulty. JavaScript is not multithreaded. It does have garbage collection.
You might expect that a language written specifically to run in a browser environment would have some rich networking capabilities. But until recently it was painfully difficult to write JavaScript code that communicated directly with a server. A recent innovation to JavaScript is called AJAX (Asynchronous JavaScript And XML). Basically, it is an object that allows JavaScript to send POSTs or GETs to web servers, and receive an answer synchronously or asynchronously, without reloading the browser screen. This small innovation has greatly enhanced JavaScript's usefulness as a language for writing rich clients in multi-tier applications. Even though they call it AJAX, you don't have to use XML as your data interchange format. JSON, or JavaScript Object Notation is a great format for sending information between a server and a JavaScript program. Any JavaScript object can easily be serialized and deserialized to/from a JSON string. JSON parsers are available for most common server-side languages.
Trying it Out
Of course, the thing that really sets JavaScript apart from other languages is that it operates within the environment of a web browser, and its purpose is to manipulate the elements in an HTML page. The HTML page is represented within JavaScript by an object called document. You will generally use both HTML and JavaScript together to define your program. User manipulation of HTML elements (like buttons, links, or text boxes) generates events which become the input to your JavaScript functions. Those functions can then add, remove, or change elements on the page to create the output of your program.
There are JavaScript IDEs and debuggers available on the web, but all you really need to start using JavaScript is a text editor and a browser. You can place the JavaScript code directly in the html file, or separately in a .js file that is referenced from the html. As your program gets more complex, you can divide into many .js files. (You may want to concatenate all of them into one file again when you deploy your program; you will save a lot of overhead when the user visits your page.)
Different browsers handle syntax errors in your JavaScript in different ways. If you forego a JavaScript debugger, Firefox’s JavaScript console will give you the clearest information about your errors. Firefox’s parser is more forgiving than IE's, so make sure you test your program in at least these two browsers.
JavaScript for Roguelikes
As mentioned at the beginning of the article, you might not think of JavaScript as a good language for writing a roguelike, and there are indeed a number of challenges that it presents. But there are also a number of advantages that using JavaScript will afford you.
First, the challenges:
1. There is no console to output to. There is no equivalent of a curses library for JavaScript. Output is accomplished by manipulating HTML elements. While this can be used to great effect, it is a very different paradigm from console output; you will have to change your way of thinking.
2. As a scripting language, JavaScript is slow. For much of your program, this will not be an issue, but you will have to be very careful writing computation intensive functions to be as efficient as possible.
3. If you want to add sound to your game, JavaScript is a bad choice. For some reason, there is no built-in support for playing sound files, and the makeshift solutions that are available do not work well.
4. JavaScript has no access to the operating system. For example, you cannot open, read, or write files with JavaScript. Which means …
5. Options for saving games are limited. Of course, most any roguelike will need a save game feature (see Saving Games below).
6. You can’t hide your source code. In order for your program to run, your JavaScript files need to be read by the browser, which means they can be read by anyone who comes to your website. There is no object format for JavaScript files. There are JavaScript obfuscators which will make your code harder to read (and smaller).
So why even consider JavaScript? Here are some reasons:
1. JavaScript is free and you already have it. There is nothing you need to download or buy to start using it.
2. JavaScript is an easy language to learn and use. There are plenty of resources on the web to show you how it's done, and many examples that you can look at for ideas.
3. Your game will have the widest potential audience. Anyone who has a web browser installed on their computer (which is just about everyone with a computer) will immediately be able to play your game without having to download or install anything.
4. Players will always be playing the latest version. If you find a bug, fix it, upload the fix to your website, and you are done. You don’t need to get patch releases out to everyone who has the game.
5. You can track your game’s popularity. Most likely, your website already gives you statistics for how much traffic each page is getting. You can use this information to see how many people are playing your game. With a little work, your game could use AJAX to communicate additional statistics; you could track which monsters are doing most of the killing, which level is the most vorpal, etc. 6. A browser is a very rich user interface engine. Creating your GUI in HTML can be a lot easier than a lot of the GUI tools available for other languages.
7. If you want to write a multi-player, client/server roguelike, JavaScript, with AJAX and JSON, is an ideal technology for creating the client.
Saving Games
One nice feature of JavaScript is the easy serialization and deserialization of objects. This makes creating save information, and restoring from that information, quite simple. However, persisting that information to long term storage is a bit trickier.
There are a couple of different strategies for saving and restoring a JavaScript game. The most straightforward is to use cookies. A cookie is a text string that a browser uses to store information on a client machine, associated with a particular web site. You are limited to 20 cookies total for your domain, and each cookie must be at most 4K. So in theory, you could save up to 80K of data in the browser. Another option is to use Ajax to communicate to a CGI application on your web site that will save the game there. This is of course more work, since you will have to write a server-side application, for example in PERL or PHP. Additionally, this means that everyone's saved games will live on your machine instead of their own.
Summary
In spite of its weaknesses, you will find JavaScript to be very flexible, easy to use, and a lot of fun to play with. It is quite possible to create a full, feature-rich roguelike using the language. Then you can immediately share that roguelike with all of your friends, even the ones who don't have the same operating system as you do.
Coding.
Visual Engine Sharing
»Coding« aims at beginner level developers who have basic knowledge of their programming language of choice and are now at the first stages of creating a roguelike. The articles, although incorporating the subjective view and – in no means perfect – programming style of the author, point out some general issues which could seem to be difficult and try to show simple methods of solutions to these issues.
What You Should Know
In order to follow my explanations, you should know, at least in theory, how SDL works (i.e. that is uses so-called surfaces to represent bitmaps and window contents). I also expect you to know the very basics of programming, i.e. that you are aware of variables, constants, functions, loops and conditions.
The Quest
You have an idea, you have time, you already have coded the first couple of lines and you want your game to run on a wide range of systems. Your target audience consists of roguelikers and players of classical RPGs. Therefore you want ASCII output for the former and graphics for the latter. What should you do to achieve this goal?
One way was to maintain two different branches of your game, with different sources, completely parted from each other. One branch could use the curses library for console output and the other branch could use SDL for displaying graphics.
Another, probably better way was to let both versions share the same code base, write routines for both display modes and just create two different binaries at compile time.
A third way, and the way described in this article, was to only create one binary for both modes and decide at runtime which mode to use.
One Output Function – Two Display Modes
The goal of this article is to show that the use of an abstract output function instead of basic functions provided by a library makes the programmer’s life much easier. Using FreePascal, we will develop a basic output system which will be capable of showing single characters, strings and tiles.
The concept is very easy. By using the chr() function, we can access characters of the extended ASCII set, i.e. all chars with a code higher than 127. With 255 chars in total, we have 128 chars which can be used for other purposes than just displaying letters. We will use these characters to display graphical tiles in SDL mode. In console mode, chars higher than 127 will be »remapped« and shown in other colors, depending on our needs.
We will create two basic functions:
CharXY (intX, intY: Integer; chLetter: Char): Boolean; TextXY (intX, intY: Integer; strText: String): Boolean;
Whenever we need to output a character or a graphical tile, we’ll use one of these two. TextXY() does nothing special, it just calls CharXY() so often as needed for displaying the complete string. The »magic« is done in CharXY() itself.
The Universal Function
Have a look at the following code:
FUNCTION CharXY (intX, intY: Integer; chLetter: Char): Boolean; VAR TilesetRect, ScreenRect: SDL_RECT; intColor: Integer; chTransformedLetter: Char; BEGIN // set the result of the function to true CharXY:=true; // check if a valid character has been given to the function IF (ord(chLetter)<32) OR (ord(chLetter)>254) THEN CharXY:=false; // if the character is valid, process it IF CharXY=true THEN BEGIN IF blUseSDL=true THEN BEGIN // ** SDL output ** // get the correct character out of the tileset surface TilesetRect.x := (ord(zeichen)-32) * TILE_WIDTH; TilesetRect.y := 0; TilesetRect.w := TILE_WIDTH; TilesetRect.h := TILE_HEIGHT; // calculate the output position in the SDL window ScreenRect.x := intX * TILE_WIDTH; ScreenRect.y := intY * TILE_HEIGHT; ScreenRect.w := TILE_WIDTH; ScreenRect.h := TILE_HEIGHT; // copy the character to the screen SDL_BlitSurface(surTileset, @TilesetRect, surScreen, @ScreenRect); END ELSE BEGIN // ** console output ** // default color for all chars < 127 (used for text) intColor:=white; // transform chars > 127 (these are the graphics in SDL // mode) into chars < 128 and change the display color IF ord(chLetter)>127 THEN BEGIN CASE ord(chLetter) OF // closed door 128: BEGIN chTransformedLetter:='+'; intColor:=darkgray; END; // opened door 129: BEGIN chTransformedLetter:='\'; intColor:=darkgray; END; // wall 130: BEGIN chTransformedLetter:='#'; intColor:=lightgray; END; END; END; // Use a VidUtil function to do the curses output TextOut(intX, intY, chTransformedLetter, intColor); END; END; END;
To understand the function, you need to know the following facts:
- We use JEDI SDL for accessing SDL types and functions.
- The content of the SDL window is stored in the surface surScreen.
- Our tiles are saved in a bitmap stored in the surface surTileset.
- The constant TILE_WIDTH determines the width of a tile, e.g. 32.
- The constant TILE_HEIGHT determines the height of a tile, e.g. 32.
- FreePascal offers several color constants we can use in our game.
- For accessing curses, we use the Video unit.
- The TextOut function is provided by the VidUtil unit.
- We have a global variable blUseSDL to determine the output mode.
Now we’ll have a more detailed look on the algorithm. First of all, we declare some variables. The SDL_RECT data type is a simple record, containing four integer elements. The values of these elements are coordinates and the record is an easy way to pass the values to various SDL functions.
After declaring, we check if the character that has been passed to the function in chLetter has an ASCII code between 32 and 254. If the value was lower or higher, the function would exit and return false.
If the character is valid, blUseSDL is evaluated to determine if SDL or console output should be used.
The SDL Part
If SDL output is desired, the function now copies a rectangle from our tile bitmap in surTileset into the window surface surScreen. The copied area contains the character or tile with the ASCII value of chLetter.
The bitmap with our tileset consists of at least 127 characters, aligned from left to right, without spaces, sorted from the lowest to the highest – like pearls on a string. The first 95 tiles (number 32 to 127) contain letters, ciphers and special chars and are used for text output. Everything after tile 95 (beginning with ASCII value 128) is used for graphics.
If you now want to draw a wall tile somewhere on the screen, you just need to know the ASCII number of the tile which depicts that wall. In the picture above and in the example source, this number is 130 (normally shown as ‚ character, but here »overridden« by a graphical tile). With this number you can simply call our function CharXY (15, 10, chr(130)); – note that we do nothing more than using FreePascals standard Chr() function to display a graphics on the screen. Rather easy, isn’t it?
A Virtual Console Window
The x- and y-coordinates used in the function call (here 15 and 10) refer to a matrix in which every cell contains one letter or tile at a time. It works like the 80????25-matrix of a console, but the actual size of every cell depends on the size of the tiles you wish to use (in fact, the cell size is the same as the size of your tiles). The total number of lines and rows in this »virtual console« depends on the width and height of your game’s main window.
If your window size was 640????480 and your tiles had a size of 32????32 (like in the example source), you would get a »resolution« of 20????15. If your window size was 800????600 and your tiles were 32????32, the available size was 25????18. And if your window size was 800????600, but your tiles had a size of 10????20 (as seen in LambdaRogue), the resulting space was 80????30.
The Console Part
Although displaying tiles that way is practical, the main advantage of the function is its ability to create console output as well. If UseSDL is false, the SDL part will be skipped. Instead, the branch after the first else will be executed.
Basically this part could look very easy, as it does not need to translate an ASCII code to a bitmap graphics. So it could just display chLetter. However, the output that is done here needs to have the same meaning as the output that would be done by the SDL part of the function – if ASCII code 130 stands for a closed door, both SDL and console output have to display a door. As there are many conventions in the roguelike genre how certain objects are symbolized, the standard character with that value can’t be used. So we have to do an intermediate step.
In this step, we use a case construct to evaluate the ASCII code of chLetter. Then, we use the variable chTranslatedLetter to store an alternative letter; in the example this is a +, easily recognized as closed door in nearly every roguelike. When the translating from the original character into the new character is done, we yet change the color of the following screen output, using one of FreePascals predefined color constants.
Finally, we call the TextOut function that accesses the console:
TextOut (intX, intY, chTransformedLetter, intColor); .
Displaying Strings
For the sake of completeness, the other function, TextXY(), shall be shown, too:
FUNCTION TextXY (intX, intY: Integer; strText: String): Boolean; VAR i: Integer; chStr: Char; BEGIN // set the result of the function to true TextXY:=true; // go through the string char by char FOR i:=1 TO length(strText) DO BEGIN // extract one char from the string chStr := strText[i]; // display the character; if this makes any // problems, set the result of TextXY to false IF CharXY (intX+i, intY, chStr) = false THEN TextXY:=false; END; END;
For displaying text, you will most likely use this function. Calling CharXY() directly will be mainly needed for dungeon output routines or functions that show »special effects«, like flying missiles or magic.
Remarks and Problems
Constrictions
If a developer decides to program his output in a way like shown here, he may feel constricted after a while, especially concerning the maximum number of available tiles. As the functions expect ASCII tiles (for showing texts) and graphical tiles (for showing dungeon features, items and creatures) to be in one bitmap file and as the maximum value the chr() function can handle is 254, he can’t use as many tiles as perhaps desired. Instead, he has to confine himself to a limited amount of tiles or (which would be the most logical reaction) adjust the functions to his needs.
It is, for example, possible to add a parameter intSubset that is used to switch between different parts of the bitmap. The calling function then has to care about the correct value of this parameter, and TilesetRect has to contain the correct part of surTileset, depending on intSubset.
The console part of the function also has to regard intSubset. This will of course complicate the, currently rather clear, case statement. In this regard we have to address another issue – the hard-coding of the different »translated chars« and their colors.
Hard-coded chars and colors
Doing so is not optimal. Instead, the chars and the colors should be read from a data file. This file would assign one ASCII value, e.g. our 130, to a character and a color. The function then would be much more flexible than at the moment. Such an assignment could be look like this:
[130] char=# color=lightgray
You might have recognized the format – it’s the one used by older Windows versions and (still) by several programs for .ini-files. Of course any other format, e.g. XML, will do just fine.
The file could be read into an array (textual color constants in the file had to be typecasted into integer). The data type of that array would be a record with two elements. The declaration in FreePascal would be:
TYPE ColoredChar = Record chChar: Char; intColor: Integer; END; VAR MyTranslatedChars: Array[128..255] of ColoredChar;
With such structures you wouldn’t need the case statement any longer. Instead, you would just write:
chTransformedLetter := MyTranslatedChars[ord(chLetter)].chChar; intColor := MyTranslatedChars[ord(chLetter)].intColor;
This is way cleaner than to hard-code all possible characters and color combinations into a function whose only job is to bring these chars on the screen.
No OOP?
As you have seen, there exists a global variable blUseSDL. This might be criticized. This was mainly done to make the example code easier. The same goes for the lack of object oriented programming. It is rather easy to think of an object that represents the game window and to implement CharXY() and TextXY() as methods of this object. A valid call could then be for example
MyScreen.TextXY(2, 2, 'Status of '+TheAvatar.strName+':')
– not very complicated at all.
Two Modes – Different Screen Sizes
Finally, I want to address an issue related to window- and tile sizes. The basics were already covered above, but out of these basics a problem is born which can lead to strange results if not handled properly.
You probably want to use a standard resolution, e.g. 800????600, for the SDL mode of your game. If you now use the described functions to output text, chars or tiles, all will work fine until you accidently use a coordinate out of range.
This can happen very easily if the SDL window offers more rows or columns than the console mode. If you don’t think about this and e.g. use a CharXY(20,27,'T'), in a 80????25 console your game will crash with an access violation.
To avoid this, you have several options. You could just stop to use rows greater than 25, but in SDL mode this would cause a fairly large amount of unused space (perhaps this could be filled by a nice background texture).
You could also check intX / intY and automatically decrease these values if they wouldn’t fit the screen. This method is used by LambdaRogue, but it may be confusing.
The best way was to use tile sizes which translate perfectly between two modes. To have no overhead of rows and columns, you might have a look at the following overview:
Window Size Optimal Tile Size 640????480 8????19 800????600 10????24 1024????768 12????30
These sizes, of course, are very uncommon. Most available tilesets come in squared sizes and editing them would need as much work as creating a completely new tileset. However, if you don’t want to use graphics, but use a virtual (SDL) console, you only need tiles with letters, ciphers and special chars. Such tiles can easily be created with every graphics editor. Just open a new file in your desired size, select a font and adjust the size of the font to make all characters fit into the center of your file. Create all files you need and copy them into one single bitmap. This bitmap is your tileset.
Summary
This article described one way to combine SDL and console mode in one binary, without needing to recompile, to maintain different versions or the need to always select the correct output mode. In fact, the function was planned to be as easy as FreePascal’s console-only function WriteXY(). If implemented in a unit, it can be used again and again as the basis for the screen output of your roguelike.
However, there are also some traps and problems, and the article discussed the most important of these issues – together with possible resolutions.
I guess that there are already similar approaches taken by other developers, but I saw the need for a clear description of the basic principles for »newbies«. Hopefully reading this article was somewhat helpful.
Directional Player Character Facing
Essential For All Modern Roguelikes
by ABCGi
There is always a lot of debate, endless it seems, about what makes a roguelike (RL) a RogueLike. With continuing development in this field by various hardy groups of coders (see newsgroup: [[rgrd|rec.games.roguelike.development] for some of them) there is perhaps a contemporary version of the old question: »what makes a modern RL«?
This finally might be the place to say a modern RL has graphics in at least tile form. »RL Purists« had good grounds to argue a traditional RL has text graphics only and one should imagine the red »a« as an ant. The modern RL question is different enough to accommodate those »RL Progressives« more fairly.
A modern roguelike?
Lets take a look at a quick list of »what makes a modern RL« from features common to many newer RLs these days. As with any such »flavour« list it is perpetually incomplete and a modern roguelike does not have to satisfy all conditions to qualify. (see note: 1)
* Tile graphics or better (e.g. H-World with very pretty isometric customisable graphics) * Sound (e.g. DoomRL great use of atmospheric themed music and sound from Doom including MP3s). * Monster inventory (been around for a while). * Small command set (not always but often). * Easier interface options (use of the mouse and menus and other handy ideas). * Faster paced gameplay (e.g. CastlevaniaRL is a fast paced RL). * Non classic gameplay (various examples of weird and wonderful ideas particularly during the 7DRL (seven day roguelike) competition. * Custom RPG systems. * Moddable (leveraging things like Lua to allow users to script their own functionality). * Open source (or other availability of code). * Larger more ambitious worlds and features. * Themed RL games based on some pop culture (e.g. DiabloRL). * Use of randomly generated plots and game worlds to add spice. * Not just one dungeon, usually an outdoor area and several locations to visit. * Ports or versions for mobile devices and other uses of latest technology. * Party members and pets that you can control. * Multiplayer and net based play. * Innovation of gameplay (extra features added on top of the traditional RL gameplay). * Special features (a modern roguelike will often have one or more features not seen in usual traditional RLs). * More playable (less time needed to look up keybindings or monster lists etc).
Note that we don’t get into the nitty gritty yet of things like permadeath which cause heated debate. Some gameplay elements are still timeless – although one could argue there is less permadeath in modern RLs. We will leave debating of what are the modern gameplay choices for a modern RL to the newsgroups. Now to move onto one important barrow to be pushed by this article …
Advantages of directional player character facing
The title of this article claims that directional PC (player character) facing is essential for all modern roguelike. Modern RLs are defined by what is currently being produced but they also need to be pushed by vision and visionaries (aka ShockFrost the brave! [rgrd in joke]). A step forward in gameplay for all modern RLs, this article argues, is the inclusion of directional facing for the PC and monsters consistently in all modern RLs as though it were as obligatory as squares to move on.(see note: 2)
This means the player faces a particular direction and can only »see« in that view cone – and the same goes for monsters. This adds a dimension to RL gaming for both the player and developer.
Monsters can sneak up behind the PC. The PC can sneak up on monsters too and more easily tell that they are »behind« a monster. Backstabbing is an obvious feat/skill to flow from this. Hearing can play a larger role with a detected sound showing a »?« behind the player indicating s/he can not see the monster but did hear it. Feat/skills relating to hearing and sneaking follow this. Seeing through keyholes and cracks are examples of possible extensions that can be added to this base by inventive developers.
Since modern RLs now feature graphics it is easier to represent the direction that the PC and monsters face. Some fun for coders in adding another layer to their LOS (Line Of Sight) algorithms and on screen representation – how to show the squares the PC can actually see at any one time as opposed to those that are lit and unlit. There are implementation options for movement/vision rules governing how the PC and monsters turn around, how long it takes in game time, and whether they can walk backwards or face directions they are not moving in (e.g. Ikari Warriors style). Possibilities abound for atmospheric and spooky settings as they also do for tactics such as ordering your pet to sneak up behind the monsters or performing distractions.
Conclusion
I hope you can see that the directional facing concept epitomises the progressive nature of modern RLs. As can be seen above, such concepts add a new dimension of interest and fun for gamers and also some novel opportunities and challenges for developers. I hope to see this feature and other such innovation became part of the stock features in all future RLs!
Go code. Go play.
Notes
1 The reader may be interested to know that the feature list is in the order of which they occurred to the think-tank assigned to produce it for this article (i.e. Slash and the author of this article).
2 The author realises that:
* There are examples of facing features out there already. * Moving on squares is not strictly necessary for a RL. * That a lot of conjuncture in this article is possible, as it always is with such RL issues, and the author chooses not to muddy the »message« by covering all caveats but invites debate.