C++ text game help

Started by
15 comments, last by Kitt3n 18 years, 5 months ago
I'm creating a text roleplaying game in c++, everything has gone quite good for a while now but i'm stuck right now. The problem is in the class "items". It's not the class itself but when I try to give every instance of the structures a value/values an error occur. Here is the code:

class user {
    class inventory {
      public:

        inventory() {
            total_items=0;
            used_items=0;
        }

        int total_items;
        int used_items;

        void add_item(int id, string name);
        void use_item();
        void show_items();
    };

  inventory inv;

  public:
    string name;

    // Player attributes and skill levels
    int hp;
    int level;
    int attack;
    int life;

    // The conclassor of the player class
    user() {
        hp=100;
        level=1;
        attack=1;
        life=1;
    }

    void inventory() {
        inv.show_items();
    }

    void pickup(int id, string item) {
        inv.add_item(id, item);
    }

    // A function that shows the player's current stats
    void stats() {
        cout << endl << endl;
        cout << "------------------------------- STATS --" << endl;
        cout << "PLAYER: " << name << endl;
        cout << "HP: " << hp << endl << endl;

        cout << "LEVEL: " << level << endl;
        cout << "ATTACK: " << attack << endl;
        cout << "LIFE: " << life << endl << endl;

        cout << "TOTAL ITEMS: " << inv.total_items << endl;
        cout << "TOTAL ITEMS USED: " << inv.used_items << endl;
        cout << "-- END STATS ---------------------------";
        cout << endl << endl;
    }

    // The function that saves the current stats in the dat file
    void save_stats() {
        ofstream save;
        save.open("save.dat");

        for (int i=0;i<25;i++) {
            cout << ".";
            Sleep(30);
        }

        cout << endl << endl;
        cout << "-- SAVE GAME ---------------------------" << endl;

        if (!save) {
            cout << "Could not save the game!" << endl;
        }

        string s_name = "PLAYER: ";
        string s_hp = "HP: ";
        string s_level = "LEVEL: ";
        string s_attack = "ATTACK: ";
        string s_life = "LIFE: ";
        string s_items = "TOTAL ITEMS: ";
        string s_used_items = "TOTAL ITEMS USED: ";

        save << s_name;
        save << name << endl;

        save << s_hp;
        save << hp << endl << endl;

        save << s_level;
        save << level << endl;

        save << s_attack;
        save << attack << endl;

        save << s_life;
        save << life << endl << endl;

        save << s_items;
        save << inv.total_items << endl;

        save << s_used_items;
        save << inv.used_items << endl << endl;

        cout << "Game saved succefully.." << endl;
        cout << "----------------------------------------";
        cout << endl << endl;

        save.close();
    }
};


class items {

// ##################################
// Item list

  // ######################
  // Weapons
      struct small_sword {
        int id;
        int damage;
        int speed;
      };

      struct medium_sword {
        int id;
        int damage;
        int speed;
      };

      struct power_sword {
        int id;
        int damage;
        int speed;
      };

      struct flash_sword {
        int id;
        int damage;
        int speed;
      };

      struct ultimate_sword {
        int id;
        int damage;
        int speed;
      };


  // #######################
  // ARMORS
      struct small_shield {
        int id;
        int armor;
      };

      struct medium_shield {
        int id;
        int armor;
      };

      struct high_shield {
        int id;
        int armor;
      };

      struct mega_shield {
        int id;
        int armor;
      };

      struct ultimate_shield {
        int id;
        int armor;
      };

  // ######################
  // General items
      struct key {
        int id;
      };

      struct healing {
        int id;
      };

      struct full_healing {
        int id;
      };

// #################################
// End of item list

// ################################
// ITEM ATTRIBUTES
// ################################

// SWORDS
//                                   id   power  speed
small_sword smallsword            = {1,   2,     2};
medium_sword mediumsword          = {2,   4,     3};
power_sword powersword            = {3,   17,    2};
flash_sword flashsword            = {4,   3,     16};
ultimate_sword ultimatesword      = {5,   14,    11};

// ARMORS
//                                   id   armor
small_shield smallshield          = {6,   2};
medium_shield mediumshield        = {7,   4};
high_shield highshield            = {8,   6};
mega_shield megashield            = {9,   8};
ultimate_shield ultimateshield    = {10,  10};

// GENERAL ITEMS
//                                  id
key key                           = {11};
healing healing                   = {12};
full_healing fullhealing          = {13};

// ################################
// END OF ITEM ATTRIBUTES
// ################################
};

