Jump to content
  • Advertisement
Sign in to follow this  
Jankos

Writing Text-Based RPG

This topic is 4745 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, im writing a single-player, text-based RPG in C++ using Visual c++ 6, in the console(?). I just started learning c++ last semester, where i had a class on it. The professor didnt know that much himself, but i learned a little on my own. I was looking for a few tips on how i should write classes and stuff like that, and how i should go about doing a game loop. Perhaps I should explain a little more about my game. It will be an RPG, room-based, where you can either type north east south west to go to different rooms, score to look at your character sheet, look to look at the room description and exits and any npcs that might be there. I want you to be able to pick up weapons and armor from npc's and equip them and be able to use their different damages and armor classes. So, any help with this would be appreciated. If you include code, i will write back explaining which parts i understand and which I need explained a little. I also had a question about pointers. I know what they are, and what they do, but i dont understand why you would use them, or HOW you would use them. I know that they point to a variables memory address, but not much more about them. Thank you for your time and help, and for reading this.

Share this post


Link to post
Share on other sites
Advertisement
The game loop can be really easy

1 Initialize it.
2 Wait for player input
3 process player input
4 process random element (monster?)
5 Update the game
6 return to 2.

it's a really basic game loop.
If you dig around (search field of the forum) you can find a lot of answer about this topic.

you can check source code of different game too.


Pointer can be used to create your own type of date.

You can create a monster data, with variable like health, location, atk power, a pointer to the next monster and a pointer to the previous one, so you can navigate easily, add more, or remove some monster of the list (we call that a linked list) . It's one way to use pointer. But actually, you could do yourself a favor and learn about the standard template library. Pointer where used a lot in C. With the STL, you don't need to use them so much. Don't bother with it right now. :)

Share this post


Link to post
Share on other sites
it will be a simple game, sorta like a single player MUD (SUD?!)

How should i make classes and objects and the like?

Share this post


Link to post
Share on other sites
Heres my source code so far, dont laugh too hard. I need a little help going from here though.




#include <iostream>
#include <time.h>
#include <vector>
#include <cstdlib>
#include <string>
using namespace std;

class race
{
public:
string name;
int racenum;
int statmod[5];
};

class clas
{
public:
string name;
int classnum;
int statmod[5];
};

class armor
{
public:
string name;
int ac;
int resisttype; //0Regular 1Undead 2Fire 3Ice 4Magic
int armortype; //Basic Types: 1Helm 2Chest 3boots 4gloves 5greaves 6belt
};

class weapon
{
public:
string name; //Weapon Name
int mindmg; //Minimum Weapon Dmg
int maxdmg; //Maximum Weapon Dmg
int weptype; //Basic Types: 1Sword, 2Axe, 3Dagger, 4Wand, 5Staff, 6PoleArm, 7Fists
bool hands; //0 for 1-h 1 for 2-h
int dmgtype; //0Regular 1Undead, 2Fire, 3Frost, 4Magic, 5Elemental, 6Lightning
int magicdmg; //Magic Dmg weapon does, if none, 0
int mpcost; //Cost of using
};

class character
{
public:
int calcdmg(int mindmg, int maxdmg, int magdmg, int magresist, int ac)
{
int dmg;
dmg = mindmg + (rand() % (maxdmg - mindmg)) - (ac/(maxdmg - mindmg)) + abs(magdmg / magresist);
return dmg;
}
int calchp(int str, int con)
{
int hp;
hp = ((str * 2 + con * 4) / 4);
return hp;
}
int calcmp(int intel, int wis)
{
int mp;
mp = ((intel*4 + wis*4)/4);
return mp;
}
string name;
int level;
int exp;
int hp;
int mp;
int ac;
clas clas;
race race;
weapon weapon;
armor armor;
vector<int> slot;
int stat[5];
};

//Unmodified base Stats
const basestat[5] = {10,10,10,10,10};
//Player
character player;
//Races
race Dwarf, Elf, Human, Iksar, Minotaur, Halfling, Satyr;

//Classes
clas Wizard, Warrior, Rogue, Barbarian, Knight, Mystic, Priest;

