Sign in to follow this  

Noob question: When is time to move on and where to?

This topic is 4811 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I just started learning C++ a week ago, so I don't expect to "move on" anytime soon, of course. But I want to know at what time I can move on and where to. FOr example, when will I be able to deal with graphics? After I mastered the console and events? And what kind of API: Win32, OpenGl, DirectX? Also, what books will help me get through certain topics? (I know there is a book review section, but I'd like specific opinions from you guys =P) For C++, I have: The Complete Reference and Beginning C++ Game Programming (I will probably finish the last this weekend, it's pretty easy).

Share this post


Link to post
Share on other sites
A 3D API like OpenGL or Direct3D would be probably be a bit daunting for you if you're still only familiar with the console. I suggest taking a swing at one of the well-known 2D libraries such as Allegro or SDL. There aren't many books on either, but they are easy enough to learn that you shouldn't need to dish out cash on books. A short browse through the Alternative Game Libraries forum should get you the answers you need on getting started with either.

Good luck!

Share this post


Link to post
Share on other sites
Kinda hard to say at this stage.Once you have mastered the DOS stuff move on to the Win32 API and after getting a good grasp start out with OpenGl or DirectX.

I preffer OpenGL since it's small and simple while DX is huge and difficult.Also OpenGL seems to work better on a verity of systems unlike DirectX.

GameTutorials
OpenGL
NeHe

Then there are 2D APIs like Allgero and SDL

SDL(Simple DirectMedia Layer)
Allegro

For Allegro you will need DJGPP which is a 32-bit DPMI DOS compiler

Share this post


Link to post
Share on other sites
i dont know it was kinda good to get the whole "event driven programming" concept with windows but (this is my opinion) windows API was so crappy i dont thinkn im going back to that so maybe skipping it will free up more time for better APIs then again if you want to try it go for it. it dose help you see inside what a windows program dose out in the open and donst hide it like alot of the other librarys do

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Cookies_Galore
Hey, I've got a noob question too. My friend who works at EA games said that theres three main ways to get into the game developing field, Art, Programming, and QA. What does QA stand for?


It stands for Quality Assurance - the guys who test the games and try to break them (find bugs and whatnot).

-Joe

Share this post


Link to post
Share on other sites
Quote:

Tricks of the Windows Game Programming Gurus


That book was my bible for a period of about 9 months =)
If you haven't bought it, do so now. It covers just about everything you will need to start making games for Windows. And I mean EVERYTHING. Mr. LaMothe also has a second edition follow-up that goes deep into 3D.

Since you are just staring, this book is probably far ahead of you, but it will definitely come in handy down the road.

Always plan ahead =)

Share this post


Link to post
Share on other sites
I'll buy it for my birthday, next month (gonna turn 17 and don't even have a car =( )
Anyway, I hope it's not over 50 bucks, cuz I haven't been able to get a job (i applied to over 50 places easily) and I have a twin, so we don't get that much money for birthday, and since the rest of my family lives in another country...

By the way, here is a nice little program that I made today (it's a two player game cuz I haven't implemented the AI)
The game revolves around making squares. If you make a square you get a point and it's your turn again, if you don't, it's the other person's turn.
The point system is a little messed up, but I'll fix it in the next version. Along with putting music (MIDI), a "clickable" '?' (help), AI (tough AI!) and other stuff....

tell me what you guys think ;) (but no flaming please, only been programming C++ for a week or so)

main.cpp
#include "game.h"
#include "conio.h"
#include <stdlib.h>



