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.

Kaduria

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
I'm in a process to design level themes and in that I thought it would help to write "design docs" for them. Since I've been talking about one of the themes earlier in my blog I can share the design doc for that level I guess.

Snow Top

Outside level located at top of the mountain. It’s a large mesa with surrounding walls thick enough to house number of cave rooms. It’s divided into two main features; in the south is a large permanently frozen lake with underground ice labyrinth. The second feature is a smaller mesa located at north side. It’s called “Top Cap” and it’s a level accessible through an ancient lift built along the wall by dwarfs. The surrounding wall area has round rooms inside and sometimes side of a room sticking outside. They are connected by narrow corridors. These round rooms have been long since abandoned and they were built by unknown people, “the ancients”. With rooms and corridors there are a number of hidden passages and labyrinths that lead to hidden rooms with remains of ancient culture. Some of them have been found and robbed; others are still to be found.

At the north side of the lake is a small watchtower. It’s very sturdy and in good condition, being repaired many times. It has a large door barred from the inside. Inside the watchtower is a hatch covered ladder leading to “Frozen Lake Labyrinth” level. The labyrinth can be also entered through a hidden, snow covered chasm located somewhere on the lake, but without a rope the player will fall into the labyrinth, taking some damage. The watchtower is easier to enter by falling into the labyrinth and then climbing up the ladder in the tower. The fourth entrance is the stairs down into the long corridor that connects this level to the main cave system.

Between the lake and walls there is some space for snow covered forest and it’s where the “guardians” of this place live. They are large, white and furry primitive humanoids who throw snowballs and sometimes rocks at the player. Despite their large size they are scared of the player and don’t attack directly, but will stay away and use throwing as their major attack type. There are also other types of creatures, mostly the kind that live in cold, snowy environment. The player can possibly avoid guardians by entering cave rooms where they will not follow.

This level doesn’t have any special items. It’s a passage type level to reach Top Cap and Frozen Lake Labyrinth.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
I have created a new list for "note:" items that were the source code. They kind of get buried there so I removed them from the source and made a list. There is a also a list for bugs which are simply "unknown" issues. The list of bugs is actually quite small (for most developers who work on a project of this size), there are only 12 open bugs. The issue list is a bit longer, it currently has 64 open items (two of them fixed!) which I'm going to show you to give some kind of idea what I'm doing at the moment. I try to fix at least one per day, in those days I'm programming Kaduria (I don't do that every day).


