Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualServant of the Lord

Posted 07 September 2012 - 11:55 AM

For handling alot of string comparisons std::map abstracts it better, making it easier to make your game data-driven and less hardcoded.

Probably std::map<std::string, scriptCallbackFunction>
Or std::map<std::string, classThatHandlesAction>
Or maybe using C++11 lambdas: std::map<std::string, lambdasCallback>,but in this situation that's unlikely.

Then you could do:
actionMap.push_back(std::make_pair("Use", UseActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Get", GetActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Attack", AttackActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Run", RunActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Climb", ClimbActionHandler(pointerToPlayerData, pointerToWorldData)));

You could also easily handle synonyms.
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Speak", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Talk", SayActionHandler(pointerToPlayerData, pointerToWorldData)));

actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Walk", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Head", GoActionHandler(pointerToPlayerData, pointerToWorldData)));

Or maybe use Regex instead (which is also abstract comparison of complex strings), and use a single action handler.
Or just map the word "Go" to a script function that handles the action.
actionMap.push_back(std::make_pair("Go", "handle_go"));

if(actionMap.contains(playerFirstWord))
{
	 functionName = actionMap[playerFirstWord];
	 CallScriptFunction(functionName, inputWords, playerPtr, worldPtr);
}
else
{
	 Output("I don't recognize " +playerFirstWord + ". Did you mean: " + actionMap.keys());
}

This doesn't keep you from having to write the logic, but it makes the logic easier to alter or expand during development, and easier to understand than 1500 lines of if(), else-if(), spaghetti going several scopes deep, and when and where you need actual if() statements, you only have them grouped together in twos and threes based on context, not hundreds.

It also makes it easier to create things like:
"Give to Bob the Monkey" -> You gave Bob, the Friendly Monkey you found. Bob looks at you quizzically.

'Give' goes to GiveActionHandler or script function, parses 'to' if present and discarded it, and using the pointer to the world, finds what NPCs exist in the room the player is in, finds a NPC named 'Bob' (otherwise outputting, "You don't see anyone named Bob around here"), parses and discards 'the' if present. Then using the pointer to the player's data, checks if the player has an item called 'Monkey' (otherwise outputting, "You don't have a Monkey"), and passes the text "Monkey" to Bob's script file for processing.

Bob's script file looks like this:
HandleLook()
{
	 Output("Bob stares back at you.")
}

HandleTalk()
{
	 //...
}

HandleGive(itemName, playerPtr, worldPtr)
{
	 if(itemName == "Monkey")
	 {
		  playerPtr.RemoveItem(itemName);
		  worldPtr.AddNPC("MonkeyNPC", worldPtr->GetCurrentRoom());
		  Output("Bob: You found Fibi! Oh thank you, " + playerPtr.name + "! I looked all over for her.")
		  Output("Bob: Here, take my spare scuba gear as thanks. You may find it comes in handy.")

		  playerPtr.GiveItem("Scuba gear");
	 }
	 else
	 {
		  Output("Bob: Uh, thanks, but I'm not interested in " + itemName + "s at the moment.');
	 }
}

This would be my first attempt, anyway. When working on the game, a better architecture may come to mind once I encounter the strengths and limitations of this approximation, having never worked on this type of game before (aside from a few attempts when first starting out as a programmer seven years ago).

#5Servant of the Lord

Posted 07 September 2012 - 11:55 AM

For handling alot of string comparisons std::map abstracts it better, making it easier to make your game data-driven and less hardcoded.

Probably std::map<std::string, scriptCallbackFunction>
Or std::map<std::string, classThatHandlesAction>
Or maybe using C++11 lambdas: std::map<std::string, lambdasCallback>,but in this situation that's unlikely.

Then you could do:
actionMap.push_back(std::make_pair("Use", UseActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Get", GetActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Attack", AttackActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Run", RunActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Climb", ClimbActionHandler(pointerToPlayerData, pointerToWorldData)));

You could also easily handle synonyms.
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Speak", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Talk", SayActionHandler(pointerToPlayerData, pointerToWorldData)));

actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Walk", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Head", GoActionHandler(pointerToPlayerData, pointerToWorldData)));

Or maybe use Regex instead (which is also abstract comparison of complex strings), and use a single action handler.
Or just map the word "Go" to a script function that handles the action.
actionMap.push_back(std::make_pair("Go", "handle_go"));

if(actionMap.contains(playerFirstWord))
{
     functionName = actionMap[playerFirstWord];
	 CallScriptFunction(functionName, inputWords, playerPtr, worldPtr);
}
else
{
     Output("I don't recognize " +playerFirstWord + ". Did you mean: " + actionMap.keys());
}

This doesn't keep you from having to write the logic, but it makes the logic easier to alter or expand during development, and easier to understand than 1500 lines of if(), else-if(), spaghetti going several scopes deep, and when and where you need actual if() statements, you only have them grouped together in twos and threes based on context, not hundreds.

It also makes it easier to create things like:
"Give to Bob the Monkey" -> You gave Bob, the Friendly Monkey you found. Bob looks at you quizzically.

'Give' goes to GiveActionHandler or script function, parses 'to' if present and discarded it, and using the pointer to the world, finds what NPCs exist in the room the player is in, finds a NPC named 'Bob' (otherwise outputting, "You don't see anyone named Bob around here"), parses and discards 'the' if present. Then using the pointer to the player's data, checks if the player has an item called 'Monkey' (otherwise outputting, "You don't have a Monkey"), and passes the text "Monkey" to Bob's script file for processing.

Bob's script file looks like this:
[code]HandleLook()
{
	 Output("Bob stares back at you.")
}

HandleTalk()
{
	 //...
}

HandleGive(itemName, playerPtr, worldPtr)
{
	 if(itemName == "Monkey")
	 {
		  playerPtr.RemoveItem(itemName);
		  worldPtr.AddNPC("MonkeyNPC", worldPtr->GetCurrentRoom());
		  Output("Bob: You found Fibi! Oh thank you, " + playerPtr.name + "! I looked all over for her.")
		  Output("Bob: Here, take my spare scuba gear as thanks. You may find it comes in handy.")

		  playerPtr.GiveItem("Scuba gear");
	 }
	 else
	 {
		  Output("Bob: Uh, thanks, but I'm not interested in " + itemName + "s at the moment.');
	 }
}

This would be my first attempt, anyway. When working on the game, a better architecture may come to mind once I encounter the strengths and limitations of this approximation, having never worked on this type of game before (aside from a few attempts when first starting out as a programmer seven years ago).

#4Servant of the Lord

Posted 07 September 2012 - 11:48 AM

For handling alot of string comparisons std::map abstracts it better, making it easier to make your game data-driven and less hardcoded.

Probably std::map<std::string, scriptCallbackFunction>
Or std::map<std::string, classThatHandlesAction>
Or maybe using C++11 lambdas: std::map<std::string, lambdasCallback>,but in this situation that's unlikely.

Then you could do:
actionMap.push_back(std::make_pair("Use", UseActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Get", GetActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Attack", AttackActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Run", RunActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Climb", ClimbActionHandler(pointerToPlayerData, pointerToWorldData)));

You could also easily handle synonyms.
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Speak", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Talk", SayActionHandler(pointerToPlayerData, pointerToWorldData)));

actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Walk", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Head", GoActionHandler(pointerToPlayerData, pointerToWorldData)));

This doesn't keep you from having to write the logic, but it makes the logic easier to alter or expand during development, and easier to understand than 1500 lines of if(), else-if(), spaghetti going several scopes deep, and when and where you need actual if() statements, you only have them grouped together in twos and threes based on context, not hundreds.

It also makes it easier to create things like:
"Give to Bob the Monkey" -> You gave Bob, the Friendly Monkey you found. Bob looks at you quizzically.