int main()
{
COORD title = {32, 10};
COORD thankyou = {60, 24};

HANDLE OutH = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(OutH, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
SetConsoleCursorPosition(OutH, title);
cout << "THE DOT.GAME!";
title.X =23;
title.Y +=1;
SetConsoleTextAttribute(OutH, FOREGROUND_RED | FOREGROUND_INTENSITY);
SetConsoleCursorPosition(OutH, title);
cout << "Created by Byte Me! Productions";
title.X =26;
title.Y +=1;
SetConsoleTextAttribute(OutH, WHITE);
SetConsoleCursorPosition(OutH, title);
cout << "Press any key to start...";

while(!kbhit()) {}

system("cls");

GAMEDATA game;

game.init();

while(1)
{
game.getInput();
if(game.gameOver()) {
game.calcWinner();
break;
}
}

SetConsoleCursorPosition(OutH, thankyou);
cout << "Thanks for playing our shitty game...";
return EXIT_SUCCESS;
}



game.cpp
#include "game.h" /* See "game.h" for more information */

/* Constructor - Only one, no need to pass parameters */
GAMEDATA::GAMEDATA()
{
srand(GetTickCount()); /* Seed random number generator */

winner = NO_WINNER; /* Nobody has one yet */
}

/* Initiate GAMEDATA */
void GAMEDATA::init()
{

/* Initiate Grid */
for(int i = 0; i < (BOARD_WDTH * BOARD_HGT); i++)
{
screen_buff[i].Char.AsciiChar = (char)grid[i];
screen_buff[i].Attributes = FOREGROUND_BLUE;
}

/* Could also do this
for(int x = 0; x < BOARD_WDTH; x++)
{
for(int y = 0; y < BOARD_HGT; y++)
{
screen_buff[x+y*BOARD_WDTH].Char.AsciiChar = (char)grid[x+y*BOARD_WDTH];
screen_buff[x+y*BOARD_WDTH].Attributes = FOREGROUND_BLUE;

}
} But we are far too cool, so we don't... */


/* Get our standard input and output handles */
out_handle = GetStdHandle(STD_OUTPUT_HANDLE);
in_handle = GetStdHandle(STD_INPUT_HANDLE);

/* Set the rect of where we want to draw to */
scr_rect.Left = X_START;
scr_rect.Right = X_START + (BOARD_WDTH - 1);
scr_rect.Top = Y_START;
scr_rect.Bottom = Y_START + (BOARD_HGT - 1);

SetConsoleMode(in_handle,ENABLE_MOUSE_INPUT);

turn = rand()%2; /* Randomly pick who starts */

p1Points = 0;
p2Points = 0;

drawScreen(); /* Draw the screen */
}

/* Draws the screen with the cool looking grid */
void GAMEDATA::drawScreen()
{
COORD p1 = {X_START,1};
COORD p2 = {BOARD_WDTH-3,1};

COORD size = {BOARD_WDTH , BOARD_HGT}; /* The size of the buffer in (width, height) format */
COORD corner = {0, 0}; /* Upper left corner to begin writing buffer from */

if(turn == 0)
{
SetConsoleTextAttribute(out_handle, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
SetConsoleCursorPosition(out_handle, p1);
cout << "Player 1";
SetConsoleTextAttribute(out_handle, WHITE);
SetConsoleCursorPosition(out_handle, p2);
cout << "Player 2";
}
else
{
SetConsoleTextAttribute(out_handle, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
SetConsoleCursorPosition(out_handle, p2);
cout << "Player 2";
SetConsoleTextAttribute(out_handle, WHITE);
SetConsoleCursorPosition(out_handle, p1);
cout << "Player 1";
}

WriteConsoleOutput(out_handle, screen_buff, size, corner, &scr_rect);
}

/* Get the user input (mouse clicks) */
void GAMEDATA::getInput()
{
int x_pos, y_pos, actX, actY;

INPUT_RECORD input_record; /* Keeps track of your inputs */
DWORD events; /* Necessary for events */
/* Get any input */
do{
ReadConsoleInput(in_handle, &input_record, 1, &events); /* '1' means only 1 event to keep record */

if(input_record.EventType == MOUSE_EVENT) /* Check for mouse events */
{
/* If they DID NOT hit the left mouse button, we don't care about the input */
if(input_record.Event.MouseEvent.dwButtonState != FROM_LEFT_1ST_BUTTON_PRESSED)
{ /* Waits for input */
}
else
{
/* Get the coordinates the clicked on */

actX = input_record.Event.MouseEvent.dwMousePosition.X-X_START;
actY = input_record.Event.MouseEvent.dwMousePosition.Y-Y_START;

if(screen_buff[actX + actY * BOARD_WDTH].Char.AsciiChar == 46) /* If it's a ".", then we are set */
{
x_pos = input_record.Event.MouseEvent.dwMousePosition.X;
y_pos = input_record.Event.MouseEvent.dwMousePosition.Y;
screen_buff[actX + actY * BOARD_WDTH].Attributes = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
drawScreen();

break; /* Breaks loop */
}

}

}
} while(1); /* Keeps going until you do what we want... */

getInput(x_pos,y_pos);

}

void GAMEDATA::getInput(int x, int y)
{
int x_pos, y_pos, actX, actY;

INPUT_RECORD input_record; /* Keeps track of your inputs */
DWORD events; /* Necessary for events */
/* Get any input */
ReadConsoleInput(in_handle, &input_record, 1, &events); /* '1' means only 1 event to keep record */

if(input_record.EventType == MOUSE_EVENT) /* Check for mouse events */
{
/* If they DID NOT hit the left mouse button, we recall the function untill they do */
if(input_record.Event.MouseEvent.dwButtonState != FROM_LEFT_1ST_BUTTON_PRESSED)
{
getInput(x,y);
return;
}
else
{
/* Get the coordinates the clicked on */
actX = input_record.Event.MouseEvent.dwMousePosition.X-X_START;
actY = input_record.Event.MouseEvent.dwMousePosition.Y-Y_START;

if(screen_buff[actX + actY * BOARD_WDTH].Char.AsciiChar == 46) /* If it's a ".", then we are set */
{
x_pos = input_record.Event.MouseEvent.dwMousePosition.X;
y_pos = input_record.Event.MouseEvent.dwMousePosition.Y;

if(x==x_pos && y==y_pos)
{
screen_buff[x-5 + (y-5) * BOARD_WDTH].Attributes = FOREGROUND_BLUE;
drawScreen();
getInput();
return;
}
else if(!validPts(x,y,x_pos,y_pos)) /* If points are not valid (i.e. 5x5 and 11x5 (too far!)), re-type a second point */
{
getInput(x,y);
return;
}

}
else /* Otherwise, recall the function */
{
getInput(x,y);
return;
}
}

}

screen_buff[actX + actY * BOARD_WDTH].Attributes = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
drawScreen();
/* FOR DEBUGGING PURPOSES: cout << x << y << " " << x_pos << y_pos; */
fillIn(x,y,x_pos,y_pos);
}

void GAMEDATA::fillIn(int x, int y, int x_pos, int y_pos)
{
int rX, rY, value;
/* vertical | */
if(x==x_pos)
{ screen_buff[x-5 + ((y+y_pos)/2-5) * BOARD_WDTH].Char.AsciiChar = (char)179;
screen_buff[x-5 + ((y+y_pos)/2-5) * BOARD_WDTH].Attributes = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
rX = x-5;
rY = (y+y_pos)/2-5;
flag = 0;

}
/* horizontal - */
if(y==y_pos)
{ screen_buff[(x+x_pos)/2-5 + (y-5) * BOARD_WDTH].Char.AsciiChar = (char)196;
screen_buff[(x+x_pos)/2-5 + (y-5) * BOARD_WDTH].Attributes = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
rX = (x+x_pos)/2-5;
rY = y-5;
flag =1;
}

screen_buff[x-5 + (y-5) * BOARD_WDTH].Attributes = FOREGROUND_BLUE;
screen_buff[x_pos-5 + (y_pos-5) * BOARD_WDTH].Attributes = FOREGROUND_BLUE;

value = madeSquare(rX,rY,flag);


if(value!=0)
if(!turn)
p1Points+=value;
else
p2Points+=value;
else
if(!turn)
turn++;
else
turn--;

drawScreen();

}

bool GAMEDATA::validPts(int x, int y, int x1, int y1)
{
if((x-2==x1 || x+2==x1) && (y==y1))
return true;

if((y-2==y1 || y+2==y1) && (x==x1))
return true;

return false;
}


int GAMEDATA::madeSquare(int x, int y, int f)
{

int total = 0;
/* If last input is horizontal*/
if(f)
{ /* Checks bottom */
if(y<18) {
if(screen_buff[x-1 + (y+1) * BOARD_WDTH].Char.AsciiChar != 32 &&
screen_buff[x+1 + (y+1) * BOARD_WDTH].Char.AsciiChar != 32 &&
screen_buff[x + (y+2) * BOARD_WDTH].Char.AsciiChar != 32) {
total++;
if(!turn) {
screen_buff[x + (y+1) * BOARD_WDTH].Attributes = FOREGROUND_RED | FOREGROUND_RED;
screen_buff[x + (y+1) * BOARD_WDTH].Char.AsciiChar = (char)49;
}
else
{
screen_buff[x + (y+1) * BOARD_WDTH].Attributes = FOREGROUND_RED | FOREGROUND_RED;
screen_buff[x + (y+1) * BOARD_WDTH].Char.AsciiChar = (char)50;
}
}
}
if(y!=0) {
if(screen_buff[x+1 + (y-1) * BOARD_WDTH].Char.AsciiChar != 32 && /* Checks top */
screen_buff[x-1 + (y-1) * BOARD_WDTH].Char.AsciiChar != 32 &&
screen_buff[x + (y-2) * BOARD_WDTH].Char.AsciiChar != 32) {
total++;
if(!turn) {
screen_buff[x + (y-1) * BOARD_WDTH].Attributes = FOREGROUND_RED | FOREGROUND_RED;
screen_buff[x + (y-1) * BOARD_WDTH].Char.AsciiChar = (char)49;
}
else
{
screen_buff[x + (y-1) * BOARD_WDTH].Attributes = FOREGROUND_RED | FOREGROUND_RED;
screen_buff[x + (y-1) * BOARD_WDTH].Char.AsciiChar = (char)50;
}
}
}
}
else
{
/* Checks right */
if(x<18) {
if(screen_buff[x+1 + (y-1) * BOARD_WDTH].Char.AsciiChar != 32 &&
screen_buff[x+1 + (y+1) * BOARD_WDTH].Char.AsciiChar != 32 &&
screen_buff[x+2 + (y) * BOARD_WDTH].Char.AsciiChar != 32) {
total++;

if(!turn) {
screen_buff[x+1 + (y) * BOARD_WDTH].Attributes = FOREGROUND_RED | FOREGROUND_RED;
screen_buff[x+1 + (y) * BOARD_WDTH].Char.AsciiChar = (char)49;
}
else
{
screen_buff[x+1 + (y) * BOARD_WDTH].Attributes = FOREGROUND_RED | FOREGROUND_RED;
screen_buff[x+1 + (y) * BOARD_WDTH].Char.AsciiChar = (char)50;
}
}
}
if(x!=0){
if(screen_buff[x-1 + (y+1) * BOARD_WDTH].Char.AsciiChar != 32 && /* Checks left */
screen_buff[x-1 + (y-1) * BOARD_WDTH].Char.AsciiChar != 32 &&
screen_buff[x-2 + (y) * BOARD_WDTH].Char.AsciiChar != 32) {
total++;

if(!turn) {
screen_buff[x-1 + (y) * BOARD_WDTH].Attributes = FOREGROUND_RED | FOREGROUND_RED;
screen_buff[x-1 + (y) * BOARD_WDTH].Char.AsciiChar = (char)49;
}
else
{
screen_buff[x-1 + (y) * BOARD_WDTH].Attributes = FOREGROUND_RED | FOREGROUND_RED;
screen_buff[x-1 + (y) * BOARD_WDTH].Char.AsciiChar = (char)50;
}

}
}
}
return total;
}

bool GAMEDATA::gameOver()
{

for(int i = 0; i < (BOARD_WDTH * BOARD_HGT); i++)
{
if(screen_buff[i].Char.AsciiChar == OPEN)
return false;
}

return true;
}


void GAMEDATA::calcWinner()
{
COORD p1 = {60,12};
COORD p2 = {60,13};

SetConsoleCursorPosition(out_handle, p1);
cout << "Player 1 - " << p1Points;
SetConsoleCursorPosition(out_handle, p2);
cout << "Player 2 - " << p2Points;
}


game.h
#ifndef GAME_H
#define GAME_H

/* Include libraries and define standard namespace */
#include <windows.h>
#include <iostream>
using namespace std;

/* Define Winners */
#define NO_WINNER 0
#define PLAYER1 1
#define PLAYER2 2
#define TIE 3

/* Define Turns */
#define P1TURN 1
#define P2TURN 2

/* Colors */
#define WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
#define BACKGROUND_WHITE BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE

/* Define Grid */
#define X_START 5
#define Y_START 5

#define BOARD_WDTH 19
#define BOARD_HGT 19

#define OPEN 32

/* 19 x 19 - OPEN = empty space and 46 = '.' */
const int grid[] =
{ 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46,
OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN,
46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46,
OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN,
46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46,
OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN,
46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46,
OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN,
46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46,
OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN,
46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46,
OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN,
46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46,
OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN,
46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46,
OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN,
46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46,
OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN, OPEN,
46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46, OPEN, 46,
};

class GAMEDATA
{
public:

/* Constructor */
GAMEDATA();

/* Deconstructor */
// ~GAMEDATA();

void init(); /* Init game data */

// Data Access ***

int getTurn() const { return turn; }
int getWinner() const { return winner; }

// *** End of Data Access

/* Sets a character on board */
void setScreenBuff(int x, int y, char c, bool scrCoords = true);

/* Draws grid on screen */
void drawScreen();

/* Gets user input */
void getInput();
void getInput(int x, int y);

/* Increments to the next persons turn */
void nextTurn();

/* Figures out who won the game */
void calcWinner();

/* Fills in grid */
void fillIn(int x, int y, int x1, int y1);

/* Free Memory */
void FreeMem();

/* Checks if they are valid points */
bool validPts(int x, int y, int x1, int y1);

/* Check if part of the grid is already filled */
bool isFilled(int x, int y);

/* Checks if Sq. Made */
int madeSquare(int x, int y, int f);

/* Check if game is over */
bool gameOver();

private:

/* The actual board */
CHAR_INFO screen_buff[BOARD_WDTH * BOARD_HGT];


HANDLE out_handle; /* Handle to the "screen" */
HANDLE in_handle; /* Handle to the "keyboard" */

SMALL_RECT scr_rect; /* This rect specifies where on the screen (where in our console
window) should we draw the tic-tac-toe board to */


int turn; /* Who's turn is it? */

int winner; /* Who has won? */

int p1Points;
int p2Points;

int flag;
};


#endif

Share this post


Link to post
Share on other sites
Quote:
Original post by lack o comments
Quote:

Tricks of the Windows Game Programming Gurus


That book was my bible for a period of about 9 months =)
If you haven't bought it, do so now. It covers just about everything you will need to start making games for Windows. And I mean EVERYTHING. Mr. LaMothe also has a second edition follow-up that goes deep into 3D.

Since you are just staring, this book is probably far ahead of you, but it will definitely come in handy down the road.

Always plan ahead =)


Is the 3d good also?
And does it cover AI, scripting, etc? I only heard good things about it, it seems like a good buy. =)