//Armors
armor LeatherHelm, ChainHelm, ScaleHelm, PlateHelm, EagleHelm;
armor LeatherArmor, ChainMail, ScaleMail, PlateMail, EagleMail;
armor LeatherBoots, ChainBoots, ScaleBoots, PlateBoots, EagleBoots;
armor LeatherGloves, ChainGloves, ScaleGloves, PlateGloves, EagleGloves;
armor LeatherGreaves, ChainGreaves, ScaleGreaves, PlateGreaves, EagleGreaves;
armor LeatherBelt, ChainBelt, ScaleBelt, PlateBelt, EagleBelt;

//Weapons
weapon SilverSword, GreatSword, FireSword, BroadSword, EagleSword;
weapon SilverAxe, GreatAxe, FireAxe, BroadAxe, EagleAxe;
weapon SilverDagger, GreatDagger, FireDagger, BroadDagger, EagleDagger;
weapon MagicWand, ElementalWand, FireWand, IceWand, LightningWand;
weapon MagicStaff, ElementalStaff, FireStaff, IceStaff, LightningStaff;
weapon SilverHalberd, GreatHalberd, FireHalberd, BroadHalberd, EagleHalberd;
weapon Fists, SilverKnuckles, SpikedKnuckles, DragonClaws, EagleClaws;

clas getclass()
{
int classnum = 0;

//Classes
Wizard.name = "Wizard";
Wizard.classnum = 1;
Wizard.statmod[0] = 0;
Wizard.statmod[0] = 0;
Wizard.statmod[0] = 0;
Wizard.statmod[0] = 10;
Wizard.statmod[0] = 5;

Warrior.name = "Warrior";
Warrior.classnum = 2;
Warrior.statmod[0] = 10;
Warrior.statmod[1] = 7;
Warrior.statmod[2] = 10;
Warrior.statmod[3] = 0;
Warrior.statmod[4] = 0;

Rogue.name = "Rogue";
Rogue.classnum = 3;
Rogue.statmod[0] = 5;
Rogue.statmod[1] = 10;
Rogue.statmod[2] = 5;
Rogue.statmod[3] = 5;
Rogue.statmod[4] = 5;

Barbarian.name = "Barbarian";
Barbarian.classnum = 4;
Barbarian.statmod[0] = 12;
Barbarian.statmod[1] = 5;
Barbarian.statmod[2] = 13;
Barbarian.statmod[3] = -2;
Barbarian.statmod[4] = -3;

Knight.name = "Knight";
Knight.classnum = 5;
Knight.statmod[0] = 7;
Knight.statmod[1] = 7;
Knight.statmod[2] = 7;
Knight.statmod[3] = 5;
Knight.statmod[4] = 5;

Mystic.name = "Mystic";
Mystic.classnum = 6;
Mystic.statmod[0] = 5;
Mystic.statmod[1] = 5;
Mystic.statmod[2] = 5;
Mystic.statmod[3] = 5;
Mystic.statmod[4] = 5;

Priest.name = "Priest";
Priest.classnum = 7;
Priest.statmod[0] = 0;
Priest.statmod[1] = 0;
Priest.statmod[2] = 0;
Priest.statmod[3] = 5;
Priest.statmod[4] = 10;

cout << "\nChoose a Class:\n"
<< "(1) Wizard\n"
<< "(2) Warrior\n"
<< "(3) Rogue\n"
<< "(4) Barbarian\n"
<< "(5) Knight\n"
<< "(6) Mystic\n"
<< "(7) Priest\n"
<< ">> ";
cin >> classnum;

switch(classnum)
{
case 1:
player.clas = Wizard;
player.weapon = MagicStaff;
break;
case 2:
player.clas = Warrior;
break;
case 3:
player.clas = Rogue;
break;
case 4:
player.clas = Barbarian;
break;
case 5:
player.clas = Knight;
break;
case 6:
player.clas = Mystic;
break;
case 7:
player.clas = Priest;
break;
default:
cout << "You Entered an Incorrect Number!";
}
return player.clas;
}