64. Herb_Data - affect data
63. Container::Create_Item_List - ordering has to be built-in for indexing to work
61. controls::get_modifier - check this
60. U_Gadget::Dig - messages to damage routine?
59. Game::Create_Character - race data may be needed for update menus
58. Game::Play - check avatar lifetime
57. Game::Play - check use of windows_quit_flag
56. Gen_Level::Load - check flat data of terrain for loading
55. U_Humanoid::Throwing_Roll - combat type doesn't work (location)
54. U_Item::Kick - check return value and flying
52. Item_Data - scythe and billhook frames
51. Items::Get_Description - add text data
50. Items::Is_Better_Weapon_Than - ordered list or pre-calculated
49. Items::Get_Currency_Value - how to determine
48. Items::Get_Food_Affect - add for edible items
47. Items::Get_Weight - weight calculations
46. Date::Advance - could also advance with number of last turns
45. U_Object::Damage - material messages
44. U_Object::Destroy - pass location or some other place to clear the map
43. Level::Jump_To_Stairs - check location set for any issues
42. Level::Add_Target - new target system
41. Level::Autopickup - check removing of items from level list
40. Level::Is_Visible - should get from gameview?
39. Level::Fly_Item_To - check distance calculation
38. Level::Handle_Opener - skill requirement data
37. Level::Caution - what is this
36. Game_Message::Determine_Message_Pool - fix location problem
35. U_Npc::Kick_Something - get target, not object
34. U_Npc::Throw_Item - get throwing force
33. U_Npc::Select_Command - lots of fixing here
32. U_Npc::Get_Bodypart_For_Spikes - use body configuration data
31. U_Npc::Pick_Up_Item - check return value -1
30. U_Npc::Unchecked_Put_Item - check this routine
29. Jug::Jug - capacity
28. Object_Level::Create_Shatter_Items - possibly make a routine in material class with bigger debris as well
27. Combat::Projectile_Hit_Roll - check the class of this routine, is it a right place?
26. Room::Herb_Garden - finish this
25. Room::Treasure_Chest - check if traverse works
24. Sequence_Level::Create_Rooms - get room coverage data from level theme
23. Sequence_Level::Create_Special_Rooms - check
22. Sequence_Level::Fix_Corridors - check this, entirely
21. Shape_Level::Draw_Dynamic_Light_Spot - unreachable code, not used at the moment
20. Basic_Stat::Clamp - check how often this changes
19. U_Terrain::Smash - make actor possible a mover
18. Tile::Random_Plant_Object - check climate condition
17. class Tile - formations, plants etc. are missing
16. Traps::Give_Trap_Type - determine trap types for different object types
15. Traps::Give_For_Gadget - determine traps for gadgets
14. Trap::Activate_Trapdoor - trap messages
13. class Object_Id_Generator - check use of this
12. Dungeon::Load - check avatar's instance creating
11. U_Door::Reveal - how to implement?
10. Container::Store - item sorting
9. Bodytype::Seek_Bodypart - get closest bodypart
8. Bodytype::Get_Floor_Touching_Bodypart - get for specific body type
7. Rugsack::Rugsack - more random / data driven distribution of starting items for creatures
6. U_Avatar::Build_Something - remove items from level
5. U_Avatar::Use_Digging_Tool - dig shifting of items, how?
4. Automap::Show - temp data change in debug functionality
3. Asset_Manager::Asset_Manager - accessory belt hit boxes
2. Anatomy::Get_Random_Fighting_Style - add styles
1. Affects::Inject - probably doesn't work, not sure
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
You know how annoying it is when you have a generic list of base class objects and you remove something from base class and now some of the list functions don't work. I was looking at the list class for a moment and then I quit the project and deleted it. In my dreams. In actuality I began to wrote a list for item objects, because they are a special case anyway. I guess the good thing is that when you have some kind of public interface as a buffer between raw list(s) and level class where objects are mostly handled then it doesn't break that hard, you just need to connect calls to new functions of the item list. This rewrite is buffering the ability to fix most of the issues in that list, because you have to run the game and check if something works rather than fix the code and hope for the best.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
It seems like the new list works, because the game runs (good enough). Rather than using base class in the list I created a class that wraps the handle of base class game object (U_Object) and then has couple of derived classes to handle more complex object types. One of them is a base class handle with coordinates, because you need those in some specific situations, in this case for stairs. They are stationary objects that still need coordinates and id for connections to work, because you need to know where to jump and how stairs are connected to each other. The new list is I guess more complicated, but if I've learned something it's that if you try to create a simple implementation it's probably going to fail. Just create a complex implementation that works. When you cast objects to derived types it can blow up in a spectacular way, but I've tried to prevent that by returning 0 from base class if you try to convert them to item or mover and the way items are added in a list are concentrated on two routines which determine the list item from the object type.

Code:
//Basic object to store in a level list, without coordinates.
struct List_Object
{
   U_Object *handle;

   List_Object() : handle(0) { }
   List_Object(U_Object *o) : handle(o) { }

   bool Is_Valid_Item_At(const Coords &c);

   virtual U_Item *Get_As_Item() { return 0; }
   virtual U_Mover *Get_As_Mover() { return 0; }
   virtual int Get_Byte_Size();
   virtual Coords Get_Location();

   virtual void Save(Tar_Ball &tb);
   virtual void Load(Tar_Ball &tb, int ot);
};

//Object's coordinates are stored with the object.
class Coords_List_Object : public List_Object
{
private:
   Coords stored_location;

public:
   Coords_List_Object(U_Object *o, const Coords &c) : List_Object(o), stored_location(c) { }

   Coords Get_Location() { return stored_location; }
   int Get_Byte_Size();

   void Save(Tar_Ball &tb);
   void Load(Tar_Ball &tb, int ot);
};

//Mover object's list item.
class Mover_List_Object : public List_Object
{
private:
   U_Mover *mover_handle;

public:
   Mover_List_Object(U_Object *m);

   Coords Get_Location();
   U_Mover *Get_As_Mover() { return mover_handle; }
};

//Item list item.
class Item_List_Object : public List_Object
{
private:
   U_Item *item_handle;

public:
   Item_List_Object(U_Object *i);