Share this post


Link to post
Share on other sites
The 3D book is great! It covers nothing but 3D graphics though so you'd have to look elsewhere for AI stuff. It also doesn't cover any API's, it uses directX basically to just draw lines and pixels and does all the 3D stuff in software. If you're serious about graphics, I'd recommend reading it before learning an API. That way you'll understand everything that's going on.

Share this post


Link to post
Share on other sites
For those who have both books, can you trace the required knowlegde and the ending knowledge (if that makes no sense, I mean how much you have to know to get started and how much will you have known when u finish)

Share this post


Link to post
Share on other sites
Quote:

I'd recommend reading it before learning an API.

I totally agree with this, I have always thought it better to learn how to do it yourself before using someone else's API

Quote:

can you trace the required knowlegde...


That is a tough question to answer because eveyone learns differently. I'm self-taught, so I had to learn all this stuff the bass-akwards way;)

I would suggest a firm understanding of the C/C++ language and at least a good concept of how exactly your program is processed by the computer. As far as math skills, the basic four aught to work. Almost all the math in the world revolves around adding, subtracting, multiplying, and dividing.

However, even if you don't know enough yet, these books will come in handy later, I assure you.

Quote:

...and ending knowledge

You will learn the very basics of the Windows programming model (enough to make a game), all the major componts of DirectX, the basics for AI and physics, and the math and theories behind all this stuff. Geez, I feel like I'm sellin' the book for the guy;)


Quote:

tell me what you guys think ...

My god! What is this crap! Why I outta.... ha ha ha, just kidding =) Keep up the good work.





Share this post


Link to post
Share on other sites

This topic is 4811 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this