Putting the 'role' back in role-playing games since 2002.
Donate to Codex
Good Old Games
  • Welcome to rpgcodex.net, a site dedicated to discussing computer based role-playing games in a free and open fashion. We're less strict than other forums, but please refer to the rules.

    "This message is awaiting moderator approval": All new users must pass through our moderation queue before they will be able to post normally. Until your account has "passed" your posts will only be visible to yourself (and moderators) until they are approved. Give us a week to get around to approving / deleting / ignoring your mundane opinion on crap before hassling us about it. Once you have passed the moderation period (think of it as a test), you will be able to post normally, just like all the other retards.

Banana Rogue

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
I found an old source code for Advanced Rogue from 1985 and began to rewrite it for a modern compiler. Most work comes from changing old C function "list" parameter style to "new" style with parameters inside parentheses, but there are some surprising finds also. One of them is 'when' keyword used in some switch - cases as some kind of optional case-keyword. It could be some kind of old keyword even internet doesn't remember, because I didn't find any information about it. As if it never was a C keyword. Maybe the source code itself is from a parallel universe and it just slipped here for some reason? The name Banana Rogue is a project name, because you have to give the derived project some other name than 'Advanced'.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
That 'when' was just a macro that combined break;case so there is no need to write break. I think those macros are going to be removed, at least that one. This kind of project is almost fun compared to working with a project that requires content. For example I've been mostly fine tuning the source code structure in my roguelike project Teemu, because it's pesky to add/fix missing content.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
One of the strange things is that there are no header files for most c files and functions. It must have been somehow possible to call functions without declaring them first. Rogue.h has some declarations in form of function name without any parameters the actual function has. Most of the work this far has been recreating header files for each c file. Great fun.

I think this kind of source code archaeology is nice, because if you know enough about programming you can understand the decisions programmers made back then, when they didn't know concepts like data-driven or OOP. Procedural code with global access to lots of stuff also underlines the difference to OOP which is the style I'm using in my own projects. I'm too old to "fight" about paradigms, in fact both styles have their pros and cons. The "distribution" of complexity is also interesting, because these old roguelikes didn't care a lot about dungeon generation, there are like only couple of functions for that where in my lightweight roguelike Teemu there are 11 .cpp files with more than 20 classes for level generation routines.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
Something weird is happening with Code::Blocks (or more like gcc). I guess it thinks the source files are C, even the project was created as C++ project. I need to check it with Visual Studio. I'm planning to replace curses with SDL2, because it's the library I'm using in my other projects. It's possible to keep the old functions and hide SDL2 in the implementation, so if someone wants to replace SDL2 later it will be relatively easy.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
Much easier to work with Visual Studio, because it's showing errors as red dots in the side scroll bar thingy. Most files are just a continuous red line... But most of the errors are missing header files and things like TRUE, FALSE and NULL which need to be replaced. There are some harder problems like function pointers. I never used them myself, but I think they could be fixed with same type of function signature.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
Most missing functions are part of curses. I think there are some functions that are not needed as such like clearok and touchwin, but to get things work it's better just write empty functions for those and see what happens. I'm not sure if you need clearok, it seems to clear a window. It may be useful. Some routines seem to add a character without x, y location (or y, x as it in this game) so each window has a cursor location. This is actually how I'm doing it in my projects as well even they are graphical. It's easy to have a cursor and when you add some text or letters you don't have to pass location every time.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
The function pointer "thing" in daemon is interesting, because you can't force it through C++. It has an object (struct) which has data for function pointer etc. The parameter data is int, but none of the functions have int parameters. Most functions have no parameters passed, but there just had to be two that has one parameter (not int). I guess C allows the parameter list of function pointer to be whatever you want, but in C++ everything has to match. To make things worse, those structs are stored in a list (there are two lists). It's not impossible to fix, nothing is, but it's going to be a bit pesky at least.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
12 files (of total 38) compile, there would be more but rip.h has an array with LINELEN size which isn't defined there. I'm probably going to replace that struct's hard arrays with std::strings. It would be really useful in many places, but the first priority is get this to compile and run. Function pointers are making me crazy, the "option" module has also those. And on top of that option has get_str which I think is used to input a string, but it's also storing something to option data?
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
I think this project failed, because I stopped at those function pointers. The problem is that C++ can't handle them, because 'void' in C can take random number of parameters! It's crazy how it works. I could actually stuff this one to github, although I rage deleted github for Visual Studio because it reset project files in one of my other projects. But you could exclude project files from repository and possibly keep it together. You can of course remove all function pointers and replace them with something else, but it's quite a task.
 

Bester

⚰️☠️⚱️
Patron
Vatnik
Joined
Sep 28, 2014
Messages
11,089
Location
USSR
Upload it to a repo.

Who made this game, was it even ever released?
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
Who made this game, was it even ever released?

