Пример #1
0
/// For if- and elsif- statements.
void Script::HandleConditional(String line)
{
	// Remove first part until (
	int index = line.Find('(');
	line = line.Part(index);
	/// Use expressions from the MathLib. First parse for functions to provide their values? Or...
	Expression exp;
	List<Variable> allVars = GameVars.GetAllExpressionVariables() + variables;
	exp.functionEvaluators = functionEvaluators; // Set evaluators.
	bool parseOK = exp.ParseExpression(line);
	if (!parseOK)
	{
		std::cout<<"\nParse error in expression "<<line;
		return;
	}
	ExpressionResult res = exp.Evaluate(allVars);
	bool statementTrue = res.GetBool();
	/// If statement is true, sign this row as finished.
	if (statementTrue)
	{
		// Set line finished to true so the actual content will be processed.
		lineFinished = true;
		// Set if-Processed to true so that no elsif- or else- clause will be handled.
		ScriptLevel & latest = stack.Last();
		latest.evaluatedAtLine = currentLine;
	}
	else 
	{
		// Check stuff.
		ScriptLevel & sl = stack.Last();
		int newRow = -1;
		int ifStack = 0;
		// If the statement is not true, find an else or endif block..!
		for (int i = currentLine+1; i < lines.Size(); ++i)
		{
			String l = lines[i];
			if (sl.type == ScriptLevel::WHILE_LOOP)
			{
				if (l.Contains("endwhile"))
				{
					// Jump to next after, as regular stopping on endwhile will reboot the loop
					newRow = i + 1;
					stack.RemoveLast();
					break; 
				}
			}
			if (sl.type == ScriptLevel::IF_CLAUSE)
			{
				if (l.Contains("elsif") || l.Contains("else") || l.Contains("endif"))
				{
					if (ifStack == 0)
					{
						newRow = i; 
						break;
					}
					if (l.Contains("endif"))
						--ifStack;
				}
				else if (l.Contains("if"))
					++ifStack;
			}
		}
		assert(newRow > 0);
		// Process it next iteration.
		currentLine = newRow;
		lineProcessed = false;
		lineFinished = false;
		return;

	}
	if (lineFinished == false)
		assert(false && "Line not finished? Something is missing in the if/else/endif block!");	
}
Пример #2
0
void Script::EvaluateLine(String & line)
{
	/// Default line processed once?
	lineProcessed = true;

	line.SetComparisonMode(String::NOT_CASE_SENSITIVE);
	// "80Gray50Alpha.png"
#define DEFAULT_TEXTURE_SOURCE	"black50Alpha.png"
#define DEFAULT_TEXT_SIZE_RATIO	0.3f
	
	/// Some state began, take not of it?
	if (line.Contains("Wait("))
	{
		WaitScript * wait = new WaitScript(line, this);
		wait->SetDeleteOnEnd(true);
		ScriptMan.PlayScript(wait);
	}
	else if (line.StartsWith("Key:"))
	{
		String keyStr = line.Tokenize(":")[1];
		keyStr.RemoveSurroundingWhitespaces();
		int keyCode = GetKeyForString(keyStr);
		assert(keyCode != 0);
		InputMan.KeyDown(MainWindow(), keyCode, false);
		InputMan.KeyUp(MainWindow(), keyCode);
		lineFinished = true;
	}
	else if (line.Contains("PlayScript("))
	{
		List<String> tokens = line.Tokenize("(),");
		// Source of script within the parenthesis.
		String source = tokens[1];
		bool wait = true;
		Script * scriptParent = this;
		if (tokens.Size() >= 3)
		{
			wait = tokens[2].ParseBool();
			if (!wait)
			{
				scriptParent = NULL;
				this->lineFinished = true;
			}
		}
		Script * script = new Script(source, scriptParent);
		script->source = source;
		bool loaded = script->Load();
		assert(loaded);
		ScriptMan.PlayScript(script);
	}
	else if (line == "DisableActiveUI")
	{
		InputMan.DisableActiveUI();
		lineFinished = true;
		uiDisabled = true;
	}
	else if (line == "EnableActiveUI")
	{
		InputMan.EnableActiveUI();
		lineFinished = true;
	}
	else if (line.Contains("PreloadTexturesInDirectory("))
	{
		// Fetch the stuff, do the buff
		String dir = line.Tokenize("()")[1];
		List<String> files;
		int num = GetFilesInDirectory(dir, files);
		for (int i = 0; i < files.Size(); ++i)
		{
			String path = dir + "/" + files[i];
			Texture * tex = TexMan.LoadTexture(path);
			Graphics.QueueMessage(new GMBufferTexture(tex));
		}
		lineFinished = true;
	}
	else if (line.Contains("Begin("))
	{
		String stateBeginning = line.Tokenize("()")[1];
		if (stateBeginning == "Cutscene")
		{
			BeginCutscene();
		}
		lineFinished = true;
	}
	else if (line.Contains("End("))
	{
		String stateEnding = line.Tokenize("()")[1];
		if (stateEnding == "Cutscene")
		{
			EndCutscene();
		}
		lineFinished = true;
	}
	else if (line.Contains("EndScript"))
	{
		// End it.
		scriptState = ENDING;
	}
	else if (line.Contains("EnterGameState("))
	{
		String name = line.Tokenize("()")[1];		
		StateChanger * changer = new StateChanger(line, this);
		ScriptMan.PlayScript(changer);
	}
	else if (line.Contains("FadeTo(") || line.Contains("FadeIn("))
	{
		FadeInEffect * fade = new FadeInEffect(line, this);
		ScriptMan.PlayScript(fade);
	}
	else if (line.Contains("FadeInBackground("))
	{
		FadeInBackground * fade = new FadeInBackground(line, this);
		ScriptMan.PlayScript(fade);
	}
	else if (line.Contains("FadeOutBackground("))
	{
		FadeOutBackground * fade = new FadeOutBackground(line, this);
		ScriptMan.PlayScript(fade);
	}
	else if (line.Contains("FadeOut"))
	{
		FadeOutEffect * fade = new FadeOutEffect(line, this);
		ScriptMan.PlayScript(fade);
	}
	else if (line.Contains("FadeText("))
	{
		FadeTextEffect * text = new FadeTextEffect(line, this);
		ScriptMan.PlayScript(text);
		lineFinished = true;
	}
	else if (line.Contains("PlaySong("))
	{
		// Just play it.
		String song = line.Tokenize("()")[1];
		TrackMan.PlayTrack(song);
		// Line finished straight away.
		lineFinished = true;
	}
	else if (line.Contains("Dialogue")){
		/// If raw string, output it straight away! (should later be queued to some kind of dialogue-manager?)
		if (line.Contains("\"")){
			/// Create dialogue UI and append it to the current UI!
			String text = line.Tokenize("\"")[1];
			std::cout<<"\n"<<text;
			UIButton * dialogue = new UIButton("Dialogue");
			dialogue->exitable = false;
			dialogue->text = text;
			dialogue->activationMessage = "PopFromStack(this)&Remove(this)&ContinueEvent("+this->name+")";
			dialogue->textureSource = DEFAULT_TEXTURE_SOURCE;
			dialogue->textSizeRatio = DEFAULT_TEXT_SIZE_RATIO;
			dialogue->sizeRatioY = 0.3f;
			dialogue->alignmentY = 0.15f;
			dialogue->state |= UIState::DIALOGUE;  // Flag the dialogue-state flag to signify importance!
			Graphics.QueueMessage(new GMAddUI(dialogue, "root"));
			Graphics.QueueMessage(GMPushUI::ToUI("Dialogue", ActiveUI()));
		}
		/// If no quotes, load the specified dialogue-file and begin processing that instead, waiting until it is finished.!
		else {
			/// Give the npc a dialogue?
		//	assert(false);
			// Send it tot he state too, to attach to the appropriate thingymajig.
			Message * message = new Message(line);
			/// Set this event as
			message->scriptOrigin = this;
			MesMan.QueueMessage(message);
			/// Instant thingies.
			lineFinished = true;
		}
	}
	else if (line.Contains("Answer")){
		///  Go to EndAnswers..!
		lineFinished = true;
		for (int i = currentLine; i < lines.Size(); ++i){
			String line = lines[i];
			if (line.Contains("EndAnswers")){
				currentLine = i;
				lineFinished = true;
				return;
			}
		}
		assert(false && "No EndAnswers found? No good, jaow ;___;");
	}
	else if (line.Contains("BeginAlternatives") || line.Contains("BeginQuestion")){
		/// Create dialogue UI and append it to the current UI!
		String text = line.Tokenize("\"")[1];
		std::cout<<"\n"<<text;
		UIElement * dialogue = new UIElement();
		dialogue->exitable = false;
		dialogue->name = "AlternativesDialogue";
	//	dialogue->activationMessage = "Remove(this)&ContinueEvent("+this->name+")";
		dialogue->textureSource = DEFAULT_TEXTURE_SOURCE;
		dialogue->sizeRatioY = 0.3f;
		dialogue->alignmentY = 0.15f;
		dialogue->state |= UIState::DIALOGUE;  // Flag the dialogue-state flag to signify importance!

		UILabel * dialogueText = new UILabel();
		dialogueText->text = text;
		dialogueText->textSizeRatio = DEFAULT_TEXT_SIZE_RATIO;
		dialogueText->sizeRatioX = 0.5f;
		dialogueText->alignmentX = 0.25f;
		dialogue->AddChild(dialogueText);

		UIList * dialogueAnswerList = new UIList();
		dialogueAnswerList->sizeRatioX = 0.5f;
		dialogueAnswerList->alignmentX = 0.75f;
		dialogue->AddChild(dialogueAnswerList);

		int answers = 0;
		List<UIElement*> answerList;
		// Parse and add answers
		for (int i = currentLine+1; i < lines.Size(); ++i){
			String l = lines[i];
			l.SetComparisonMode(String::NOT_CASE_SENSITIVE);
			List<String> tokens = l.Tokenize(" ");
			String token1 = tokens[0];
			token1.SetComparisonMode(String::NOT_CASE_SENSITIVE);

			if (token1 == "text"){
				l.Remove(token1);
				dialogueText->text = l;
				dialogueText->text.RemoveInitialWhitespaces();
				dialogueText->text.Remove("\"");
				dialogueText->text.Remove("\"");
			}
			else if (l.Contains("Answer")){
				++answers;
				UIButton * answerButton = new UIButton();
				answerButton->name = token1;
				l.Remove("Answer");
				l.RemoveInitialWhitespaces();
				l.Remove("\"");
				l.Remove("\"");
				answerButton->textureSource = DEFAULT_TEXTURE_SOURCE;
				answerButton->text = l;
				answerButton->sizeRatioY = 0.2f;
				answerButton->activationMessage = "ActivateDialogueAlternative("+name+","+answerButton->name+")&PopFromStack("+dialogue->name+")&Remove("+dialogue->name+")";
				answerList.Add(answerButton);
			}
			else if (l.Contains("EndAlternatives")){
				// Donelir. o-o
				break;
			}
			else {
				assert(false && "Bad line! Should only be Answer before EndAlternatives!");
			}
		}
		assert(answers);
		float sizeRatioY = 0.95f / answers;
		for (int i = 0; i < answers; ++i){
			UIElement * ans = answerList[i];
		//	ans->sizeRatioY = sizeRatioY; // Stupid to set the sizeRatioY to be this dynamic, yo.
			dialogueAnswerList->AddChild(ans);
		}
		isInAlternativeDialogue = true;
		Graphics.QueueMessage(new GMAddUI(dialogue, "root"));
		Graphics.QueueMessage(GMPushUI::ToUI(dialogue, ActiveUI()));
	}
	else if (line.Contains("elsif") || line.Contains("elseif") || line.Contains("else if"))
	{
		/// Should be in an if-stack, check if we already evaluated.
		ScriptLevel sl = stack.Last();
		assert(sl.type == ScriptLevel::IF_CLAUSE);
		/// If already evaluated, jump to endif.
		if (sl.evaluatedAtLine > 0)
		{
			// Jump to endif.
			JumpToEndif();
			return;
		}
		/// If not, handle the conditional first.
		HandleConditional(line);
	}
	else if (line.Contains("if(") || line.Contains("if ("))
	{
		// Add to stack.
		stack.AddItem(ScriptLevel(ScriptLevel::IF_CLAUSE, currentLine));
		HandleConditional(line);
	}
	else if (line.Contains("else"))
	{
//		if (ifProcessed)
		//	JumpToEndif();
		ScriptLevel sl = stack.Last();
		assert(sl.type == ScriptLevel::IF_CLAUSE);
		if (sl.evaluatedAtLine > 0)
		{
			JumpToEndif();
			return;
		}
		lineFinished = true;
		return;
	}
	else if (line.Contains("endif"))
	{
		ScriptLevel sl = stack.Last();
		assert(sl.type == ScriptLevel::IF_CLAUSE);
		stack.RemoveLast();
		lineFinished = true;
	}
	else if (line.Contains("endwhile"))
	{
		// Go to start!
		ScriptLevel sl = stack.Last();
		assert(sl.type == ScriptLevel::WHILE_LOOP);
		currentLine = sl.evaluatedAtLine;
		String startLine = lines[currentLine];
		HandleConditional(startLine);
//		lineFinished = true;
		// Evaluate?
//		stack.RemoveLast();
	}
	else if (line.Contains("while"))
	{
		stack.AddItem(ScriptLevel(ScriptLevel::WHILE_LOOP, currentLine));
		HandleConditional(line);
	}
/*	else if (line.Contains("CreateInt")){
		List<String> tokens = line.Tokenize(" \t");
		String varName = tokens[1];
		int initialValue = 0;
		if (tokens.Size() >= 3)
			initialValue = tokens[2].ParseInt();
		if (!GameVars.Get(varName)){
			GameVars.CreateInt(varName, initialValue);
		}
		lineFinished = true;
	}
	/*
	else if (line.Contains("SetInt ")){
		List<String> tokens = line.Tokenize(" \t");
		String varName = tokens[1];
		int value = tokens[2].ParseInt();
		GameVars.SetInt(varName, value);
		lineFinished = true;
	}*/
	else if (line.Contains("Repeatable")){
		/// Flag the event as repeatable.
		repeatable = true;
		lineFinished = true;
	}
	// Consider just making an else-clause for all remaining events to be processed by the specific game instead?
	else if (
		line.Contains("SpawnEntity") ||
		line.Contains("OnApproach") ||
		line.Contains("OnInteract") ||
		line.Contains("DisableMovement") ||
		line.Contains("EnableMovement") ||
		line.Contains("Zone(") ||
		line.Contains("PlacePlayer(") ||
		line.Contains("TrackPlayer")
		)
	{
		Message * message = new Message(line);
		/// Set this event as
		message->scriptOrigin = this;
		MesMan.QueueMessage(message);
		/// Instant thingies.
		lineFinished = true;
	}
	else {
		/// Try evaluate it as an expression.
		Expression exp;
		List<Variable> allVars = GameVars.GetAllExpressionVariables() + variables;
		exp.functionEvaluators = functionEvaluators; // Set evaluators.
		bool parseOK = exp.ParseExpression(line);
		if (line.Contains("SetMovementPattern"))
			int p = 4;;
		if (parseOK)
		{
			ExpressionResult res = exp.Evaluate(allVars);
			/// Continue until it returns true! o.o
			if (res.type != DataType::NO_TYPE)
			{
				if (res.GetBool() == true)
				{
					lineFinished = true;
					return;
				}
			}
		}


//		std::cout<<"\nUndefined event command: "<<line;
//		std::cout<<"\nPassing it as a custom command to the game states for further processing.";
		Message * message = new Message(line);
		/// Set this event as source of it.
		message->scriptOrigin = this;
		MesMan.QueueMessage(message);
		lineFinished = true;
	//	assert(false && "Undefined event command!");
	};
}