Part dev log, part ramble, all Mega.
Because of the length of this blog, and the picky nature of anybody reading it, I've divided it into neat little sections again.This time I'm dealing with four topics: > Text Parsing for Adventure Games > How far my adventure game is coming along > My impressions of Terraria so far > Another show I'm watching now which is awesome.Text Parsing for Adventure Games
I don't know about any of you other programmers out there, but a text adventure game was one of the first things I tried to make the second I 'got' the basics of my language.Of course, along the way lie many stumbling blocks, and one of these is that mystical 'black box' in a text-adventure that somehow translates your English sentences into actions. Believe me, it took me a while to figure it out. Also keep this in mind:
Well, I was sitting around a few days ago trying to figure out in my mind the way that the text parser was going to work. I settled on a large nested if-else block (The brute force approach, but I'm working by 'Make games, not engines').Then I figured something out halfway: This isn't much different to the way that I, and many other programmers, handle command-line arguments in our programs.Let me examine a single piece of user data, a single line of input, and then work through the processing steps involved: > Reading the text (Input) > Parsing the text (Processing) > Executing the correct function(s) based on the text (Output)Any of you who have taken that boring ol' introductory design course will recognize the three sections there. Let's pick them apart.Note: The code here is C++, but it shouldn't be hard at all to 'translate' it to your favorite languageReading the textThe first stumbling block, and often the one that beginners will give up on. Sounds easy, right? Read a line of text? Not if you're not told how to. JAVA courses tend to leave out console input for a long time because it requires at least a minor explanation of exception handling in order to implement it, for instance.But that's only half of the problem.Most console input functions have one serious problem: They truncate the resulting input at the first whitespace character (That is, a press of the spacebar, or a press of the enter key).In cases like this, we'd rather read in a whole line of input, up until the user presses Enter. Of course, not having any offline documentation for MingW and it's libraries, I went ahead and made my own function, called getline(), to read a whole line… only to find out a month later that the standard library has a getline() function that does the exact same thing. Here's a code snippet:
(std:: identifiers left in to avoid confusion as to where the datatypes and functions come from).As you can see, getline takes two arguments. The first is the Source, the second is a Reference to the Destination. In this case, I'm using the Stream CIN (Console IN) as the source. You can also use a file input stream (ifstream).It blocks until the user has finished entering a line of text and places that text into a string, sans the '\n' escape sequence at the end.Well, now we can get text. Now how do we do anything meaningful with it?Parsing the textPython is a wonderful language for text processing. It contains many functions that modify and process strings in useful ways. But C, or C++, do not. C++ does offer the upper() and lower() functions, in ctypes.h, but there was another function that I needed: Something that could split a string into sub-strings given an arbitrary 'delimiter'. So I made the split() function.
This is a slow, but sure way to split the string up into sub-strings (Stored in the vector container, which allows for easy random access).My step with this whole process, after getting the input and splitting it, is to copy the split set into another, but leaving out any unnecessary words, such as AN, THE, A, AT.Usually for this I create a function that returns bool and scans each word for a match with words in a std::list/vector, but for my game I hard coded an if block like this: (I'm using my own upper() and lower() functions, because I know how they work):
Simple, not too fast, but effective (Not fast because I'm not overly concerned about speed when it comes to a text adventure game; I want the codebase to be easy to work with though, which becomes more difficult if I spend time creating a more efficient system.)Executing the correct function(s) based on the textThis step is a bit difficult and simple to explain at the same time. Difficult because I have to explain the system I currently have going.In my code, there exist some primary objects (classes): m_room m_player m_item m_npcThe m_room class contains lists of items and npcs. On the global level, I have these three important variables defined:m_room* map_frame[100]; // A 10x10 map grid at a timem_room* room_ptr; // A pointer to the currently active room.m_player* player_ptr; // A global pointer to the playerWith this in mind, observe a snippet from my code that deals with part of the EXAMINE command:
Now, if you take the time to read it carefully, you'll notice that the whole lot is just a bunch of simple if-else blocks. Nothing spectacular.It's not a very elegant approach, but that's the whole point: It's not meant to be. It's meant to be readable, changeable, and above all: Bug free.An interesting thing to note is that all the object types have a set of act_*() functions, which are overridden by inherited classes to defineextra behavior (One NPC's act_conversation() will be different from another's). In the spirit of Java, I'm including all new items/npcs/rooms intheir own header/source sets, in sub-folders to keep everything neat.Hope this provided an interesting read. I had to get it out.
Quote:
Rule for working with unfamiliar projects/ideasDon't try to make an elegant approach. Make a messy one, figure out the pitfalls, and refine the design later.
// Returns a string containing a line of input
std::string getString() {
std::string res;
std::getline(std::cin, res);
return res;
}
std::vector<std::string> split(std::string str, char delim)
{
std::vector<std::string> temp_v;
std::string temp = "";
for(int i = 0; i < str.size(); i++)
{
if(str[i] != delim)temp += str[i];
else
{
if(!temp.empty())temp_v.push_back(temp);
temp = "";
}
if(i == str.size()-1)
{
if(!temp.empty())temp_v.push_back(temp);
temp = "";
}
}
return temp_v;
}
vector<string> strip_uwords(vector<string> text_set) {
vector<string> new_set;
for(int i = 0; i < text_set.size(); i++)
{
if(( mio::same( mio::lower(text_set[i]), "an") ) ||
( mio::same( mio::lower(text_set[i]), "the") ) ||
( mio::same( mio::lower(text_set[i]), "a") ) ) // Etc
{
// Do not perform any operations
}
else
{
// Copy to new set
new_set.push_back(text_set[i]);
}
}
return new_set;
}
if(same(lower(tx[0]), "examine"))
{
// Check element count
if(tx.size() > 1)
{
// Special 'inventory' or 'i' or 'items' cases.
if(same(lower(tx[1]), "inventory") ||
same(lower(tx[1]), "i") ||
same(lower(tx[1]), "items") )
{
// Call player's inventory list function
if(player_ptr)
{
player_ptr->act_inventory();
return 0;
}
}
else
{
// Passes 'argument' to the current room's examine code, which
// checks it's item list for a match, and displays an
// "I don't see the <x> here" message if it can't find one.
if(room_ptr)
{
room_ptr->act_examine(tx[1]);
return 0;
}
}
}
else
{
// Call room look code since no 'arguments' provided.
if(room_ptr)
{
room_ptr->act_look();
return 0;
}
}
}
Well between yesterday and now (The 20th, as of this moment), nowhere. Terraria.That is, I got nowhere with the code, but I managed to soar ahead with the story andoverall idea. I'm not going to spoil any story, but I can mention settings:A crazy half-French half-British hamlet during the 1500's. Whether this is historically accurate or not, I don't know (nor care); it suits my story though. What is the story about?Love, Loss, Revenge, and most importantly: ALE. I'm an amateur writer. I've written countless beginnings (And even some endings). But like all writers, it takes me ages to actually get anywhere without motivation.Also, I'm way out of my comfort zone with this story. Writing a romantic comedy is not something I'm used to (It has to be comical. Monkey Island changed my view of adventure games forever). Anyway, time to devote some time to my game before the Terraria shortcut beckons once more. – UPDATE AFTER THIS BLOG WAS WRITTEN –I managed to complete the basics of item/environment interaction. Also, you now get an amusing assortment of satire when you attempt to walk through a non-existant exit.Oh. And you can sing… Heh. So far, so good. I'm very pleased with the way this is turning out. Now I just need to figure out the area layout on paper, and map it into the game. Also, I need to create some puzzles. I've still got nearly 20 days for this, so I ought to be able to flesh it out nicely. I'll probably even be nice and release the source code for it when I'm done =P
Well, I connected my PC to the ADSL yesterday (After transporting it to the other houseon the property, the one my parents dwell in). And soon, I had three of my Steam gamesdownloaded and ready to play.Except for L4D2. I put that into my gifts inventory, since I can't possibly download it anytime this decade, unless I miraculously receive unlimited internet from some unknown source soon. Which I'm working on.So, first of all I tried The Polynomial. Took a bit of getting used to (And it took a while to see past all the funky lights), and I discovered a perfectly challenging shooter underneath.Then… Terraria. I started it up with my two brothers watching me. First impressions: lol Simple graphics, lol Minecraft knockoff, lol crafting bench, lol NPC help/hint/crafting guide.And then I started noticing the differences. Terraria makes the exploration factor fun. So much, in fact, that it seemed I just blinked and suddenly it was 1AM. I almost laughed myself into a coma when I discovered and crafted the Goldfish Bowl, and figured it's use out, as well as the bucket. Single Player has me extremely impressed so far; Multiplayer is going to be a veritable time-drainer, so I daren't play it yet. Not until I have lots of free time.It's a conspiracy. You just let me win the last comp so I'd have a soul-sucking game to keep me distracted and inable to get any other work done. I SEE YOUR PLANS…. *shifty eyes* I won't give in…. just let me finish exploring this little bit of cave quickly…– UPDATE, NEXT MORNING AT ABOUT 3AM –It got me again. Dammit. Also, something amusing. I accidentally summoned another Eye of Cthulhu when one was already on-screen. Twice the fun (I won, of course). Oh, and the villagers in my village were all slaughtered by a vicious army of goblins.
OK. I've only watched ONE episode, and it's also on The Hub. No, it's not Transformers. I can't stand the new generations. The Dan vs. series.Here's the episode I watched yesterday with my brother:
What made this funnier is that my name is Daniel, and I have a black and white cat.I do not keep a list of things I dislike intensely though. Heh.Give it a watch if you dare.
I think writing a romantic story is probably the hardest kind of writing a person can do. But, from what you said, the setting sounds right, and the gameplay sounds like it's going to be fun.
Remind me when I download it to go walk through nonexistent exitsTerraria seems pretty damn fun. I really wanna go get it now that you've fully described it. DON'T LET IT SUCK YOUR SOUL! RESIST! RESIST!!Oh god, this cartoon seems so fucking demented and I love it. Why had I never heard of this show before? I'll go watch it when I have some time.Duuude, this sounds interesting.
Is it gonna be like Sam and Max?
Try digging down until you hit the underworld in Terraria, if you haven't already.
…then defeat the boss down there to turn on "hard mode".It's not the boss that's hard. It's the hell that gets unleashed after you defeat it.
But you're not going to get the high spec armor before you do that. The higher spec armor is mostly only available after you unleash hell. Well. I guess you could go up to Molten Armor if that's not what you already have. (Hellstone armor) So why aren't you mining that? It doesn't take long to do. Well. It takes a lot longer as of the recent patch (1.1 or whatever) since hellstone blocks release lava. They didn't used to and it was way easier back then.
I've got a few Obsidian Skin potions for that, but I kept getting flanked by a bunch of Imps. Also, the journey down is taking a while. I'm methodically working on blowing a hole at least halfway down. Good thing I have lots of gold.