Answer» New programming methods; new thread warranted.
I've taken Neil's advice and written a small file parser. This will allow for cleaner code in the .cpp file itself, and players can mod the dialog a little if, for some reason, they want to. Right now the parser has full functionality and can get through any properly formatted text file.
Now, back to the programming... I don't understand this. It's really starting to piss me off. I'm trying to make a Door class, and something I'm doing is pissing off the compiler. I've tried it command by command...
First, I make this:
class Door { public: Door(); ~Door(); };
and use this:
Door::Door() { }
Door::~Door() {}
This compiles.
Slowly, I add things, compiling every time. (I have other classes, but they are currently commented out.)
Finally, it looks like this:
class Door { public: Door(); ~Door(); bool getLocked() const { RETURN isLocked; } void setLocked(bool x) { isLocked = x; } bool getClosed() const { return isClosed; } void setClosed(bool x) { isClosed = x; } USHORT* getCode() { return lockCode; } void setCode(USHORT x[4]){ for(int i = 0; i < 4; i++) { lockCode = x; } private: bool isClosed; bool isLocked; USHORT lockCode[4]; };
Compiles.
Then, I add an enumerated variable:
enum DOORTYPE { STANDARD, STANDARD_LOCKED, CODE_LOCK };
class Door { public: Door(DOORTYPE x); ~Door(); bool getLocked() const { return isLocked; } void setLocked(bool x) { isLocked = x; } bool getClosed() const { return isClosed; } void setClosed(bool x) { isClosed = x; } USHORT* getCode() { return lockCode; } void setCode(USHORT x[4]){ for(int i = 0; i < 4; i++) { lockCode = x; } private: bool isClosed; bool isLocked; USHORT lockCode[4]; };
Implementation of
Door::Door(DOORTYPE x) { isClosed = true; isLocked = true; //Testing, will add if logic later. }
Door::~Door() {}
This will NOT compile; I get 15 errors. But read some of these errors:
58 escape.cpp `Door::Door()' and `Door::Door()' cannot be overloaded 66 escape.hpp `isLocked' undeclared (first use this function)
escape.hpp In member function `void Door::setLocked(bool)': isLocked' undeclared (first use this function)
I think to myself: Oookay, there MUST be an error in the DOORTYPE. Logical assumption. So I remove all references to DOORTYPE. I compile... and get the same errors!
I remove all code from the constructor... same result.
Here's the full body of uncommented code:
Code: [SELECT]//Escape.hpp typedef unsigned short int USHORT; enum DOORTYPE { STANDARD, STANDARD_LOCKED, CODE_LOCK };
class Door { public: Door(DOORTYPE x); ~Door(); bool getLocked() const { return isLocked; } void setLocked(bool x) { isLocked = x; } bool getClosed() const { return isClosed; } void setClosed(bool x) { isClosed = x; } USHORT* getCode() { return lockCode; } void setCode(USHORT x[4]){ for(int i = 0; i < 4; i++) { lockCode[i] = x[i]; } private: bool isClosed; bool isLocked; USHORT lockCode[4]; };
Code: [Select]//Escape.cpp //Includes #include <iostream> #include <ctime> //time() <--Delays, RNG #include <cstdlib> //srand() and rand() #include <string> #include "escape.hpp"
//Macros #define SET_RANDOM_CODE \ srand (time(NULL)); \ USHORT r; \ for(int i = 0; i < 4; i++) \ { \ r = rand()%999; \ r /= 100; \ code[i] = r; \ }
//Using using namespace std;
//Global Variables, soon to be replaces in a Player class... string input; //Player's reply ROOM location; //Player's location
Door::Door(DOORTYPE x) { isClosed = true; isLocked = true; //Testing, will add if logic later. }
Door::~Door() {}
int MAIN() { return 0; }The errors I get:
58 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.cpp `Door::Door()' and `Door::Door()' cannot be overloaded
62 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.cpp `Door::~Door()' and `Door::~Door()' cannot be overloaded
110 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.cpp expected `}' at end of input
C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp In member function `bool Door::getLocked() const':
66 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp `isLocked' undeclared (first use this function)
C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp In member function `void Door::setLocked(bool)': 67 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp `isLocked' undeclared (first use this function)
C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp In member function `bool Door::getClosed() const':
68 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp `isClosed' undeclared (first use this function)
C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp In member function `void Door::setClosed(bool)': 69 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp `isClosed' undeclared (first use this function)
C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp In member function `USHORT* Door::getCode()': 70 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp `lockCode' undeclared (first use this function)
C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp In member function `void Door::setCode(USHORT*)': 71 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp `lockCode' undeclared (first use this function)
72 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp expected primary-expression before "private"
72 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp expected `;' before "private"
72 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.hpp At global scope:
110 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.cpp expected unqualified-id at end of input
110 C:\Documents and Settings\Timothy\My Documents\CPP\C++\source\Escape\escape.cpp expected `,' or `;' at end of input NOOO...
Ignore previous two posts...
This line was the culprit:
void setCode(USHORT x[4]){ for(int i = 0; i < 4; i++) { lockCode = x; }
I AM MISSING A BRACKET!!!
This compiled fine:
void setCode(USHORT x[4]){ for(int i = 0; i < 4; i++) { lockCode = x; } }
I'm leaving this here as a testament to how one character can cause tons of mistakes. Haha welcome to the wonderful world of C++! This is why trying to squeeze everything onto 1 line is a bad idea Also when creating a new function, it's a good idea to create the skeleton for it first (the tabs, {}, etc) then fill it in, as not to forget anything.I originally wrote it as multiple lines, then I compressed it. I guess I struck that Delete key one too many times. I normally don't condone double-posting, but as I may have updates any time, I feel it acceptable in this thread.
The bare MINIMUM code required to create the bedrooms of my house is complete. Using aggregation, I have four true OOP rooms. All 145 errors (another bracket or two missing) fixed, and that is complete. Next, I write the story for the first room. Which means moving my text file parser into this program (that'll be fun...).
EDIT: File parser is implemented. The ideas for a command parser are being drawn up, too. I believe I have written the most important piece of code in the program -- and it's only about 8 working lines.
Code: [Select]void parseFile(string begin, string end) //Within selected header, output contents { string parser; ifstream fin("escape.dialog"); fin.seekg(0, ios_base::beg); //Just to be safe, put the parser at the beginning while(parser != begin) //Search for the first tag { getline(fin, parser); } //Start tag is in parser right now. //Output text to the screen until the end tag is reached for(getline(fin, parser); parser != end; getline(fin, parser)) { cout << parser << endl; } //End tag is in parser now. //Doesn't matter; the variable is destroyed now. fin.close(); } The comments about what is in the variable are only there to cement my understanding of what's going on in my program's code. I'm not inept, really.
I tested this, passing "#INTRO" and "#END_INTRO" as arguments. The contents of escape.dialog are:
Quote Sample comment; nothing outside of header tags are used. #INTRO Welcome to Escape by Timothy Bennett. The object of this game is to escape my house. This is debugging filler to test the file parser. #END_INTRO
Output:
Welcome to Escape by Timothy Bennett. The object of this game is to escape my house. This is debugging filler to test the file parser.
It's up and running!
I can safely say I've never written a for loop that way before. With the file parser down, it's time to work on the command parser.
The command parser will make figuring out the file parser look easy. The problem isn't so much writing the code as figuring out the best way.
In earlier attempts at this program, the room-specific commands were functions inside of the class the room was in. This made it easy to write a command function as I had direct access to the variables I needed to access. No accessor functions, no "returning a reference to an object" so I can manipulate a variable.
However, this may not be technically feasible anymore. Three instances will use the same class, SmallBedroom, so using that method I'd have to put the commands for timsBedroom in the same spot as sarahsBedroom in the same spot as -- well, you get the idea. I don't want to do that, because not only does that place undue importance on the enumerated ROOM, but it's unorganized.
The other strategy, which I'm starting to like more and more, is to put all parsers and command functions in a Command class. Public will contain the parsers; private will be the commands. That's a lot of functions for one class, but then it's out of the way.Cool. I am reading your posts but I've been too busy to make a decent reply to them.
How exactly are these commands going to work? I was thinking of something like the following, but more complicated. Create a dynamic number of event/scene classes containing an id number, a string for the description of the area, and a dynamic number of choices with a string for each choice and the destination id. Each event stored in the script has an id number, string description and a number of choices and destinations. For example, choice 2 is "go in second door" and leads to event id 7 (that room) or you could name each scene if that's more convienient. That's a simplification of the way I would do it. Is this similar to the way you are planning to do it?If the house in question were large, I'd do something very close to that. (Or maybe I am; I didn't follow you 100%.) If you were saying that the user pick from a menu of available options, then that is something I would gladly do if this game were much larger. As it is, it's not very large(!), so it's going to be somewhat of a throwback to the old command-line games, where the user enters a string of text, such as "take item". An example of an online form of this game style can be seen here: http://thcnet.net/zork/
Of course, this requires a good deal of creativity on my part, making sure the parser accepts multiple variants of the same command. Even better, they could be in a file, allowing them to be edited without having to recompile the program. It's a matter of how much of the game I want to expose for editing. This, I feel, can be done.
Again, I wouldn't do this if there was any real difficulty in the game itself. It may have a few points, but I don't think so. (Then again, I'm writing this game and know exactly how to win. )Update:
Class-work for the first room is complete. File parser is complete; I'm working on the command parser. I'm noticing the downside of OOP. This game needs OOP, but how often can I type things like this and remain sane?
if(timsBedroom->getComputerDesk()->getLight()->inInventory == false) { timsBedroom->getComputerDesk()->getLight()->inInventory == true; parseFile("#TAKE_LIGHT", "#END_TAKE_LIGHT", 1.5); //Delay getline for 1.5 seconds }
As you can see, I'm using pointers for all my classes so I can delete them and set them to 0 as needed (each SmallBedroom instance has different classes, so this is required), but that means I'm eternally calling functions that return pointers to classes.
TO-DO LIST:
Finish first room 1. Write command parsers 2. Write command functions 3. Write dialog
I'll worry about the rest of the game later. Try macros.
#define location timsBedroom->getComputerDesk()->getLight()->inInventory
I'm not sure if you can redefine marcos but if you can then just redefine location at the start of each section withs lots of repetitive object names.
You could even combine them.
#define area timsBedroom->getComputerDesk() #define subarea getLight()
area->subarea->inInventory
#define subarea getBook()
area->subarea->inInventory
|