'Give' goes to GiveActionHandler, parses 'to' if present and discarded it, and using the pointer to the world, finds what NPCs exist in the room the player is in, finds a NPC named 'Bob' (otherwise outputting, "You don't see anyone named Bob around here"), parses and discards 'the' if present. Then using the pointer to the player's data, checks if the player has an item called 'Monkey' (otherwise outputting, "You don't have a Monkey"), and passes the text "Monkey" to Bob's script file for processing.

Bob's script file looks like this:
HandleLook()
{
	 Output("Bob stares back at you.")
}

HandleTalk()
{
	 //...
}

HandleGive(itemName, playerPtr, worldPtr)
{
	 if(itemName == "Monkey")
	 {
		  playerPtr.RemoveItem(itemName);
		  worldPtr.AddNPC("MonkeyNPC", worldPtr->GetCurrentRoom());
		  Output("Bob: You found Fibi! Oh thank you, " + playerPtr.name + "! I looked all over for her.")
		  Output("Bob: Here, take my spare scuba gear as thanks. You may find it comes in handy.")

		  playerPtr.GiveItem("Scuba gear");
	 }
	 else
	 {
		  Output("Bob: Uh, thanks, but I'm not interested in " + itemName + "s at the moment.');
	 }
}

This would be my first attempt, anyway. When working on the game, a better architecture may come to mind once I encounter the strengths and limitations of this approximation, having never worked on this type of game before (aside from a few attempts when first starting out as a programmer seven years ago).

#3Servant of the Lord

Posted 07 September 2012 - 11:47 AM

For handling alot of string comparisons std::map abstracts it better, making it easier to make your game data-driven and less hardcoded.

Probably std::map<std::string, scriptCallbackFunction>
Or std::map<std::string, classThatHandlesAction>
Or maybe using C++11 lambdas: std::map<std::string, lambdasCallback>,but in this situation that's unlikely.

Then you could do:
actionMap.push_back(std::make_pair("Use", UseActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Get", GetActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Attack", AttackActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Run", RunActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Climb", ClimbActionHandler(pointerToPlayerData, pointerToWorldData)));

You could also easily handle synonyms.
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Speak", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Talk", SayActionHandler(pointerToPlayerData, pointerToWorldData)));

actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Walk", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Head", GoActionHandler(pointerToPlayerData, pointerToWorldData)));

This doesn't keep you from having to write the logic, but it makes the logic easier to alter or expand during development, and easier to understand than 1500 lines of if(), else-if(), spaghetti going several scopes deep, and when and where you need actual if() statements, you only have them grouped together in twos and threes based on context, not hundreds.

It also makes it easier to create things like:
"Give to Bob the Monkey" -> You gave Bob, the Friendly Monkey you found. Bob looks at you quizzically.

'Give' goes to GiveActionHandler, parses 'to' if present and discarded it, and using the pointer to the world, finds what NPCs exist in the room the player is in, finds a NPC named 'Bob' (otherwise outputting, "You don't see anyone named Bob around here"), parses and discards 'the' if present. Then using the pointer to the player's data, checks if the player has an item called 'Monkey' (otherwise outputting, "You don't have a Monkey"), and passes the text "Monkey" to Bob's script file for processing.

Bob's script file looks like this:
HandleLook()
{
	 Output("Bob stares back at you.")
}

HandleTalk()
{
	 //...
}