   U_Item *Get_As_Item() { return item_handle; }
   U_Mover *Get_As_Mover();
   Coords Get_Location();
};
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
There was also one thing I had to fix for game objects and it was a parameter for coordinates that was passed for each object type, but since it's no longer needed there were 13 constructors to fix (for each object type) and also 13 news for each type, because they passed coordinates. Coordinates weren't really used anyway, only doors had a weird call from Hide() to Level class which should be made other way anyway. A door is hidden by making its frame to 0 (transparent) and then a wall (or something else) is created on top of the door. When you work with proper OOP code often only constructors change, but if the public interface part is working as it should then things that change inside the class doesn't really matter. That's why this weird list change rewrite was quite easy to do and the rest of the code has no idea something changed.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
This far I've fixed 5 issues from that list. Today I've fixed two and my goal is one fix per coding session which could be a realistic pace. I'm keeping track of fixes with a date so I can see when I've fixed something and how fast I'm proceeding. The issues this far have been quite easy, but mandatory all the same. I try to be practical and do anything, even write as complex code as possible to find a way around some problem I have to fix.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
I can't write a routine that sorts items by item group when the group ordering is a custom list. It works when I'm using the actual order of groups. I'm looking at the values in the list in a debugger and I can't still figure out why it doesn't work. It's too simple, that's the reason. I can't understand too simple things.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
Fixed 4 bugs and 1 issue today already, not too bad. Everything related to inventory menu, but not yet the manual ordering of item types. Menus broke when I changed to index-type order for items, which means it finds the item from menu location. But this isn't as simple as it sounds, because menus can have less items than in actual list (when you choose some special items like tools etc.) and also menus have separators which are physical items in the menu's list, but not in the item list. Menu items need an index to the item list and working with all that is quite complicated, but now it works.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
Classes for level themes are an example where the complexity that is of object-oriented programming can take you:

Code:
//Deep caves are harder than natural caves and they come after market place.
class Deep_Cave : public Level
{
public:
   Deep_Cave(int id, int w, int h);

   void Theme_Creation();
};

//Basic cave type level.
class Natural_Cave : public Level
{
public:
   Natural_Cave(int id, int w, int h);

   void Theme_Creation();
};

//The dwarven mining site.
class Minetown : public Level
{
public:
   Minetown(int id, int w, int h);

   void Theme_Creation();
};
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
I think it could be interesting to monitor metrics in the last phase before first release. I haven't done it frequently, because it's not that important. I'm sure once a month is a good interval to check out metrics. What was a bit of surprise is that LOC is only 58K. I thought it passed 60K some time ago? There are 303 source files and 393 classes (I think it also counts structs as class). The source code is C++ and I'm using mostly OOP (classes) with some functions.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
I've been pretty stoked about the idea where I'm using procedures in "action" type routines. It's like creating your own C library that you use in class programming. Classes are obviously great for keeping data, both pod and lists of other objects, but when you are doing some action it can become quite fragmented in a weird way. Procedures can be called from everywhere and they don't break OOP if you keep it strict.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
I already have 10 files for procedures, but I think it's worth the minor refactoring. The "main" module of procedures is actions.cpp which at the moment looks like this:

Code:
void bandage(U_Humanoid *person, U_Item *i);
bool break_wall(U_Terrain *terra, U_Npc *actor, int breaking_type);
void build(U_Avatar *builder, Level *lvl, int bt);
void camp();
bool drink_from_watersource(Level *lvl, U_Npc *actor, const Coords &c, int srctype);
void examine_item(U_Item *i, const Rectangle &wr);
void examine_object(Level *lvl, const Coords &c);
void fill_flask(Level *lvl, U_Humanoid *person, U_Item *i, const Coords &c);
int handle_opener(Level *lvl, U_Npc *actor, const Coords &c, int style, int item);
void harvest(Level *lvl, U_Avatar *person, U_Plant *p, const Coords &c);
bool kick(Level *lvl, U_Npc *kicker, int dir);
void loot(Level *lvl, U_Avatar *person, const Coords &c);
bool pickaxe(Level *lvl, U_Humanoid *digger, U_Item *axe, int dir);
void play_instrument(Level *lvl, U_Humanoid *person, U_Item *i);
void read_scroll(U_Avatar *person, U_Item *i);
void search(Level *lvl, U_Avatar *person);
void shoot_item(Level *lvl, U_Npc *shooter, U_Item *ammo, int shootmode, int dir);
void stomp_kick(Level *lvl, U_Npc *actor, const Coords &c);
int use_key(Level *lvl, U_Humanoid *person, const Coords &c, int item);
bool use_object(Level *lvl, U_Npc *actor, const Coords &c);

With procedures you want to keep parameters simple, as consistent as possible and readable. This is not the full list of actions, some of them are in the Player class, but can be later moved in this module. Some of the actions are closely tied to Player class so moving them could result in stuff like accessing private data from Player's class. It's one of the "problems" when you are using procedures, but it's doable.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
The project has now 60K lines of code. It actually had that a while ago, but after I moved a lot of text data to external files from source files, it's now mostly increased in code. There are 402 classes and 174 C-style functions. It's close to what it needs.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289