For example: small_shield smallshield = {6, 2); If I edit it to: small_shield smallshield; without giving it a value, it works, if I edit every instance of the structures. Here comes the error message, I will paste a part of it. 7 start.cpp c:\documents and settings\xxx\desktop\game\classes.h:204: ANSI C++ forbids initialization of member `smallsword' 204 classes.h making `smallsword' static 204 classes.h in-class initialization of static data member of non-integral type `items::small_sword' 205 classes.h ANSI C++ forbids initialization of member `mediumsword' 205 classes.h making `mediumsword' static 205 classes.h in-class initialization of static data member of non-integral type `items::medium_sword' etc..... This is really frustruating, mostly because it shouldn't be any error because I did the same thing, almost, in the user class on the top. Anyways there shouldn't be anything wrong. That aside, what do you think of my code style, is it a good way to build a text based c++ game or does it just plain suck? took the opportunity to ask that while i'm at it :) Thankful for help... [Edited by - password on November 4, 2005 4:30:03 AM]
Advertisement
Sorry, but I cant really help the way you have your code pasted. Use this:
[ source]
//code
[ /source]
Ofcourse, remove the space in between the '[' and 's' and the '[' and '/'. I just did it for the tags to ahow, not the box.
-----------------------------....::::DRAGON BALL Z::::....C<<"+"<<"+"; // Go C++ !!!-----------------------------
Its hard to tell without the indenting and because its kindof confusing. I took a quick look but you are trying to initialize the member variables inside of the class 'user'. That should really be inside the constructor if you want to init them to those stats. I am not sure it it works but you could try making them static if every item of that type has those stats. You might not able to init them directly in the class declaration though. You might have to do something like
small_shield user::smallshield = ... outside of the decalartion of the class. I am not sure if that will work with structures though. The easiest way would be probably to just init them inside of the user constructor. Hope that helps.

Cya,
vbuser

[edit] typo
Quote:Original post by dudedbz1
Sorry, but I cant really help the way you have your code pasted. Use this:
[ source]
//code
[ /source]
Ofcourse, remove the space in between the '[' and 's' and the '[' and '/'. I just did it for the tags to ahow, not the box.


I'll have to second that. It really really helps!!

From trying to move through your code i cant even find a main() function, so iv no idea how everything is being called.

You should definitely be splitting up everything into .h and .cpp files, with the definition for all of your classes in the .h and the implementation in the .cpp. I assume that your not doing this, but if you are then obviously thats not a problem :)

You seem to declare a few classes within other ones. Im not sure that you necessarily need to do this with how you have structured things, it just seems to confuse me a bit (then again, with using tags and proper indenting it might be clearer)<br><br>For class items, you have many similar identical structures. This is not required, you want a single structure definition and then it being instanced in different ways. For example for the structures for Swords, instead of having a structure for small_sword, medium_sword etc etc, the following would work better:<br><br><pre><br>struct Sword<br>{<br> int Id;<br> int Damage;<br> int Speed;<br>};<br></pre><br><br>and then in the function where you need to declare new swords, hold the data in different instance variables. For example:<br><br><pre><br>Sword Basic_Sword;<br><br>Basic_Sword.Id = 0;<br>Basic_Sword.Damage = 5;<br>Basic_Sword.Speed = 5;<br><br>// use Basic_Sword wherever its needed....<br><br>Sword Really_Awesome_Sword;<br><br>Really_Awesome_Sword.Id = 1;<br>Really_Awesome_Sword.Damage = 453759436;<br>Really_Awesome_Sword.Speed = 5437534897694;<br><br>// use swords wherever...<br><br></pre><br><br>Hopefully that makes sense to you. If not then il try to clarify what im saying later :)
"Leave it to the computer programmers to shorten the "Year 2000 Millennium Bug" to "Y2K." Isn't that what caused this problem in the first place?"
Taking Tesl's suggestion, you could even go a step further with it.

class Sword{	private:		int mID;		int mDamage;		int mSpeed;	public:		Sword( int = -1, int = 5, int = 1 );};Sword::Sword( int pID, int pDamage, int pSpeed )	: mID( pID ), mDamage( pDamage ), mSpeed( pSpeed ){}


From that, you'd have a sword that is always initialized to whatever base settings you want. You could inherit from that and add whatever magical effects or abilities you want on a special sword. Of course, you could do that even better with an Ability class, but I'll hold back on that for now, heh.

