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,291
I realized that the multilist routine is recursive. So.. yeah, I'm going to completely rewrite inventory routines and remove endless recursiveness from it. Then it's going to have I guess normal container routines that doesn't allow containers inside other containers. When it's done I can write new item selection routines. It's not hard, this game just has made it way more difficult than it should be and this is one way you can hit a wall during the development of the project which no doubt happened in this case.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Or.. I could in fact keep it recursive, just figure out how to write a better routine for it. While I was writing item save & load I found out that the 'type' of item is the "main type", and the 'group' is sometimes set same as type, and sometimes it's used for weapon groups, as it should. Items are 'typeless', because the type doesn't point to static data or refer to the individual "type", rather the data is copied to each item instance. For the sake of clarity it would be smart to check out how/when 'group' is actually used and reserve it only to weapon groups etc.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
The group and type was more complicated than I thought. In the item data 'type' is the main type and group sometimes refers to the index of the item data, or some kind of special type. But, in at least some function parameters 'group' is actually the type, and 'type' is the group... yeah... not joking. But this is a somewhat easy fix, just use better naming. I decided to replace the confusing 'group' with 'subtype'. I think it's a better name at least compared to 'group'. Now 'type' is the main type (weapon, scroll, etc.) and subtype is the type of item (bow, sword, etc.) or it's something else depending on the item type. It's still 'typeless', because the type is not always same as the index of item data.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Inventory's main routine is basically the only unfinished large feature, but then there are those 100+ notes I've left in the source code, so lots of small fixes. But it's "soon" ready to compile and run. Then the real development begins.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
After 1+ year of development I finally hit another (second) checkpoint in source monitor and it almost seems something is wrong... LOC went from 35684 to 16422 and number of functions dropped from 608 to 140. Then again amount of classes went from 7 to 80. I don't recall accidentally removing any important parts from the game and even the file count has increased from 99 to 134 so it seems right. Did I really refactor out that many lines of code?
 

vlzvl

Arcane
Developer
Joined
Aug 7, 2017
Messages
191
Location
Athens
After 1+ year of development I finally hit another (second) checkpoint in source monitor and it almost seems something is wrong... LOC went from 35684 to 16422 and number of functions dropped from 608 to 140. Then again amount of classes went from 7 to 80. I don't recall accidentally removing any important parts from the game and even the file count has increased from 99 to 134 so it seems right. Did I really refactor out that many lines of code?
Nice to see someone using Sourcemonitor... Actually, instead of checking LOC, is far better to check metrics such as "Avg Stmts/Method" and "Avg Complexity" over time, do regular refactoring on those monstrous functions and compare those kiviat graphs between checkpoints to see how good is the refactoring. The classes increase is definitely a good sign but if the complexity was increased to beginner level, the decreased LOC wont do you any good..
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Avg Stmts has decreased from 8,3 to 6,6 and complexity from 7,80 to 4,72. Not sure what it means. Anyway, since I was so close at compiling I decided to comment out the inventory routine and also learned that if a struct has constructors it can't be used to initialize structs inside structs unless there is a constructor for that I think. If you remove all constructors it's ok... weird. After fixing tons of linker errors (somehow there still were differences in declarations and definitions of functions) it ran and... crashed. Seems like it can't initialize 'stdscr' of curses which probably means the pre-compiled pdcurses I downloaded from some shady web page is not working, or it's not the same architecture as the game itself. I think I'm going to try something extremely difficult: compiling pdcurses from source in Windows.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
The old pdcurses could have worked, but I compiled a new one from the source. It was easier than I thought, but I did write a quick help file to include in the game for Windows users like myself... The missing thing was #define PDC_DLL_BUILD you have to use before including curses.h if you are using pdcurses.dll (dynamic linking).

