RCRPG/C++98: Difference between revisions
Thundergnat (talk | contribs) m (Avoid miscounting tasks twice) |
|||
Line 3: | Line 3: | ||
* If you enter a room that you visited, at least 3 minutes ago, there is a 40% chance that the loot will re-spawn. |
* If you enter a room that you visited, at least 3 minutes ago, there is a 40% chance that the loot will re-spawn. |
||
* The Treasure Room is placed at random in the cave. |
* The Treasure Room is placed at random in the cave. |
||
<span style='font-family: "Linux Libertine",Georgia,Times,serif;font-size:150%;'>[[C++]]</span><hr> |
|||
=={{header|C++}}== |
|||
<lang cpp> |
<lang cpp> |
||
#include <stdio.h> |
#include <stdio.h> |
Revision as of 15:36, 18 January 2020
Yet another C++ RCRPG, this one has some tweaks though:
- You can lose: If you try to break one of the cave's boundary walls, your sledge will break. If that happens in a room that has no exits (first room), you are trapped and dies!
- If you enter a room that you visited, at least 3 minutes ago, there is a 40% chance that the loot will re-spawn.
- The Treasure Room is placed at random in the cave.
<lang cpp>
- include <stdio.h>
- include <time.h>
- include <iostream>
- include <algorithm>
- include <map>
- include <vector>
- include <sstream>
typedef unsigned uint;
const std::string directions[] = { "north", "south", "east", "west", "up", "down" }; const std::string objectName[] = { "nothing", "gold", "ladder", "sledge" }; const uint MAX_DOORS = sizeof( directions ) / sizeof( directions[0] ), MX_R = 26;
enum keyWord { north, south, east, west, up, down, inventory, unequip, look, help, quit, attack, drop, take, equip, alias, name, all, nothing, gold, ladder, sledge }; const keyWord inverted[] = { south, north, west, east, down, up };
class position { public:
position() : x(0), y(0), z(0) { } position( int a, int b, int c ) : x(a), y(b), z(c) { } void set( int a, int b, int c ) { x = a; y = b; z = c; } bool operator ==( const position o ) { return o.x == x && o.y == y && o.z == z; } position& operator =( position o ) { x = o.x; y = o.y; z = o.z; return *this; } position& operator +=( const position& o ) { x += o.x; y += o.y; z += o.z; return *this; } friend position operator+( position l, const position& r ) { return l += r; } int x, y, z;
};
const position dirVec[] = { position( 0, -1, 0 ), position( 0, 1, 0 ), position( 1, 0, 0 ), position( -1, 0, 0 ), position( 0, 0, -1 ), position( 0, 0, 1 ) };
typedef struct {
keyWord action, subKey; std::string str1, str2;
}command;
typedef void ( *callee )( command );
class parser { public:
parser() { std::string c[] = { directions[0], directions[1], directions[2], directions[3], directions[4], directions[5], "inventory", "unequip", "look", "help", "quit", "attack", "drop", "take", "equip", "alias", "name", "all", objectName[0], objectName[1], objectName[2], objectName[3] }; for( uint i = 0; i < sizeof( c ) / sizeof( c[0] ); i++ ) { actions.insert( std::make_pair( hashStr( c[i] ), static_cast<keyWord>( i ) ) ); names.insert( std::make_pair( static_cast<keyWord>( i ), c[i] ) ); } } void addAlias( std::string or, std::string nw ) { std::map<uint, keyWord>::iterator it = actions.find( hashStr( or ) ); if( it == actions.end() ) { std::cout << "Keyword " + or + " doesn't seem to exist!\n"; return; } actions.insert( std::make_pair( hashStr( nw ), it->second ) ); std::cout << "Done\n"; } bool parse( std::string a, command& cmd ) { std::transform( a.begin(), a.end(), a.begin(), ::tolower ); std::istringstream iss( a ); std::vector<std::string> vec; copy( std::istream_iterator<std::string>( iss ), std::istream_iterator<std::string>(), std::back_inserter<std::vector<std::string> >( vec ) ); std::map<uint, keyWord>::iterator it = actions.find( hashStr( vec[0] ) ); if( it == actions.end() ) { std::cout << "'" + vec[0] + "' doesn't make any sense!\n"; return false; } cmd.action = it->second; if( cmd.action < attack ) return true; if( cmd.action < name ) { if( vec.size() < 2 ) { std::cout << "What should I '" + names[cmd.action] + "'?\n"; return false; } if( !vec[1].compare( "coin" ) || !vec[1].compare( "coins" ) ) vec[1] = "gold"; it = actions.find( hashStr( vec[1] ) ); if( it == actions.end() ) { std::cout << "I don't know what '" + vec[1] + "' means.\n"; return false; } cmd.subKey = it->second; if( cmd.action == alias ) { if( vec.size() < 3 ) { std::cout << "Aren't you forgetting something?\n"; return false; } std::map<uint, keyWord>::iterator it = actions.find( hashStr( vec[2] ) ); if( it != actions.end() ) { std::cout << "'" + vec[2] + "' is already a keyword!\n"; return false; } if( cmd.subKey > name ) { std::cout << "No alias for '" + vec[1] + "' is allowed!\n"; return false; } cmd.str1 = vec[1]; cmd.str2 = vec[2]; } return true; } if( cmd.action == name ) { if( vec.size() < 2 ) { std::cout << "What name?\n"; return false; } cmd.str1 = vec[1]; return true; } std::cout << "I can't understand '" + vec[0] + "'!\n"; return false; }
private:
unsigned hashStr( std::string s ) { unsigned wrd = 0x4e67c6a7, p = 0; while( p < s.length() ) wrd ^= ( ( wrd << 5 ) + s[p++] + ( wrd >> 2 ) ); return wrd; } std::map<uint, keyWord> actions; std::map<keyWord, std::string> names;
};
class treasure { public:
treasure( keyWord k, uint c ) : key(k), cnt(c) { } keyWord key; uint cnt;
};
class box { public:
void display() { if( !stuff.size() ) { std::cout << objectName[0] + ".\n\n"; return; } std::ostringstream oss; for( std::map<keyWord, uint>::iterator it = stuff.begin(); it != stuff.end(); it++ ) { if( it->second > 0 ) { oss << " + " << it->second << " " << objectName[it->first - nothing]; std::cout << oss.str(); if( it->first == gold ) std::cout << ( it->second > 1 ? " coins" : " coin" ); else std::cout << ( it->second > 1 ? "s" : "" ); std::cout << "\n"; oss.str( "" ); } } std::cout << "\n"; } void stow( std::vector<treasure> t ) { for( std::vector<treasure>::iterator i = t.begin(); i != t.end(); i++ ) { std::map<keyWord, uint>::iterator it = stuff.find( ( *i ).key ); if( it == stuff.end() ) stuff.insert( std::make_pair( ( *i ).key, ( *i ).cnt ) ); else it->second += ( *i ).cnt; } } std::vector<treasure> dump( keyWord k, uint c = 0 ) { std::vector<treasure> t; if( k == all ) { for( std::map<keyWord, unsigned>::iterator it = stuff.begin(); it != stuff.end(); it++ ) { t.push_back( treasure( ( *it ).first, ( *it ).second ) ); } stuff.clear(); } else { std::map<keyWord, unsigned>::iterator it = stuff.find( k ); if( it == stuff.end() ) return t; uint z = ( it->second ); c = k == ladder ? 1 : !c ? z : c; it->second -= c; if( !it->second ) stuff.erase( it ); t.push_back( treasure( k, c ) ); } return t; } size_t size() { return stuff.size(); } uint count( keyWord k ) { std::map<keyWord, unsigned>::iterator it = stuff.find( k ); if( it != stuff.end() ) return ( *it ).second; return 0; }
private:
std::map<keyWord, uint> stuff;
};
class room { public:
room( std::string n ) : name(n), visited(false) { memset( bRooms, 0, sizeof( bRooms ) ); memset( ladderZ, 0, sizeof( ladderZ ) ); } void describe() { std::cout << "\n\t** Room: " + name + " **\n\n"; std::vector<std::string> ex; getExits( ex ); if( !ex.size() ) std::cout << "There are no exits from this room.\n"; else { std::cout << "From here, you can go "; for( std::vector<std::string>::iterator x = ex.begin(); x != ex.end(); x++ ) { std::cout << *x + " "; } std::cout << "\n"; } if( loot.size() ) { std::cout << "Here you can see:\n"; loot.display(); return; } std::cout << "You see nothing useful here.\n"; } room* atk( keyWord d, uint lvl ) { if( bRooms[d] ) return 0; room* r = new room( "no name" ); bRooms[d] = r->bRooms[inverted[d]] = true; r->addLoot( false, lvl ); return r; } void addLoot( bool forceSledge, uint lvl ) { std::vector<treasure> t; if( forceSledge ) t.push_back( treasure( sledge, 1 ) ); else if( rand() % 10 > 6 ) t.push_back( treasure( sledge, 1 ) ); if( rand() % 10 > 6 ) t.push_back( treasure( gold, rand() % 8 + 1 ) ); if( rand() % 10 == 2 || ( !ladderZ[lvl] && rand() % 10 < 5 ) ) { t.push_back( treasure( ladder, 1 ) ); ladderZ[lvl] = true; } loot.stow( t ); } void setName( std::string n ) { name = n; std::cout << "OK\n"; } std::vector<treasure> tak( keyWord k ) { return loot.dump( k ); } void drp( std::vector<treasure> t ) { loot.stow( t ); } uint count( keyWord k ) { return loot.count( k ); } void setVisited() { visited = true; lastTime = time( 0 ); } bool wasVisited() { return visited; } time_t lastTimeVisited() { return lastTime; } void getExits( std::vector<std::string>& ex ) { for( uint x = 0; x < MAX_DOORS; x++ ) if( bRooms[x] ) ex.push_back( directions[x] ); }
private:
std::string name; box loot; time_t lastTime; bool bRooms[MAX_DOORS], ladderZ[MX_R], visited;
};
class player { public:
player() : curRoom(0) { } ~player() { deleteRooms(); } void init() { equipped = nothing; deleteRooms(); curRoom = new room( "Where it all begins" ); curRoom->setVisited(); curRoom->addLoot( true, pos.z ); do pos.set( rand() % MX_R, rand() % MX_R, rand() % MX_R ); while( pos.x == 8 && pos.y == 8 && pos.z == 8 ); cave.insert( std::make_pair( pos.x + pos.y * MX_R + MX_R * MX_R * pos.z, curRoom ) ); lok(); } void lok() { curRoom->describe(); if( equipped > nothing ) std::cout << "You are equipped with a " << objectName[equipped - nothing] << "\n"; } void une() { if( equipped == nothing ) { std::cout << "You are equipped with nothing!\n"; return; } equipped = nothing; std::cout << "Done\n"; } void inv() { std::cout << "You are carrying"; std::cout << ( !loot.size() ? " " : ":\n" ); loot.display(); } void tak( keyWord k ) { if( k < gold && k != all ) { std::cout << "I don't know how to do that!\n"; return; } if( k == ladder && loot.count( k ) ) { std::cout << "These things are so heavy, you can't carry more than one!\n"; return; } std::vector<treasure> t = curRoom->tak( k ); if( !t.size() ) { if( k == all ) std::cout << "There is nothing here to take!\n"; else std::cout << "I can't take what's not here!\n"; return; } loot.stow( t ); if( k == all ) { uint lc = loot.count( ladder ); while( lc > 1 ) { drp( ladder, true ); lc--; } } std::cout << "Taken\n"; } void equ( keyWord k ) { if( k < sledge ) { std::cout << "I don't know how to equip this!\n"; return; } if( equipped != nothing ) return;
if( !loot.count( k ) ) { std::cout << "You are not carrying one of those."; return; } equipped = k; std::cout << "OK\n"; } bool atk( keyWord k ) { if( equipped == nothing ) { std::cout << "I cannot let you hurt yourself!\n"; return true; } if( checkBoundaries( k ) ) { std::cout << "The rocks here are too hard, you broke your sledge!\n"; equipped = nothing; std::vector<std::string> ex; curRoom->getExits( ex ); if( !ex.size() ) { std::cout << "\nUnfortunately you are trapped in here ---- FOREVER!\n\n" "\t*** G A M E * O V E R ***\n\n"; return false; } return true; } uint lvl = pos.z + k == up ? -1 : k == down ? 1 : 0; room* r = curRoom->atk( k, lvl ); if( !r ) { std::cout << "There is already a doorway there!\n"; return true; } position p = pos + dirVec[k]; cave.insert( std::make_pair( p.x + MX_R * p.y + MX_R * MX_R * p.z, r ) ); std::cout << "KA-POW!\n"; } void mov( keyWord d ) { if( d > down ) { std::cout << "I don't know how to move in that direction!\n"; return; } if( d == up && loot.count( ladder ) ) { std::cout << "You are not strong enough to climb up there carrying a ladder!\n"; return; } position p = pos + dirVec[d]; std::map<uint, room*>::iterator it = cave.find( p.x + MX_R * p.y + MX_R * MX_R * p.z ); if( it == cave.end() ) { std::cout << "There is a "; if( d == up ) std::cout << "ceiling"; else if( d == down ) std::cout << "floor"; else std::cout << "wall"; std::cout << " blocking your way!\n\n"; } else { curRoom = it->second; pos = p; if( d == up && !curRoom->count( ladder ) ) { std::cout << "I didn't know you could fly!\n"; return; } if( curRoom->wasVisited() ) { if( rand() % 10 > 5 && difftime( time( 0 ), curRoom->lastTimeVisited() ) > 180 ) curRoom->addLoot( false, pos.z ); } curRoom->setVisited(); } } void drp( keyWord k, bool silence = false ) { curRoom->drp( loot.dump( k ) ); if( !silence ) std::cout << "Dropped\n"; } room* currentRoom() { return curRoom; } position getPos() { return pos; }
private:
void deleteRooms() { for( std::map<uint, room*>::iterator it = cave.begin(); it != cave.end(); it++ ) delete it->second; cave.clear(); } bool checkBoundaries( keyWord k ) { return k == up && pos.z - 1 < 0 || k == down && pos.z + 1 >= MX_R || k == west && pos.x - 1 < 0 || k == east && pos.x + 1 >= MX_R || k == north && pos.y - 1 < 0 || k == south && pos.y + 1 >= MX_R; } room* curRoom; box loot; position pos; keyWord equipped; std::map<uint, room*> cave;
};
class game { public:
game() { instance = this; goal.set( 3, 3, 3 ); callee c[] = { mov, mov, mov, mov, mov, mov, inv, une, lok, hlp, qit, atk, drp, tak, eqp, als, nam, 0, 0, 0, 0 }; for( uint i = 0; i < sizeof( c ) / sizeof( c[0] ); i++ ) functions.insert( std::make_pair( static_cast<keyWord>( i ), c[i] ) ); } void play() { command cmdLine; std::string a; while( true ) { initGame(); while( !gameOver ) { std::cout << "\n>"; std::getline( std::cin, a ); if( !cmdParser.parse( a, cmdLine ) ) continue; std::map<keyWord, callee>::iterator it = functions.find( cmdLine.action ); if( it == functions.end() ) { std::cout << "What do you mean?"; continue; } it->second( cmdLine ); } if( playerQuit ) return; std::cout << "Play again (Y/N)?\n>"; std::getline( std::cin, a ); if( a[0] != 'y' && a[0] != 'Y' ) return; } }
private:
void checkWin() { if( plr.getPos() == goal ) { std::cout << "\nYou have found the ** TREASURE ROOOM **\n\n" "\nAll around you are thousands and thousands of piles of gold\n\n ** and they are all yours! ** \n" "\n\nCONGRATULATIONS!!!\n\n\n\n"; gameOver = true; playerQuit = false; return; } plr.currentRoom()->describe(); } void initGame() { gameOver = false; playerQuit = true; plr.init(); } void showHelp() { std::cout << "\n ** Welcome Dungeon Explorer **\n\nDig your way to Room 8, 8, 8! (...but where is it?)\n\n" "In your journey you can use following commands:\n\n* north, south, east, west, up and down: move in that direction\n" "* attack <direction>: if equipped with sledge, it will open a passage\n in that direction\n" "* drop <object>: drops the object in the room you are\n* take <object>: takes a object from room into you inventory\n" "* inventory: list all things you are carrying\n* look: describes the room you are in\n""* equip <object>: equip you " "with the object\n* unequip: the opposite of equip\n* name <new name>: rename the room you are in\n" "* alias <command> <new name>: creates a alias for the command\n* quit: terminates the game\n* help: show this long text...\n\n" " ** To go upwards, you need a ladder! **\n\n"; } static void atk( command c ) { if( !instance->plr.atk( c.subKey ) ) { instance->gameOver = true; instance->playerQuit = false; } } static void mov( command c ) { instance->plr.mov( c.action ); instance->checkWin(); } static void inv( command c ) { instance->plr.inv(); } static void une( command c ) { instance->plr.une(); } static void lok( command c ) { instance->plr.lok(); } static void drp( command c ) { instance->plr.drp( c.subKey ); } static void tak( command c ) { instance->plr.tak( c.subKey ); } static void eqp( command c ) { instance->plr.equ( c.subKey ); } static void nam( command c ) { instance->plr.currentRoom()->setName( c.str1 ); } static void als( command c ) { instance->cmdParser.addAlias( c.str1, c.str2 ); } static void hlp( command c ) { instance->showHelp(); } static void qit( command c ) { instance->gameOver = true; }
bool gameOver, playerQuit; std::map<keyWord, callee> functions; parser cmdParser; player plr; position goal; static game* instance;
};
game* game::instance = 0; int main( int argc, char* argv[] ) {
srand( static_cast<uint>( time( NULL ) ) ); game g; g.play(); return 0;
} </lang>