Working on a Text Adventure

I am working on a text adventure right now, and it's pretty good if I do say so myself. But right now there is one big issue that continues to vex me. Help would be appreciated!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
a = 0;
	b = 5;

	while (a > 5)
	{
  if (answer5 == "2")                                                              //this is if answer is 2
  { cout << "You die from being really fat and your fat suffocates you."<<endl; 
    Sleep (4 * 1000);
		a = 1;
		b = 500;
		while (a < b)
	{ cout << "-  -    -      - -  -    -  - -   -     -       -   -    -   - -    -  -";
		a = a + 1; } 
		system("CLS");
		cout << "YOU DIED";
		Sleep (4 * 1000);
		system("CLS");
		cout << "Would you like to restart?"<<endl;
		cin >> answer1;

		if ( answer1 == "yes" || answer1 == "Yes")
		{ goto  Beginning; }
		
		else if (answer1 == "no" || answer1 == "No")
			{ return 0; }
  }


  else if (answer5 != "1" || answer5 != "2")
			{ cout << "Did you read the instructions? Either you didn't read the instructions or your just plain stupid."<<endl;  //security protocol if someone doesnt answer yes or no
		Sleep (4* 1000);                                                                                                          //need to add it throughout program
		return 0; }
	


  else if (answer5 == "1")  //this is if answer is 1 (CORRECT)
  {   system("CLS");
	  goto yes1; }        
    
	

  Sleep(2 * 1000);
  a = a + 1;
  if (a >= 5)
  {goto timerunout;}
	}


The problem is that I don't know how to make the program go to the time run out.
I assume (but might be wrong) that the program would go through this whole portion until until either 'option 1' or 'option 2' was entered or 'a' became equal to 5.

This isn't my whole text adventure, just the part that gives me trouble. So
all the 'gotos' and answer5 are taken care of outside of this portion of the program. Thanks for any help.
Start timer in another thread, communicate with current somehow.
what you said just made no sense
Look. Sleep pauses currnet thread. Input operations pauses current thread. You cannot do what do you want until you have asynchronous timer running in background (Actually you can take raw input from keyboard, process it manually, check timer on each iteration of infinite loop, but it is too much work)
else if (answer5 != "1" || answer5 != "2")

This condition is always true. Did you want && instead of || ?
No...it's supposed to be that way. That way someone can't just skip the program by saying 'hi.'
Giraffatron is correct. That expression will always evaluate to true. You should change it.
Unfortunately, there's no simple way to do what you're looking for. I'd say it's too ambitious for you to tackle at this point.
Last edited on
I would just like to add that you shouldn't make duplicate threads on the forum.
http://www.cplusplus.com/forum/general/101945/
I apologize for making an extra thread but it had been 3 days without a response. Also, the main reason I have the else if (answer5 != "1" || answer5 != "2") statement is because it is designed to terminate the program if the player does not type in the 2 options given to him. That way they could not bypass my program by typing 'hi.'

Back to the point: are you saying there is no way to solve my first issue?
Last edited on
That else if statement doesn't do what you want:

Suppose answer5 = "1"
Is answer 5 not equal to "1"? no. Is answer 5 not equal to "2"? yes. (no OR yes) == yes. So it evaluates to true.

Suppose answer5 = "2"
Is answer 5 not equal to 1? yes. So it evaluates to true.

Suppose answer5 = "z" or anything else
Is answer 5 not equal to "1"? yes. So it evaluates to true.

So, no matter the value of answer5, you always get the same result. If you switched to && (logical and) instead of || (logical or), you would get a more useful behavior.

