Time to dig into the useful stuff. We’re gonna work on the USE command which will enable players to actually effect their environment directly. There’s a bit of work involved here, and it’s mostly in the setup. The USE function is very simple in itself, and the USE command in the stepper is fairly straightforward, however we’re going to have to add a bunch of information to our nouns, or objects, so that we can use them with each other.
As usual we’re just going to start with a little housekeeping. In the parser in the GO command an error was made when we wanted to go through a door, we would say GO SOUTH and the go command would look at south, see there was a door there, check the doors other location and put the player there. we used drs[stepper[i+j+1]] inside the for K look when we should have used drs[k] so the loop should look like this:
for(int k = 0; k < MAX_DOORS; k++)
{
if(rms[loc].exits_to_room[stepper[i+j+1]] == drs[k].code)
{
isdoor = true;
if(!drs[k].islocked)
{
if(drs[k].isopen)
{
if(loc == drs[k].location_1)
{
loc = drs[k].location_2;
look(loc, rms, nns, dir, drs);
}
else
{
loc = drs[k].location_1;
look(loc, rms, nns, dir, drs);
}
}
else
{
cout << “The ” + drs[k].word + ” is closed.\n”;
}
}
else
{
cout << “The ” + drs[k].word + ” is locked.\n”;
}
}
}
So, lets start with the basics. We need to add USE as a verb so add it to the enum in the properties file and then set it up in the verbs file. Now we have to think a little about our puzzle. We have a string and a stick and a wire we can combine to make a fishing rod. But we need to do it in stages. We could combine the stick and the string to make a fishing pole, or the string and the wire to make a hook (with line), we could combine the pole with the wire to make a fishing rod, or the hook with the stick to do the same. We can then use the fishing rod with the key to get the key and now we have a means to unlock the cell door!
So we will need 3 new nouns to cover the different way a fishing rod can be made, and the fishing rod itself, we need POLE, HOOK and ROD. Our enums now look like this:
enum en_VERBS {GO, LOOK, GET, DROP, INV, USE, MAX_VERBS};
enum en_NOUNS {STICK, POLE, STRING, HOOK, WIRE, ROD, KEY, MAX_NOUNS};
We also need to put more information into nouns so that we can use them to do things. We need to know what it can be combined with, what the result of that combination is, we need to tell the player something has happened and we need to know if the item can used again or not. And since objects may have multiple interactions we’ll make the new variables as vectors so we can add all the interaction we want.
struct noun
{
string word;
string description;
string on_examination;
int code;
int location;
bool can_carry;
bool can_reuse;
vector<int> combineWith;
vector<int> combinationResult;
vector<string> combineComment;
};
Now that we have the structure for the nouns it’s time to add all that extra content. Keep in mind that the several nouns will need more than one combination. The string can be used with the stick or the wire, the stick can be used with the string or the hook, and the wire can be used with the string or the pole. The stick now looks like this:
nns[STICK].word = “STICK”;
nns[STICK].code = STICK;
nns[STICK].description = “a STICK”;
nns[STICK].on_examination = “a crooked, thin stick as long as my arm”;
nns[STICK].can_carry = true;
nns[STICK].can_reuse = false;
nns[STICK].location = CELL;
nns[STICK].combineWith.push_back(STRING);
nns[STICK].combinationResult.push_back(POLE);
nns[STICK].combineComment.push_back(“I tied the string to the stick and got a fishing POLE”);
nns[STICK].combineWith.push_back(HOOK);
nns[STICK].combinationResult.push_back(ROD);
nns[STICK].combineComment.push_back(“I tied the hook to the stick and got a fishing ROD”);
And you’re going to have to give the rest of the nouns the same treatment. I’ll include the nouns.cpp file at the end of the blog as per usual.
In main.cpp we’re going to create a USE function. We’re going to need some information from the parser, the two objects we’re combining of course, our location and the list of nouns.
int use(int itemA, int itemB, int &loc, noun *nns)
{
//Do some stuff
We’re also going to return the combined item so instead of void we’ve used int because to track everything we’re using the nouns int code.
First thing we need to do inside the function is check the the items the player want to combine are either in the room with the player or in their possession:
if((nns[itemA].location == loc || nns[itemA].location == POCKET)
&& (nns[itemB].location == loc || nns[itemB].location == POCKET))
{
//Do some more stuff
Great, now we know the two items are within reach. Now we need to combine them together. To do that we’ll loop through itemA’s combineWith vector to see if one matches itemB, easy peasy:
for(int i = 0; i < static_cast<signed int>(nns[itemA].combineWith.size()); i++)
{
if(nns[itemA].combineWith[i] == nns[itemB].code)
{
//Combine the items!!
Great, we’ve found that they match. Since we know what all the outcomes are for combining the separate objects we’ll just go ahead and do that. We’ll need to check if both items are re usable, and if now we will get rid of them by changing their location to NONE, we’ll then ensure the new item can be carried and change it’s location to POCKET so the player can have it, we’ll then tell the player what they’ve done and return the new item:
if(nns[itemA].can_reuse == false)
{
nns[itemA].location = NONE;
}
if(nns[itemB].can_reuse == false)
{
nns[itemB].location = NONE;
}
nns[nns[itemA].combinationResult[i]].can_carry = true;
nns[nns[itemA].combinationResult[i]].location = POCKET;
cout << nns[itemA].combineComment[i] + “.\n”;
return nns[itemA].combinationResult[i];
}
}
}
return NONE;
}
We then return NONE at the end to avoid any warnings as this function isn’t void. Now that we have all our information in place and now have a way to use and combine it, it’s time to get this all accessible in the parser! We have our template to start everything off with:
if(stepper[i] == )
{
//Check if there’s another word in the stepper to use
if((i+j+1) < static_cast<signed int>(stepper.size()))
{
//The next word is a direction
if(commander[i+j+1] == “DIR”)
{
}
//The next word is a noun
else if(commander[i+j+1] == “NOUN”)
{
}
//The next word is a door
else if(commander[i+j+1] == “DOOR”)
{
}
//The next word is a verb and we haven’t done anything yet
else if(commander[i+j+1] == “VERB” && j == 0)
{
}
}
//if there’s no more words in stepper to use and we haven’t already done something
else if((i+j+1) == static_cast<signed int>(commander.size()) && j == 0)
{
}
}
Of course stepper[i] will be USE and as usual lets start wit the simple stuff. If there’s no word following the verb USE we’ll just ask the player what they want to use, and if the next word is a verb we can’t do much there either so we’ll let the player know.
//The next word is a verb and we haven’t done anything yet
else if(commander[i+j+1] == “VERB” && j == 0)
{
cout << “You can’t use a verb!\n”;
}
}
//if there’s no more words in stepper to use and we haven’t already done something
else if((i+j+1) == static_cast<signed int>(commander.size()) && j == 0)
{
cout << “Use what?\n”;
}
}
If the next word is a direction, well, you can’t use a direction can you?
//The next word is a direction
if(commander[i+j+1] == “DIR”)
{
cout << “I cannot use that.\n”;
}
So that leaves us with doors and nouns. When using doors we’ll simple check if the door is locked and if not we’ll check if it is open, if it’s open we close it and vice versa.
else if(commander[i+j+1] == “DOOR”)
{
//is it locked
if(drs[stepper[i+j+1]].islocked == false)
{
//is it open
if(drs[stepper[i+j+1]].isopen == false)
{
drs[stepper[i+j+1]].isopen = true;
cout << “I have opened the ” + drs[stepper[i+j+1]].word + “.\n”;
}
else
{
drs[stepper[i+j+1]].isopen = false;
cout << “I have closed the ” + drs[stepper[i+j+1]].word + “.\n”;
}
}
else
{
cout << “The door is locked.\n”;
}
Now for the slightly more complicated bit. If the next word is a noun. Really we need the next two words to be nouns if we want to do something right? But just in case the player enters only one noun, we’ll let them know they need to enter more.
Also, we’re going to loop through all the upcoming nouns inside the USE command instead of letting the parser do it for us to avoid any problems, and at the end of looping we’ll add the number of loops, or words we’ve gone through in the stepper, to our index i so as not to cause any more issues.
//The next word is a noun
else if(commander[i+j+1] == “NOUN”)
{
int k = 0;
//count how many nouns there are to be used
//We will deal with them all here rather then the main loop as combining items and then combining again could invalidate the procedure
int numberNouns = 1;
while(commander[i+j+numberNouns] == “NOUN” && i+j+numberNouns+1 < static_cast<signed int>(stepper.size()))
{
numberNouns++;
}
if(numberNouns == 1)
{
cout << “use ” + nns[stepper[i+j+1]].word + ” with what?\n”;
}
else if(numberNouns > 1)
{
//Time to combine!
before we go into the loop itself we need to set itemA, once in the loop we’ll set itemB using the stepper as it will always be the next word and set itemA with the USE function so the the loop will iterate through each combination. So essential we’ll combine itemA and itemB and set the combination result as itemA, then combine the new itemA with the next item on the list which we set to itemB until we’ve gone through all the commands.
So: use stick with string with wire will combine the string and the stick to make the pole, then combine the pole with the wire to make the fishing rod. Easy right?
int itemA = nns[stepper[i+j+1]].code;
//loop ahead using each word
for(k = 1; k < numberNouns; k++)
{
cout << k;
int itemB = nns[stepper[i+j+k+1]].code;
itemA = use(itemA, itemB, loc, nns);
}
}
i = i + k;
}
And that’s it, the player can not open and close unlocked doors, and they can combine items to make more items. There are a few more interactions we’ll need to code into USE such as doors and non combine use items but we’ll leave it there for now.
As always, if you have any question or queries feel free to post a comment or reach out to me on twitter (@SeveralBytes). Thanks for reading and I hope you get something from this!
Here is all the code for the parser after today’s additions:
properties.cpp
#ifndef __PROPERTIES_H_INCLUDED___
#define __PROPERTIES_H_INCLUDED___
#include <string>
#include <vector>
using namespace std;
enum en_DIRS {NORTH, SOUTH, EAST, WEST, MAX_DIRS};
enum en_ROOMS {CELL, DUNGEON, HALLWAY, KEEP, GATE, FREEDOM, POCKET, MAX_ROOMS};
enum en_VERBS {GO, LOOK, GET, DROP, INV, USE, MAX_VERBS};
enum en_NOUNS {STICK, POLE, STRING, HOOK, WIRE, ROD, KEY, MAX_NOUNS};
enum en_Doors {CELLDOOR, MAX_DOORS};
const int NONE = -1;
struct verb
{
string word;
vector<string> synonyms;
int code;
};
struct noun
{
string word;
string description;
string on_examination;
int code;
int location;
bool can_carry;
bool can_reuse;
vector<int> combineWith;
vector<int> combinationResult;
vector<string> combineComment;
};
struct room
{
string description;
int exits_to_room[MAX_DIRS];
};
struct door
{
string description_1_open;
string description_1_closed;
string description_2_open;
string description_2_closed;
string on_examination_1;
string on_examination_2;
int location_1;
int location_2;
bool isopen;
bool islocked;
string word;
int code;
};
#endif //__PROPERTIES_H_INCLUDED___
verbs.cpp
#ifndef __VERBS_H_INCLUDED__
#define __VERBS_H_INCLUDED__
#include “properties.cpp”
inline void set_directions(verb *dir)
{
dir[NORTH].code = NORTH;
dir[NORTH].word = “NORTH”;
dir[SOUTH].code = SOUTH;
dir[SOUTH].word = “SOUTH”;
dir[EAST].code = EAST;
dir[EAST].word = “EAST”;
dir[WEST].code = WEST;
dir[WEST].word = “WEST”;
}
inline void set_verbs(verb *vbs)
{
vbs[GO].code = GO;
vbs[GO].word = “GO”;
vbs[LOOK].code = LOOK;
vbs[LOOK].word = “LOOK”;
vbs[GET].code = GET;
vbs[GET].word = “GET”;
vbs[INV].code = INV;
vbs[INV].word = “INV”;
vbs[DROP].code = DROP;
vbs[DROP].word = “DROP”;
vbs[USE].code = USE;
vbs[USE].word = “USE”;
}
#endif // __VERBS_H_INCLUDED__
nouns.cpp
#ifndef __NOUNS_H_INCLUDED__
#define __NOUNS_H_INCLUDED__
#include “properties.cpp”
inline void set_nouns(noun *nns)
{
nns[STICK].word = “STICK”;
nns[STICK].code = STICK;
nns[STICK].description = “a STICK”;
nns[STICK].on_examination = “a crooked, thin stick as long as my arm”;
nns[STICK].can_carry = true;
nns[STICK].can_reuse = false;
nns[STICK].location = CELL;
nns[STICK].combineWith.push_back(STRING);
nns[STICK].combinationResult.push_back(POLE);
nns[STICK].combineComment.push_back(“I tied the string to the stick and got a fishing POLE”);
nns[STICK].combineWith.push_back(HOOK);
nns[STICK].combinationResult.push_back(ROD);
nns[STICK].combineComment.push_back(“I tied the hook to the stick and got a fishing ROD”);
nns[POLE].word = “POLE”;
nns[POLE].code = POLE;
nns[POLE].description = “a fishing POLE”;
nns[POLE].on_examination = “a rudimentary fishing pole, though it doesn’t have a hook”;
nns[POLE].can_carry = true;
nns[POLE].can_reuse = false;
nns[POLE].location = NONE;
nns[POLE].combineWith.push_back(WIRE);
nns[POLE].combinationResult.push_back(ROD);
nns[POLE].combineComment.push_back(“I tied the wire to the pole and got a fishing ROD”);
nns[STRING].word = “STRING”;
nns[STRING].code = STRING;
nns[STRING].description = “a piece of STRING”;
nns[STRING].on_examination = “a bit of rough but sturdy twine of origins unknown”;
nns[STRING].can_carry = true;
nns[STRING].can_reuse = false;
nns[STRING].location = CELL;
nns[STRING].combineWith.push_back(STICK);
nns[STRING].combinationResult.push_back(POLE);
nns[STRING].combineComment.push_back(“I tied the string to the stick and got a fishing POLE”);
nns[STRING].combineWith.push_back(WIRE);
nns[STRING].combinationResult.push_back(HOOK);
nns[STRING].combineComment.push_back(“I tied the string to the wire and got a HOOK”);
nns[HOOK].word = “HOOK”;
nns[HOOK].code = HOOK;
nns[HOOK].description = “a string tied to a piece of curved wire”;
nns[HOOK].on_examination = “a piece of string with the wire bent into a hook, not very useful on it’s own”;
nns[HOOK].can_carry = true;
nns[HOOK].can_reuse = false;
nns[HOOK].location = NONE;
nns[HOOK].combineWith.push_back(STICK);
nns[HOOK].combinationResult.push_back(ROD);
nns[HOOK].combineComment.push_back(“I tied the hook to the stick and got a fishing ROD”);
nns[WIRE].word = “WIRE”;
nns[WIRE].code = WIRE;
nns[WIRE].description = “a bit of WIRE”;
nns[WIRE].on_examination = “a small bit of wire, bent into an uneven U shape, I feel like I’ve seen this before”;
nns[WIRE].can_carry = true;
nns[WIRE].can_reuse = false;
nns[WIRE].location = CELL;
nns[WIRE].combineWith.push_back(STRING);
nns[WIRE].combinationResult.push_back(HOOK);
nns[WIRE].combineComment.push_back(“I tied the string to the wire and got a HOOK”);
nns[WIRE].combineWith.push_back(POLE);
nns[WIRE].combinationResult.push_back(ROD);
nns[WIRE].combineComment.push_back(“I tied the wire to the pole and got a fishing ROD”);
nns[ROD].word = “ROD”;
nns[ROD].code = ROD;
nns[ROD].description = “a fishing ROD”;
nns[ROD].on_examination = “a rudimentary fishing rod, with hook and line”;
nns[ROD].can_carry = true;
nns[ROD].can_reuse = true;
nns[ROD].location = NONE;
nns[ROD].combineWith.push_back(KEY);
nns[ROD].combinationResult.push_back(KEY);
nns[ROD].combineComment.push_back(“I got the key”);
nns[KEY].word = “KEY”;
nns[KEY].code = KEY;
nns[KEY].description = “a KEY in the Dungeon”;
nns[KEY].on_examination = “The key to get out of this cell, but it’s out of reach”;
nns[KEY].can_carry = false;
nns[KEY].can_reuse = false;
nns[KEY].location = CELL;
nns[KEY].combineWith.push_back(ROD);
nns[KEY].combinationResult.push_back(KEY);
nns[KEY].combineComment.push_back(“I got the key”);
}
#endif // __NOUNS_H_INCLUDED__
main.cpp
#include <iostream>
#include <string>
#include <vector>
#include “rooms.cpp”
#include “nouns.cpp”
#include “verbs.cpp”
using namespace std;
bool section(string userInput, vector<string> &words)
{
string subString;
if(!userInput.empty())
{
//Make everything upper case for easier handling
for(int i = 0; i <= static_cast<signed int>(userInput.length()-1); i++)
{
userInput[i] = toupper(userInput[i]);
}
//Split userInput into a string vector for even easier handling later
for(int i = 0; i <= static_cast<signed int>(userInput.length()-1); i++)
{
if(userInput[i] != ‘ ‘ && i <= static_cast<signed int>(userInput.length()-1))
{
subString += userInput[i];
}
if(userInput[i] == ‘ ‘ || i == static_cast<signed int>(userInput.length()-1))
{
words.push_back(subString);
subString.clear();
}
}
}
else
{
words.push_back(“LOOK”);
}
return true;
}
bool look(int loc, room *rms, noun *nns, verb *dir, door *drs)
{
string str = “I’m in a ” + rms[loc].description + “. “;
bool andadded = false;
bool isdoor = false;
int numObjects = 0;
for(int i = 0; i < MAX_NOUNS; i++)
{
if(nns[i].location == loc)
{
if(numObjects == 0)
{
str = str + “I see “;
}
numObjects++;
str = str + nns[i].description;
}
int ismore = 0;
int j;
for(j = i+1; j < MAX_NOUNS; j++)
{
if(nns[j].location == loc)
{
ismore++;
}
}
if(ismore == 1 && !andadded && numObjects > 1)
{
str = str + ” and “;
andadded = true;
}
if(ismore > 1)
{
str = str + “, “;
}
}
if(numObjects > 0)
{
str = str + “. “;
}
for(int i = 0; i < MAX_DIRS; i++)
{
//flag to make sure we don’t output twice by accident
isdoor = false;
//Check that there’s something at this direction
if(rms[loc].exits_to_room[i] != NONE)
{
//Check that if it’s a door rather than a exit at a direction
for(int j = 0; j < MAX_DOORS; j++)
{
//Check if it is in fact a door
if(rms[loc].exits_to_room[i] == drs[j].code)
{
//change flag to avoid doubling up now we know it’s a room
isdoor = true;
//check which room location we’re at
if(loc == drs[j].location_1)
{
if(!drs[j].isopen)
{
str = str + “To the ” + dir[i].word + ” is ” + drs[rms[loc].exits_to_room[i]].description_1_closed + “, “;
if(drs[j].islocked)
{
str = str + “it is locked. “;
}
else
{
str = str + “it is unlocked. “;
}
}
else
{
str = str + “To the ” + dir[i].word + ” is ” + drs[rms[loc].exits_to_room[i]].description_1_open + “, “;
if(drs[j].islocked)
{
str = str + “it is locked. “;
}
else
{
str = str + “it is unlocked. “;
}
}
}
else
{
if(!drs[j].isopen)
{
str = str + “To the ” + dir[i].word + ” is ” + drs[rms[loc].exits_to_room[i]].description_2_closed + “, “;
if(drs[j].islocked)
{
str = str + “it is locked. “;
}
else
{
str = str + “it is unlocked. “;
}
}
else
{
str = str + “To the ” + dir[i].word + ” is ” + drs[rms[loc].exits_to_room[i]].description_2_open + “, “;
if(drs[j].islocked)
{
str = str + “it is locked. “;
}
else
{
str = str + “it is unlocked. “;
}
}
}
}
}
//It’s not a door so it must be a direction to a room
if(!isdoor)
{
str = str + “To the ” + dir[i].word + ” is a ” + rms[rms[loc].exits_to_room[i]].description + “. “;
}
}
}
str = str + “\n”;
cout << str;
return true;
}
bool inventory(noun *nns)
{
bool emptyPockets = true;
for(int i = 0; i < MAX_NOUNS; i++)
{
if(nns[i].location == POCKET)
{
cout << “I have a ” + nns[i].word + “.\n”;
emptyPockets = false;
}
}
if(emptyPockets)
{
cout << “I’m not carrying anything.\n”;
}
return true;
}
int use(int itemA, int itemB, int &loc, noun *nns)
{
//check both items are available for use, either in pocket or in the same room
if((nns[itemA].location == loc || nns[itemA].location == POCKET)
&& (nns[itemB].location == loc || nns[itemB].location == POCKET))
{
for(int i = 0; i < static_cast<signed int>(nns[itemA].combineWith.size()); i++)
{
if(nns[itemA].combineWith[i] == nns[itemB].code)
{
if(nns[itemA].can_reuse == false)
{
nns[itemA].location = NONE;
}
if(nns[itemB].can_reuse == false)
{
nns[itemB].location = NONE;
}
nns[nns[itemA].combinationResult[i]].can_carry = true;
nns[nns[itemA].combinationResult[i]].location = POCKET;
cout << nns[itemA].combineComment[i] + “.\n”;
return nns[itemA].combinationResult[i];
}
}
}
return NONE;
}
bool parser (int &loc, room *rms, verb *dir, verb *vbs, noun *nns, vector<string> words, door *drs)
{
//By using a vector we can have multiple actions in one input
vector<int> stepper;
vector<string> commander;
int i = 0;
int j = 0;
for(i = 0; i < static_cast<signed int>(words.size()); i++)
{
//check for verb
for(j = 0; j < MAX_VERBS; j++)
{
if(words[i] == vbs[j].word)
{
stepper.push_back(vbs[j].code);
commander.push_back(“VERB”);
}
}
//check for route command
for(j = 0; j < MAX_DIRS; j++)
{
if(words[i] == dir[j].word)
{
stepper.push_back(dir[j].code);
commander.push_back(“DIR”);
}
}
//check for nouns
for(j = 0; j < MAX_NOUNS; j++)
{
if(words[i] == nns[j].word)
{
stepper.push_back(nns[j].code);
commander.push_back(“NOUN”);
}
}
//check for doors
for(j = 0; j < MAX_DOORS; j++)
{
if(words[i] == drs[j].word)
{
stepper.push_back(drs[j].code);
commander.push_back(“DOOR”);
}
}
}
if(stepper.empty() && words[0] != “QUIT”)
{
cout << “That didn’t make any sense.\n”;
return true;
}
for(i = 0; i < static_cast<signed int>(stepper.size()); i++)
{
j = 0;
if(commander[i] == “VERB”)
{
for(j = 0; j+i < static_cast<signed int>(stepper.size()); j++)
{
if(stepper[i] == LOOK)
{
//check if there’s another word in the stepper to use
if((i+j+1) < static_cast<signed int>(stepper.size()))
{
//The next word is a direction
if(commander[i+j+1] == “DIR”)
{
//Check there’s something to look at
if(rms[loc].exits_to_room[stepper[i+j+1]] != NONE)
{
cout << “I see a ” + rms[rms[loc].exits_to_room[stepper[i+j+1]]].description + “.\n”;
}
else
{
cout << “There is nothing to the ” + dir[stepper[i+j+1]].word + “.\n”;
}
}
//The next word is a noun
else if(commander[i+j+1] == “NOUN”)
{
//Check the object is actually in the same location
if(nns[stepper[i+j+1]].location == loc)
{
cout << “I see ” + nns[stepper[i+j+1]].description + “.\n”;
}
else
{
cout << “I don’t see one of those here”;
}
}
//The next word is a door
else if(commander[i+j+1] == “DOOR”)
{
//Check which door location we’re at so we can respond appropriately
if(loc == drs[stepper[i+j+1]].location_1)
{
if(drs[stepper[i+j+1]].isopen)
{
if(drs[stepper[i+j+1]].islocked)
{
cout << “I see ” + drs[stepper[i+j+1]].description_1_open + “, it is locked.\n”;
}
else
{
cout << “I see ” + drs[stepper[i+j+1]].description_1_open + “, and it is unlocked.\n”;
}
}
else
{
if(drs[stepper[i+j+1]].islocked)
{
cout << “I see ” + drs[stepper[i+j+1]].description_1_closed+ “, it is locked.\n”;
}
else
{
cout << “I see ” + drs[stepper[i+j+1]].description_1_closed+ “, and it is unlocked.\n”;
}
}
}
else
{
if(drs[stepper[i+j+1]].isopen)
{
if(drs[stepper[i+j+1]].islocked)
{
cout << “I see ” + drs[stepper[i+j+1]].description_2_open + “, it is locked.\n”;
}
else
{
cout << “I see ” + drs[stepper[i+j+1]].description_2_open + “, and it is unlocked.\n”;
}
}
else
{
if(drs[stepper[i+j+1]].islocked)
{
cout << “I see ” + drs[stepper[i+j+1]].description_2_closed+ “, it is locked.\n”;
}
else
{
cout << “I see ” + drs[stepper[i+j+1]].description_2_closed+ “, and it is unlocked.\n”;
}
}
}
}
//The next word is a verb and we haven’t done anything yet
else if(commander[i+j+1] == “VERB” && j == 0)
{
look(loc, rms, nns, dir, drs);
}
}
//If there’s no more words in stepper to use and we haven’t already done something
else if((i+j+1) == static_cast<signed int>(commander.size()) && j == 0)
{
look(loc, rms, nns, dir, drs);
}
}
if(stepper[i] == GO)
{
//Check if there’s another word in the stepper to use
if((i+j+1) < static_cast<signed int>(stepper.size()))
{
//The next word is a direction
if(commander[i+j+1] == “DIR”)
{
//Check there’s somewhere to actually go
if(rms[loc].exits_to_room[stepper[i+j+1]] != NONE)
{
bool isdoor = false;
for(int k = 0; k < MAX_DOORS; k++)
{
if(rms[loc].exits_to_room[stepper[i+j+1]] == drs[k].code)
{
isdoor = true;
if(!drs[k].islocked)
{
if(drs[k].isopen)
{
if(loc == drs[k].location_1)
{
loc = drs[k].location_2;
look(loc, rms, nns, dir, drs);
}
else
{
loc = drs[k].location_1;
look(loc, rms, nns, dir, drs);
}
}
else
{
cout << “The ” + drs[k].word + ” is closed.\n”;
}
}
else
{
cout << “The ” + drs[k].word + ” is locked.\n”;
}
}
}
if(!isdoor)
{
loc = rms[loc].exits_to_room[stepper[i+j+1]];
look(loc, rms, nns, dir, drs);
}
}
else
{
cout << “There is no exit that way.\n”;
}
}
//The next word is a noun
else if(commander[i+j+1] == “NOUN”)
{
cout << “You cannot go there.\n”;
}
//The next word is a door
else if(commander[i+j+1] == “DOOR”)
{
if(!drs[stepper[i+j+1]].islocked)
{
if(drs[stepper[i+j+1]].isopen)
{
if(loc == drs[stepper[i+j+1]].location_1)
{
loc = drs[stepper[i+j+1]].location_2;
look(loc, rms, nns, dir, drs);
}
else
{
loc = drs[stepper[i+j+1]].location_1;
look(loc, rms, nns, dir, drs);
}
}
else
{
cout << “The ” + drs[stepper[i+j+1]].word + ” is closed.\n”;
}
}
else
{
cout << “The ” + drs[stepper[i+j+1]].word + ” is locked.\n”;
}
}
//The next word is a verb and we haven’t done anything yet
else if(commander[i+j+1] == “VERB” && j == 0)
{
cout << “Go where?\n”;
}
}
//if there’s no more words in stepper to use and we haven’t already done something
else if((i+j+1) == static_cast<signed int>(commander.size()) && j == 0)
{
cout << “Go where?\n”;
}
}
if(stepper[i] == GET)
{
//Check if there’s another word in the stepper to use
if((i+j+1) < static_cast<signed int>(stepper.size()))
{
//The next word is a direction
if(commander[i+j+1] == “DIR”)
{
cout << “Did you mean GO ” + dir[stepper[i+j+1]].word + “?\n”;
}
//The next word is a noun
else if(commander[i+j+1] == “NOUN”)
{
if(nns[stepper[i+j+1]].can_carry == true)
{
if(nns[stepper[i+j+1]].location == loc)
{
nns[stepper[i+j+1]].location = POCKET;
cout << “I picked up ” + nns[stepper[i+j+1]].description + “.\n”;
}
else if(nns[stepper[i+j+1]].location == POCKET)
{
cout << “I already have ” + nns[stepper[i+j+1]].description + “.\n”;
}
else
{
cout << “There isn’t ” + nns[stepper[i+j+1]].description + ” here.\n”;
}
}
else
{
cout << “I can’t pick that up.\n”;
}
}
//The next word is a door
else if(commander[i+j+1] == “DOOR”)
{
cout << “You can’t get that.\n”;
}
//The next word is a verb and we haven’t done anything yet
else if(commander[i+j+1] == “VERB” && j == 0)
{
cout << “Get what?\n”;
}
}
//if there’s no more words in stepper to use and we haven’t already done something
else if((i+j+1) == static_cast<signed int>(commander.size()) && j == 0)
{
cout << “Get what?\n”;
}
}
if(stepper[i] == DROP)
{
//Check if there’s another word in the stepper to use
if((i+j+1) < static_cast<signed int>(stepper.size()))
{
//The next word is a direction
if(commander[i+j+1] == “DIR”)
{
cout << “Drop what?\n”;
cout << “Did you mean to GO ” + dir[stepper[i+j+1]].word + “?\n”;
}
//The next word is a noun
else if(commander[i+j+1] == “NOUN”)
{
if(nns[stepper[i+j+1]].location == POCKET)
{
nns[stepper[i+j+1]].location = loc;
cout << “I dropped ” + nns[stepper[i+j+1]].description + “.\n”;
}
else
{
cout << “I can’t drop something I don’t have.\n”;
}
}
//The next word is a door
else if(commander[i+j+1] == “DOOR”)
{
cout << “You can’t drop what you couldn’t get in the first place.\n”;
}
//The next word is a verb and we haven’t done anything yet
else if(commander[i+j+1] == “VERB” && j == 0)
{
cout << “Drop what?\n”;
}
}
//if there’s no more words in stepper to use and we haven’t already done something
else if((i+j+1) == static_cast<signed int>(commander.size()) && j == 0)
{
cout << “Drop what?\n”;
}
}
if(stepper[i] == INV)
{
//Check if there’s another word in the stepper to use
if((i+j+1) < static_cast<signed int>(stepper.size()))
{
//The next word is a direction
if(commander[i+j+1] == “DIR”)
{
inventory(nns);
cout << “Did you mean GO ” + dir[stepper[i+j+1]].word + “?\n”;
}
//The next word is a noun
else if(commander[i+j+1] == “NOUN”)
{
if(nns[stepper[i+j+1]].location == POCKET)
{
cout << “I have a ” + nns[stepper[i+j+1]].word + ” in my inventory.\n”;
}
else if(nns[stepper[i+j+1]].location == loc)
{
cout << “I don’t have a ” + nns[stepper[i+j+1]].word + ” but there’s one in the room.\n”;
}
else
{
cout << “I don’t have a ” + nns[stepper[i+j+1]].word + “.\n”;
}
}
//The next word is a door
else if(commander[i+j+1] == “DOOR”)
{
cout << “That’s not in any kind of inventory, except maybe the castle blueprints.\n”;
}
//The next word is a verb and we haven’t done anything yet
else if(commander[i+j+1] == “VERB” && j == 0)
{
inventory(nns);
}
}
//if there’s no more words in stepper to use and we haven’t already done something
else if((i+j+1) == static_cast<signed int>(commander.size()) && j == 0)
{
inventory(nns);
}
}
if(stepper[i] == USE)
{
//Check if there’s another word in the stepper to use
if((i+j+1) < static_cast<signed int>(stepper.size()))
{
//The next word is a direction
if(commander[i+j+1] == “DIR”)
{
cout << “I cannot use that.\n”;
}
//The next word is a noun
else if(commander[i+j+1] == “NOUN”)
{
int k = 0;
//count how many nouns there are to be used
//We will deal with them all here rather then the main loop as combining items and then combining again could invalidate the procedure
int numberNouns = 1;
while(commander[i+j+numberNouns] == “NOUN” && i+j+numberNouns+1 < static_cast<signed int>(stepper.size()))
{
numberNouns++;
}
if(numberNouns == 1)
{
cout << “use ” + nns[stepper[i+j+1]].word + ” with what?\n”;
}
else if(numberNouns > 1)
{
int itemA = nns[stepper[i+j+1]].code;
//loop ahead using each word
for(k = 1; k < numberNouns; k++)
{
cout << k;
int itemB = nns[stepper[i+j+k+1]].code;
itemA = use(itemA, itemB, loc, nns);
}
}
i = i + k;
}
//The next word is a door
else if(commander[i+j+1] == “DOOR”)
{
//is it locked
if(drs[stepper[i+j+1]].islocked == false)
{
//is it open
if(drs[stepper[i+j+1]].isopen == false)
{
drs[stepper[i+j+1]].isopen = true;
cout << “I have opened the ” + drs[stepper[i+j+1]].word + “.\n”;
}
else
{
drs[stepper[i+j+1]].isopen = false;
cout << “I have closed the ” + drs[stepper[i+j+1]].word + “.\n”;
}
}
else
{
cout << “The door is locked.\n”;
}
}
//The next word is a verb and we haven’t done anything yet
else if(commander[i+j+1] == “VERB” && j == 0)
{
cout << “You can’t use a verb!\n”;
}
}
//if there’s no more words in stepper to use and we haven’t already done something
else if((i+j+1) == static_cast<signed int>(commander.size()) && j == 0)
{
cout << “Use what?\n”;
}
}
//stop inner loop if the next word is a verb or you hit the end of stepper
if(i+j+1 < static_cast<signed int>(stepper.size()))
{
if(commander[i+j+1] == “VERB”)
{
break;
}
}
if(i+j+1 >= static_cast<signed int>(stepper.size()))
{
break;
}
}
}
i = i + j;
}
return true;
}
int main()
{
string userInput;
vector<string> words;
int location = CELL;
verb directions[MAX_DIRS];
set_directions(directions);
verb verbs[MAX_VERBS];
set_verbs(verbs);
room rooms[MAX_ROOMS];
set_rooms(rooms);
noun nouns[MAX_NOUNS];
set_nouns(nouns);
door doors[MAX_DOORS];
set_doors(doors);
do
{
words.clear();
getline(cin, userInput);
section(userInput, words);
parser(location, rooms, directions, verbs, nouns, words, doors);
}while(words[0] != “QUIT”);
}