HandleGive(itemName, playerPtr, worldPtr)
{
	 if(itemName == "Monkey")
	 {
		  playerPtr.RemoveItem(itemName);
		  worldPtr.AddNPC("MonkeyNPC", worldPtr->GetCurrentRoom());
		  Output("Bob: You found Fibi! Oh thank you, " + playerPtr.name + "! I looked all over for her.")
		  Output("Bob: Here, take my spare scuba gear as thanks. You may find it comes in handy.")

		  playerPtr.GiveItem("Scuba gear");
	 }
	 else
	 {
		  Output("Bob: Uh, thanks, but I'm not interested in " + itemName + "s at the moment.');
	 }
}

This would be my first attempt, anyway. When working on the game, a better architecture may come to mind once I encounter the strengths and limitations of this approximation.

#2Servant of the Lord

Posted 07 September 2012 - 11:45 AM

For handling alot of string comparisons std::map abstracts it better, making it easier to make your game data-driven and less hardcoded.

Probably std::map<std::string, scriptCallbackFunction>
Or std::map<std::string, classThatHandlesAction>
Or maybe using C++11 lambdas: std::map<std::string, lambdasCallback>,but in this situation that's unlikely.

Then you could do:
actionMap.push_back(std::make_pair("Use", UseActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Get", GetActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Attack", AttackActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Run", RunActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Climb", ClimbActionHandler(pointerToPlayerData, pointerToWorldData)));

You could also easily handle synonyms.
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Speak", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Talk", SayActionHandler(pointerToPlayerData, pointerToWorldData)));

actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Walk", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Head", GoActionHandler(pointerToPlayerData, pointerToWorldData)));

This doesn't keep you from having to write the logic, but it makes the logic easier to alter or expand during development, and easier to understand than 1500 lines of if(), else-if(), spaghetti going several scopes deep, and when and where you need actual if() statements, you only have them grouped together in twos and threes based on context, not hundreds.

It also makes it easier to create things like:
"Give to Bob the Monkey" -> You gave Bob, the Friendly Monkey you found. Bob looks at you quizzically.

'Give' goes to GiveActionHandler, parses 'to' if present and discarded it, and using the pointer to the world, finds what NPCs exist in the room the player is in, finds a NPC named 'Bob' (otherwise outputting, "You don't see anyone named Bob around here"), parses and discards 'the' if present. Then using the pointer to the player's data, checks if the player has an item called 'Monkey' (otherwise outputting, "You don't have a Monkey"), and passes the text "Monkey" to Bob's script file for processing.

Bob's script file looks like this:
HandleLook()
{
     Output("Bob stares back at you.")
}

HandleTalk()
{
     //...
}

HandleGive(itemName, playerPtr, worldPtr)
{
     if(itemName == "Monkey")
     {
          playerPtr.RemoveItem(itemName);
          worldPtr.AddNPC("MonkeyNPC", worldPtr->GetCurrentRoom());
          Output("Bob: You found Fibi! Oh thank you, " + playerPtr.name + "! I looked all over for her.")
          Output("Bob: Here, take my spare scuba gear as thanks. You may find it comes in handy.")

          playerPtr.GiveItem("Scuba gear");
     }
     else
     {
          Output("Bob: Uh, thanks, but I'm not interested in " + itemName + "s at the moment.');
     }
}

#1Servant of the Lord

Posted 07 September 2012 - 11:31 AM

For handling alot of string comparisons std::map abstracts it better, making it easier to make your game data-driven and less hardcoded.

Probably std::map<std::string, scriptCallbackFunction>
Or std::map<std::string, classThatHandlesAction>
Or maybe using C++11 lambdas: std::map<std::string, lambdasCallback>

Then you could do:
actionMap.push_back(std::make_pair("Use", UseActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Get", GetActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Attack", AttackActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Run", RunActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Climb", ClimbActionHandler(pointerToPlayerData, pointerToWorldData)));

You could also easily handle synonyms.
actionMap.push_back(std::make_pair("Say", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Speak", SayActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Talk", SayActionHandler(pointerToPlayerData, pointerToWorldData)));

actionMap.push_back(std::make_pair("Go", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Walk", GoActionHandler(pointerToPlayerData, pointerToWorldData)));
actionMap.push_back(std::make_pair("Head", GoActionHandler(pointerToPlayerData, pointerToWorldData)));

PARTNERS