Specifically, here's how I might approach this. I'd create a Menu object:
class Menu
{
public:
Menu(const string &name, const string &prompt,
const std::vector<std::pair<string, string> > &choices
= std::vector<std::pair<string, string> >{});
virtual ~Menu();
const string& getChoice() const;
bool operator==(const string &name) const;
private:
static const string menuend;
string _name, _prompt;
std::vector<std::pair<string, string> > _choices;
};
Implementations are here:
Menu::Menu(const string &name, const string &prompt,
const std::vector<std::pair<string, string> > &choices)
: _name(name), _prompt(prompt), _choices(choices)
{}
bool Menu::operator==(const string &name) const
{
return name==_name;
}
const string& Menu::getChoice() const
{
if (_choices.size() == 0) {
cout << _prompt;
return menuend;
}
unsigned choice;
int i;
do {
cout << _prompt;
i = 1;
for (auto ch : _choices)
cout << i++ << ": " << ch.first << '\n';
cin >> choice;
--choice;
} while (choice >= _choices.size());
return _choices[choice].second;
}
Menu::~Menu()
{}
const string Menu::menuend{"END"};
Finally, we can construct the game itself as a std::vector of these Menu objects:
std::vector<Menu> game{
Menu("mainroad",
"You are on a road that heads west and east of your position.\n"
"Which way will you go?\n", std::vector<std::pair<string,string> >{
{"Go West", "spider"},
{"Go East", "brickhouse"},
{"Wait for something to happen", "dragon"}}),
Menu("spider",
"You travel down the road, about only 100 metres and you encounter \n"
"a giant spider with vicious poison coated fangs.\n"
"its hideous appearance causes your throat to dry and your knees to shake!\n"
"What on earth will you do?\n\n", std::vector<std::pair<string, string> >{
{"Attempt to attack the spider with your sword.","spiderattack"},
{"Throw your sword in the off chance it might kill it.","throwsword"},
{"RUN FOR YOUR LIFE!", "running"}}),
Menu("spiderattack",
"You viscously swing your sword at the spiders general direction.\n"
"The swing was so great, your arms jolts out of place,\n"
"creating a surge of pain.\n"
"Your arm is now broken, and you fall to the ground in pain....\n"
"The spider launches 3 metres straight into your body...\n"
"What on earth is it doing?\n"
"Oh My God! The spider is devouring everything....\n"
"All that remained was bones of the once mobile adventurer.\n"),
Menu("brickhouse",
"After a mile walk, you arrive at an old brick house.\n"
"You walk slowly inside.\n"
"The door slams behind you and the room lightens up.\n"
"What on earth is going on...?\n\n"
"Unable to open the door, you look around for anything of use.\n"
"Nothing, not a single piece of furniture.\n"
"What will you do?\n", std::vector<std::pair<string, string> >{
{"Wait for someone to save you.", "trapdoor"},
{"Or Wait for someone to save you.", "library"}})
};
The game itself becomes entirely data-driven:
void road() {
auto menu = std::find(game.begin(), game.end(), "mainroad");
while (menu != game.end())
menu = std::find(game.begin(), game.end(), menu->getChoice());
}
If you need more than the plain Menu class provides, you can simply derive a new kind of class and put that into the vector. It should also be obvious that this could very easily all be read as a script from a file, simply by defining an ostream extractor for the Menu class.