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.

Legend of Saladir remake

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
So, a while ago I learned that the original developer of an ancient roguelike project Legend of Saladir had released the source code. It's not open source per se, but I downloaded it and began to tinker anyway. For those who are too young to remember, Saladir was one of "those" roguelike projects which we all had at that point. Everyone tried to create the next major roguelike, which today is not a thing anymore.

This project is interesting in the source code level, because it seems to be a quite complex game, but it had some problems the developer was unable to solve for some reason. For example he tells that the game is slow, because for FOV the game is looping through every list of everything that affects the fov. Which is strange, because you can easily fix that by using a map for fov values or something like that. Another interesting thing about the source is that it's using classes (it's in C++) and it was not that common in 1998 (the last release date I think). There are also procedures and the use of classes is in many ways incomplete which is typical even in today's programming when people don't know how to use OOP.

Just as with Advanced Rogue, I've tried to work on this to compile in Windows and C++17. This I think is going to be easier than Rogue, because the problems seem to be specific mainly to file handling (linux style) and const correctness with strings.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Fixed const correctness issues and added _CRT_SECURE_NO_DEPRECATE for Visual Studio, because it doesn't even compile if using sprintf etc. without it. It looks like the source code has been touched after 1998 and it probably is according to github file dates. There are some newer C++ stuff, but only a little bit. The project has total 99 files with 47 .cc files. 35K lines of code. Only 7 classes, but of course it has lots of structs. 608 functions. So it is more like procedural style. In comparison the current version of Teemu has also 35K lines, but 237 classes and 93 functions, so it's more OOP style. 35K is not overly large project and it does look like this game is not ready, but an unfinished project with some detailed ideas like weather and bodyparts.

Only four files have problems with compiling, mainly for old style file handling. The way old programs did file handling was that they often directly saved bits and structures to disk without any type of container ideas.

