Link Bar

Home | Games | Programming | Tutorials | Donate | Legal (These are mostly empty right now. Placeholders!)

warning code

This website contains adult content.

Friday, March 9, 2012

Day 20: "Noob Game" launched!

Early update today, since I stayed up writing my tutorial.  Feels good to be ahead of schedule for a change!  Now if only I can find some work today...

Noob Game can be downloaded on the free right here!  Below the jump is a tutorial on how to write this game (or something like it) all by yourself in C++.  But be warned:  the source code contains spoilers.  Because I know you're super-concerned about those.


Without further ado:

/* Hooray for inclusion!  These "#include" commands tell the program what to load up at the start, and may add functionality you might otherwise not have. */

#include "stdafx.h"
#include "NoobGame.h" /* In reality, this file is empty at the moment.  But don't forget to include your own header if you make one! */
#include <string>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>


using namespace std;


/* Now we get into the "real meat" of the program, parts that do things that other programs won't do! */


//CHARACTER SHEET!


//playerActionsTaken are fundamental
int playerActionsTaken = 0;
/* There are other parts to the player character's makeup, but they are able to be declared in-game.  The reason for declaring playerActionsTaken and playerHealth here is because they will always have the same value at the start of any new game.  Defining them inside the game loop will simply reinitialize them to these values with every action the player takes, and that's no good! */
int playerHealth = 12;
//everything else derives from playerActionsTaken in-game.


//we'll make playerLocation an integer variable, too.
int playerLocation=0;


//END CHARACTER SHEET!



//GAME WORLD:


//Place Names
string placeName[] = {"Noob Camp", "Noob Town", "Noob Forest", "Pro Mountain", "Wild Blue Yonder"};
/* Here I declared a string, called "placeName," which is itself an array of other strings, which are the actual place names.  We can use "placeName[0]" to refer to "Noob Camp," and so on, making it much easier to change references to these places in-game if the place name changes.  But mainly, this is for "future-proofing," it's not a necessary feature at the moment (except for the fact that I made it necessary to this game...). */
//NPC Names
string npcName[] = {"Noob Trainer", "Noob Civilian", "Noob Enemy", "Pro Troll"};
/* Similarly, I made NPC names such that you can easily refer to them by npcName[X], which is useful because in this game each location has a unique NPC population and they all react differently to the player! */
//Inventory items
string itemName[] = {"Noob Shit", "Noob Loot", "Noob Sword", "Noob Armor"};
//Start with no money or items
int playerGold = 0;
bool haveNoobShit = false;
bool haveNoobLoot = false;
bool haveNoobSword = false;
bool haveNoobArmor = false;
bool noobQuestOne = false;
bool noobQuestTwo = false;
bool noobQuestThree = false;
bool noobQuestFour = false;
/* These are variables we will want to use later.  For now, we don't need to worry about them; just remember them for when they crop up later, and most importantly, remember how they're used and what they accomplish! */


//
//MAIN GAME FUNCTION!
//