race getrace()
{
int racenum = 0;

//Races
Dwarf.name = "Dwarf";
Dwarf.racenum = 1;
Dwarf.statmod[0] = 11;
Dwarf.statmod[1] = 5;
Dwarf.statmod[2] = 12;
Dwarf.statmod[3] = 0;
Dwarf.statmod[4] = 0;

Elf.name = "Elf";
Elf.racenum = 2;
Elf.statmod[0] = 5;
Elf.statmod[1] = 10;
Elf.statmod[2] = 5;
Elf.statmod[3] = 3;
Elf.statmod[4] = 2;

Human.name = "Human";
Human.racenum = 3;
Human.statmod[0] = 5;
Human.statmod[0] = 5;
Human.statmod[0] = 5;
Human.statmod[0] = 5;
Human.statmod[0] = 5;

Iksar.name = "Iksar";
Iksar.racenum = 4;
Iksar.statmod[0] = 0;
Iksar.statmod[1] = 0;
Iksar.statmod[2] = 5;
Iksar.statmod[3] = 15;
Iksar.statmod[4] = 10;

Minotaur.name = "Minotaur";
Minotaur.racenum = 5;
Minotaur.statmod[0] = 12;
Minotaur.statmod[1] = 5;
Minotaur.statmod[2] = 14;
Minotaur.statmod[3] = -3;
Minotaur.statmod[4] = -2;

Halfling.name = "Halfling";
Halfling.racenum = 6;
Halfling.statmod[0] = 2;
Halfling.statmod[1] = 5;
Halfling.statmod[2] = 2;
Halfling.statmod[3] = 10;
Halfling.statmod[4] = 15;

Satyr.name = "Satyr";
Satyr.racenum = 7;
Satyr.statmod[0] = 0;
Satyr.statmod[1] = 15;
Satyr.statmod[2] = 2;
Satyr.statmod[3] = 10;
Satyr.statmod[4] = 2;

cout << "\nChoose a Race:\n"
<< "(1) Dwarf\n"
<< "(2) Elf\n"
<< "(3) Human\n"
<< "(4) Iksar\n"
<< "(5) Minotaur\n"
<< "(6) Halfling\n"
<< "(7) Satyr\n"
<< ">> ";
cin >> racenum;

MagicStaff.name = "Magic Staff";
MagicStaff.mindmg = 20;
MagicStaff.maxdmg = 30;

switch(racenum)
{
case 1:
player.race = Dwarf;
break;
case 2:
player.race = Elf;
break;
case 3:
player.race = Human;
break;
case 4:
player.race = Iksar;
break;
case 5:
player.race = Minotaur;
break;
case 6:
player.race = Halfling;
break;
case 7:
player.race = Satyr;
break;
default:
cout << "You Entered an Incorrect Number!";
}
return player.race;
}

string getname()
{
cout << "Enter Your Name:"
<< "\n>> ";
cin >> player.name;
return player.name;
}

character getcharacter()
{
player.name = getname();
player.race = getrace();
player.clas = getclass();
player.level = 1;
for(int a=0;a<5;a++) //Fill stats array from race and class
{
player.stat[a] = player.stat[a] + basestat[a] + player.race.statmod[a] + player.clas.statmod[a];
}
player.hp = player.calchp(player.stat[0], player.stat[2]);
player.mp = player.calcmp(player.stat[3], player.stat[4]);
return player;
}


void score(character player)
{
cout << "+-------------------------+\n";
cout << " Name: " << player.name << endl;
cout << " Str Agi Con Int Wis\n";
for(int a=0;a<5;a++)
cout << " " << player.stat[a] << " " << " ";
cout << "\n HP: " << player.hp << "\t MP: " << player.mp << " AC: " << player.armor.ac << endl;
cout << " Race: " << player.race.name
<< " Class: " << player.clas.name << endl;
cout << " Weapon: " << player.weapon.name << " "
<< player.weapon.mindmg << "-" << player.weapon.maxdmg << endl;
}
int main()
{
player = getcharacter();
score(player);

return 0;
}

Share this post


Link to post
Share on other sites
would you like to work with me? I am currently developing an item filing system and working with binary format. This would make the catalogueing of items in the game a lot easier. I've been programming about 3 years in c++ now, and could help you with things like pointers. I've never taken a class, and I'm 16, but I know how you could do something like this.

