Labyrinth Quest - A text-based roguelike

I’m new to this site and game development in general, but I’ve been working on this pet project of mine (in between highschool classes) for a few months now. I plan on it being a quirky rougelike adventure that can be played completely in any terminal. So far, this is the work I have to show for it: ( All criticism welcomed! :stuck_out_tongue: )

Hey and welcome! Really intresting and goob job so far!

I just took a quick look at your code and could give you some hints what i found noticeable:
This feedback is depending on a quick look, so I’m sorry already in case I misunderstood anything or did not read correctly.

1. Packages
If you take a look at
I can see that you are not using any packages to divide the classes of your game. You have all your stuff under lq. I’m not sure where you want to go with your game but I only can recommened to use some packages to divide your game into small parts. This will help you a lot to keep track of your game structure and your code when your games grows. Right now it’s totally fine but keep in mind that your codebase will increase if you want to add new functionalities and your code is not structured very well it’s hard to maintain. You could for instance create a package with items, actors, engine/game.

I also saw that you are using a lot of protected attributes, there is no point in using procted attributes if you have no packages. Also clean code often suggests to not use protected variables for various reasons:

2. Attribute and Class Naming
I’m assuming you are developing this game by yourself and not in a team, but naming is really important in development. When reading your code I was a bit confused by your class names for example, if you are planning to work in a team intuitive naming of everything is really important. I had to do some research what you mean by LQ, LQCLI, LQIS, LQOS, pop, etc.

3. Switches
I’m seeing that you are using a lot of switches, eventhough they might be okay sometimes I’d usually try to avoid them. Especially in the cases you are using them. Let’s take this method for example:

    void addEnemy(int positx, int posity, String ene_type) throws IOException
            case "rotter":
                for(pop = 0; CUR_ENES.containsKey("rotter" + pop); ++pop);
                CUR_ENES.put("rotter" + pop, new Rotter());
                CUR_ENES.get("rotter" + pop).spawn(CUR_ENES.get(
                    "rotter" + pop).SYMBOL, positx, posity);

You did something similiar with Items for example. So each time you create a new item or enemy (same with removing) you need to adapt your switch case. This might result in a really, really long switch case depending on where you are planning to go with your game. You maybe should consider working serialisation and deserialisation, meaning you store the information for enemy and items not directly in your code but for instance in a .json or .txt file. This will help you to adapt stats, add and remove objects.

4. Readability / Logic
If we take a look at the following:

 static void outDMG(String name, String dmg_name, long dmg)
        System.out.printf("\n\u001B[1m%s\u001B[0m: used %s, "
            + "\u001B[31m%d damage dealt\u001B[0m\n\u001B[32m---", name, dmg_name, dmg);
    static void outDia(String name, String dialog)
        System.out.printf("\n\u001B[1m%s\u001B[0m: %s"
            + "\u001B[0m\n\u001B[32m---", name, dialog);

I’m assuming that you wrote these methods by hand? This is aiming at the same spot as my advice with naming, switches packages etc. Keeping your code maintainable through intuitive naming and a good structure. This code is really, really hard to read and to maintain. I’m guessing these are colours or something? Me as an outstander of your project only has a little idea what it is about but it really looks confusing.

another thing is:

class Lucas extends Movement

This is counter intuitive as well for me. I’m assuming Lucas is the protagonist of the game? But why does he if he is the hero of the game extends Movement? That would mean he is childtype of movement, not the protragonist. Maybe you should consider using an interface called Moveable or extending him from a class named MoveableGameObject or something. Again if your code bases becomes bigger such things might be confusing. Same thing for Weightend? Why does it extend Movement?

Abstraction of your classes is really important otherwise you will get lost in too many classes if you are trying to add a new feature.
Think about your game structure. What objects does my game contain? Are they really a child of some sort of other objects?
This for example would make much more sense to me:

Lucas extends Player implements Moveable extends GameObject

Ofcourse this feedback depends on where you want to go with your game. If you are planning to finish the development as soon as possible and keep it rather small that’s totally fine. But if your codebase gets bigger make sure it’s maintainable this will ease the development a lot.

In addition this is only my humble opinion. I’m not that experienced myself but I’m sure one of the more experienced guys here could maybe correct me or give you some better more suitable advices. Also I just took a quick look at your code. As well keep in mind that game released with bad code is still better then a game which is not released at all. Gamedev is hard and finishing and releasing a game is major undertaking. Keep it up and don’t mind asking me if you have any questions :slight_smile:

PS. I just saw you are using a .txt file to keep track on your todos, that’s good! Maybe you should consider using a real tasktracker if this helps you. Something like trello.

Thanks for the help! I’ll definitely try and implement some of the advice you gave me in my code. My aim with this project isn’t so much as to push out a game as it is to learn the ins and outs of Java as well as the conventions that come along with it. Don’t get me wrong though, pushing out a game is always an added bonus :wink:

As we talk about conventions… you should accustom yourself to properly “break;” your switch statement blocks. Many of them are not, and w/o having more insight to your code I can only assume that’s a bug in most cases.

This means to:

  • “break;” every case, even the last one. If you add another case, and forget to adjust the now-not-last-anymore block, you are in trouble
  • if the fall-through case is intended, I prefer to leave a comment at the place to remind future-me or any other passer-by about it
  • the only exception is if the block ends with a return statement -> the break only adds visible noise in this case