Readme says Michael Morgan and Ken Dalka, but there are other names as well. I think those guys have now died in old age, so there is that. I guess it was released, there were versions based on Rogue. I have continued working on this with VS C++17. It's giving a whole new set of errors, but I think this is my idea of "fun". One thing I'm going to do before uploading this to some repo is fix all const char issues with std::string. Also it makes sense to replace old school C style string code with std::string, because it removes tons of possible bugs related to C style string handling, and it makes the code cleaner. I'm going to create a new source file / module for text handling alone, it doesn't exist yet, all text handling is in some random source files.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
The source code will also look much better when you rearrange functions to more logical files. For example there is no rpg or level/map files in this game, everything related to those are in random files. There is some kind of attempt to use logical file names, but in my opinion it fails more than often. I can understand it when you want to quicky add something and in C it didn't matter, because you didn't need to declare the function, it was visible in the whole project.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
Funny example is player.cpp which now has only four functions and no data at all. Those functions are cast, eat, steal and sense_gold. Magic stuff can be placed into specific modules for magic and the rest goes into some kind of action module. It means player.cpp can be removed which is kind of weird if you think about typical implementation of player character. But in this style of code the data is so dispersed it makes the player as data "disappear" into the procedural code.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
I've began to break down rogue.h which has most of the stuff in it, like macro definitions etc. This is something you don't need to do if you just want to compile the project, but I think it does make it easier to understand what actually is in the project. It is always a good idea to make things more "modular", even in C code. The original structure is based on functions (=actions) of gameplay and the way data is stored is quite random, it's all over the place, but mostly in rogue.h. It's certainly a different kind of concept compared to C++ and classes.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
Another interesting thing is how dungeon generation is not in any specific file or files, it's everywhere. But that can be fixed, too. Now that I have worked on this for a while I'm beginning to get a better idea what is going on. Still, the "daemon" system is quite weird with those function pointers, but if I can understand what it is trying to do I can rewrite it.
 
Joined
Jan 14, 2018
Messages
50,754
Codex Year of the Donut
One of the strange things is that there are no header files for most c files and functions. It must have been somehow possible to call functions without declaring them first. Rogue.h has some declarations in form of function name without any parameters the actual function has. Most of the work this far has been recreating header files for each c file. Great fun.
"C/C++" is a bit of a meme, C has quite a few quirks that are missing in C++. This is one of them. Pre-ANSI C(the language as described in the first edition of K&R) didn't even have function prototypes.
Calling a function that hasn't been declared yet creates an implicit declaration. The function returns int and takes an arbitrary number of parameters, the programmer handled it and was very error prone. Any modern compiler will give you a warning about it because it's almost never what you want to do and exists solely for backwards compatibility.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
Funny thing is that I now use procedures in my C++ projects, because I think they are easier to write when you have some kind of "linear" action, like most game commands. It's partly because I've been working on this project and noticed how procedures work. C++ is really good at data+objects, but the generic structure of program ("actions") can get quite defragmented. Anyways, the more modular style in this project is starting to get in better shape. Sometimes it's not that clear where something belongs, but usually it is. I would probably already upload this to git, but I rage quit it (when Visual Studio's git suddenly reset VS project file) and really I don't like git at all. I don't even like the guy who created git, Linus.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
The project has now 102 files from which only 14 doesn't compile. The problems are in function pointer functions, because most of them don't follow the function signature, but give random number of parameters (not possible to compile in C++). Then there is pick_one() function which returns magic_item object type, but it's constantly assigned to int, also not possible in C++. If the int data is just plain int (who knows how it works), then it's possible to make it return int, which is simply an index to list of object data. Then there is state.cpp which is 2400 lines of suffering in old school C style save game routines. But it could be replaced entirely with modern approach. The rest of errors are mostly calls to output routines that don't exist, they are a bit easier. Almost forgot, there is also options.cpp with its own function pointers (for whatever reason), but it could be quite easy to fix.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
I'm still trying to figure out "daemons" and options. I think options will be easier, because it's only storing and getting options. The project has now more errors (in 16 files total) because VC includes variables that are not initialized. This seemed to happen often with C when you had big functions, sometimes the variable was initialized in some condition, but not always. I'm probably going to just delete previous save/load routines after looking at what it is saving, then write a new one from scratch. Again, I don't think it's going to be super hard, because it's simply saving the state of the game (or rather the program).
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
The options were working kind of funny way. They were taken from environment string which is old way (actually, I think it's coming back in Windows 10 which is becoming more like linux) of storing data in a computer. Then it's parsed and copied into an array of structs which has function and data pointers that point in global variables for options. Both environment as storage and that array will be replaced with a class that holds data for options, but I'm still going to "parse" them into those global variables at least for now.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
Both "daemons" and "fuses" make some kind of sense now when you just read the source code. They use delayed_action struct which has a function pointer to functions in daemons.cpp. Daemons are permanent actions while fuses have a timer and when that timer is done a fuse is removed and the function pointer is called once I guess. They are used in various random ways, for example the player's stomach functionality is a daemon so they are somewhat like a feature attached to a creature or object.

My plan for these is that I try to keep the function pointer style if it's possible, maybe using C++ functors or stuff like that which I don't know that much about. I did already replace static arrays with std::list, because it makes much more sense. I bet there were problems when the max values for daemons or fuses ran out. I think there is nothing wrong with function pointers and if I wanted to replace them it would require some kind of enum list with actions linked to their functions and a gigantic switch-case (or even worse, a virtual class hierarchy).

Well, there is a switch-case in save/load game routines which seems to indicate that the function pointers need to be saved as integer values and when loading, replace them with corresponding function, so there is that.
 
Last edited:

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,319
I did keep function pointer style for daemons and fuses, but I wasn't clever enough to create a generic routine for them so I just wrote routines for function pointers that required a parameter. Luckily there are only two functions of that kind, for 'thing' and 'object' struct parameters. The difficult part was that function pointers were stored into a list item which didn't take only one type of function pointer so for them I wrote a class hierarchy with virtual dispatch. It does compile, but I'm not yet sure it works 100%.

Another idea I had was to break rogue.h into pieces, because in old days people used to stuff everything into one header file (for the entire project). However it would be a lot of work for no good reason so I have changed only some parts of it. The right way to proceed is CppCheck: with it you can find shadow variables and stuff like that which will reduce the amount of subtle bugs you had with traditional C style.
 

As an Amazon Associate, rpgcodex.net earns from qualifying purchases.
Back
Top Bottom