(There's a major potential gotcha here, too: answer5 had better be a type of object that has an appropriate comparison operator for strings. If it's just a character pointer, for example, you can't assume that a string reading "2" in one place has the same address as a different string reading "2" elsewhere.)

You should be aware that goto statements are usually regarded as very bad practice for a couple reasons, foremost that they quickly make code hard to follow.
I will make the change to the 'else if' statement, but I don't know a better way than the goto statement. Also, my original problem of not knowing how to make it so that if you don't type in an answer for 'answer5' in 10 seconds then it takes you to the 'timerunout.'
goto statements can usually be replaced by loops, especially do/while and while loops.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//goto
int main(){
   bool keep_playing=true;
   My_ASM_like_label:
     //hundreds of lines of code that will make you forget
     //   where My_ASM_like_label refers to or where it is
   if(keep_playing)   goto My_ASM_like_label;  //have to keep track of two things
}
//versus loop
int main(){
   bool keep_playing=true;
   do{
      //hundreds of lines of code
   }while(keep_playing);  //yay only one thing to worry about
}


As for your original question, some people have already mentioned multi-threading, which allows you to run things at the same time but is an advanced concept.
If you are asking about how to do something with the console without waiting for the user, but while still checking for user input, that isn't a trivial problem. The C++ console functions aren't designed for simultaneous non-blocking input.

Threads have been mentioned as one way to do this. That could work. There are other ways. Generally, these are platform-specific.

Here's how you might do it under Windows. This program uses the console and prints a dot every half-second unless the user sent input during that time. If the user did send input, the program displays the keystrokes and adds them to a buffer. When the user presses Enter, the buffer is swapped out (where it could then be used elsewhere as received input, e.g. sent to the interpreter in a text adventure). In this program, the received input string is just displayed back to the user when that happens.

The key functions here are WaitForSingleObject, PeekConsoleInput, and FlushConsoleInputBuffer.

It's a little rough, but it should give you a useful idea of what you could do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <Windows.h>
#include <iostream>
#include <string>

using namespace std;


int main()
{
	const int bufferSize = 100;

	bool runflag = true;
	bool inputSent = false;

	wstring userInput;
	wstring lastSentInput;

	HANDLE hin = GetStdHandle(STD_INPUT_HANDLE);
	INPUT_RECORD irBuffer[bufferSize] = { };
	DWORD mode;
	DWORD inputCount;
	DWORD pollState;
	TCHAR t;

	// Change to raw input mode
	GetConsoleMode(hin, &mode);	// Store the previous console mode for later restoration
	SetConsoleMode(hin, 0);		// Disable input echoing etc.

	FlushConsoleInputBuffer(hin);

	while(runflag)
	{	
		// Give the input stream 500 ms to respond
		pollState = WaitForSingleObject(hin, 500);

			if(pollState == WAIT_OBJECT_0)	// If the input stream signals back...
			{
				// Record up to (bufferSize) input events, then flush the stream
				PeekConsoleInput(hin, irBuffer, bufferSize, &inputCount);
				FlushConsoleInputBuffer(hin);

					for(DWORD i = 0; i < inputCount; i++)
						if(irBuffer[i].EventType == KEY_EVENT)
							if(irBuffer[i].Event.KeyEvent.bKeyDown)
							{
								t = irBuffer[i].Event.KeyEvent.uChar.UnicodeChar;
									switch(t)
									{
									case VK_RETURN:
										lastSentInput = userInput;
										userInput = L"";
										inputSent = true;
									break;	

									case VK_ESCAPE:	// Quit on Esc
										runflag = false;
									break;

									case 0:
									case VK_SHIFT:
										// Do nothing
									break;

									default:
										userInput += t;
										wcout << t;	// Echo the input
									}
							}
			}
			else if(pollState == WAIT_TIMEOUT) // If the input stream times out (no input)
				wcout << ".";
			else
				{ wcout << "\nError: WaitForSingleObject failed"; break; }

			if(inputSent)
			{
				inputSent = false;
				wcout << L"\n\nString received: " << lastSentInput
						<< endl << endl;
			}
	}

	// Restore previous console mode
	SetConsoleMode(hin, mode);

	wcout << "\nGoodbye.\n";
	return 0;
}
Topic archived. No new replies allowed.