I'm planning on starting a kind of group-learning programming club for my school next year. No teachers or other students out of the 2000 that go to my high school program! I want to teach them, and I think that I could do that. If you would like me to teach you along the way, it would be good experiance for both of us.

Plus, I'm friendly! :)

Email: silverphyre673@comcast.net

-Ben

Share this post


Link to post
Share on other sites
Yeah sure, id like your help with c++ and the game, do you have any instant messenger programs?

my email is b3aup@yahoo.com




anyone else have any input BTW?

Share this post


Link to post
Share on other sites
no, but i can get one. what do you use? i prefer to stay away from aim, out of principle. I'll be in touch later - its late where I am (washington state, us). where are you?

Share this post


Link to post
Share on other sites
A couple of things to mention....

First of all, you have a logic error that you may or may not have already caught. Consider this block of code:


clas getclass()
{
int classnum = 0;

//Classes
Wizard.name = "Wizard";
Wizard.classnum = 1;
Wizard.statmod[0] = 0;
Wizard.statmod[0] = 0;
Wizard.statmod[0] = 0;
Wizard.statmod[0] = 10;
Wizard.statmod[0] = 5;


You're assigning a series of different values to the same element of Wizard.statmod. Looking at the following code, that obviously wasn't intentional. Small error, no biggie.

Another thing to mention is that you're using classes more as structs in this case. That's not necessarily bad, but as far as proper OOP goes, it's a little ugly. It's not a big deal, but if you want to make it prettier, you might look into researching public/private members and accessor functions.

Also, a little research into some basic data structures might help you out so you don't have those ugly collections of armor and weapons, but that really depends on how extensive you want your game to be.

For the character creation, you might want to create a function called "CreateCharacter" or similar and pass it the character reference and a 'clas' variable, both by reference (or pointer!), to initialize the characters. That would clean up those 50-ish lines of creation code to about 15 (new function + function calls). By the way, 'clas' is a rather poor choice of names.... Makes it look like a typo. Don't be afraid to use a more desriptive class name, like you did for your armor variables.

And here's the real gem.... Want bullet-proof user input? Do something like this:


bool endGame = false; // State of whether or not to continue the game
char buffer[ 10 ]; // Input buffer for user input

while ( !endGame ) // While the user continues to play...
{
// Output menu options
cout << "Descriptive text here";

GetUserInput( buffer, 10, input ); // Get user input

// Some sort of game logic like the following
if ( atoi( buffer ) == 1 ) // Play game
PlayGame( output, input );
else if ( atoi( buffer ) == 2 ) // Quit
endGame = true;
}


where GetUserInput is the following function:


// buffer is the POINTER! to a character array to store user input
// characters is the maximum amount of characters you want the user to enter
// input is the input method; in this case, just pass "cin"
void GetUserInput( char * buffer, int characters, istream & input )
{
// Clear unused characters from keyboard buffer
input.ignore ( input.rdbuf()->in_avail() );

// Get user input
input.get ( buffer, characters );

// Clear any bad flags from bad key sequences, like hitting Enter
// without providing input
input.clear();
}


That's a little gem I came up with back in my basic C++ classes. From all the testing I've done, it's never been broken by bad user input, plus it allows you to use alternative input methods than just cin. And it uses a pointer to write to a character array of "unknown" size (that's why we pass in the second variable). One thing to note: Don't pass in a number of characters greater than the buffer size. This can be avoided by creating a #define MAX_INPUT 10 to replace the "10" in the buffer declaration and the GetUserInput call.

Good luck on your project!

EDIT: Oh, another thing. When you create something like "char buffer[10]", essentially you're creating a pointer to a sequence of ten allocated char's. You can pass buffer into a function that expects a "char *". The bracket operators "[]" are simply a way to dereference the pointer. The compiler may make a few distinctions between pointers and variables created with brackets, but under the hood, they end up being accessed as a contiguous block of memory that is accessed by pointers.

Share this post


Link to post
Share on other sites
pointers are the best, aren't they! You'll get used to them in time - you just have to crash a lot of programs along the way.

and hannibal - wow, thats really nice if it works. don't have time to test right now, but cool!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!