/* This first line sets up the function itself; everything that takes place after that first "{" is part of the game until we "return 0" at the end.  Zach provides a good explanation of the anatomy of this function here. */
int _tmain(int argc, _TCHAR* argv[])
{
cout<<"One Man Show"<<endl;
cout<<""<<endl;
cout<<"Welcome to Noob Game. Enter 1 to play.  Unexpected inputs will end playtime."<<endl;
/* Heh, this part's kinda important!  I still haven't figured out how to make unexpected inputs not skip to the end of the game function.  But for now, don't worry about it! */
char choiceOne[10]; /* This sets up a 10-character array called "choiceOne."  Ten is more than we strictly need, but leaves room for other input options (even though this game only uses single-character inputs). */
cin.getline(choiceOne,10);
/* This retrieves the value, and next we actually do something with it. */


if(choiceOne[0]=='1'){ /* So if choiceOne is entered as 1, then we do these things: */
//PRAY!
cout<<"Welcome to your new game of Noob Game!"<<endl;
cout<<"What is your name, Noob?"<<endl;
char playerName[100];
cin.getline(playerName,100);
cout<<"Hello, " <<playerName <<".  Did I pronounce that right?  Lord, what a noobish name."<<endl; /* Here the user defines his/her own name. */
cout<<endl;


/* OK, now we come to the actual "gamey-game" game part of the game.  Game. */
//GAME LOOP!
bool playerDeath = false;
/* Declaring playerDeath as false is what powers this next while loop, which will keep looping around until or unless the player reaches zero HP, thereby setting playerDeath to "true" (this condition is defined explicitly near the bottom, we'll see it when we get to it). */
while (playerDeath != true) {


//GAME WORLD DESCRIPTION:
cout<<"You are standing at " <<placeName[playerLocation] <<"."<<endl;
cout<<placeName[playerLocation + 1] <<" looms in the distance."<<endl;
cout<<"There is a " <<npcName[playerLocation] <<" here."<<endl;
cout<<endl;


/* The first thing the game loop will do is to tell you where you are, what's close, and who's around.  Simple enough, right?  And it does this every time you take a turn! */


//calculate player stats:
//playerExperience as a function of playerActionsTaken
int playerExperience = playerActionsTaken;
//level as a function of playerExperience
int playerLevel = playerExperience / 10;
//HP
int playerMaxHealth = 12 + (playerLevel * 4);


/* Here we invisibly calculate the player's stats.  Initial values are taken from up above the game loop, but here we make sure that they get recalculated each turn, otherwise bugs occur!  For the longest time, I kept getting all my HP back every turn, or couldn't move, or something weird just because of the interplay between 1) where I declared a variable, and 2) where/how that variable was altered later. */


//description of player stats:
cout<<"You have " <<playerHealth <<" HP at level " << playerActionsTaken / 10 <<"."<<endl;
cout<<endl;


/* Note here that there are spaces  before closing quotation marks and after opening quotation marks when putting a variable into cout.  This is because 'cout<<"You have" <<PlayerHealth <<"HP...' will show up as "You have8HP..." (if you have 8 HP) since we didn't put spaces around anything.  And 'endl;' makes a new line while flushing a buffer, so it's nice to use to make carriage returns (you can also use '\n' for 'new line,' but it won't flush the buffer) and break up the blocks o' text. */


//description of possible player actions:
cout<<"What do you do, " <<playerName <<"?" <<endl;
if (playerLocation==0) {
cout<<"Press W to win, G to anger the gods, S to speak with the " <<npcName[playerLocation] <<" (or A to attack), T to travel to " <<placeName[playerLocation + 1] <<", or R to rest." <<endl;
}
else cout<<"Press W to win, G to anger the gods, S to speak with the" <<npcName[playerLocation] <<" (or A to attack), T to travel to " <<placeName[playerLocation + 1] <<", or R to retreat to " <<placeName[playerLocation - 1] <<"." <<endl;

char playerAction[10];
cin.getline(playerAction,10);
cout<<"~*~*~*~*~*~*~*~"<<endl;
/* Lots going on here!  OK, first we have possible actions as a function of player location.  This is because you can advance or retreat from locations 1, 2, and 3; but you can't retreat from location 0, where you start out.  So I made R into "rest" on this screen instead, since we need a way to recover HP (there is no other way!).  Where the player can travel/retreat to is also spelled out in the text, as you can see.  Finally, after retrieving the player's action, I added a line of tildes and asterisks just to make it easier to distinguish where one turn ends and another begins (I also use "x-x-x" later to indicate that an NPC is done speaking).  Never forget to take aesthetics into account! */


//if (condition) { doSomething(); }
//else {doSomethingElse(); (if "condition" resolves as false)
//WINNING!
if (playerAction[0]=='w') {
if (noobQuestThree == true) {
cout<<"Congratulations, " <<playerName <<", you have TRULY won the game.\nYour victory feels more substantial than if you had simply won at the start."<<endl;
}
else {cout<<"Congratulations, " <<playerName <<"!  You have won the game!"<<endl;
}
}
/* You can see that I used '\n' up there, mainly for my own ease because I wasn't putting many variables in there and just wanted to go faster.  Also, notice that the "win" button works differently depending on whether you've completed the third quest or not... */


//CURSE THE GODS!
else if (playerAction[0]=='g'){
if (noobQuestThree == true) {
cout<<"Even the gods hesitate to strike you down.  Behold their tepid and hesitant vengeance!"<<endl;
cout<<"You take " <<playerHealth/2 <<" damage."<<endl;
playerHealth = playerHealth - (playerHealth/2);
cout<<"You now have " <<playerHealth <<" HP, and feel the need to wander out into the" <<placeName[4] <<"."<<endl;
noobQuestFour = true;
}
else {
cout<<"Foolish mortal!  In your hubris, you have angered the gods!  Behold their swift and terrible vengeance!"<<endl;
cout<<"You take " <<playerHealth <<" damage."<<endl;
playerHealth= playerHealth - playerHealth;
cout<<"You now have " <<playerHealth <<" HP."<<endl;
}
}
/* I first put this "feature" in the game so that I would know that death worked correctly and also so that I could exit quickly while debugging without needing to click any other buttons or menus.  But as you can see, I worked it into the story anyway.  I'm awesome like that, and now you can be, too! */


//TRAVEL SUBROUTINE.
else if (playerAction[0]=='t') {
if (playerLocation==3) {
if (noobQuestFour==true) {
cout<<"Having defied the gods and lived to tell the tale, you venture out into the " <<placeName[playerLocation + 1] <<" to seek adventure.\nEventually, adventure finds you, and it is NOT in the mood for horseplay."<<endl;
cout<<"A wild grue attacks you for " <<playerHealth <<" damage, and you finally meet your gruesome end."<<endl;
playerHealth = playerHealth - playerHealth;
}
else {
cout<<"You're already at " <<placeName[playerLocation] <<".  You can't venture out into the " <<placeName[playerLocation + 1] <<" just yet."<<endl;
}
}
else {playerLocation = playerLocation + 1;
cout<<"You travel to " <<placeName[playerLocation] <<" by taking an action."<<endl;
playerActionsTaken = playerActionsTaken + 1;
cout<<"You now have " <<playerActionsTaken <<" experience points."<<endl;
}
}
/* The travel subroutine simply adds 1 to playerLocation whenever T is entered.  Easy enough, right?  Then we just add some other conditional functions for when the player is somewhere from which they cannot travel further (unless they can, in which case we do something different!) */


//RETREAT SUBROUTINE.
else if (playerAction[0]=='r') {
if (playerLocation==0) {
cout<<"You rest and your wounds heal."<<endl;
playerHealth = playerMaxHealth;
}
else playerLocation = playerLocation - 1;
cout<<"You retreat to " <<placeName[playerLocation] <<" by taking an action."<<endl;
playerActionsTaken = playerActionsTaken + 1;
cout<<"You now have " <<playerActionsTaken <<" experience points."<<endl;
}
/* The retreat subroutine is basically the opposite of the travel subroutine, except that it allows the player to rest at Noob Camp.  This next one is pretty damn long, and also should be pretty self-explanatory by now.  The important part is that the "attack" action depends on playerLocation, and so we squeeze a lot of context-based functionality out of relatively few lines of code.  Also of note are the "respawn" indicators which basically allow me to be a lazy coder. */


//ATTACK SUBROUTINE.
else if (playerAction[0]=='a') {
playerActionsTaken = playerActionsTaken + 1;
cout<<"You attack the " <<npcName[playerLocation] <<"."<<endl;
//ATTACKING AT NOOB CAMP:
if (playerLocation==0) {
cout<<"He whups you soundly for your insolence."<<endl;
playerHealth = playerHealth - 4;
cout<<"You now have " <<playerHealth <<" HP."<<endl;
}
//ATTACKING AT NOOB TOWN:
else if (playerLocation==1) {
cout<<"A guard defends the " <<npcName[playerLocation] <<" from your noobish assault."<<endl;
cout<<"In your noobishness, you find yourself attacking the guard's sword with your neck."<<endl;
playerHealth = playerHealth - playerHealth;
}
//ATTACKING AT NOOB WOODS:
else if (playerLocation==2) {
if (haveNoobLoot==true) {
cout<<"Wait.  No, you don't.  You already have all the " <<itemName[1] <<" you can carry."<<endl;
cout<<"Why not go back to " <<placeName[playerLocation - 1] <<" to sell, you noob?"<<endl;
}
else {cout<<"The " <<npcName[playerLocation] <<" defends itself ineptly from your assault."<<endl;
if (haveNoobSword == true) {
cout<<"You run the " <<npcName[playerLocation] <<" through with your " <<itemName[2] <<"."<<endl;
cout<<"You find all the " <<itemName[1] <<" you can carry just as another " <<npcName[playerLocation] <<" wanders into sight."<<endl;
haveNoobLoot = true;
}
else if (playerLevel>=1) {
cout<<"You slaughter the " <<npcName[playerLocation] <<" with your superior combat experience."<<endl;
cout<<"You find all the " <<itemName[1] <<" you can carry just as another " <<npcName[playerLocation] <<" wanders into sight."<<endl;
haveNoobLoot = true;
}
else if (playerGold==0) {
cout<<"Your broke ass wouldn't know how to fight a " <<npcName[playerLocation] <<" if it bit you in the face."<<endl;
cout<<"You do no damage, and the " <<npcName[playerLocation] <<" bites you in the face for 1 damage."<<endl;
playerHealth = playerHealth - 1;
}
else {
cout<<"Still, you do no damage, and anger the " <<npcName[playerLocation] <<"."<<endl;
cout<<"Thinking quickly, you huck a coin at its eye, killing it."<<endl;
cout<<"You retrieve your coin and find all the " <<itemName[1] <<" you can carry just as another " <<npcName[playerLocation] <<" wanders into sight."<<endl;
haveNoobLoot = true;
}
}
}
//ATTACKING AT PRO MOUNTAIN:
else if (playerLocation==3) {
if (haveNoobSword==true) {
cout<<"The " <<npcName[playerLocation] <<" fights fiercely, but you manage to best it."<<endl;
playerHealth = playerHealth - 4;
cout<<"You take 4 damage."<<endl;
cout<<npcName[playerLocation] <<":  WTF HAX!  BLARG I AM DEAD."<<endl;
noobQuestThree = true;
cout<<"Just then, another " <<npcName[playerLocation] <<" comes into sight."<<endl;
}
else {
cout<<"The " <<npcName[playerLocation] <<" is impervious to your noobish assault."<<endl;
playerHealth = playerHealth - 4;
cout<<"You take 4 damage."<<endl;
cout<<npcName[playerLocation] <<":  TROLOLOL.  CAN'T HURT ME.  U MAD, BRO?"<<endl;
cout<<"x-x-x-x"<<endl;
}
}
}
/* Well, that was easier than I thought it would be!  Then again, defining combat outcomes across four NPCs isn't exactly rocket surgery...  Now it's on to speech!  Again, notice that speech depends directly on location, since that also determines what NPCs are around for you to speech your speechy speech at.  The shopping UI in Noob Town is barely even rudimentary; really, it only allows you to make one gold by selling Noob Loot, or spend ten gold on a sword and some armor (and you don't even have a choice about that!).  Also, it should be clear from examining the code below that the Noob Trainer is the quest hub.  Double also:  it's often easier to code for the things you don't expect to have happen first, and leave the introductory stuff as leftovers that get run when more advanced content requirements are not met. */


//SPEECH SUBROUTINE.
else if (playerAction[0]=='s') {
cout<<"You speak to " <<npcName[playerLocation] <<" by taking an action."<<endl;
playerActionsTaken = playerActionsTaken + 1;
//SPEECHING AT NOOB CAMP:
if (playerLocation==0) {
if (noobQuestOne == true) {
cout<<npcName[playerLocation] <<":  Welcome back to " <<placeName[playerLocation] <<", " <<playerName <<"!"<<endl;
if (noobQuestThree == true) {
cout<<npcName[playerLocation] <<":  Wow, " <<playerName <<", you killed the " <<npcName[playerLocation + 3] <<" of " <<placeName[playerLocation + 3] <<"!  Why, I do believe you're worthy of winning the game now."<<endl;
}
else if (noobQuestTwo == true) {
cout<<npcName[playerLocation] <<":  That's some fancy " <<itemName[3] <<" you got on there, " <<playerName <<"!  I bet you could even take on the " <<npcName[playerLocation + 3] <<" at " <<placeName[playerLocation + 3] <<" with that gear."<<endl;
}
else {
cout<<npcName[playerLocation] <<":  Say, " <<playerName <<", you look like you could use something to do.  Why don't you go kill some " <<npcName[playerLocation + 2] <<" in the " <<placeName[playerLocation + 2] <<"?"<<endl;
}
cout<<"x-x-x-x"<<endl;
}
else if (haveNoobShit == true) {
cout<<npcName[playerLocation] <<":  Get going, you noob!  Once you deliver that " <<itemName[0] <<", we'll be on a first-name basis."<<endl;
cout<<"x-x-x-x"<<endl;
}
else {cout<<npcName[playerLocation] <<":  Welcome to " <<placeName[playerLocation] <<"!  Now take this " <<itemName[0] <<" to " <<placeName[playerLocation + 1] <<", you fuckin' noob."<<endl;
cout<<"x-x-x-x"<<endl;
cout<<"You pick up the " <<itemName[0] <<"."<<endl;
haveNoobShit = true;
}
}
//SPEECHING AT NOOB TOWN:
else if (playerLocation==1) {
cout<<npcName[playerLocation] <<":  Welcome to " <<placeName[playerLocation] <<"!";
if (noobQuestOne == false) {
cout<<"  Do you have any " <<itemName[0] <<" for me?";
} else {};
cout<<endl;
cout<<"x-x-x-x"<<endl;
if (haveNoobShit == true) {
cout<<"Deliver the " <<itemName[0] <<" by entering Q to perform the quest action."<<endl;
cin.getline(playerAction,10);
if (playerAction[0]=='q') {
cout<<npcName[playerLocation] <<":  Oh, thank you!  I was waiting for some " <<itemName[0] <<" today.  Here, have a coin for your trouble."<<endl;
cout<<"x-x-x-x"<<endl;
haveNoobShit = false;
noobQuestOne = true;
playerGold = playerGold + 1;
playerActionsTaken = playerActionsTaken + 1;
cout<<"You deliver the " <<itemName[0] <<" and receive 1 gold coin.  Noob."<<endl;
}
}
else {
cout<<"Press B to barter with the " <<npcName[playerLocation] <<"."<<endl;
cin.getline(playerAction,10);
if (playerAction[0]=='b') {
//SHOPPING!
if (haveNoobLoot == true) {
haveNoobLoot = false;
playerGold = playerGold + 1;
cout<<"You sell your " <<itemName[1] <<" to the " <<npcName[playerLocation] <<" for 1 gold."<<endl;
playerActionsTaken = playerActionsTaken + 1;
}
else;
if (playerGold >= 10) {
cout<<"You spend 10 gold on " <<itemName[2] <<" and " <<itemName[3] <<"."<<endl;
playerGold = playerGold - 10;
haveNoobSword = true;
haveNoobArmor = true;
noobQuestTwo = true;
playerActionsTaken = playerActionsTaken + 1;
}
cout<<"After bartering with " <<npcName[playerLocation] <<", you have " <<playerGold <<" coins."<<endl;
}
else;
}
}
//SPEECHING AT NOOB FOREST:
if (playerLocation == 2) {
cout<<"You attempt to speak with the " <<npcName[playerLocation] <<", but your honeyed words fall on deaf ears."<<endl;
}
//SPEECHING AT PRO MOUNTAIN:
if (playerLocation == 3) {
cout<<"You try to speak with the " <<npcName[playerLocation] <<", but the " <<npcName[playerLocation] <<" doesn't want to hear it."<<endl;
cout<<"The " <<npcName[playerLocation] <<" attacks you with a vicious swipe of its mighty arm!"<<endl;
cout<<"You take 4 damage."<<endl;
playerHealth = playerHealth - 4;
}


cout<<"You now have " <<playerActionsTaken <<" experience points."<<endl;
}
/* That's "it"! Well, mostly. Remember playerDeath? Here we want to make sure it properly exits the game loop. */


if (playerHealth==0) {
//you die
cout<<"You have died."<<endl;
playerDeath = true;
}
}




};


//replay module:
cout<<"Playtime's over.  Enter 1 to play again, or anything else to quit."<<endl;
char replay[10];
cin.getline(replay,10);
if(replay[0]=='1'){
//pray again!
cout<<"Just kidding!  You CAN'T play again, you mook."<<endl;
}
else {
cout<<"OK, quitter."<<endl;
}


cout<<"The game is now over.  Press Enter to close."<<endl;
cin.getline(choiceOne,10);
;
//game ends
return 0;
}
/* OK!  We're done!  You've just coded your very own Noob Game, and the rest is just a matter of expanding everything into more substantial versions of what they already are.  This game leaves a lot to be desired (like, oh, pictures and music), but the skeleton is there and it all works perfectly! */

No comments:

Post a Comment