When it finally ran there were some problems to fix. First I couldn't see most of the texts, because my_printf had no output. Then I noticed that keyboard commands in Windows are different than in the original version, so I had to undef and define some critical commands like Return and Backspace keys. For some reason Return is 10 in curses, not 13 as you would think. It's also defined as KEY_ENTER which should be the keypad enter, but nevermind. Then the game crashed, because current level (c_level) was not set when entering a dungeon. After that it crashed, because item's material was not set. This is the constructor problem I was talking about and it looks like some values are not set for all items, because the item creation routine is let's say procedural. But I can fix that by clearing all variables in the item_def::clear().
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Well, in fact the material was set, but I had not finished item_def::clone() which makes a clone of the static data of items. I think if = didn't copy the data then each item was using the actual static data (pointed to it) and items changed that data randomly. I bet it could have been confusing. I wasn't yet able to see the gameplay, because the next crash came from a monster trying to wear an item, but since its location was outside map it crashed. What I learned from programming Kaduria was that you can never predict the index value to a terrain map (or any array), so it's easier to check it before accessing the map with get/set routines. The index will be outside the map in some cases, there is no way you can control it. The terrain map is in level_type (this is the level class, the name is just confusing) class so map access refactoring could be a smart move.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
It was working for a while and I got into the gameplay! For some reason you can't move (arrow keys don't work), but more annoying bug is that message routine seems to break the message data somehow. When I changed some things the item bug returned so I assume it's some kind of bigger problem with memory leaks etc. Not fun to fix. I don't know, somehow I imagined everything would work and life would be magic.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
The item bug was easy to fix: the number of items in each type (armors, weapons, etc.) was determined by counting the amount of entries in the data. But, there has to be an empty entry at the end of each list and guess what was missing from most of the lists. Interestingly it doesn't crash when you check the size of the list, only when the entire entry is outside the number of actual items which is strange, but I guess it's some kind of padding at the end that prevents the crash in the first case. I also fixed the message displaying bug and just like that it works. Movement keys are keypad numbers with num lock on, that's why arrow keys didn't work. It's still missing the inventory routine, but I think this is the right time to take a break and check out my other projects.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Working on save/load game and it's almost done, needs save/load (serialization) for some classes. I spent a lot of time to refactor monster and player's x, y location to the base class, because previously both had their own member variables. The message routine still doesn't work, I think I'm going to rewrite it, it's quite messy. I'm planning to make this a variant with a new background story and one new feature related to the story. The only thing that scares me is asking the permission to release this from the original author.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Message routine is fixed and I also added a debug message routine with its own message log so that debug messages don't pop on player's messages and you can better keep track of problems indicated by debug messages. This game really needs more debug routines, the next one I'm going to code is a summary of things created in the level so I don't have to wonder where everything is. Even though the inventory routine is still missing I feel positive about this project, it's getting easier to understand how it works.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Writing a debug list for rooms was useful, now I don't have to wander around, it's easier to find stuff. The room system of this game is I would say advanced for its time and I can almost see the ambitious plan he had for it. Shops are already (almost) fully working and they look great.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
The first optimization didn't seem to speed up a turn that much, but then again it was not that much faster and just feels better I guess. Previously the game was checking if the player was inside a room by going through the room list, then checking if the player was inside a room rectangle. I changed that by creating a 2D gameview array that has information about each tile, like the room id of the tile. If it's bigger than -1 it's a room, pointing to the room array. Rooms are copied in the gameview when another level is entered, since the gameview is shared for all levels, I think it's better that way, no need to store a gameview for each level.

The speed seems to be anything between 800 to 20000 microseconds during a turn, but usually something like 3000-5000, using a regular Intel i5. I think the slowest part is Curses/terminal actually, because the terminal in Windows is ridiculously slow for whatever reason (=Microsoft).
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
The game freezes sometimes which seems to be a result of buffer overrun. I suspect it is the level's map data 'loc', a two-dimensional raw array. In my experience trying to use valid index for a raw array is difficult, if not impossible. It's way easier to check the index. It's slower, but doesn't really matter during the gameloop, because it's only used with game object movement. There are 292 references to loc, so it's somewhat tedious to rewrite, but not impossible and you can write member functions in level class to make the code cleaner. I'm also going to use a flat array with x, y notation rather than "reverse" y, x. If I understand the code correctly the game doesn't use 0,0 location (row and column) of the level, rather coordinates start from 1, 1. Well it wont make any difference, you can live with it.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
I decided not to change the 2-dimensional [y][x] -style level array, but try to restrict access through member functions mainly. At this point I'm trying to clean up the source code for release, but it's going to take couple of months I guess. But for a strange reason I like to work on this project, even it is quite a mess. With my experience it's easy to understand how this project got out of control and was abandoned. One way I'm trying to gain more control is slowly merging player & npc routines into one when they are using the base class data.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Tile class for the level map is something I'm going to fix, because it has data for doors and traps per each tile. It means I have to write a game object classes for doors and traps, maybe for stairs also (not sure). The tile class or 'cave_type' looks like this:

Code:
struct cave_type
{
    int16u flags;    //CAVE_... -values in caves.h, generic data of a tile
    int type;        /* room, corridor, shop etc.. */
    int sval;        /* secret door level etc...*/
                    //for staircases, doorfl is the staircase number (or some kind of direction)
    int8u doorfl;    /* door flags, see doors.h for DOOR_... -values */
    int trap;        //trap type, zero (TRAP_NOTRAP) if nothing
    int trap_st;    //trap strength/damage value

    void clear_trap();
    void initialize(int tt);
    void jam_door();
    void random_trap(int tt);
    void stairs_down(int8u number);
    void stairs_up(int8u number);

    void save(Tar_Ball &tb);
    void load(Tar_Ball &tb);
};

That 'sval' is not actually for secret doors, it's a counter value for a jammed door. 'doorfl' is also used for stairs, but it's some kind of direction(?) as I wrote in the comment. I try to add comments for every data member in a class when they are missing or not updated. When doors and traps are objects you don't need to store empty data per each tile and you can also add features without bloating the tile class.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Great minds think alike, the first debug message (in case something goes wrong) is from this project and the second is from Teemu:

Code:
        /* update level with opened door */
        door_open2closed(level, dx, dy);
        return DOORSTAT_SUCCESS;
    }
    else
        msg.newmsg("Paska", C_RED);

---

    if (Position_Outdoors_Room(fr, way::North)==false)
        t_debug->Creation_Message("Kana kakkasi.");
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
I went back working more than one project at a time and I like this kind of project more than "actual" game development.. in a way.. For this I'm working on stuffing most of the code in classes and also creating a class design documentation to better figure out how this game is supposed to work.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Trying to think how to implement dungeon generation. I think the Level class can become a bit large if you just stuff dungeon generation in it. You could also inherit from the Level class to something like Create_Level class that has generation routines, but they would not be part of the base class. Or you could create a class that has the level as handle, but doesn't inherit from it. I think this works more in cases where the "place" of routines is not well defined. For example you could put a routine like Open_Door in both level or creature class, because the creature is opening the door, but the door is in the level class. That's exactly what I'm doing for (some) actions, to make creature/player classes less crowded:

Code:
struct Action
{
    level_type *level; //in what level the action happens
    Actor *tonttu; //who is making the action
    int msgno; //points to current message in doormsg[]

    Action(level_type *luola, Actor *elf)
        : level(luola), tonttu(elf), msgno(0) { }

    bool Is_Handle_Stuck(const Coord &c); //check door handle

    int Close_Door(const Coord &c);
    int Open_Door(const Coord &c);
};
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
After some hours of coding the level generation is now in Genlevel class inheriting from level_type which is the base class now. Some generation routines are still procedural, but I think it's fine. Room generation is procedural in roomgen.cpp and then there are some generic terrain routines in randgen.cpp. After refactoring level_type is 751 lines and Genlevel is 551 lines of code so they are not huge. The only thing left is the outworld generation which looks like it's better to refactor as a class, because there is a large raw array and it has no index protection I guess. It may be the (or one) source of memory corruption problems. I don't understand the outworld generation algorithm, but hopefully I can get it right when making it memory safe.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
Still trying to find the source of memory corruption. It works in strange ways, for example some keyboard commands point to completely different command when you try to assign a new keyboard code for some new routine. The "weird" thing is that it doesn't seem to crash the program. It could be a local problem with the keyboard routine which has an array of command data with a function pointer to a routine. Thinking about rewriting it removing function pointers, so the command routines don't have to be void type and without parameters. Also the command reading routine is using strcat which I guess is a notorious source of bugs.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,291
After rewriting keyboard commands it still doesn't work, but I think it's not a memory corruption bug but some kind of internal wiring of curses and/or windows console which means some keyboard commands simply refuse to work. Ctrl+V is one, also Ctrl+A seems to do something weird like trying to select the characters in the windows, but it stops at the player character for some reason. Since Ctrl+A is select all it's probably hardwired to the console or something. So, I just switched to another keyboard combination and it seems to work. I tried to find "reserved" keys for curses but didn't find anything, the "manual" for (pd)curses is hilariously bad. I guess they never planned Ctrl+ keys to be used in the program itself?
 

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