Sunday, March 21, 2010

Common Functions

//Common.h: Common formulas, procedures, etc..
////////////////////////////////////////////////////////////////////
//This is the freeware version 1.0
////////////////////////////////////////////////////////////////////
// Included in the zipfile:
//ShelbyWorks Graphics Library V1.0 -- It's pretty nice, look it over
//Waveplay routine by Steven H. Don -- Pretty in depth and complicated
//Getpass.h by Thomas Grimes -- Password routine that only shows ***** when password is entered
// None of these are related to this product, or to me
////////////////////////////////////////////////////////////////////////
//Made by Matt Selnekovic instar@rocketmail.com <-Feel free to send bug reports, etc.
//You MUST prototype the functions
//Good idea to print this out so you don't have to look it up each time
//This code was tested on Microsoft Visual C++, version 1.0
/////////////////////////////////////////////////////////////////////////
//Visit my homepage which has nothing to do with programming, but oh well updates are coming sometime this millenia
//http://www.geocities.com/southbeach/lagoon/8410/index.html
/////////////////////////////////////////////////////////////////////////
//Sorry if the coding style varies slightly, I'm trying to get a consistant style, but it takes time It is readable (to me) enough that I can make sense of it
/////////////////////////////////////////////////////////////////////////
//Yes, I know that many of these are implemented in some headers included with compilers already, but most are compiler specific and lots are macros, so I think that this will help clear some of it up
/////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include
#include
#include"getpass.h" //Make sure to put getpass.h and this file in the same directory, so this will work, or you could be like me and put all these files in the \include directory (cause I can never remember to put <>'s or ""'s)
#include

////////////////////////////////
//Define PI to be 3.141592, and also define the function keys so they can be used in programs easily
//Use the F1 - F10 shortcuts with the getKey() function

#define PI 3.141592
#define F1 0x3b00
#define F2 0x3c00
#define F3 0x3d00
#define F4 0x3e00
#define F5 0x3f00
#define F6 0x4000
#define F7 0x4100
#define F8 0x4200
#define F9 0x4300
#define F10 0x4400
#define TRUE 1 //True is 1
#define FALSE (!TRUE) //False is not 1 or 0
#define COLS 80 //DOS screen columns
#define ROWS 25 //DOS screen rows
#define VIDEO 0x10 //Video interrupt
#define KEYBOARD 0x16 //Keyboard interrupt
#define MODE_13H 0x13 //VGA 320x200x256
#define TEXT_MODE 0x03 //Default Text Mode
#define SCREEN_WIDTH 320//Graphics information
#define SCREEN_HEIGHT 200
#define PALETTE_MASK 0x3C6
#define PALETTE_REGISTER_RD 0x3C7
#define PALETTE_REGISTER_WR 0x3C8
#define PALETTE_DATA 0x3C9
#define UPKEY 18432 //Define UPKEY as 18432 to be used with getKey returning an integer
#define DOWNKEY 20480 //Downkey is 20480 with getKey
#define LEFTKEY 19200 //Left is 19200
#define RIGHTKEY 19712 //Right is 19712
#define ESC 283 //Escape is 283

//Common typedefs for data types, good for short quick access to commonly used variables
typedef unsigned char BYTE; //Unsigned char is a BYTE
typedef unsigned short WORD; //Unsigned short integer is a WORD
typedef unsigned long DWORD; //Unsigned long integer is a DWORD
typedef int BOOL; //Integer is a BOOL
typedef unsigned int UINT; //Unsigned integer is a UINT

///////////////////
//The Prototypes //
///////////////////
int square(int x);
int cube(int x);
float xToYth(int x, int y);
int maximum(int x,int y);
int minimum(int x, int y);
int rnd(int range);
int random(int range);
void pause(int delayp);
void doDOS(char *command);
void locate(int col, int row);
void cls(void);
int getKey(void);
int yorn(void);
void microDelay (long microSecs);
void milliDelay (long milliSecs);
void secDelay(long secs);
void minDelay(long mins);
void upperString(char *pS);
void lowerString(char *pS);
int password(char *prompt, char *pword);
float areaOfCircle(int r);
float circumference(int r);
float regionOfCircle(int r, int m);
float lengthOfArc(int r, int m);
float areaOfTriangle(int h, int b);
int areaOfRect(int l, int w);
float areaOfTrap(int h, int t, int b);
float areaOfQuadPD(int d, int e);
float areaOfPoly(int p, int t);
int volumeOfRect(int h, int w, int l);
int volumeOfPrism(int b, int h);
float volumeOfPyramid(int b, int h);
float volumeOfCylinder(int r, int h);
float volumeOfCone(int r, int h);
float volumeOfSphere(int r);

//////////////////////////////////////
// M A T H F U N C T I O N S //
//////////////////////////////////////

int square(int x)//Squares an int
{
x*=x;
return(x);
}

int cube(int x)//Cubes an int
{
x=x*x*x;
return(x);
}