That aside, I'd have to say I'm a tad confused as to why you're defining the inventory and such inside the user. If you're doing it for purposes of keeping everything neat and tidy together, I'd recommend using a namespace instead.
Quote:
That aside, what do you think of my code style, is it a good way to build a text based c++ game or does it just plain suck? took the opportunity to ask that while i'm at it :)


I think you have the right idea but maybe a bit "wrong" structuring.
I would consider something like
class Item {public:  int id;};class Sword : public Item{public:  int speed, dmg;};class HeavySword : public Sword {public:  int special_effect;};...main(){// Keeping many swords...  vector<Item*> vec_swords;// Or use one sword for all purposes...  Sword sword;  HeavySword heavy_sword;  ...}


If I needed more special effects in the HeavySword object
Id consider using bit fields
...class HeavySword : public Sword {public:  union {    struct {      unsigned int critical : 1;      unsigned int whirlwind : 1;    } effect;    unsigned int align;  };};...maain(){  HeavySword heavy_sword;  heavy_sword.effect.critical = 1;  ...}


EDIT:
This code misses everything from virtual destructors to proper testing

[Edited by - pulpfist on November 3, 2005 11:51:41 PM]
I think you are quite confused. Nesting classes is generally something you don't want to get in to without a good reason. It appears here like you want 'small_sword', 'medium_sword' etc. to be *instances* of a simple sword class - they all have the same *kind* of data, but simply different *values* for the data members. Similarly for shields. Meanwhile, both a sword and a shield are supposed to be a *kind of* item. That relationship is not properly represented by nesting the classes, but instead by inheritance.

class Item {  // There isn't really such a thing as an unspecified 'item'; that's just an  // abstract concept that exists to let us say that swords and shields are  // kinds of items.  int id; // something that all items have.  // We want every Item that ever exists to have a different ID - that's the  // proper use for an ID value, really; there's no sense using it to represent  // the object type, because, well, the object's actual type (as understood by  // the compiler) already does that.  // This is a setup we can use to accomplish this:  static int nextIdToAssign;  public:  Item() : id(nextIdToAssign++) {}  // Since we're going to inherit from this class, we should put a  // "virtual destructor"  virtual ~Item() {} // it doesn't need to do anything for the base class.};// The static int line above only declared the variable (that's a weird thing// with static class members in C++); we need to define it out here as well.static int Item::nextIdToAssign = 0; // starting value.class Sword : public Item {  // Here is stuff that a Sword has that other items don't.  int damage;  int speed;  // We'll make a constructor that lets us specify the damage and speed  // when we make a sword. Since a Sword "is a" Item, the data structure  // implicitly includes an id as well, which will be implicitly assigned by  // the implicitly-called Item constructor during Sword construction.  public:  Sword(int damage, int speed) : damage(damage), speed(speed) {}};// Now here's a convenience function that will let us create small, etc. swords,// each of which with (naturally) a unique ID.Sword createSmallSword() {  return Sword(2, 2);} // and we could do similarly for other sword types.// If we wanted to make sure that *every* sword is one of those specific types,// then we could instead change the constructor to take some enumeration value// (e.g. we might say ''Sword mySword(Sword::SMALL)'' after setting that up),// and look up the necessary damage/speed values from a (static) table.// Similarly we can make other Item subclasses, and then we can have a container// of Items in the Inventory. You will want to store them using some "smart// pointer" wrapper. Storing Item objects in an array or other container// direction *will not work*, because of "object slicing" - look it up - and// raw pointers here will be a memory management nightmare.
Quote:
vector<Item*> vec_swords;

vector<HeavySword*> vec_heavy_swords;

Shouldn't be slicing here if i kept a vector for each sword type.
Sorry, I tried the tag but it didn't work. I will update the first post now, thanks for your replies. There were many good methods you posted, can't wait to test them, will update the post if it works.

I edited the code to this:
class item {    int id;    static int nextIdToAssign;  public:    item() : id(nextIdToAssign++) {}    virtual ~item();};int item::nextIdToAssign = 0;class sword : public item {    int damage;    int speed;  public:    sword(int damage, int speed) : damage(damage), speed(speed) {}};


It didn't work with
static int item::nextIdToAssign = 0;

outside the class, it resulted in compile error but it did work with int alone like this:
int item::nextIdToAssign = 0;

It has the same effect right? I understand what you mean except the virtual destructor, what it does.

[Edited by - password on November 4, 2005 4:28:53 AM]
thats right, same effect :p
Actually I think it was a bug even

you need virtual destructor so that when you
delete a Sword object, not only the sword part of the object is
deleted, but also the Item part. (Inhertitage)

This topic is closed to new replies.

Advertisement