Kaduria is a (hopefully major) roguelike game I've been developing since 1995. The style is still debatable, but probably leaning on survival and low fantasy style. For a long time people thought this isn't an actual project, and that I'm just posting about it for fun. Then I released Teemu (a small pirate themed adventure game in style of a roguelike) and I think at least some people now think Kaduria might be a real game project. I have also increased the roguelike-ness of Teemu, but it's became such a large project itself that it's difficult to finish the next version.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
Wish I had realized this before, but it makes sense to clean up classes from "action" code I was talking about earlier, by making actions procedures. In a way, using classes where they excel (=objects) and removing actions from them. I'm actually getting mildly excited, because some difficult tasks seems to become easier to write as procedures, like AI stuff for example.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
I think those procedures are just some kind of pattern in C++, but whatever. "Composition over inheritance" is just a meme. In OOP languages inheritance should be the priority, but creating good class hierarchy is a bit difficult in my experience. And, multiple inheritance is the hidden power of OOP, but at least in C++ I don't think many are using it. I guess component systems work, but I feel they do fix your suckage at OOP. If you can't create sane class hierarchies and use inheritance to full you kind of suck at programming.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
One of the things to realize is that paradigms are goot at something, but not at everything. In OOP the class is good at handling data, but the overall structure can be rigid and difficult to work with. Procedural C doesn't really have any kind of structure, so there is that, but without a class it's quite difficult to handle large amounts of data without getting messy. This realization is something I had after years of programming, but better that than never. Some people never figure it out. They pick their side and decide that functional language is the best for everything and linux is the best OS etc.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
The new strategy of finishing one issue before moving to another seems to work. For example I had this maze generation problem waiting in the issue list for months, but it took "only" 3-4 days to fix it when you just focus on that problem. I can't say I liked those days, but this was never easy anyway.

I've got some new motivation from that incident when I was permanently banned from Rogue Temple. It's just the way they did it. No explanation, just kick out a long standing member of the "community". Then again, they actually never were roguelike developers. Well, maybe some of them are, but not the mods. I would have been content if they would have told the reason to me in simple words. But they can't, because they want to have their SJW club without "negative" thinking about games that are nowhere near roguelikes.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
Out of curiosity, how playable is Kaduria at the moment? Is it further along the Teemu in regards to playability?

Depends what "playability" means, but it sure has more content. Both projects suffer from my inability to create a role-playing game system. With those they are pretty much both ready. Kaduria is still missing some dungeon generation, but I find it quite easy to do.

You got banned for saying racist stuff, and the mods probably didn't trust you to recognise or change that behaviour.

I didn't even realize it (and they didn't point it out), but maybe SJWs look at everything "suspicious" as racist. That's whay they do, everyone else is racist or some kind of bad person than them.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
Also, how did you organise your action functions before you changed to the procedural system?

Mostly it was Player::Eat() style. I haven't moved everything to procedures, only more complex routines. I guess sometimes it makes more sense to use object.verb style, like when you kick an object, there are virtual functions for object types receiving a kick + base class generic routine.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
Do you know what you want out of your role-playing system, or is the struggle programming related?

It's the design for sure. It's quite difficult to create a role-playing system without creating something like D&D. But I don't like the way D&D works. I like other aspects of role-playing games than working on numbers to get better experience levels, stats, items, whatever.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
The currency value issue is going to be somewhat difficult I think. It's one of the places where I refuse to use "plain" data for each item and one of the reasons is I guess that using more complex way to determine value makes it easier to handle data later if needed. Some items do have a "static" value like coins on which the economy is based. For rest of item types I'm planning a somewhat abstract value type which determines how much it will cost in a shop. Weapons and armour are going to be most expensive items. No 1000 gold coins for a loaf of bread, but something based on real history with copper/silver/gold coins. For example I read that in Rome you could buy two loafs of bread with one sestertius.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
I started a new project which is going to delay other projects for years I think... well, maybe not. But I had to try how it would work if you created classes only when needed and otherwise code in procedural C style. There are also other "rules" or things I'm trying to follow like not including anything else than library headers in header files. I want to keep the project itself a secret, because I feel like I'm oversharing my roguelike projects anyway (what is in them etc.). This one is not even going to be a roguelike.
 

Krice

Arcane
Developer
Joined
May 29, 2010
Messages
1,289
It's not particularly fun knowing that you have the correct amount of money to purchase an item, but not the correct change, so you cannot buy it. Even in D&D it's a pain. Alternatively, you could use a data type for currency, and have a function extract out the copper, silver, and gold values

The shopkeeper gives back change if you have only gold coins etc. The money you have is shown in worth of copper, you don't have to count it. If you have something like a diamond it could be even fun to find some kind of place (a bank?) to break it in coins while shopkeepers would not accept it as payment. I also like the idea that you could exchange things rather than use money to buy something.

If you're going down that route, why not program directly in C?

I want to know how many classes there will be if you try to avoid creating them, already has 5.

Is it still a game? An RPG of a kind? :)

It's a RPG.
 

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