There are also lots of bugs reported by VS and CppCheck. Buffer overruns, pointer issues etc. the usual suspects.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Thinking more about it, I guess the original developer must have been quite young in 1998, then it all makes sense. After all I'm probably one of the oldest from The New Wave of Roguelike Developers. I was 24 in 1998, I remember it well because I went to study animation and in fact became an animator in paper at least. I never got any jobs related to it.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Save and load routines use some kind of linux invention with a number id for file which isn't compatible with Windows, so I decided to replace them with my "tar ball" system which collects data to a string. There are only two classes using index saving outside file.cc, so it was easy to rewrite them. Now the only thing that needs refactoring is file.cc which also has save/load game routines. There are some fopen functions elsewhere, but since VS seems to compile them ok, then it's fine. In fact I'm also using fopen etc. to save and load in Tar_Ball. It seems to be the standard C option in both linux and Windows (at least without specific file flags you see in linux code). As a side note this project suffers from "typeoiditis" which is using all possible types and even renaming them (sint, int16u, int32s etc.). There are number of type conversions in result of that. What I do in my projects is I'm using only int, char and double (sometimes float). You rarely need to use unsigned types for example, maybe for something like RGBA data but that's it.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Think I'm going to butcher the file system in file.cc for Windows at least. I don't like linux style where the program is in different (root) directory than data. This is also creeping to Windows with some programs saving data to users/username/etc. and whatever goes there is never removed. If you look at the file.cc you can understand why linux people can't have nice things. I try to keep the old code for linux, but it's probably impossible to keep the shared parts. However I think it's going to be easy to refactor back if someone, somewhere in time, decides to do that.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
The savefile has a rather old convention of saving each level file to temp, then concatenating them to one save file and there is also a compression routine for it. I think it would be viable to remove that temp file stage and keep all levels in memory, then save them directly to a file. But first I need to figure out what the game is saving to save game and how nagivation between levels is done. Again, this turned out to be more complex than I thought...
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
And then there are the manual C style linked lists, I think they are just too much trouble along with the fact how they are used. It's likely that the structure will become easier to understand once the list routines are refactored to proper container classes. Also in this project it makes sense to break up some monolithic files to smaller ones for stuff like enchantments, materials etc. since they do have their data structs. That way they become more like user defined types they are and you can use things like constructors for more safe initialization.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
This became much harder when I decided to replace most instances of global text buffers that were used in sprintf-routines etc. Using sprintf (with shared buffers) is not that bad, but I wanted to use more std::string anyway. Another big problem is how inventory routines work, but they too can be replaced.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Text stuff is almost replaced. I got a bit frustrated for a moment, but after working on some other projects and back it doesn't seem impossible. Inventory routines and equipment are mostly what is left to fix, and textview which is working in funny way, because it's always loading stuff from files, either from existing files or first creating them and then loading. Inventory is going to be rewritten a lot, because it's more complicated than it should be which in inventory handling is quite bad thing.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Inventory routines are slowly starting to make sense. I'm replacing confusing inv2inv -routines with simpler, more descriptive routines like drop_item which moves the item from inventory on ground etc. and the way object duplication is made is simpler I think. I also made a container class for monsters. Sometimes the combination of procedural and class-based code looks ugly, but it can be improved later.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
When I get it to compile I'm planning to put it on github, but it's probably going to need a permission from the original author. Much like Abura Tan this project was abandoned before it was ready, so it's difficult to say how to proceed. I certainly have some of my own projects to finish as well, but this is quite fun anyway. It's interesting to work on someone else's project.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Cleaning up inventory routines. There is one difficult routine to fix and it's the multilist-thingy, but if I remember it correctly it's just creating a list out of items in inventory based on type of item etc. What I'm also going to add is a factory class for creating objects. I find it makes thing easier to follow when you know where objects are created.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
When you refactor something it's in some cases easier if you read (try to understand) the original source code, rename function/variable names and add comments. Even if you replace it later with something else, like a class implementation. This is what I have to do with the multilist routines, because the use of lists is quite confusing I think. In this type of situation you always wish the original author would have added a comment about what the code/function/etc. is trying to do. I guess I'm no better than anyone in that, because it is a particular skill to write good comments.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
I had to create a base class (Actor) for monsters and player, I just couldn't watch that madness anymore. It will make save/load easier and maybe later also some routines can use the Actor class handle rather than setting up pointers for monster or player depending on who it is. But until that I think the base class works in a way that the old code doesn't even notice anything, since the base class is just a part of both 'being' and 'playerinfo' classes.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
There is a big roadblock in refactoring Actor, because 'being' is using 'monsterdef' as part of it, which is also static data for npcs. The naming is kind of wacky though, monsterdef is for higher class npcs (shopkeepers and special npcs) while 'Npcrace' is data for basic monsters. This is one of the parts where static and dynamic data are mixed, I've noticed some other places, too. It's never a great idea. Even if in this case monsterdef is a dynamic copy of static data. It is possible to use monsterdef in the base class, but I think at least stats (int, dex, str..) would then have a copy in the statpack array. Also, everything player has related to monsterdef would have to be refactored, because player has copies of those.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Scoreboard of this game seems to be complex for whatever reason. I don't yet know how it works, but it doesn't just show a list of best scores. That would be too simple, it's doing something else as well. Maybe I'll just remove all that and create a normal score list. The sorting rule include time and moves, I guess it makes sense if you get the same score, but with less time or moves, it's better. I'm thinking about changing the name of this game, because it's already a bit different with all the linux file system code removed.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Scoreboard (the original) created a list of scores and then a list of scores for the current player based on the name of the character. I guess it could be related to some kind of shared scoreboard over some kind of network (again, a wild guess). Afaik there was no check for the size of the scoreboard so in theory the score file would have no other than system file size limit. Well I removed all that and restricted the score size to 100 scores. Rewriting was quite easy, I just removed almost everything and copied some code from Teemu. Later I refactored dice.cpp which is the random number generator, it was also easy, because these days you don't have to code RNG yourself, you can use std::random_device for that. Luckily there was no need to rewrite user functions, only the internal implementation of the rng.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Trying to figure out how to refactor World class for navigation between levels. The structure is simple, it has a Dungeon structure with main entrances and each contain a list of levels. One of the problems is that both Dungeon and Level data have static flags for things like if they have been visited. This means that the game was designed to run once, then exit, because the static flags are not cleared manually elsewhere. I think it would be nicer to separate dynamic data for world and use static level data as actually static (or const in terms of C++) data. So, rather than using static tables for navigation I'm going to create a list (or vector) of locations as nodes.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
World class is now ready except for saving and loading, but adding it is easy and it was one of the main purposes of World class. Levels no longer have temp files, they are stored in the memory. Next refactoring target is file.cpp which mostly has old savegame routines that can be removed.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
I took a detour to refactor monster and player classes, because then it's easier to save that data. Mainly by moving more stuff in the Actor, a base class for both monsters and the player. The hardest part being the monsterdef data that was "duplicated" in player class with separate variables for some of the exact same data. I think even couple of member functions make the code much cleaner and more abstract (by not using variables directly from monsterdef), but I try to keep the original procedural code in place as much as possible. It's always possible to refactor it to classes, but it's just more work.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,322
Inventory routines are the only unfinished feature (to get the project to compile). I think the way to fix them is just understand how it was supposed to work, because if you try to rewrite the old routine directly it probably doesn't work. The "multilist" selection routine is quite a thing to behold and to figure out how it works is a bit hard. But in a nutshell it lists items based on some filters and you can select one or more items, but in the middle of the routine it's changing lists in creative ways I yet have to decipher.
 

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