float xToYth(int x, int y) //Stands for x to yth power
{
int i=0; //loop counter
int b=x;
if(y==0)
return(1); //If y is zero then return 1 (special case of powers)
if(y==1)
return(x); //If y is one then return the x (another special case)
if(y==-1)
return(1/x); //If y is negative one then return 1/x (another special case)
if(y<0) //If y is less than -1, then you must put 1 over x to yth
{
i--;
while(i>y)
{
i--;
x*=b;
}
return((float)1/x);
}
if(y>0) //Regular x to yth number
{
i++;
while(i
{
i++;
x*=b;
}
return(x);
}
return(0); //Return 0 if nothing above works(actually, all numbers work out, but the C++ compilier(mine) says that it doesn't have a default handler or something)
}

int maximum(int x,int y)//find larger number
{
if(x==y)
return(0); //Note: If this function returns a 0, then both are equal
if(x
x=y;
return(x);
}

int minimum(int x, int y)//Find smaller number
{
if(x==y)
return(0); //Note: If this function returns a 0, then both are equal
if(x>y)
x=y;
return(x);
}

int absolute(int x)//Find absolute value (distance from zero)
{
return(maximum(x,-x));
}

int isPos(int x)//Finds out if the number is positive, doesn't change it use it for simple range checks
{
if(x==0)
return(FALSE); //If number is 0, then it can't be either!(that's what I was taught in algebra)
if(x>0)
return(TRUE);
else
return(FALSE);
}

int isNeg(int x)//Finds out if number is negative, doesn't change it
{
if(x==0)
return(FALSE); //if number is 0, then it can't be negative, its not either
if(x<0)
return(TRUE);
else
return(FALSE);
}

int toPos(int x)//Changes number to positive
{
if(isNeg(x))
x=-x;//Two negatives equal a postive (remember that from algebra?)
return(x);
}

int toNeg(int x)//Changes number to negative
{
if(isPos(x))
x=-x;//One negative equals... you get the picture
return(x);
}

int isEven(int x)//Finds if number is even
{
if(x%2==0)
return(TRUE);//If its remainder of division is 0, then it is even(return TRUE)
else
return(FALSE);
}

int isOdd(int x)//Finds if number is odd
{
if(x%2==1)
return(TRUE);
else
return(FALSE);
}

//////////////////////////////////////////////////////////////
// B I O S A N D O T H E R F U N C T I O N S //
//////////////////////////////////////////////////////////////

int rnd(int range) //Requires STDLIB.h
{
int r;
r=rand()%range; //Make random number, pare it down
return(r);
}
int random(int range) //Call this function ONLY (for random numbers that is (Well, maybe just be careful with the rnd function, it doesn't seed randomizer))
{ //needs time.h
srand((unsigned)time(NULL));//Call timer, make unsigned, plant random seed
return(rnd(range)); //Make random number, send to rnd() function
}

void pause(int delayp) //This function takes in delayp*10000 to get time to wait so put in seconds or so
{
int delay;
delayp*=10000;
for(delay=0;delay //wait loop, seems easy enough change 10000 if not long enough
}

void doDOS(char *command) //This works in DOS programs, Windows programs might be messed up
{
system(command); //Needs stdlib.h, simple enough
getch(); //Wait here until key pressed
}

void locate(int col, int row)//Locate cursor at location on screen, also use in DOS programs only
{
union REGS regs;
regs.h.ah=0x02;
regs.h.bh=0x00;
regs.h.dh=row;
regs.h.dl=col;
int86(VIDEO,&regs,&regs);
}

void cls(void) //clear screen, same as DOS command DOS programs only
{
union REGS regs;
regs.h.ah=0x06;
regs.h.al=0x00;
regs.h.bh=0x07;
regs.h.ch=0x00;
regs.h.cl=0x00;
regs.h.dh=ROWS-1;
regs.h.dl=COLS-1;
int86(VIDEO,&regs,&regs);
locate(0,0); //Home cursor
}
int getKey(void) //Reads keyboard for input, returns integer scancode (For function keys, and combinations (shift, alt, control etc.))
{
union REGS regs;
regs.h.ah=0x00;
int86(KEYBOARD,&regs,&regs);
return(regs.x.ax);
}

int yorn(void) //Gets a Y(es) or N(o) and returns TRUE for Y and FALSE for N use it in if() statements or something
{
int done=FALSE;
char c;
while(!done)
{
c=toupper(getch());
if(c=='Y' || c=='N')
done=TRUE;
}
if(c=='Y') return(TRUE);
return(FALSE);
}

void microDelay(long microSecs)//A much better pause or delay function for C in microseconds
{ //Assembly code, don't try mucking with it (unless you know it)
_asm {
mov cx, word ptr [microSecs+2]
mov dx, word ptr [microSecs]
mov ah, 0x86
int 0x15
}
}

void milliDelay(long milliSecs)//Milliseconds pause delay
{
microDelay(milliSecs*1000);
}

void secDelay(long secs)//Seconds delay
{
milliDelay(secs*1000);
}

void minDelay(long mins)//Minute delay, not that usefull, nobody wants to sit around for a minute
{
secDelay(mins*60);
}

void upperString(char *pS)//Makes a string uppercase, takes a string
{
while(*pS)//goes from start of string to the /0 (NULL) thing at the end
{
if(islower(*pS))//If the character is lowercase...
*pS=toupper(*pS);//Then make it uppercase and...
pS++; //go to the next character in the string
}
}

void lowerString(char *pS)//Makes a string lowercase, takes a string
{
while(*pS)
{
if(isupper(*pS))//Same as above(close, but reversed in key places)
*pS=tolower(*pS);
pS++;
}
}

int password(char *prompt, char *pword)//This password routine takes in two strings, first, the prompt message(add a \n at the end of it), and second, the actual password
{ //This function basically simplifies the getpass function defined in getpass.h it was given to me by Thomas Grimes, for which I thank him
int i=strcmp(getpass(prompt),pword);//String compare what you get from getpass, and the password
if(i==0) //Strcmp returns three values 0 means exactly alike
return(TRUE);//If the person types the right one, then this returns TRUE(notice I didn't display the message confirming the right password, you do that
else
return(FALSE);//If the bloody scalawag doesn't then return FALSE
}
////////////////////////////////////////////////////////////////////////
// G E O M E T R Y F O R M U L A S //
////////////////////////////////////////////////////////////////////////
//From here on in, I'll provide formula in comments for clarification //
//Also, in circle formulas r is radius, m is measure of degrees //
//In triangles, h is height, b is base //
//In rectangles, l is length, w is width //
////////////////////////////////////////////////////////////////////////
//Now you can write your own geometry program... //
//Actually, this could be useful for some types of graphics //
////////////////////////////////////////////////////////////////////////

float areaOfCircle(int r)
{
float a; //area variable
//Finds area of a circle in terms of radius r A=PI*r*r(r squared)
r*=r; //R squared
a=(float)PI*r;
return(a);
}

float circumference(int r)
{
float c; //circumference variable
//finds circumference of circle C=2*PI*r
c=(float)2*PI*r;
return(c);
}

float regionOfCircle(int r, int m)
{
float a; //area variable
//find area of region in circle (think pie wedge) m/360*PI*r*r (r squared)
a=(m/360)*(float)(PI*r*r);
return(a);
}

float lengthOfArc(int r, int m)
{
float l; //length variable
float c; //circumference variable
//find length of arc in circle (think pie crust) l/c=m/360
c=circumference(r);
l=c*(m/360);
return(l);
}

float areaOfTriangle(int h, int b)
{
float a; //area variable
//finds area of triangle 1/2*b*h
a=(float)0.5*(b*h);
return(a);
}

int areaOfRect(int l, int w)
{ //Note: Rectangles, squares, and parallelograms have same area formula
int a;
//finds area of rectangle l*w
a=l*w;
return(a);
}

float areaOfTrap(int h, int t, int b) //H is height, T is top, B is base
{
float a=(float)0.5*h*(t+b); //Area of trapezoid is 1/2 height times the sum of the two bases 1/2*H*(Top+Bottom)
return(a);
}

float areaOfQuadPD(int d, int e) //Area of quadrilateral with perpendicular diagonals d is diagonal 1, e is diagonal 2 (doesn't matter what order)
{
float a=(float)0.5*d*e;
return(a);
}

float areaOfPoly(int p, int t) //Area of a regular polygon, p is perimeter, t is the apothem
{
float a=(float)0.5*p*t; //Area is 1/2 of perimeter times apothem
return(a);
}

int volumeOfRect(int h, int w, int l) //Volume of a right rectangular prism
{
int v=h*w*l; //Volume is height times length times width
return(v);
}

int volumeOfPrism(int b, int h) //Volume of generic prism, b is area of base, use above formulas to find
{
int v=b*h; //Volume of prism is area of base times height
return(v);
}

float volumeOfPyramid(int b, int h) //Volume of pyramid
{
float v=(b*h)/3; //Volume of pyramid is 1/3 area of base times height
return(v);
}

float volumeOfCylinder(int r, int h) //r radius of base, h height
{
float v;
r*=r; //R squared
v=(float)PI*r*h; //Volume of cylinder is PI*r*r*h
return(v);
}

float volumeOfCone(int r, int h)
{
float v;
r*=r; //R squared
v=(float)(PI*r*h)/3; //Volume of cone is 1/3 of PI*r*r*h
return(v);
}

float volumeOfSphere(int r)
{
float x=4/3;
float v;
r=r*r*r; //R cubed
v=(float)PI*r*x; //Volume of sphere is 4/3 PI*r*r*r
return(v);
}
///////////////////////////////////////////////////////////
//Anything this or you do to your computer is not my fault.

///////////////////////////////////////////////////////////
//COPYRIGHT INFORMATION
//This source code can be used by any person in their own programs for free. The Author of this source code allows anyone to freely use this as they please in their own programs.
//DOS is a copyright of Microsoft. Other copyrights are trademarks of their respective owners.
//Copying this for commercial sale, exploitation, or any other uses not implied here is not allowed.




2.



//ShelbyWorks Graphics Library V1.0
//Graphic.h

#include

#include

#include

#include

#include

#include

#include

#define sgn(x) ((x<0)?-1:((x>0)?1:0)) /* macro to return the sign of a
number */

/* macro to skip bytes in a file */
#define fskip(fp,n) \
{ \
int i; \
\
for (i=0;i
fgetc(fp); \
}

typedef unsigned char byte;
typedef unsigned short word;
typedef long fixed16_16;
typedef unsigned long dword;

//Circle
fixed16_16 SIN_ACOS[1024];

word VID = 0;


//for line draw alogorthim
byte *VGA=(byte *)0xA0000000L; /* this points to video memory. */
byte *screen=(byte *)0xA0000000L; /* this points to video memory. */

void SineTable()
{
word i;
for(i=0;i<1024;i++)>
{
SIN_ACOS[i]=sin(acos((float)i/1024))*0x10000L;
}
}

// maximum screen width
int getmaxx(void)

{
if (VID == 1)
return 639;
if (VID == 2)
return 319;
else
return 0;
}

//maximum screen hieght
int getmaxy(void)

{

if(VID == 1)
return 479;
if (VID == 2)
return 199;
else
return 0;
}

//maximum mumber of colors
int getmaxcolor(void)

{

return 255;

}

//sets screen to 320*200*250 VGA/EGA
void SetVGA()
{

VID = 2;

union REGS regs;

regs.h.ah = 0x00;
regs.h.al = 0x13;
int86(0x10, &regs, &regs);
}

//sets screen to 640*480*250 SVGA
void SetSVGA(void)

{
VID = 1;

asm mov ax,0x4f02;

asm mov bx,0x101;

asm int 0x10;

}

// sets 80x25 Text mode
void SetTEXT(void)

{
VID = 0;

asm mov ax,0x0003;

asm int 0x10;

}

//Put Pixel VGA
void VGAPixel (unsigned int x, unsigned int y, unsigned char c)
{
VGA[(y <<>
}

//Put Pixel SVGA
void SVGAPixel (unsigned int x, unsigned int y, unsigned char c)
{
VGA[y * 640 + x] = c;
}

// draws a line // Using Floating Point for Accuracy //VGA ONLY
void drawline(float x1, float y1, float x2, float y2, byte color)
{
int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;

dx=x2-x1; /* the horizontal distance of the line */
dy=y2-y1; /* the vertical distance of the line */
dxabs=abs(dx);
dyabs=abs(dy);
sdx=sgn(dx);
sdy=sgn(dy);
x=dyabs>>1;
y=dxabs>>1;
px=x1;
py=y1;

VGA[py*320+px]=color;

if (dxabs>=dyabs) /* the line is more horizontal than vertical */
{
for(i=0;i
{
y+=dyabs;
if (y>=dxabs)
{
y-=dxabs;
py+=sdy;
}
px+=sdx;
VGAPixel(px,py,color);
}
}
else /* the line is more vertical than horizontal */
{
for(i=0;i
{
x+=dxabs;
if (x>=dyabs)
{
x-=dyabs;
px+=sdx;
}
py+=sdy;
VGAPixel(px,py,color);
}
}
}

//Draws Non-Filled Rectangle SVGA ONLY
void Rect(int left,int top, int right, int bottom, byte color)
{
word top_offset,bottom_offset,i,temp;

if (top>bottom)
{
temp=top;
top=bottom;
bottom=temp;
}
if (left>right)
{
temp=left;
left=right;
right=temp;
}

top_offset=(top<<8)+(top<<6);
bottom_offset=(bottom<<8)+(bottom<<6);

for(i=left;i<=right;i++)
{
VGA[top_offset+i]=color;
VGA[bottom_offset+i]=color;
}
for(i=top_offset;i<=bottom_offset;i+=640)
{
VGA[left+i]=color;
VGA[right+i]=color;
}
}

//Draws Filled in Rectangle SVGA ONLY
void SolidRect(int left,int top, int right, int bottom, byte color)
{
word top_offset,bottom_offset,i,temp,width;

if (top>bottom)
{
temp=top;
top=bottom;
bottom=temp;
}
if (left>right)
{
temp=left;
left=right;
right=temp;
}

top_offset=(top<<8)+(top<<6)+left;
bottom_offset=(bottom<<8)+(bottom<<6)+left;
width=right-left+1;

for(i=top_offset;i<=bottom_offset;i+=640)
{
memset(&VGA[i],color,width);
}
}

//Bitmap Viewer Begins Here*******************************

//Bitmap File Structure
typedef struct tagBITMAP /* the structure for a bitmap. */
{
word width;
word height;
byte *data;
} BITMAP;

//Bitmap Loader
void load_bmp(char *file,BITMAP *b)
{
FILE *fp;
long index;
int x;
int num_colors;

/* open the file */
if ((fp = fopen(file,"rb")) == NULL)
{
printf("Error opening file %s.\n",file);
exit(1);
}

/* check to see if it is a valid bitmap file */
if (fgetc(fp)!='B' || fgetc(fp)!='M')
{
fclose(fp);
printf("%s is not a bitmap file.\n",file);
exit(1);
}

/* read in the width and height of the image, and the
number of colors used; ignore the rest */
fskip(fp,16);
fread(&b->width, sizeof(word), 1, fp);
fskip(fp,2);
fread(&b->height,sizeof(word), 1, fp);
fskip(fp,22);
fread(&num_colors,sizeof(word), 1, fp);
fskip(fp,6);

/* assume we are working with an 8-bit file */
if (num_colors==0) num_colors=256;


/* try to allocate memory */
if ((b->data = (byte *) malloc((word)(b->width*b->height))) == NULL)
{
fclose(fp);
printf("Error allocating memory for file %s.\n",file);
exit(1);
}

/* Ignore the palette information for now.
See palette.c for code to read the palette info. */
fskip(fp,num_colors*4);

/* read the bitmap */
for(index=(b->height-1)*b->width;index>=0;index-=b->width)
for(x=0;xwidth;x++)
b->data[(word)index+x]=(byte)fgetc(fp);

fclose(fp);
}

//Draws Bitmap //TransParent //SVGA ONLY
void draw_bmp(BITMAP *bmp,int x,int y)
{
int i,j;
word screen_offset = y * 640;
word bitmap_offset = 0;
byte data;

for(j=0;jheight;j++)
{
for(i=0;iwidth;i++,bitmap_offset++)
{
data = bmp->data[bitmap_offset];
if (data) VGA[screen_offset+x+i] = data;
}
screen_offset+=640;
}
}

void VGA_bmp(BITMAP *bmp,int x,int y)
{
int i,j;
word screen_offset = y * 320;
word bitmap_offset = 0;
byte data;

for(j=0;jheight;j++)
{
for(i=0;iwidth;i++,bitmap_offset++)
{
data = bmp->data[bitmap_offset];
if (data) VGA[screen_offset+x+i] = data;
}
screen_offset+=320;
}
}
//Ends Here*******************************

//Graphics Interchange Format (.GIF) 87a and 89a Veiwer
typedef
struct GIFHeader {
char Signature [7];
unsigned int ScreenWidth, ScreenHeight;
unsigned char Depth, Background, Zero;
};
struct GIFDescriptor {
char Separator;
unsigned int ImageLeft, ImageTop, ImageWidth, ImageHeight;
unsigned char Depth;
};

FILE *GIFFile;
unsigned int BPointer;
unsigned char Buffer [257];
//GIF data is stored in blocks of a certain size
unsigned char BlockSize;
//For loading the code
unsigned char CodeSize;
char BitsIn;
unsigned char Temp;
//Coordinates
unsigned int X, Y, tlX, tlY, brX, brY;
//The string table
unsigned int Prefix [4096];
unsigned char Suffix [4096];

void SetDAC(unsigned char DAC, unsigned char R, unsigned char G, unsigned char B)
{
outportb (0x3C8, DAC);
outportb (0x3C9, R);
outportb (0x3C9, G);
outportb (0x3C9, B);
}

unsigned char LoadByte ()
{
//Read next block}
if (BPointer == BlockSize) {
fread (Buffer, BlockSize + 1, 1, GIFFile);
BPointer = 0;
}

//Return byte
return Buffer [BPointer++];
}

//Procedure to read the next code from the file
unsigned int ReadCode ()
{
int Counter;
unsigned int Code;

Code = 0;
//Read the code, bit by bit
for (Counter = 0; Counter <>
//Maybe, a new byte needs to be loaded with a further 8 bits
if (++BitsIn == 9) {
Temp = LoadByte ();
BitsIn = 1;
}

//Add the current bit to the code
if (Temp & 1) Code += 1 <<>
Temp >>= 1;
}
return Code;
}

//Procedure to draw a pixel
void NextVGA (unsigned int c)
{
//Actually draw the pixel on screen
VGAPixel (X, Y, c & 255);

//Move to next row, if necessary
if (++X == brX) {
X = tlX;
Y++;
}
}

void NextSVGA (unsigned int c)
{
//Actually draw the pixel on screen
SVGAPixel (X, Y, c & 255);

//Move to next row, if necessary
if (++X == brX) {
X = tlX;
Y++;
}
}

//Local function to output a string. Returns the first character.
unsigned char OutString (unsigned int CurCode)
{
unsigned int OutCount;
unsigned char OutCode [1024];

//If it's a single character, output that
if (CurCode <>
NextVGA (CurCode);
} else {
OutCount = 0;

//Store the string, which ends up in reverse order
do {
OutCode [OutCount++] = Suffix [CurCode];
CurCode = Prefix [CurCode];
} while (CurCode > 255);

//Add the last character
OutCode [OutCount++] = CurCode;

//Output all the string, in the correct order
do {
NextVGA (OutCode [--OutCount]);
} while (OutCount);
}
//Return 1st character
return CurCode;
}

//This actually loads the GIF
void VGA_GIF (char *Filename)
{
//For loading from the GIF file
struct GIFHeader Header;
struct GIFDescriptor Descriptor;

//Colour information
unsigned char BitsPerPixel,
NumOfColours;
unsigned int DAC;
unsigned char Palette [256][3];

//For indexing the string table
unsigned int FirstFree, FreeCode;

//All the code information
unsigned char InitCodeSize;
unsigned int Code, OldCode, MaxCode;

//Special codes
unsigned int ClearCode, EOICode;

//Check whether the GIF file exists, and open it
GIFFile = fopen (Filename, "rb");
if (GIFFile == 0) {
SetTEXT ();
printf ("Could not open file %s", Filename);
return;
}

//Read header
fread (&Header, 6, 1, GIFFile);
Header.Signature [6] = 0;
fread (&Header.ScreenWidth, sizeof (Header) - 7, 1, GIFFile);

//Check signature and terminator
if ((strcmp (Header.Signature, "GIF87a")
&& strcmp (Header.Signature, "GIF89a"))
|| Header.Zero) {
SetTEXT ();
printf ("Not a valid GIF file\n");
return;
}

//Get amount of colours in image
BitsPerPixel = 1 + (Header.Depth & 7);
NumOfColours = (1 <<>

//Load global colour map
fread (Palette, 3, (NumOfColours + 1), GIFFile);
for (DAC = 0; DAC <= NumOfColours; DAC++)
SetDAC (DAC, Palette [DAC][0] >> 2,
Palette [DAC][1] >> 2,
Palette [DAC][2] >> 2);

//Load the image descriptor
fread (&Descriptor, sizeof (Descriptor), 1, GIFFile);

if (Descriptor.Separator != ',') {
SetTEXT ();
printf ("Incorrect image descriptor.\n");
return;
}

//Get image corner coordinates
tlX = Descriptor.ImageLeft;
tlY = Descriptor.ImageTop;
brX = tlX + Descriptor.ImageWidth;
brY = tlY + Descriptor.ImageHeight;

//Some restrictions apply
if (Descriptor.Depth & 128) {
SetTEXT ();
printf ("Local colour maps not supported\n");
return;
}
if (Descriptor.Depth & 64) {
SetTEXT ();
printf ("Interlaced images not supported\n");
return;
}

//Get initial code size
fread (&CodeSize, 1, 1, GIFFile);

//GIF data is stored in blocks, so it's necessary to know the size
fread (&BlockSize, 1, 1, GIFFile);

//Start loader
BPointer = BlockSize;

//Special codes used in the GIF spec
ClearCode = 1 <<>
EOICode = ClearCode + 1; //End of file

//Initialize the string table
FirstFree = ClearCode + 2; //Strings start here
FreeCode = FirstFree; //Strings can be added here

//Initial size of the code and its maximum value
InitCodeSize = ++CodeSize;
MaxCode = 1 <<>

BitsIn = 8;

//Start at top left of image
X = Descriptor.ImageLeft;
Y = Descriptor.ImageTop;

do {
//Read next code
Code = ReadCode ();

//If it's an End-Of-Information code, stop processing
if (Code == EOICode) break;
//If it's a clear code...
else if (Code == ClearCode) {
//Clear the string table
FreeCode = FirstFree;

//Set the code size to initial values
CodeSize = InitCodeSize;
MaxCode = 1 <<>

//The next code may be read
Code = ReadCode ();
OldCode = Code;

//Set pixel
NextVGA (Code);
//Other codes
} else {
/*If the code is already in the string table, it's string is displayed,
and the old string followed by the new string's first character is
added to the string table.*/
if (Code <>
Suffix [FreeCode] = OutString (Code);
else {
/*If it is not already in the string table, the old string followed by
the old string's first character is added to the string table and
displayed.*/
Suffix [FreeCode] = OutString (OldCode);
NextVGA (Suffix [FreeCode]);
}

//Finish adding to string table
Prefix [FreeCode++] = OldCode;

//If the code size needs to be adjusted, do so
if (FreeCode >= MaxCode && CodeSize <>
CodeSize++;
MaxCode <<= 1;
}

//The current code is now old
OldCode = Code;
}
} while (Code != EOICode);

//Close the GIF file
fclose (GIFFile);
}


//Problem See Note at bottom or Readme File
void SVGA_GIF (char *Filename)
{
//For loading from the GIF file
struct GIFHeader Header;
struct GIFDescriptor Descriptor;

//Colour information
unsigned char BitsPerPixel,
NumOfColours;
unsigned int DAC;
unsigned char Palette [256][3];

//For indexing the string table
unsigned int FirstFree, FreeCode;

//All the code information
unsigned char InitCodeSize;
unsigned int Code, OldCode, MaxCode;

//Special codes
unsigned int ClearCode, EOICode;

//Check whether the GIF file exists, and open it
GIFFile = fopen (Filename, "rb");
if (GIFFile == 0) {
SetTEXT ();
printf ("Could not open file %s", Filename);
return;
}

//Read header
fread (&Header, 6, 1, GIFFile);
Header.Signature [6] = 0;
fread (&Header.ScreenWidth, sizeof (Header) - 7, 1, GIFFile);

//Check signature and terminator
if ((strcmp (Header.Signature, "GIF87a")
&& strcmp (Header.Signature, "GIF89a"))
|| Header.Zero) {
SetTEXT ();
printf ("Not a valid GIF file\n");
return;
}

//Get amount of colours in image
BitsPerPixel = 1 + (Header.Depth & 7);
NumOfColours = (1 <<>

//Load global colour map
fread (Palette, 3, (NumOfColours + 1), GIFFile);
for (DAC = 0; DAC <= NumOfColours; DAC++)
SetDAC (DAC, Palette [DAC][0] >> 2,
Palette [DAC][1] >> 2,
Palette [DAC][2] >> 2);

//Load the image descriptor
fread (&Descriptor, sizeof (Descriptor), 1, GIFFile);

if (Descriptor.Separator != ',') {
SetTEXT ();
printf ("Incorrect image descriptor.\n");
return;
}

//Get image corner coordinates
tlX = Descriptor.ImageLeft;
tlY = Descriptor.ImageTop;
brX = tlX + Descriptor.ImageWidth;
brY = tlY + Descriptor.ImageHeight;

//Some restrictions apply
if (Descriptor.Depth & 128) {
SetTEXT ();
printf ("Local colour maps not supported\n");
return;
}
if (Descriptor.Depth & 64) {
SetTEXT ();
printf ("Interlaced images not supported\n");
return;
}

//Get initial code size
fread (&CodeSize, 1, 1, GIFFile);

//GIF data is stored in blocks, so it's necessary to know the size
fread (&BlockSize, 1, 1, GIFFile);

//Start loader
BPointer = BlockSize;

//Special codes used in the GIF spec
ClearCode = 1 <<>
EOICode = ClearCode + 1; //End of file

//Initialize the string table
FirstFree = ClearCode + 2; //Strings start here
FreeCode = FirstFree; //Strings can be added here

//Initial size of the code and its maximum value
InitCodeSize = ++CodeSize;
MaxCode = 1 <<>

BitsIn = 8;

//Start at top left of image
X = Descriptor.ImageLeft;
Y = Descriptor.ImageTop;

do {
//Read next code
Code = ReadCode ();

//If it's an End-Of-Information code, stop processing
if (Code == EOICode) break;
//If it's a clear code...
else if (Code == ClearCode) {
//Clear the string table
FreeCode = FirstFree;

//Set the code size to initial values
CodeSize = InitCodeSize;
MaxCode = 1 <<>

//The next code may be read
Code = ReadCode ();
OldCode = Code;

//Set pixel
NextSVGA (Code);
//Other codes
} else {
/*If the code is already in the string table, it's string is displayed,
and the old string followed by the new string's first character is
added to the string table.*/
if (Code <>
Suffix [FreeCode] = OutString (Code);
else {
/*If it is not already in the string table, the old string followed by
the old string's first character is added to the string table and
displayed.*/
Suffix [FreeCode] = OutString (OldCode);
NextSVGA (Suffix [FreeCode]);
}

//Finish adding to string table
Prefix [FreeCode++] = OldCode;

//If the code size needs to be adjusted, do so
if (FreeCode >= MaxCode && CodeSize <>
CodeSize++;
MaxCode <<= 1;
}

//The current code is now old
OldCode = Code;
}
} while (Code != EOICode);

//Close the GIF file
fclose (GIFFile);
}
//Ends Here*******************************

//PaintBrush (.PCX) Graphics File Viewer //VGA ONLY

void LoadPCX (char *FileName)
/*
This loads in the actual PCX-file and displays it.
*/
{
/*PCX Header structure*/
struct PCXHeader {
char Manufacturer, Version, Encoding, BitsPerPixel;
int xMin, yMin, xMax, yMax;
char Other[116];
} Header;
/*File handle*/
FILE *PCXFile;
/*Required for decoding and palette*/
unsigned char DataByte, HowMany, Palette[256][3];
int x, y, c;

/*Check to see whether the file exists and can be opened*/
PCXFile = fopen (FileName, "rb");
if (PCXFile == NULL) {
strcat (FileName,".PCX");
PCXFile = fopen (FileName, "rb");
if (PCXFile == NULL) {
printf ("Couldn't open file.");
return;
}
}

/*Read in header information*/
fread (&Header, 128, 1, PCXFile);
/*Check to see whether we can display it*/
if (Header.Version != 5) {
/*If other version than 5 don't display*/
fclose (PCXFile);
return;
}
if (Header.xMax>319 || Header.xMin<0>200 || Header.yMin<0)>
/*If it doesn't fit on-screen, don't display*/
fclose (PCXFile);
return;
}

/*Load in the palette*/
fseek (PCXFile, -769, SEEK_END);
/*Read in identifier*/
fread (&DataByte, 1, 1, PCXFile);
if (DataByte!=12) {
/*If there is no palette, don't display*/
}

fread (&Palette, 768, 1, PCXFile);
for (c=0; c<255;>
SetDAC (c,Palette[c][0] >> 2, Palette[c][1] >> 2, Palette[c][2] >> 2);
}

/*Go back to start of graphic data*/
fseek (PCXFile, 128, SEEK_SET);
y=Header.yMin;
x=Header.xMin;
Header.xMax++;
Header.yMax++;

/*Decode and display graphics*/
while (y
/*Read next byte*/
fread (&DataByte, 1, 1, PCXFile);

/*Reset counter*/
HowMany=1;

/*If it is encoded, extract the count information and read in the colour byte*/
if ((DataByte & 0xC0)==0xC0) {
HowMany = (DataByte & 0x3F);
fread (&DataByte, 1, 1, PCXFile);
}

/*Display it*/
for (c=1; c<=HowMany; c++) {
/*Calculate on-screen offset, display Pixel and go to next pixel*/
screen[(((y <<>
/*If End of Line reached, next line*/
if (x>=Header.xMax) {
y++; x=Header.xMin;
}
}
}
fclose (PCXFile);
}
//Ends Here******************************************

//Sets Pallate to Blue //VGA & SVGA
void BluePalette ()
{
int DAC;
for (DAC = 1; DAC <>
SetDAC (DAC, DAC >> 3, DAC >> 3, 32 + (DAC >> 3));
}

//Sets Pallate to Red //VGA & SVGA
void RedPalette ()
{
int DAC;

for (DAC = 1; DAC <>
SetDAC (DAC,32 + (DAC >> 3), DAC >> 3, DAC >> 3);
}

//Sets Pallate to Green //VGA & SVGA
void GreenPalette ()
{
int DAC;

for (DAC = 1; DAC <>
SetDAC (DAC, DAC >> 3, 32 + (DAC >> 3), DAC >> 3);
}

//This rotates the palette //VGA & SVGA
void RotatePal ()
{
int DAC, OffSet;

do {
//Set up the new colours
for (DAC = 0; DAC <>
//don't change colour 0 or the screen border would flash
if ((DAC + OffSet) & 0xFF)
SetDAC ((DAC + OffSet) & 0xFF, DAC >> 3, DAC >> 3, 32 + (DAC >> 3));
OffSet++;
} while (!kbhit());
}

//This makes a rain like pattern //VGA ONLY!!!!! (for Now)
void MakeDrip ()
{
unsigned int x, y, r, s;

for (x = 0; x <>
//For each column on screen, choose a different starting point...
r = random (255) <<>
//...and speed
s = (128 + random (128)) <<>
for (y = 0; y <>
//Set each pixel on the column, don't use color 0
if (!(r & 0xff00))
VGAPixel (x, y, 1);
else
VGAPixel (x, y, r >> 8);
//Move on to the next colour
r += s;
}
}
}

void SVGA_circle(int x,int y, int radius, byte color)
{
SineTable();
fixed16_16 n=0,invradius=(1/(float)radius)*0x10000L;
int dx=0,dy=radius-1;
word dxoffset,dyoffset,offset = (y*640)+x;

while (dx<=dy)
{
dxoffset = (dx * 640);
dyoffset = (dy * 640);
VGA[offset+dy-dxoffset] = color; /* octant 0 */
VGA[offset+dx-dyoffset] = color; /* octant 1 */
VGA[offset-dx-dyoffset] = color; /* octant 2 */
VGA[offset-dy-dxoffset] = color; /* octant 3 */
VGA[offset-dy+dxoffset] = color; /* octant 4 */
VGA[offset-dx+dyoffset] = color; /* octant 5 */
VGA[offset+dx+dyoffset] = color; /* octant 6 */
VGA[offset+dy+dxoffset] = color; /* octant 7 */
dx++;
n+=invradius;
dy = (int)((radius * SIN_ACOS[(int)(n>>6)]) >> 16);
}
}

void VGA_circle(int x,int y, int radius, byte color)
{
SineTable();
fixed16_16 n=0,invradius=(1/(float)radius)*0x10000L;
int dx=0,dy=radius-1;
word dxoffset,dyoffset,offset = (y*320)+x;

while (dx<=dy)
{
dxoffset = (dx * 320);
dyoffset = (dy * 320);
VGA[offset+dy-dxoffset] = color; /* octant 0 */
VGA[offset+dx-dyoffset] = color; /* octant 1 */
VGA[offset-dx-dyoffset] = color; /* octant 2 */
VGA[offset-dy-dxoffset] = color; /* octant 3 */
VGA[offset-dy+dxoffset] = color; /* octant 4 */
VGA[offset-dx+dyoffset] = color; /* octant 5 */
VGA[offset+dx+dyoffset] = color; /* octant 6 */
VGA[offset+dy+dxoffset] = color; /* octant 7 */
dx++;
n+=invradius;
dy = (int)((radius * SIN_ACOS[(int)(n>>6)]) >> 16);
}
}

void VGA_SolidCircle(int x,int y, int radius, byte color)
{
SineTable();
fixed16_16 n=0,invradius=(1/(float)radius)*0x10000L;
int dx=0,dy=radius-1,i;
word dxoffset,dyoffset,offset = (y<<8)+(y<<6)+x;

while (dx<=dy)
{
dxoffset = (dx<<8)>
dyoffset = (dy<<8)>
for(i=dy;i>=dx;i--,dyoffset-=320)
{
VGA[offset+i -dxoffset] = color; /* octant 0 */
VGA[offset+dx-dyoffset] = color; /* octant 1 */
VGA[offset-dx-dyoffset] = color; /* octant 2 */
VGA[offset-i -dxoffset] = color; /* octant 3 */
VGA[offset-i +dxoffset] = color; /* octant 4 */
VGA[offset-dx+dyoffset] = color; /* octant 5 */
VGA[offset+dx+dyoffset] = color; /* octant 6 */
VGA[offset+i +dxoffset] = color; /* octant 7 */
}
dx++;
n+=invradius;
dy = (int)((radius * SIN_ACOS[(int)(n>>6)]) >> 16);
}
}

void SVGA_SolidCircle(int x,int y, int radius, byte color)
{
SineTable();
fixed16_16 n=0,invradius=(1/(float)radius)*0x10000L;
int dx=0,dy=radius-1,i;
word dxoffset,dyoffset,offset = (y*640)+x;

while (dx<=dy)
{
dxoffset = (dx*640);
dyoffset = (dy*640);
for(i=dy;i>=dx;i--,dyoffset-=640) //320 Looks Fat!!!!
{
VGA[offset+i -dxoffset] = color; /* octant 0 */
VGA[offset+dx-dyoffset] = color; /* octant 1 */
VGA[offset-dx-dyoffset] = color; /* octant 2 */
VGA[offset-i -dxoffset] = color; /* octant 3 */
VGA[offset-i +dxoffset] = color; /* octant 4 */
VGA[offset-dx+dyoffset] = color; /* octant 5 */
VGA[offset+dx+dyoffset] = color; /* octant 6 */
VGA[offset+i +dxoffset] = color; /* octant 7 */
}
dx++;
n+=invradius;
dy = (int)((radius * SIN_ACOS[(int)(n>>6)]) >> 16);
}
}





//MOST "//" style comments are mine
// all "/*" style comments were added from pieces of code added from other people

//SVGA_GIF Function draws 2 pictures!?! I can't figure out why. If you can please
//let me know thug_death@hotmail.com.

//Copyright(c) 1998 ShelbyWorks Software
// All alorthims property of the respective owners

//Borland C++3.1+; Watcom C/C++; Microsoft C; Symantec C++
// NOT tested or approved for djgpp, Intel C/C++, or GNU gcc(Linux/Unix)






Game Programming information -- this article is inspired from a friend's research.

Welcome! Common questions:

  1. How do I get started? (for everyone)
  2. How do I make games? (for programmers)
  3. How can I write my own (more complex) game?
  4. How much fun is game programming?
  5. What do I need to learn in school?
  6. What do I need to learn once I know how to program?
  7. What do I do after school?

What’s on this page? I’m interested in producing complexity out of simple parts. This page contains bookmarks that I collected while working on games; I did not write most of the content linked from here. As a result the set of links here reflects the types of things I needed to know: only a few specific topics (not everything related to game programming), general ideas instead of platform-specific information (graphics, sound, compilers), and ideas and designs instead of source code (I find it easier to go from an idea to code than from code to an idea). Other sites, like Gamedev and Gamasutra, cover lots more topics than mine does. These are the topics I cover:

Who am I? I’m a hobbyist game programmer. I don’t work in the games industry, and I am not looking for a job. This page is the result of gathering information I needed for my own games. I work on these games in my spare time, so development is fairly slow. I keep a blog diary about game development and game design.

Shortest Paths

Determining how to move around on a map is an interesting problem. There are many different approaches, ranging from simple (walk forward until you hit something) to the complex (path finding algorithms with heuristics). These are pages about pathfinding in general, with some bias towards A*:

These pages are about specific techniques for pathfinding and object movement:

A*

My current favorite algorithm is A*, because it can handle varying terrain costs well, and it seems to be faster than most graph searching algorithms. However, there are several reasons not to use A*. A* deals with discrete steps, not with continuous movement; A* works on graphs and does not take full advantage of spatial coherence (i.e., a map location is very similar to its neighbors) or temporal coherence (e.g., if we already found a path a few seconds ago, it’s likely if we try again the path we find will be similar). If the game world is changing quickly it’s not worth planning very far ahead. Map representation [last updated May 2009] is an important but often overlooked problem; grids are commonly used but are not always the best choice.

Code and Demos

The link to my A* code is to the second version [4-Feb-1998], with bug fixes, optimizations, and parameterization for different heuristics and cost functions. The first version of my code is available on Steve Woodcock’s pages, and it may be easier to read and understand.

Search for more pages on A*, pathfinding.

Tile Based Games

There are two topics that come up with tile based games: display and world representation. The two issues are orthogonal. You can have a 2-D game without tiles; you can have a tile based game with a full 3-D view.

  1. Tile-based games tend to have top-down (2-D) or isometric (2.5-D) views.

    2-D graphics allows artists to use more detail—they can control individual pixels and form complex shapes, which is harder in a world of 3-D polygons and texture mapping.


  2. Tile-based worlds are made by combining small pieces into interesting patterns.

    Compare Chinese Hanzi (sixty thousand complex characters forming two hundred thousand words) to Roman letters (between twenty and thirty simple characters forming two hundred thousand words). It’s much easier to create new words with Roman letters than with Chinese characters. Or compare Lego Bricks from decades ago (mostly … bricks) to Lego Bricks today (mostly specialized pieces). It’s much easier to create new maps by combining a few simple reusable pieces than with a large set of customized components.

Search for more pages on influence maps, isometric maps, line of sight.

Hexagonal Grids

Many war games use hexagonal grids instead of square grids. Squares share an edge with four neighbors but also touch another four neighbors at just one point. This often complicates movement along grids because diagonal movements are hard to weight properly with integer movement values. You either have four directions or eight directions with squares, but with hexagons, you have a compromise—six directions. Hexagons don’t touch any neighbor at only a point; they have a small perimeter-to-area ratio; and they just look neat. Unfortunately, in our square pixel world of computers, hexagons are harder to use, so I’ve collected some articles that may help you turn common square-grid algorithms into hex-grid algorithms.

Search for more pages on hexagons.

Artificial Intelligence

Many times I play a game and wish that the computer opponents were written better. Sometimes the computer player is given different rules; other times it has the same rules but gets more money (or other resources) than you. The result is that the game doesn’t seem balanced: it’s just too obvious that the computer is not playing well, and that the game is brain vs. brawn rather than brain vs. brain. At the same time I don’t want AI that’s too good; if it were, then it’d always beat me and I’d be frustrated!

Computer AI is most commonly used to implement opponents for the player. However it can also be used to implement the world (for example, all the businesses in Railroad Tycoon), assistants to the player (for example, the automatic city management in Civilization), or computer players that are not necessarily opponents (for example, non-player characters in role-playing games).

Everyone talks about neural networks and genetic algorithms. I’m not going to provide any references for them. Instead, I’ll point to some techniques that are not discussed nearly enough:

In choosing a technique for AI in your games, keep it as simple as possible. If you know the answer, put the answer into the program. If you know how to compute the answer, put the algorithm for computing it into the program. Only if you don’t know the answer, and don’t even know how to compute the answer, should you resort to complex techniques that can learn how to find the answer (neural networks, simulated annealing, genetic algorithms, subsumption architecture, reinforcement learning, genetic programming). These complex techniques can come at a high price, in terms of programming time, game performance, difficulty of debugging, and lack of control.

Search for more pages on artificial intelligence.

Object Oriented Programming

I have found that the best places to use object oriented programming are user interfaces, operating systems, and games. At the same time, it’s commonly believed that object-oriented programming is the best way to program, but there are lots of situations where other approaches work much better.

Below are articles related to object oriented design but not specifically about games.

Search for more pages on objects.

Adventure Games

Although I’m not a big fan of adventure games, I’ve found that adventure game writers often have more time to work on story and game design than people working on action games. If you’re looking for story ideas or story design tips, or if you’re working on a MUD or massively multiplayer online game, take a look at these.

Search for more pages on interactive fiction, adventure games.

Game Design

A lot of what is hard about writing a game is getting the design right. What makes a game fun? Game design is an art, not a science. It’s not just the rules of the game but the way in which you interact with the game.

Search for more pages on game design, design documents.

Scripting Languages

I usually recommend putting general rules (“find a path from here to there”) in source code and specific rules (“if sensor 9 triggers in corridor 3, make guard 18 find a path to sensor 9”) in data files. However some things fall in between and are hard to express purely as data. That’s where scripting languages come in.

Scripting languages give you a way to write a lot of non-speed-critical code with comparatively little effort. You can design the language to specifically deal with your game, so the amount of work you have to do is less than for a general purpose language. Also, you can write the compiler to optimize for different things (like size instead of speed), allow more features (like dynamic patching at run-time), and even user customization (for enthusiastic users!).

I think for the best results, the scripting language should be game specific. I want to be able to write scripts, not code. For example, a script for a play might look like this:

       Amit [to Steve]: Hello, friend!        Steve [nods to Bryan]: Welcome to CGDC.        [Amit exits left.]

Note that it’s very high level: it doesn’t specify exactly how Amit speaks or how Steve nods or even the timing. For this to work, you need to have some assumptions about how people behave, and that makes the language specific to the system you are setting up. In this particular language, the use of brackets marks actions and the colon marks speech. In another language brackets might mark optional parameters and colons mark sections. The more general purpose your language, the fewer assumptions you can make, so it becomes more verbose. For example, the conversation might look like this:

       Amit.turns_towards(Steve);        Amit.walks_within(3);        Amit.says_to(Steve, "Hello, friend!");        Amit.waits(1);        Steve.turns_towards(Bryan);        Steve.walks_within(5);        Steve.nods_to(Bryan);        Steve.waits(1);        Steve.says_to(Bryan, "Welcome to CGDC.");        Amit.waits(3);        Amit.face_direction(DIR_LEFT);        Amit.exits();

That’s a program, not a script. See the difference? The script is high level, and specifies what you want to be done, while the program is low level, and specifies exactly how to do it. It’s not a great deal harder to interpret the first syntax than the second. You already have a programming language (C, C++, Pascal, Basic, etc.). You don’t need another! (Unless your goal is simply to allow run-time flexibility, which can be done with dynamically loaded libraries, or by using an existing language like Python.)

Try to think differently. Your scripting language doesn’t have to look just like C. Think about using an event-based structure. For example, have commands like “when X happens, do Y.” Think about having many things happen at once. Amit doesn’t have to stop just because Steve is saying something. Think about different styles of programming, like rule based, functional, imperative, logic, and object-oriented. Think about alternate rules of logic, like fuzzy logic (truth isn’t certain) or linear logic (one truth can turn into another, making the first false). Make the language take advantage of the structure of your game, and you may find it much easier to build parts of your game world.

Search for more pages on scripting languages.

Economics

Economics is the study of human choices when it comes to managing resources (money, time, happiness, raw materials, goods, and so on). In many strategy games, economics is an important aspect of the design. Balancing the resources of your world can be a fun part of the game. Economics is also important in multi-player game dynamics: you want to reward people for making money, yet you don’t want them to have so much power that new players cannot have fun. One thing I want to explore is how location influences economics. In high school economics, businesses compete by price. Whichever business sells for less will win. But if transportation cost is a factor, then both businesses can coexist, and the player has to make interesting decisions about where to place new facilities to balance all the variables (availability of labor, transportation cost of raw materials, transportation cost of product, tax rates, zoning laws, etc.).

It’s hard to come up with rules for economics in an online virtual world when the underlying costs are so different. In the physical world, “objects” take resources to build, but they typically do not use resources to keep (if you don’t use them), and you typically do not get those resources back when you throw the object away. Therefore our real world economy is based on buyingthings. In the virtual world, the “objects” take a small amount of memory and if you destroy the object, you get the memory back. At the same time, the veryexistence of a virtual object costs CPU time, which cannot be recovered. Therefore the virtual world economy might be based on renting things. If your world’s economy reflects the underlying costs, a diamond ring may “cost” as much as a bucket of sand. Although this reflects real costs of running your server, and therefore would discourage players from overloading it, it may not make sense for your game.

In addition to the economics of objects, you have to consider the economics of living in the world. In the physical world, mere existence of a person has a cost; in the virtual world, existence is cheap. Since a player may not be “logged on” all the time, it’s hard to come up with fair rules for the cost of existence without penalizing either players who play a lot (your core audience) or players who can’t log on much (who are likely to leave if penalized for not being there all the time). If you require someone to work for a living, the casual players may not be able to compete, and may leave.