home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Game Programming for Dummies (2nd Edition)
/
WinGamProgFD.iso
/
mac
/
Source
/
GPCHAP18
/
UNDERWLD.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
2002-05-01
|
234KB
|
7,467 lines
// UNDERWLD.CPP - The final game
// remember to compile you need GPDUMB1.CPP, GPDUMB2.CPP and
// DirectX libraries DDRAW.LIB, DSOUND.LIB, DINPUT.LIB, DINPUT8.LIB and
// WINMM.LIB
// INCLUDES ///////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN
#define INITGUID
#include <windows.h> // include important windows stuff
#include <windowsx.h>
#include <mmsystem.h>
#include <iostream.h> // include important C/C++ stuff
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <fcntl.h>
#include <ddraw.h> // directX includes
#include <dsound.h>
#include <dinput.h>
#include "gpdumb1.h" // game library includes
#include "gpdumb2.h"
//#include "mono.h"
// DEFINES ////////////////////////////////////////////////
// defines for windows
#define WINDOW_CLASS_NAME "WINXCLASS" // class name
#define WINDOW_WIDTH 64 // size of window
#define WINDOW_HEIGHT 48
// defines for font
#define FONT_NUM_CHARS 96 // entire character set
#define FONT_WIDTH 16
#define FONT_HEIGHT 16
#define FONT_WIDTH_NEXT_NUM 12
#define FONT_WIDTH_NEXT_LOWER 12
#define FONT_WIDTH_NEXT_UPPER 12
// demo object position
#define DUG_DEMO_X 188
#define DUG_DEMO_Y 352
#define POO_DEMO_X 188
#define POO_DEMO_Y 234
#define PUFF_DEMO_X 188
#define PUFF_DEMO_Y 190
// defines for high score bitmaps
#define NUM_SCORES 16
#define SCORE_DISPLAY_COUNT 50
#define SCORE_OFF 0
#define SCORE_ON 1
// defines for grappling pumps
#define NUM_GPUMPS 8
#define GPUMP_INJECTION 50 // pressure of a single gpump
#define GPUMP_STATE_DEAD 0
#define GPUMP_STATE_MOVING 1
#define GPUMP_STATE_ATTACHED 2
#define GPUMP_SPEED 6
// defines for fireballs
#define NUM_FBALLS 8
#define NUM_FBLASTS 3
#define FBALL_STATE_DEAD 0
#define FBALL_STATE_EXPLODING 1
#define FBALL_STATE_MOVING 2
#define FBALL_SPEED 4
#define FBALL_TYPE_RED 0
#define FBALL_TYPE_GREEN 1
#define FBALL_ANIM_RED_FLY 0
#define FBALL_ANIM_RED_EXPLODE 1
#define FBALL_ANIM_GREEN_FLY 2
#define FBALL_ANIM_GREEN_EXPLODE 3
// defines for rocks
#define ROCK_STATE_DEAD 0
#define ROCK_STATE_STABLE 1
#define ROCK_STATE_SHAKING 2
#define ROCK_STATE_FALLING 3
#define ROCK_STATE_CRUMBLING 4
#define ROCK_COUNT_SHAKE 30
#define NUM_ROCKS 16 // maximum number of rocks in simulation
#define ROCK_INIT_VELOCITY 4 // initial velocity
#define ROCK_GRAVITY 0.25 // gravity field
#define ROCKS_DROP_FOR_PRIZE 2 // rocks that need to be dropped per level for prize
// defines for prizes
#define NUM_PRIZES 9
#define PRIZE_X_POS 320
#define PRIZE_Y_POS 200
#define PRIZE_DISPLAY_TIME 375
#define PRIZE_STATE_OFF 0
#define PRIZE_STATE_ON 1
#define POINTS_NEW_MAN 35000
// defines for level loading
#define MAX_LEVELS 64
#define LEVEL_COLUMNS 16
#define LEVEL_ROWS 10
#define STARTING_LEVEL_NUMBER 0 // starting level of game
// possible data id values in level data
#define OBJECT_ID_ROCK 'r'
#define OBJECT_ID_PUFF 'd'
#define OBJECT_ID_POO 'p'
#define OBJECT_ID_VHOLE 'v'
#define OBJECT_ID_HHOLE 'h'
// defines for score rendering
#define SCORE_X 32
#define SCORE_Y 2
#define SCORE_COLOR_BOLD 10
#define SCORE_COLOR_TEXT 15
// defines for mushrooms
#define MUSH_START_X (SCREEN_WIDTH - 32)
#define MUSH_START_Y 34
// defines for small dugs
#define DUG_LIVES_X 8
#define DUG_LIVES_Y (SCREEN_HEIGHT - 16)
// defines for prizes
#define NUM_PRIZES 9
// defines for important colors
#define COLOR_INDEX_HOLE 224 // color index for hole
// defines for holes
#define NUM_HOLE_BITMAPS 10
#define HOLE_INDEX_H 8
#define HOLE_INDEX_V 9
// defines for poo's
#define NUM_POOS 16 // max num of poos available
#define POO_SPEED 2 // starting speed of all poos
#define POO_EXPLORE_TIME 500 // amount of time to explore
#define POO_BOUNCES_PREMPT 3 // number of bounces before a preempt from
// explore to chase
#define POO_STATE_DEAD 0 // the poo is dead
#define POO_STATE_ALIVE 1 // the poo is alive
#define POO_STATE_INFLATING 2 // the poo is inflating (immobile)
#define POO_STATE_DYING 3 // dying in some manner
// anim states
#define POO_ANIM_STATE_BOUNCE 0 // the poo is bouncing like normal
#define POO_ANIM_STATE_CRUSHED 1 // the poo is being crushed by a rock
#define POO_ANIM_STATE_BURROW 2 // the poo is burrowing
#define POO_ANIM_STATE_INFLATING 3 // the poo is being inflated
// poo animations
#define POO_ANIM_BOUNCE_LEFT 0 // bouncing left animation index
#define POO_ANIM_BOUNCE_RIGHT 1 // bouncing right animation index
#define POO_ANIM_CRUSH_LEFT 2 // getting crushed facing left
#define POO_ANIM_CRUSH_RIGHT 3 // getting grushed facing right
#define POO_ANIM_BURROW 4 // poo is burrowing
// ai states
#define POO_AI_STATE_STOP 0 // the poo is stopped and thinking
#define POO_AI_STATE_EXPLORE 1 // the pos is just exploring
#define POO_AI_STATE_CHASE 2 // the poo chasing the player
#define POO_AI_STATE_EVADE 3 // the poo is evading the player
#define POO_AI_STATE_BURROW 4 // the poo is burrowing
#define POO_AI_STATE_CRUSHED 5 // the poo is being crushed
#define POO_AI_STATE_INFLATING 6 // the poo is being inflated
#define POO_AI_STATE_POPPED 7 // the poo has finally popped
// variable indices
#define POO_INDEX_AI_STATE 0 // the mode of the ai
#define POO_INDEX_ANIM_STATE 1 // the state of the animation
#define POO_INDEX_ANIM_DIR 2 // the direction of animation left or right
#define POO_INDEX_CURR_DIR 3 // the actual nautical direction
#define POO_INDEX_LAST_DIR 4 // the last actual nautical direction
#define POO_INDEX_DESIRED_DIR 5 // the desired nautical direction
#define POO_INDEX_2ND_DESIRED_DIR 6 // the secondary desired nautical direction
#define POO_INDEX_PSI_COUNT 7 // used in inflation algorithm
#define POO_INDEX_EXPLORE_COUNTER 8 // used to track how long poo in explore mode
// tracking for bouncing
#define POO_INDEX_SUM_X 9 // number of x direction bounces
#define POO_INDEX_SUM_Y 10 // number of y direction bounces
#define POO_INDEX_BOUNCE_MAX 11 // general counter
#define POO_INDEX_OBJECT_PTR 12 // general reference ptr
// used to reset level
#define POO_INDEX_SAVED_X 13
#define POO_INDEX_SAVED_Y 14
#define POO_INDEX_SAVED_DIR 15
// defines for PUFF's
#define NUM_PUFFS 16 // max num of PUFFs available
#define PUFF_SPEED 2 // starting speed of all PUFFs
#define PUFF_EXPLORE_TIME 400 // amount of time to explore
#define PUFF_STATE_DEAD 0 // the PUFF is dead
#define PUFF_STATE_ALIVE 1 // the PUFF is alive
#define PUFF_STATE_INFLATING 2 // the PUFF is inflating (immobile)
#define PUFF_STATE_DYING 3 // dying in some manner
// anim states
#define PUFF_ANIM_STATE_BOUNCE 0 // the PUFF is bouncing like normal
#define PUFF_ANIM_STATE_CRUSHED 1 // the PUFF is being crushed by a rock
#define PUFF_ANIM_STATE_BURROW 2 // the PUFF is burrowing
#define PUFF_ANIM_STATE_INFLATING 3 // the PUFF is being inflated
// PUFF animations
#define PUFF_ANIM_BOUNCE_LEFT 0 // bouncing left animation index
#define PUFF_ANIM_BOUNCE_RIGHT 1 // bouncing right animation index
#define PUFF_ANIM_CRUSH_LEFT 2 // getting crushed facing left
#define PUFF_ANIM_CRUSH_RIGHT 3 // getting grushed facing right
#define PUFF_ANIM_BURROW 4 // burrowing animation
// ai states
#define PUFF_AI_STATE_FIRE 0 // the PUFF is stopped and preparing to fire
#define PUFF_AI_STATE_EXPLORE 1 // the PUFF is just exploring
#define PUFF_AI_STATE_CHASE 2 // the PUFF chasing the player
#define PUFF_AI_STATE_EVADE 3 // the PUFF is evading the player
#define PUFF_AI_STATE_BURROW 4 // the PUFF is burrowing
#define PUFF_AI_STATE_CRUSHED 5 // the puff is being crushed
#define PUFF_AI_STATE_INFLATING 6 // the puff is being inflated
#define PUFF_AI_STATE_POPPED 7 // the puff has finally popped
// variable indices
#define PUFF_INDEX_AI_STATE 0 // the mode of the ai
#define PUFF_INDEX_ANIM_STATE 1 // the state of the animation
#define PUFF_INDEX_ANIM_DIR 2 // the direction of animation left or right
#define PUFF_INDEX_CURR_DIR 3 // the actual nautical direction
#define PUFF_INDEX_LAST_DIR 4 // the last actual nautical direction
#define PUFF_INDEX_DESIRED_DIR 5 // the desired nautical direction
#define PUFF_INDEX_2ND_DESIRED_DIR 6 // the secondary desired nautical direction
#define PUFF_INDEX_PSI_COUNT 7 // used in inflation algorithm
#define PUFF_INDEX_EXPLORE_COUNTER 8 // used to track how long PUFF in explore mode
// tracking for bouncing
#define PUFF_INDEX_SUM_X 9 // number of x direction bounces
#define PUFF_INDEX_SUM_Y 10 // number of y direction bounces
#define PUFF_INDEX_BOUNCE_MAX 11 // general counter
#define PUFF_INDEX_OBJECT_PTR 12 // general reference ptr
// used to reset level
#define PUFF_INDEX_SAVED_X 13
#define PUFF_INDEX_SAVED_Y 14
#define PUFF_INDEX_SAVED_DIR 15
// motion defines for dug
#define DUG_SPEED 2
// defines for dug states
#define DUG_STATE_DEAD 0
#define DUG_STATE_DYING 1
#define DUG_STATE_INVINCIBLE 2
#define DUG_STATE_ALIVE 3
#define DUG_STATE_REBIRTH 4
#define DUG_STATE_CRUSHED 5
// defines for position
#define DUG_MIN_Y_WALK 32
#define DUG_X_INTERVAL 40
#define DUG_Y_INTERVAL 40
#define DUG_MIN_ROCK_LINE 64
// animation sequences
#define DUG_ANIM_WALK 0
#define DUG_ANIM_DIG 1
#define DUG_ANIM_FIRE 2
#define DUG_ANIM_WALK_LEFT 0
#define DUG_ANIM_DIG_LEFT 1
#define DUG_ANIM_FIRE_LEFT 2
#define DUG_ANIM_WALK_RIGHT 3
#define DUG_ANIM_DIG_RIGHT 4
#define DUG_ANIM_FIRE_RIGHT 5
#define DUG_ANIM_WALK_UP 6
#define DUG_ANIM_DIG_UP 7
#define DUG_ANIM_FIRE_UP 8
#define DUG_ANIM_WALK_DOWN 9
#define DUG_ANIM_DIG_DOWN 10
#define DUG_ANIM_FIRE_DOWN 11
#define DUG_ANIM_DEATH 12
#define DUG_ANIM_REBIRTH 13
#define DUG_ANIM_CRUSHED 14
// general directional defines
#define DIR_NULL -1
#define DIR_LEFT 0
#define DIR_RIGHT 1
#define DIR_UP 2
#define DIR_DOWN 3
// indexed state variables
#define DUG_INDEX_SCORE 0 // score of dig
#define DUG_INDEX_LIVES 1 // number of lives left
#define DUG_INDEX_LEVEL 2 // current level of play
#define DUG_INDEX_DAMAGE 3 // current damage level
#define DUG_INDEX_ANIM_MODE 4 // animation mode: walk, dig, fire
#define DUG_INDEX_PUMP_PSI 5 // the psi of dugs pump
#define DUG_INDEX_KILLS 6 // number of kills on this level
#define DUG_INDEX_DIR 8 // direction of dig
#define DUG_INDEX_OBJECT_PTR 12 // general reference ptr
// defines for dug pump
#define DUG_MIN_PSI 40
#define DUG_MAX_PSI 100
#define DUG_MAX_RADIATION 600 // that's about enough
#define DUG_CRITICAL_RADIATION 400 // getting a sun burn
// general game states
#define GAME_STATE_INIT 0
#define GAME_STATE_NEXT_LEVEL 1
#define GAME_STATE_RUNNING 2
#define GAME_STATE_PAUSED 3
#define GAME_STATE_OVER 4
#define GAME_STATE_WIN 5
#define GAME_STATE_EXIT 6
#define GAME_STATE_MENU 7
#define GAME_STATE_WAIT_FOR_TERMINATION 8
#define END_LEVEL_DELAY 100
// TYPES //////////////////////////////////////////////////
// this contains the data of a single level
typedef struct LEVEL_REC_TYP
{
char level_name[80]; // name if level
char image_file[80]; // file name of .BMP file containing image
char author[80]; // name of author
int bonus; // special bonus for level
int diff; // difficulty of level from 1 to 100
CHAR data[LEVEL_ROWS][LEVEL_COLUMNS]; // level data
} LEVEL_REC, *LEVEL_REC_PTR;
// GLOBALS ////////////////////////////////////////////////
HWND main_window_handle = NULL; // save the window handle
HINSTANCE main_instance = NULL; // save the instance
char buffer[80]; // used to print text
int high_score = 10000; // the current high score
int new_man_tracker = POINTS_NEW_MAN; // tracks if the player gets a new man
int radiation_message_played = 0; // has the radiation message been played
BITMAP_IMAGE background_bmp, // used to hold backgrounds
menu_bmp; // holds the menu
int game_state = GAME_STATE_INIT; // state of game
int end_level_counter = 0; // end level counter
BOB torch, // the burning torches
dug, // the digdumb bob
dug_demo, // demo clone
small_dug, // the miniture dug
puffy, // the bob holding all the inflated versions of the poos and puffs
poos[NUM_POOS], // the poo poos
poo_demo, // demo clone
puffs[NUM_PUFFS], // the puff dragons
puff_demo, // demo clone
mushroom, // the level counting mushrooms
prizes[NUM_PRIZES], // the level prizes
rocks[NUM_ROCKS], // the falling rocks
gpumps[NUM_GPUMPS], // the grappling pumps
fballs[NUM_FBALLS], // the fire balls
scores[NUM_SCORES]; // holds the score bitmaps
BITMAP_IMAGE dug_holes[NUM_HOLE_BITMAPS], // the holes dug digs
fblasts[NUM_FBLASTS], // holes fire balls make
font[FONT_NUM_CHARS], // holds the bitmap font
andre; // little picture of me
// sound id's
int intro_music_id = -1, // intro music
win_snd_id = -1, // win sound/music
credits_snd_id = -1, // the credits
over_snd_id = -1, // loose sound/music
level_snd_id = -1, // next level
main_music_ids[3] = {-1,-1,-1}, // main music tracks
fball_snd_ids[4] = {-1,-1,-1,-1}, // fire ball sounds
expl_snd_ids[4] = {-1,-1,-1,-1}, // explosion sounds
fall_snd_ids[4] = {-1,-1,-1,-1}, // falling rocks sounds
gpump_snd_ids[4] = {-1,-1,-1,-1}, // gpumps fire sound
air_snd_ids[4] = {-1,-1,-1,-1}, // air inflation
pop_snd_ids[4] = {-1,-1,-1,-1}, // creature poping
crunch_snd_ids[4] = {-1,-1,-1,-1}, // crunching sounds
crumble_snd_ids[4] = {-1,-1,-1,-1}, // crumble sounds
dyclops_talk_snd_ids[4] = {-1,-1,-1,-1}, // dyclops talking
puff_talk_snd_ids[4] = {-1,-1,-1,-1}, // growling
dug_walk_snd_id = -1, // dug walking sound
dug_push_snd_id = -1, // dug pushing the rock
dug_die_snd_id = -1, // dug dying sound
dug_trans_snd_id = -1, // dug transport sound
dug_life_snd_id = -1, // dug gets a new life
fire_snd_id = -1, // ambient fire sound
radiation_snd_id = -1, // radiation level critical
game_over_snd_id = -1, // sound for game over
prize_out_snd_id = -1, // sound when prize comes out
prize_win_snd_id = -1; // sound when dug gets prize
// animations for dug motion
int dug_anims[15][12]={
{0,1,0,2,-1,-1,-1,-1,-1,-1,-1,-1}, // left
{3,4,3,5,-1,-1,-1,-1,-1,-1,-1,-1},
{6,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
{0+8,1+8,0+8,2+8,-1,-1,-1,-1,-1,-1,-1,-1}, // right
{3+8,4+8,3+8,5+8,-1,-1,-1,-1,-1,-1,-1,-1},
{6+8,7+8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
{0+16,1+16,0+16,2+16,-1,-1,-1,-1,-1,-1,-1,-1}, // up
{3+16,4+16,3+16,5+16,-1,-1,-1,-1,-1,-1,-1,-1},
{6+16,7+16,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
{0+24,1+24,0+24,2+24,-1,-1,-1,-1,-1,-1,-1,-1}, // down
{3+24,4+24,3+24,5+24,-1,-1,-1,-1,-1,-1,-1,-1},
{6+24,7+24,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
{32,33,34,35,36,37,38,39,40,40,-1,-1}, // death
{39,38,37,36,35,34,33,32,-1,-1,-1,-1}, // rebirth
{41,42,43,-1,-1,-1,-1,-1,-1,-1,-1,-1,} }; // crush sequence
// animations for dug grappling pump weapon
int gpump_anims[4][4] = {{0,1,2,1}, {3,4,5,4}, {6,7,8,7}, {9,10,11,10}};
// animations for fireballs
int fball_anims[4][5] = {{0,1,2,3,4}, {5,6,7,-1,-1}, {8,9,10,11,12}, {13,14,15,-1,-1}};
// animations for poos: bounce, crush, burrow
int poo_anims[5][4] = { {0,1,-1,-1}, {2,3,-1,-1}, {4,5,-1,-1}, {6,7,-1,-1}, {8,9,10,9} };
// animations for puffs
int puff_anims[5][4] = { {0,1,0,2}, {3,4,3,5}, {6,7,-1,-1}, {8,9,-1,-1}, {10,11,12,11} };
// level stuff
LEVEL_REC game_levels[MAX_LEVELS]; // holds all level data
int num_levels = 0, // number of levels currently loaded
curr_level = 0, // level being played
level_name_counter = 0, // global counter used to display level name
num_creatures_on_level = 0; // number of creatures on this level
//MONOPRINT mono; // debugger
int draw_on = 1; // info display flag
// PROTOTYPES //////////////////////////////////////////////
// game console
int Game_Init(void *parms=NULL);
int Game_Shutdown(void *parms=NULL);
int Game_Main(void *parms=NULL);
int Game_Reset(void);
int Init_Prize(int prize_index, int count);
int Start_Level(int level);
int Start_Score(int x, int y, int score);
int Start_Rock(int x, int y);
int Start_Poo(int x, int y, int dir);
int Start_Puff(int x, int y, int dir);
int Start_Fball(int x, int y, int dir, int fball_type);
int Start_Gpump(int x, int y, int dir);
void Start_Dug_Death(void);
int Process_Poos(void);
int Process_Puffs(void);
int Draw_Poos(void);
int Draw_Puffs(void);
int Fast_Distance(int x, int y);
int Copy_Screen(UCHAR *source_bitmap,UCHAR *dest_buffer, int lpitch, int transparent);
int Draw_String(BITMAP_IMAGE_PTR font_ptr,char *string,int x, int y, UCHAR *buffer, int lpitch,int trans);
int Draw_Bitmap2(BITMAP_IMAGE_PTR source_bitmap,UCHAR *dest_buffer, int lpitch, int transparent);
int Play_Sound_From_Pool(int *ids, int num_ids);
int Pause_Sound(int id);
int Resume_Sound(int id);
// FUNCTIONS //////////////////////////////////////////////
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
// this is the main message handler of the system
PAINTSTRUCT ps; // used in WM_PAINT
HDC hdc; // handle to a device context
// what is the message
switch(msg)
{
case WM_CREATE:
{
// do initialization stuff here
return(0);
} break;
case WM_PAINT:
{
// start painting
hdc = BeginPaint(hwnd,&ps);
// end painting
EndPaint(hwnd,&ps);
return(0);
} break;
case WM_KILLFOCUS:
{
return(0);
} break;
case WM_DESTROY:
{
// kill the application
PostQuitMessage(0);
CloseWindow(hwnd);
return(0);
} break;
default:break;
} // end switch
// process any messages that we didn't take care of
return (DefWindowProc(hwnd, msg, wparam, lparam));
} // end WinProc
// WINMAIN ////////////////////////////////////////////////
int WINAPI WinMain( HINSTANCE hinstance,
HINSTANCE hprevinstance,
LPSTR lpcmdline,
int ncmdshow)
{
// this is the winmain function
WNDCLASS winclass; // this will hold the class we create
HWND hwnd; // generic window handle
MSG msg; // generic message
HDC hdc; // generic dc
PAINTSTRUCT ps; // generic paintstruct
// first fill in the window class stucture
winclass.style = CS_DBLCLKS | CS_OWNDC |
CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
// register the window class
if (!RegisterClass(&winclass))
return(0);
// create the window, note the use of WS_POPUP
if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
"WinX Game Console", // title
WS_POPUP | WS_VISIBLE,
0,0, // x,y
WINDOW_WIDTH, // width
WINDOW_HEIGHT, // height
NULL, // handle to parent
NULL, // handle to menu
hinstance,// instance
NULL))) // creation parms
return(0);
// save the window handle and instance in a global
main_window_handle = hwnd;
main_instance = hinstance;
// perform all game console specific initialization
Game_Init();
Game_Reset();
// enter main event loop
while(1)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
// test if this is a quit
if (msg.message == WM_QUIT)
break;
// translate any accelerator keys
TranslateMessage(&msg);
// send the message to the window proc
DispatchMessage(&msg);
} // end if
// main game processing goes here
Game_Main();
} // end while
// shutdown game and release all resources
Game_Shutdown();
#if 1
char *wimps[]={"Not Bad For A Human.",
"See You Later Carbon Unit",
"Had Enough Huh?",
"Send In Some Real Competition!",
"Maybe Next Time You'll Win!",
"I Am Invincible!",
"I Eat Players Like You For Lunch!"};
// one last message
MessageBox(NULL,
wimps[rand()%7],
"UnderWorld Message...",
MB_ICONEXCLAMATION);
#endif
// return to Windows like this
return(msg.wParam);
} // end WinMain
// GAME FUNCTIONS /////////////////////////////////////////////
int Load_WAV2(char *filename)
{
// this function loads a .wav file, sets up the directsound
// buffer and loads the data into memory, the function returns
// the id number of the sound, this version was needed since
HMMIO hwav; // handle to wave file
MMCKINFO parent, // parent chunk
child; // child chunk
WAVEFORMATEX wfmtx; // wave format structure
int sound_id = -1, // id of sound to be loaded
index; // looping variable
UCHAR *snd_buffer, // temporary sound buffer to hold voc data
*audio_ptr_1=NULL, // data ptr to first write buffer
*audio_ptr_2=NULL; // data ptr to second write buffer
DWORD audio_length_1=0, // length of first write buffer
audio_length_2=0; // length of second write buffer
// step one: are there any open id's ?
for (index=0; index < MAX_SOUNDS; index++)
{
// make sure this sound is unused
if (sound_fx[index].state==SOUND_NULL)
{
sound_id = index;
break;
} // end if
} // end for index
// did we get a free id?
if (sound_id==-1)
return(-1);
// set up chunk info structure
parent.ckid = (FOURCC)0;
parent.cksize = 0;
parent.fccType = (FOURCC)0;
parent.dwDataOffset = 0;
parent.dwFlags = 0;
// copy data
child = parent;
// open the WAV file
if ((hwav = mmioOpen(filename, NULL, MMIO_READ | MMIO_ALLOCBUF))==NULL)
return(-1);
// descend into the RIFF
parent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
if (mmioDescend(hwav, &parent, NULL, MMIO_FINDRIFF))
{
// close the file
mmioClose(hwav, 0);
// return error, no wave section
return(-1);
} // end if
// descend to the WAVEfmt
child.ckid = mmioFOURCC('f', 'm', 't', ' ');
if (mmioDescend(hwav, &child, &parent, 0))
{
// close the file
mmioClose(hwav, 0);
// return error, no format section
return(-1);
} // end if
// now read the wave format information from file
if (mmioRead(hwav, (char *)&wfmtx, sizeof(wfmtx)) != sizeof(wfmtx))
{
// close file
mmioClose(hwav, 0);
// return error, no wave format data
return(-1);
} // end if
// make sure that the data format is PCM
if (wfmtx.wFormatTag != WAVE_FORMAT_PCM)
{
// close the file
mmioClose(hwav, 0);
// return error, not the right data format
return(-1);
} // end if
// now ascend up one level, so we can access data chunk
if (mmioAscend(hwav, &child, 0))
{
// close file
mmioClose(hwav, 0);
// return error, couldn't ascend
return(-1);
} // end if
// descend to the data chunk
child.ckid = mmioFOURCC('d', 'a', 't', 'a');
if (mmioDescend(hwav, &child, &parent, MMIO_FINDCHUNK))
{
// close file
mmioClose(hwav, 0);
// return error, no data
return(-1);
} // end if
// finally!!!! now all we have to do is read the data in and
// set up the directsound buffer
// allocate the memory to load sound data
snd_buffer = (UCHAR *)malloc(child.cksize);
// read the wave data
mmioRead(hwav, (char *)snd_buffer, child.cksize);
// close the file
mmioClose(hwav, 0);
// set rate and size in data structure
sound_fx[sound_id].rate = wfmtx.nSamplesPerSec;
sound_fx[sound_id].size = child.cksize;
sound_fx[sound_id].state = SOUND_LOADED;
// set up the format data structure
memset(&pcmwf, 0, sizeof(WAVEFORMATEX));
pcmwf.wFormatTag = WAVE_FORMAT_PCM; // pulse code modulation
pcmwf.nChannels = 1; // mono
pcmwf.nSamplesPerSec = 11025; // always this rate
pcmwf.nBlockAlign = 1;
pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign;
pcmwf.wBitsPerSample = 8;
pcmwf.cbSize = 0;
// prepare to create sounds buffer
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE;
dsbd.dwBufferBytes = child.cksize;
dsbd.lpwfxFormat = &pcmwf;
// create the sound buffer
if (lpds->CreateSoundBuffer(&dsbd,&sound_fx[sound_id].dsbuffer,NULL)!=DS_OK)
{
// release memory
free(snd_buffer);
// return error
return(-1);
} // end if
// copy data into sound buffer
if (sound_fx[sound_id].dsbuffer->Lock(0,
child.cksize,
(void **) &audio_ptr_1,
&audio_length_1,
(void **)&audio_ptr_2,
&audio_length_2,
DSBLOCK_FROMWRITECURSOR)!=DS_OK)
return(0);
// copy first section of circular buffer
memcpy(audio_ptr_1, snd_buffer, audio_length_1);
// copy last section of circular buffer
memcpy(audio_ptr_2, (snd_buffer+audio_length_1),audio_length_2);
// unlock the buffer
if (sound_fx[sound_id].dsbuffer->Unlock(audio_ptr_1,
audio_length_1,
audio_ptr_2,
audio_length_2)!=DS_OK)
return(0);
// release the temp buffer
free(snd_buffer);
// return id
return(sound_id);
} // end Load_WAV2
/////////////////////////////////////////////////////////////////////////////
int Pause_Sound(int id)
{
// this function pauses
if (sound_fx[id].dsbuffer)
{
sound_fx[id].dsbuffer->Stop();
} // end if
// return success
return(1);
} // end Pause_Sound
///////////////////////////////////////////////////////////
int Resume_Sound(int id, int flags=0)
{
// this function plays a sound, the only parameter that
// works is the flags which can be 0 to play once or
// DSBPLAY_LOOPING
if (sound_fx[id].dsbuffer)
{
// continue playing
if (sound_fx[id].dsbuffer->Play(0,0,flags)!=DS_OK)
return(0);
} // end if
// return success
return(1);
} // end Resume_Sound
//////////////////////////////////////////////////////////
int Load_Sound_Music(void)
{
// this function loads all the sounds and music
int index; // looping variable
// load in intro music
if ((intro_music_id = Load_WAV("UNDSOUND/UNDINTRO.WAV",0))==-1)
return(0);
// load in credits music
if ((credits_snd_id = Load_WAV("UNDSOUND/UNDCRED.WAV",0))==-1)
return(0);
// win sound/music
if ((win_snd_id = Load_WAV("UNDSOUND/UNDWIN.WAV",0))==-1)
return(0);
// load the end sound/music
//if ((over_snd_id = Load_WAV("NULL.WAV"))==-1)
// return(0);
// load the next level sound/music
if ((level_snd_id = Load_WAV("UNDSOUND/UNDNLEV2.WAV",0))==-1)
return(0);
// load music
//if ((main_music_ids[0] = Load_WAV("NULL.WAV"))==-1)
// return(0);
// load music
//if ((main_music_ids[1] = Load_WAV("NULL.WAV"))==-1)
// return(0);
// load music
//if ((main_music_ids[2] = Load_WAV("NULL.WAV"))==-1)
// return(0);
// fire ball sounds
if ((fball_snd_ids[0] = Load_WAV("UNDSOUND/UNDFBAL1.WAV",0))==-1)
return(0);
if ((fball_snd_ids[1] = Load_WAV("UNDSOUND/UNDFBAL0.WAV",0))==-1)
return(0);
// now make copies
for (index=2; index < 4; index++)
{
// replicate sound
fball_snd_ids[index] = Replicate_Sound(fball_snd_ids[index%2]);
} // end for index
// explosion sounds
if ((expl_snd_ids[0] = Load_WAV("UNDSOUND/UNDEXPL.WAV",0))==-1)
return(0);
// now make copies
for (index=1; index < 4; index++)
{
// replicate sound
expl_snd_ids[index] = Replicate_Sound(expl_snd_ids[0]);
} // end for index
// crumbling rock sounds
if ((crumble_snd_ids[0] = Load_WAV("UNDSOUND/UNDRHIT.WAV",0))==-1)
return(0);
// now make copies
for (index=1; index < 4; index++)
{
// replicate sound
crumble_snd_ids[index] = Replicate_Sound(crumble_snd_ids[0]);
} // end for index
// gpumps fire sound
if ((gpump_snd_ids[0] = Load_WAV("UNDSOUND/UNDGPUMP.WAV",0))==-1)
return(0);
// now make copies
for (index=1; index < 4; index++)
{
// replicate sound
gpump_snd_ids[index] = Replicate_Sound(gpump_snd_ids[0]);
} // end for index
// air sound
if ((air_snd_ids[0] = Load_WAV("UNDSOUND/UNDAIR.WAV",0))==-1)
return(0);
// now make copies
for (index=1; index < 4; index++)
{
// replicate sound
air_snd_ids[index] = Replicate_Sound(air_snd_ids[0]);
} // end for index
// pop sound
if ((pop_snd_ids[0] = Load_WAV("UNDSOUND/UNDBLOW2.WAV",0))==-1)
return(0);
// now make copies
for (index=1; index < 4; index++)
{
// replicate sound
pop_snd_ids[index] = Replicate_Sound(pop_snd_ids[0]);
} // end for index
// crunching sounds
if ((crunch_snd_ids[0] = Load_WAV("UNDSOUND/UNDCRUNC.WAV",0))==-1)
return(0);
// now make copies
for (index=1; index < 4; index++)
{
// replicate sound
crunch_snd_ids[index] = Replicate_Sound(crunch_snd_ids[0]);
} // end for index
// rock shake and falling sound
if ((fall_snd_ids[0] = Load_WAV("UNDSOUND/UNDSHAK2.WAV",0))==-1)
return(0);
// now make copies
for (index=1; index < 4; index++)
{
// replicate sound
fall_snd_ids[index] = Replicate_Sound(fall_snd_ids[0]);
} // end for index
// dyclops talking
for (index=0; index<4; index++)
{
sprintf(buffer,"UNDSOUND/UNDDYTK%d.WAV",index);
if ((dyclops_talk_snd_ids[index] = Load_WAV(buffer,0))==-1)
return(0);
} // end for index
// puff dragons growling
for (index=0; index<4; index++)
{
sprintf(buffer,"UNDSOUND/UNDPFTK%d.WAV",index);
if ((puff_talk_snd_ids[index] = Load_WAV(buffer,0))==-1)
return(0);
} // end for index
// dug walking sound
//if ((dug_walk_snd_id = Load_WAV("NULL.WAV"))==-1)
// return(0);
if ((dug_push_snd_id = Load_WAV("UNDSOUND/UNDPUSH1.WAV",0))==-1)
return(0);
// dug dying sound
if ((dug_die_snd_id = Load_WAV("UNDSOUND/UNDDIE.WAV",0))==-1)
return(0);
// dug transport sound
if ((dug_trans_snd_id = Load_WAV("UNDSOUND/UNDTRANS.WAV",0))==-1)
return(0);
// dug game over sound
if ((game_over_snd_id = Load_WAV("UNDSOUND/UNDOVER.WAV",0))==-1)
return(0);
// dug new life
if ((dug_life_snd_id = Load_WAV("UNDSOUND/UNDLIFE.WAV",0))==-1)
return(0);
// prize out sound
if ((prize_out_snd_id = Load_WAV("UNDSOUND/UNDPRIZ0.WAV",0))==-1)
return(0);
// prize win sound
if ((prize_win_snd_id = Load_WAV("UNDSOUND/UNDPRIZ1.WAV",0))==-1)
return(0);
// radiation level critical
if ((radiation_snd_id = Load_WAV("UNDSOUND/UNDRAD.WAV",0))==-1)
return(0);
// the ambient fire
//if ((fire_snd_id = Load_WAV("NULL.WAV"))==-1)
// return(0);
// return sucess
return(1);
} // end Load_Sound_Music
///////////////////////////////////////////////////////////////
int Play_Sound_From_Pool(int *ids, int num_ids)
{
// this function starts a sound given the array of sounds and number of available replicants
// start sound up
for (int sound_index=0; sound_index < num_ids; sound_index++)
{
// test if this sound is playing
if (Status_Sound(ids[sound_index])==0)
{
Play_Sound(ids[sound_index]);
return(1);
} // end if
} // end for sound_index
// error
return(-1);
} // end Play_Sound_From_Pool
///////////////////////////////////////////////////////////////
int Draw_String(BITMAP_IMAGE_PTR font_ptr,
char *string,
int x, int y,
UCHAR *buffer,
int lpitch,
int trans)
{
// this function draws a string on the screen using the loaded bitmap font
// get length to print
int length = strlen(string);
// print the string
for (int index=0; index<length; index++)
{
// get index of character
int cindex = string[index] - ' ';
// set x,y
font_ptr[cindex].x = x;
font_ptr[cindex].y = y;
// draw the bitmap
Draw_Bitmap2(&font_ptr[cindex],buffer,lpitch,trans);
// move over to next character position
if (string[index] >= ' ' && string[index] <= '9')
x+=(FONT_WIDTH_NEXT_NUM);
else
if (string[index] >= ':' && string[index] <= 'Z')
x+=(FONT_WIDTH_NEXT_UPPER);
else
if (string[index] > 'Z' && string[index] <= '~')
x+=FONT_WIDTH_NEXT_LOWER;
} // end if
// return success
return(1);
} // end Draw_String
////////////////////////////////////////////////////////////////
int Copy_Screen(UCHAR *source_bitmap,UCHAR *dest_buffer, int lpitch, int transparent)
{
// this function draws the bitmap onto the destination memory surface
// if transparent is 1 then color 0 will be transparent
// note this function does NOT clip, so be carefull!!!
UCHAR *dest_addr, // starting address of bitmap in destination
*source_addr; // starting adddress of bitmap data in source
UCHAR pixel; // used to hold pixel value
int index, // looping vars
pixel_x;
// test if this bitmap is loaded
// compute starting destination address
dest_addr = dest_buffer;
// compute the starting source address
source_addr = source_bitmap;
// is this bitmap transparent
if (transparent)
{
// copy each line of bitmap into destination with transparency
for (index=0; index < SCREEN_HEIGHT; index++)
{
// copy the memory
for (pixel_x=0; pixel_x < SCREEN_WIDTH; pixel_x++)
{
if ((pixel = source_addr[pixel_x])!=0)
dest_addr[pixel_x] = pixel;
} // end if
// advance all the pointers
dest_addr += lpitch;
source_addr += SCREEN_WIDTH;
} // end for index
} // end if
else
{
// non-transparent version
// copy each line of bitmap into destination
for (index=0; index < SCREEN_HEIGHT; index++)
{
// copy the memory
memcpy(dest_addr, source_addr, SCREEN_WIDTH);
// advance all the pointers
dest_addr += lpitch;
source_addr += SCREEN_WIDTH;
} // end for index
} // end else
// return success
return(1);
} // end Copy_Screen
/////////////////////////////////////////////////////////////////////////
int Fast_Distance(int x, int y)
{
// this function computes the distance from 0,0 to x,y with 3.5% error
// first compute the absolute value of x,y
x = abs(x);
y = abs(y);
// compute the minimum of x,y
int mn = min(x,y);
// return the distance
return(x+y-(mn>>1)-(mn>>2)+(mn>>4));
} // end Fast_Distance
///////////////////////////////////////////////////////////////
int Animate_BOB2(BOB_PTR bob)
{
// this function animates a bob, basically it takes a look at
// the attributes of the bob and determines if the bob is
// a single frame, multiframe, or multi animation, updates
// the counters and frames appropriately
// is this a valid bob
if (!bob)
return(0);
// test the level of animation
if (bob->attr & BOB_ATTR_SINGLE_FRAME)
{
// current frame always = 0
bob->curr_frame = 0;
return(1);
} // end if
else
if (bob->attr & BOB_ATTR_MULTI_FRAME)
{
// update the counter and test if its time to increment frame
if (++bob->anim_counter >= bob->anim_count_max)
{
// reset counter
bob->anim_counter = 0;
// move to next frame
if (++bob->curr_frame >= bob->num_frames)
{
// reset frame
bob->curr_frame = 0;
// set animation state message to done
bob->anim_state = BOB_STATE_ANIM_DONE;
} // end if
} // end if
} // end elseif
else
if (bob->attr & BOB_ATTR_MULTI_ANIM)
{
// this is the most complex of the animations it must look up the
// next frame in the animation sequence
// first test if its time to animate
if (++bob->anim_counter >= bob->anim_count_max)
{
// reset counter
bob->anim_counter = 0;
// increment the animation frame index
bob->anim_index++;
// extract the next frame from animation list
bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
// is this and end sequence flag -1
if (bob->curr_frame == -1)
{
// test if this is a single shot animation
if (bob->attr & BOB_ATTR_ANIM_ONE_SHOT)
{
// set animation state message to done
bob->anim_state = BOB_STATE_ANIM_DONE;
// reset frame back one
bob->anim_index--;
// extract animation frame
bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
} // end if
else
{
// reset animation index
bob->anim_index = 0;
// extract first animation frame
bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
// set animation state message to done
bob->anim_state = BOB_STATE_ANIM_DONE;
} // end else
} // end if
} // end if
} // end elseif
// return success
return(1);
} // end Animate_BOB2
///////////////////////////////////////////////////////////
int Set_Animation_BOB2(BOB_PTR bob, int anim_index)
{
// this function sets the animation to play
// is this a valid bob
if (!bob)
return(0);
// set the animation index
bob->curr_animation = anim_index;
// reset animation
bob->anim_index = 0;
bob->anim_counter = 0;
bob->anim_state = 0;
bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
// return success
return(1);
} // end Set_Animation_BOB2
//////////////////////////////////////////////////////////////////
UCHAR Get_Pixel(int x, int y,UCHAR *video_buffer, int lpitch)
{
// this function gets the pixel value at x,y
return(video_buffer[x + y*lpitch]);
} // end Get_Pixel
///////////////////////////////////////////////////////////////
void Dig_Hole(void)
{
// this function digs the hole infront of dug
// test if dug can dig
if ((dug.y < 64 && dug.varsI[DUG_INDEX_DIR]==DIR_UP) ||
(dug.y < 42 && dug.varsI[DUG_INDEX_DIR]==DIR_DOWN) ||
(dug.y == 32) )
return;
int hole_noise = ((rand()%2) << 2);
dug_holes[dug.varsI[DUG_INDEX_DIR]+hole_noise].x = dug.x;
dug_holes[dug.varsI[DUG_INDEX_DIR]+hole_noise].y = dug.y;
Draw_Bitmap(&dug_holes[dug.varsI[DUG_INDEX_DIR]+hole_noise],background_bmp.buffer,background_bmp.width,1);
} // end Dig_Hole
///////////////////////////////////////////////////////////////
void Dug_Dig_Test(int x, int y)
{
// this function tests if dug needs to dig and sets the animation sequence appropriately
static int score_counter = 0; // used to track when to add to score
// first test if dug is up top, if so override
if ( (dug.y == 32) && (dug.varsI[DUG_INDEX_ANIM_MODE]!=DUG_ANIM_WALK))
{
// set to walk mode -- no digging!!!
dug.varsI[DUG_INDEX_ANIM_MODE] = DUG_ANIM_WALK;
Set_Animation_BOB2(&dug, dug.varsI[DUG_INDEX_ANIM_MODE] + dug.varsI[DUG_INDEX_DIR]*3);
return;
} // end if
else
if (dug.y == 32)
return;
// first test if there is any rock ahead
if (Get_Pixel(x,y,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE)
{
// turn digging on if it's off
if (dug.varsI[DUG_INDEX_ANIM_MODE]!=DUG_ANIM_DIG)
{
dug.varsI[DUG_INDEX_ANIM_MODE] = DUG_ANIM_DIG;
Set_Animation_BOB2(&dug, dug.varsI[DUG_INDEX_ANIM_MODE] + dug.varsI[DUG_INDEX_DIR]*3);
} // end if
if (++score_counter > 5)
{
// add some to the score
dug.varsI[DUG_INDEX_SCORE]+=10;
// reset counter
score_counter = 0;
} // end if
} // end if
else
if (dug.varsI[DUG_INDEX_ANIM_MODE]!=DUG_ANIM_WALK)
{
dug.varsI[DUG_INDEX_ANIM_MODE] = DUG_ANIM_WALK;
Set_Animation_BOB2(&dug, dug.varsI[DUG_INDEX_ANIM_MODE] + dug.varsI[DUG_INDEX_DIR]*3);
} // end if
} // end Dug_Dig_Test
///////////////////////////////////////////////////////////////
void Draw_Info(void)
{
// this function draws all the information about the game including bitmaps of the player
// and level
static int blink_counter = 0, // state of all blinkin objects
blink_state = 1,
glow_color = 128;
int index; // looping var
char blank_number[8]; // used to generate 7 digit numbers
// draw the name of the level
if (level_name_counter > 0)
{
// draw the level name
Draw_Text_GDI(game_levels[curr_level].level_name,
(SCREEN_WIDTH/2) - 4*strlen(game_levels[curr_level].level_name),
SCORE_Y+16,
RGB(0,(glow_color%256),0),lpddsback);
glow_color+=16;
// dec counter
level_name_counter--;
//sprintf(buffer,"LeveL=%d Name='%s'",curr_level,game_levels[curr_level].level_name);
//mono.set_cursor(0,6);
//mono.print(buffer);
} // end if
else
{
// update blinker
if (++blink_counter > 15)
{
// reset counter
blink_counter = 0;
// toggle state of blink
blink_state=-blink_state;
} // end if
// lock back buffer
DD_Lock_Back_Surface();
if (keyboard_state[DIK_RCONTROL] && keyboard_state[DIK_RALT] && keyboard_state[DIK_A])
{
Draw_String(font,"Created by Andre' LaMothe 1998",320-180,240,back_buffer, back_lpitch,0);
Draw_Bitmap(&andre,back_buffer, back_lpitch,0);
} // end if
// first the current score
if (blink_state==1)
Draw_String(font,"1UP",SCORE_X-16,SCORE_Y,back_buffer, back_lpitch,0);
//Draw_Text_GDI("1UP", SCORE_X, SCORE_Y, SCORE_COLOR_BOLD, lpddsback);
// sprintf(buffer, "%d",dug.varsI[DUG_INDEX_SCORE]);
itoa(dug.varsI[DUG_INDEX_SCORE],buffer,10);
strcpy(blank_number,"0000000");
memcpy(blank_number+7-strlen(buffer),buffer,strlen(buffer));
Draw_String(font,blank_number,SCORE_X+36,SCORE_Y,back_buffer, back_lpitch,0);
// draw rads
itoa(dug.varsI[DUG_INDEX_DAMAGE],buffer,10);
Draw_String(font,buffer,SCORE_X+36,SCORE_Y+16,back_buffer, back_lpitch,0);
// Draw_Text_GDI(blank_number, SCORE_X+36, SCORE_Y,SCORE_COLOR_TEXT, lpddsback);
// draw the psi display
//Draw_String(font,"PSI",SCORE_X+136,SCORE_Y,back_buffer, back_lpitch,0);
//Draw_Text_GDI("PSI", SCORE_X+128, SCORE_Y, SCORE_COLOR_BOLD, lpddsback);
// sprintf(buffer, "%d",dug.varsI[DUG_INDEX_SCORE]);
itoa(dug.varsI[DUG_INDEX_PUMP_PSI],buffer,10);
Draw_String(font,buffer,SCORE_X+180,SCORE_Y,back_buffer, back_lpitch,0);
//Draw_Text_GDI(buffer, SCORE_X+156, SCORE_Y,SCORE_COLOR_TEXT, lpddsback);
// now the high score
//Draw_String(font,"HIGH SCORE",SCORE_X+240,SCORE_Y,back_buffer, back_lpitch,0);
//Draw_Text_GDI("HIGH SCORE", SCORE_X+240, SCORE_Y, SCORE_COLOR_BOLD, lpddsback);
// sprintf(buffer, "%d",high_score);
itoa(high_score,buffer,10);
strcpy(blank_number,"0000000");
memcpy(blank_number+7-strlen(buffer),buffer,strlen(buffer));
Draw_String(font,blank_number,SCORE_X+368,SCORE_Y,back_buffer, back_lpitch,0);
//Draw_Text_GDI(blank_number, SCORE_X+332, SCORE_Y, SCORE_COLOR_TEXT, lpddsback);
// now the level
//Draw_String(font,"LEVEL",SCORE_X+500,SCORE_Y,back_buffer, back_lpitch,0);
//Draw_Text_GDI("LEVEL", SCORE_X+500, SCORE_Y, SCORE_COLOR_BOLD, lpddsback);
// sprintf(buffer, "%d",dug.varsI[DUG_INDEX_LEVEL]);
itoa(dug.varsI[DUG_INDEX_LEVEL]+1,buffer,10);
Draw_String(font,buffer,SCORE_X+564,SCORE_Y,back_buffer, back_lpitch,0);
//Draw_Text_GDI(buffer, SCORE_X+548, SCORE_Y, SCORE_COLOR_TEXT, lpddsback);
} // end text info
// unlock back buffer
DD_Unlock_Back_Surface();
// bitmap of the level with mushrooms
int mush_tens = (dug.varsI[DUG_INDEX_LEVEL]+1) / 10;
int mush_ones = (dug.varsI[DUG_INDEX_LEVEL]+1) % 10;
// start off in starting position
int mush_x = MUSH_START_X;
int mush_y = MUSH_START_Y;
// draw the tens mushrooms
for (index=0; index < mush_tens; index++, mush_x-=32)
{
// set the position of the sprite
mushroom.x = mush_x;
mushroom.y = mush_y;
// set frame to tens
mushroom.curr_frame = 1;
// draw the mushroom
Draw_BOB(&mushroom, lpddsback);
} // end for index
// draw the ones mushrooms
for (index=0; index < mush_ones; index++, mush_x-=32)
{
// set the position of the sprite
mushroom.x = mush_x;
mushroom.y = mush_y;
// set frame to tens
mushroom.curr_frame = 0;
// draw the mushroom
Draw_BOB(&mushroom, lpddsback);
} // end for index
// bitmaps of number of players left
small_dug.x = DUG_LIVES_X;
small_dug.y = DUG_LIVES_Y;
for (index=0; index < dug.varsI[DUG_INDEX_LIVES]; index++, small_dug.x+=16)
{
// draw another little man
Draw_BOB(&small_dug, lpddsback);
} // end for index
} // end Draw_Info
///////////////////////////////////////////////////////////////
int Draw_Bitmap2(BITMAP_IMAGE_PTR source_bitmap,UCHAR *dest_buffer, int lpitch, int transparent)
{
// this function draws the bitmap onto the destination memory surface
// if transparent is 1 then color 0 will be transparent
// note this function does NOT clip, so be carefull!!!
UCHAR *dest_addr, // starting address of bitmap in destination
*source_addr; // starting adddress of bitmap data in source
UCHAR pixel; // used to hold pixel value
int index, // looping vars
pixel_x;
// test if this bitmap is loaded
if (source_bitmap->attr & BITMAP_ATTR_LOADED)
{
// compute starting destination address
dest_addr = dest_buffer + (int)source_bitmap->y*lpitch + (int)source_bitmap->x;
// compute the starting source address
source_addr = source_bitmap->buffer;
// is this bitmap transparent
if (transparent)
{
// copy each line of bitmap into destination with transparency
for (index=0; index<source_bitmap->height; index++)
{
// copy the memory
for (pixel_x=0; pixel_x<source_bitmap->width; pixel_x++)
{
if ((pixel = source_addr[pixel_x])!=0)
dest_addr[pixel_x] = pixel;
} // end if
// advance all the pointers
dest_addr += lpitch;
source_addr += source_bitmap->width;
} // end for index
} // end if
else
{
// non-transparent version
// copy each line of bitmap into destination
int lwidth = source_bitmap->width;
int lheight = source_bitmap->height;
_asm
{
mov edx, lheight // counter = height
copy_loop:
mov edi, dest_addr // set destination address
mov esi, source_addr // set source address
mov ecx, lwidth // set number of bytes
shr ecx, 2 // compute number of quads
rep movsd // perform movement
mov eax, lpitch // dest+=lpitch
add dest_addr, eax
mov ebx, lwidth // source+=lwidth
add source_addr, ebx
dec edx // if edx > 0 loop
jne copy_loop
} // end asm
} // end else
// return success
return(1);
} // end if
else
return(0);
} // end Draw_Bitmap2
////////////////////////////////////////////////////////////////////
int Get_Line(char *string, FILE *fp)
{
// this is a little helper function that reads until it finds a line
// find data line, skip blank lines
while(1)
{
// get the current line
if (!fgets(string, 80, fp))
return(0);
// we have a string, now test if it's good
for (int scan=0; scan < strlen(string); scan++)
{
if (string[scan]=='<' || string[scan]=='.')
{
// found a good string, so return success
return(1);
} // end if
else
if (string[scan]=='#')
break;
} // end if
} // end while
// return error
return(0);
} // end Get_Line
/////////////////////////////////////////////////////////////////////
int Parse_Value(char *source, char *value)
{
// this function scans for the value between the " symbol
int start = 0, // start of value
end = 0; // end of value
// find first quote
while((source[start]!='"') && (start < strlen(source)))
start++;
// test for error
if (start >= strlen(source))
return(0);
// set scanner right after
end = ++start;
// find second quote
while((source[end]!='"') && (end < strlen(source)))
end++;
// test for error
if (end >= strlen(source))
return(0);
// now value is trapped from start to end inclusive
memcpy(value, &source[start], end-start);
// null terminate
value[end-start] = 0;
// return success
return(1);
} // end Parse_Value
/////////////////////////////////////////////////////////////////////
int Load_Levels(char *level_filename)
{
// this function loads the level file data into the level array
FILE *fp_level; // used to open level file
char string[80], // data string
value[80]; // value string
// open file
if ((fp_level = fopen(level_filename,"r"))==NULL)
{
// return error
return(0);
} // end if
// load in the number of levels
if (!Get_Line(string, fp_level)) return(0);
if (!Parse_Value(string,value)) return(0);
// set number of levels
num_levels = atoi(value);
Write_Error("\nNumber of levels = %d",num_levels);
#if 0
// this contains the data of a single level
typedef struct LEVEL_REC_TYP
{
char level_name[80]; // name if level
char image_file[80]; // file name of .BMP file containing image
char author[80]; // name of author
int bonus; // special bonus for level
int diff; // difficulty of level from 1 to 100
CHAR data[LEVEL_ROWS][LEVEL_COLUMNS]; // level data
} LEVEL_REC, *LEVEL_REC_PTR;
#endif
// now load all thel levels in
for (int curr_level = 0; curr_level < num_levels; curr_level++)
{
// first load the level name
if (!Get_Line(string, fp_level)) return(0);
if (!Parse_Value(string,value)) return(0);
strcpy(game_levels[curr_level].level_name,value);
Write_Error("\nLevel name = %s", game_levels[curr_level].level_name);
// now load the name of the file containing bitmap
if (!Get_Line(string, fp_level)) return(0);
if (!Parse_Value(string,value)) return(0);
strcpy(game_levels[curr_level].image_file,value);
Write_Error("\nimage file = %s", game_levels[curr_level].image_file);
// now the author
if (!Get_Line(string, fp_level)) return(0);
if (!Parse_Value(string,value)) return(0);
strcpy(game_levels[curr_level].author,value);
Write_Error("\nauthor name = %s", game_levels[curr_level].author);
// the bonus
if (!Get_Line(string, fp_level)) return(0);
if (!Parse_Value(string,value)) return(0);
game_levels[curr_level].bonus = atoi(value);
Write_Error("\nbonus = %d", game_levels[curr_level].bonus);
// the difficulty level
if (!Get_Line(string, fp_level)) return(0);
if (!Parse_Value(string,value)) return(0);
game_levels[curr_level].diff = atoi(value);
Write_Error("\ndiff = %d\n", game_levels[curr_level].diff);
// load level data itself
for (int row=0, start=0; row < LEVEL_ROWS; row++)
{
// load the next line of data
if (!Get_Line(string, fp_level)) return(0);
// kill any whitespace
start = 0;
while(isspace(string[start]))
start++;
strcpy(buffer, &string[start]);
Write_Error(buffer);
// copy data into array
memcpy(game_levels[curr_level].data[row], &string[start], 16);
} // end for row
} // end for curr_level
// close the level file
fclose(fp_level);
// return success
return(1);
} // end Load_Levels
///////////////////////////////////////////////////////////////
int Start_Level(int level)
{
// this function starts a level up and resets everything
// reset everything
level_name_counter = 75;
// set current level
curr_level = level;
// load image
Load_Bitmap_File(&bitmap8bit, game_levels[level].image_file);
// scan image into bitmap
Load_Image_Bitmap(&background_bmp,&bitmap8bit,0,0,BITMAP_EXTRACT_MODE_ABS);
// draw display header info
Draw_String(font,"PSI",SCORE_X+136,SCORE_Y,background_bmp.buffer, SCREEN_WIDTH,0);
Draw_String(font,"HIGH SCORE",SCORE_X+240,SCORE_Y,background_bmp.buffer, SCREEN_WIDTH,0);
Draw_String(font,"LEVEL",SCORE_X+500,SCORE_Y,background_bmp.buffer, SCREEN_WIDTH,0);
Draw_String(font,"Rads",SCORE_X-16,SCORE_Y+16,background_bmp.buffer, SCREEN_WIDTH,0);
// unload object bitmap
Unload_Bitmap_File(&bitmap8bit);
// process level data: dig holes, place objects
for (int row=0; row < LEVEL_ROWS; row++)
{
for (int col=0; col < LEVEL_COLUMNS; col++)
{
// get data values
char data = game_levels[level].data[row][col];
// what is the data object
switch(data)
{
case OBJECT_ID_ROCK:
{
// start a rock
Start_Rock(0 + col*40,64+24 + row*40);
} break;
case OBJECT_ID_POO:
case OBJECT_ID_PUFF:
{
// increase number of creatures on level
num_creatures_on_level++;
// dig a horizontal tunnel segment
dug_holes[HOLE_INDEX_H].x = 0 + col*40;
dug_holes[HOLE_INDEX_H].y = 64+8 + row*40;
Draw_Bitmap(&dug_holes[HOLE_INDEX_H],background_bmp.buffer,background_bmp.width,1);
// test if there is a segment downward
char data_dx;
if (col < LEVEL_COLUMNS-1)
{
data_dx = game_levels[level].data[row][col+1];
// is the index directly under another vertical or horizontal hole
if ((data_dx==OBJECT_ID_VHOLE) ||
(data_dx==OBJECT_ID_HHOLE) ||
(data_dx==OBJECT_ID_POO) ||
(data_dx==OBJECT_ID_PUFF))
{
// draw inbetween chunk
dug_holes[HOLE_INDEX_H].x = 0 + col*40 + 16;
dug_holes[HOLE_INDEX_H].y = 64+8 + row*40;
Draw_Bitmap(&dug_holes[HOLE_INDEX_H],background_bmp.buffer,background_bmp.width,1);
} // end if
} // end if
// test if there is a segment downward
char data_dy;
if (row < LEVEL_ROWS-1)
{
data_dy = game_levels[level].data[row+1][col];
// is the index directly under another vertical or horizontal hole
if ((data_dy==OBJECT_ID_VHOLE) ||
(data_dy==OBJECT_ID_HHOLE) ||
(data_dy==OBJECT_ID_POO) ||
(data_dy==OBJECT_ID_PUFF))
{
// draw inbetween chunk
dug_holes[HOLE_INDEX_V].x = 0 + col*40;
dug_holes[HOLE_INDEX_V].y = 64+8 + row*40 + 16;
Draw_Bitmap(&dug_holes[HOLE_INDEX_V],background_bmp.buffer,background_bmp.width,1);
} // end if
} // end if
// test for poo
if (data==OBJECT_ID_POO)
{
int sx = col*40,
sy = 64+8 + row*40;
// start a poo in the right direction
if (Get_Pixel(sx - 2,sy + 16,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
Start_Poo(sx,sy, DIR_LEFT);
else
if (Get_Pixel(sx + 34,sy + 16,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
Start_Poo(sx,sy, DIR_RIGHT);
else
if (Get_Pixel(sx + 16,sy - 2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
Start_Poo(sx,sy, DIR_UP);
else
if (Get_Pixel(sx + 16,sy + 34,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
Start_Poo(sx,sy, DIR_DOWN);
else
Start_Poo(sx,sy, rand()%4);
} // end if
else
if (data==OBJECT_ID_PUFF)
{
int sx = col*40,
sy = 64+8 + row*40;
// start a puff in the right direction
if (Get_Pixel(sx - 2,sy + 16,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
Start_Puff(sx,sy, DIR_LEFT);
else
if (Get_Pixel(sx + 34,sy + 16,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
Start_Puff(sx,sy, DIR_RIGHT);
else
if (Get_Pixel(sx + 16,sy - 2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
Start_Puff(sx,sy, DIR_UP);
else
if (Get_Pixel(sx + 16,sy + 34,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
Start_Puff(sx,sy, DIR_DOWN);
else
Start_Puff(sx,sy,rand()%4);
} // end if
} break;
case OBJECT_ID_VHOLE:
{
// dig a vertical tunnel segment
dug_holes[HOLE_INDEX_V].x = 0 + col*40;
dug_holes[HOLE_INDEX_V].y = 64+8 + row*40;
Draw_Bitmap(&dug_holes[HOLE_INDEX_V],background_bmp.buffer,background_bmp.width,1);
// test if there is a segment downward
char data_dy;
if (row < LEVEL_ROWS-1)
data_dy = game_levels[level].data[row+1][col];
else
break;
// is the index directly under another vertical or horizontal hole
if ((data_dy==OBJECT_ID_VHOLE) ||
(data_dy==OBJECT_ID_HHOLE) ||
(data_dy==OBJECT_ID_POO) ||
(data_dy==OBJECT_ID_PUFF))
{
// draw inbetween chunk
dug_holes[HOLE_INDEX_V].y +=16;
Draw_Bitmap(&dug_holes[HOLE_INDEX_V],background_bmp.buffer,background_bmp.width,1);
} // end if
} break;
case OBJECT_ID_HHOLE:
{
// dig a horizontal tunnel segment
dug_holes[HOLE_INDEX_H].x = 0 + col*40;
dug_holes[HOLE_INDEX_H].y = 64+8 + row*40;
Draw_Bitmap(&dug_holes[HOLE_INDEX_H],background_bmp.buffer,background_bmp.width,1);
// test if there is a segment downward
char data_dx;
if (col < LEVEL_COLUMNS-1)
data_dx = game_levels[level].data[row][col+1];
else
break;
// is the index directly under another vertical or horizontal hole
if ((data_dx==OBJECT_ID_VHOLE) ||
(data_dx==OBJECT_ID_HHOLE) ||
(data_dx==OBJECT_ID_POO) ||
(data_dx==OBJECT_ID_PUFF))
{
// draw inbetween chunk
dug_holes[HOLE_INDEX_H].x +=16;
Draw_Bitmap(&dug_holes[HOLE_INDEX_H],background_bmp.buffer,background_bmp.width,1);
} // end if
} break;
default: break;
} // end switch
} // end for col
} // end for row
// return success
return(1);
} // end Start_Level
///////////////////////////////////////////////////////////////
int Start_Rock(int x, int y)
{
// this function starts a rock
for (int rindex = 0; rindex < NUM_ROCKS; rindex++)
{
// is this rock dead?
if (rocks[rindex].state == ROCK_STATE_DEAD)
{
// compute position of new rock
rocks[rindex].x = x;
rocks[rindex].y = y;
// set state of rock
rocks[rindex].state = ROCK_STATE_STABLE;
rocks[rindex].anim_state = 0;
// set current frame of rock
rocks[rindex].curr_frame = 0;
// set number of rocks dropped to 0
// note the use of rocks[0] to store the global
rocks[0].varsI[8] = 0;
// success, so exit case
return(rindex);
} // end if
} // end for rindex
// return failure
return(0);
} // end Start_Rock
//////////////////////////////////////////////////////////////////
int Process_Rocks(void)
{
// this function process all the rocks
for (int index=0; index < NUM_ROCKS; index++)
{
// test state of rock
switch(rocks[index].state)
{
case ROCK_STATE_DEAD:
break;
case ROCK_STATE_STABLE:
{
// check if it's time to shake!
// compute sample position
int sx = rocks[index].x;
int sy = rocks[index].y + 32+6;
// test samples
if ( (Get_Pixel(sx+2,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE) ||
(Get_Pixel(sx+6,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE) ||
(Get_Pixel(sx+10,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE) ||
(Get_Pixel(sx+16,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE) ||
(Get_Pixel(sx+22,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE) ||
(Get_Pixel(sx+26,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE) ||
(Get_Pixel(sx+30,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE) )
{
// nothing there
break;
} // end if
else
{
// last test to see if dug is in the way?
int dx = abs(dug.x - rocks[index].x);
int dy = abs(dug.y - rocks[index].y);
// test how far dug is
if (dx >=4 || dy >= 34)
{
// save current position for shaking algorithm
// in 0,1
rocks[index].varsI[0] = rocks[index].x;
rocks[index].varsI[1] = rocks[index].y;
// set shake count
rocks[index].counter_1 = ROCK_COUNT_SHAKE;
// set new state
rocks[index].state = ROCK_STATE_SHAKING;
// start sound
Play_Sound_From_Pool(fall_snd_ids, 4);
} // end if
} // end else
} break;
case ROCK_STATE_SHAKING:
{
// shake rock randomly
rocks[index].x = rocks[index].varsI[0]-2+rand()%5;
rocks[index].y = rocks[index].varsI[1]-2+rand()%5;
// decrement shaking counter
if (--rocks[index].counter_1 < 0)
{
// switch states to falling
//...
// set new state to falling
rocks[index].state = ROCK_STATE_FALLING;
// set gravity
rocks[index].varsF[0] = ROCK_INIT_VELOCITY;
// reset initial position
rocks[index].x = rocks[index].varsI[0];
rocks[index].y = rocks[index].varsI[1];
} // end if
} break;
case ROCK_STATE_FALLING:
{
// test if rock has hit bottom
int sx = rocks[index].x;
int sy = rocks[index].y + 32;
// test samples
if ( (Get_Pixel(sx+6,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE) ||
(Get_Pixel(sx+16,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE) ||
(Get_Pixel(sx+26,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE) ||
rocks[index].y >= (SCREEN_HEIGHT - 32))
{
// stop rock, it's stable
rocks[index].state = ROCK_STATE_CRUMBLING;
// start sound
Play_Sound_From_Pool(crumble_snd_ids, 4);
} // end if
else
{
// move rock
rocks[index].y+=rocks[index].varsF[0];
// apply gravity
rocks[index].varsF[0]+=ROCK_GRAVITY;
}
} break;
case ROCK_STATE_CRUMBLING:
{
// just let the animation do it's thing
} break;
default: break;
} // end switch
} // end for index
// return success
return(1);
} // end Process_Rocks
///////////////////////////////////////////////////////////////
int Draw_Rocks(void)
{
// this function draws and animates all the rocks
for (int index=0; index<NUM_ROCKS; index++)
{
// test state of rock
switch(rocks[index].state)
{
case ROCK_STATE_DEAD:
break;
case ROCK_STATE_STABLE:
case ROCK_STATE_SHAKING:
case ROCK_STATE_FALLING:
{
// draw the first frame only
Draw_BOB(&rocks[index],lpddsback);
} break;
case ROCK_STATE_CRUMBLING:
{
// draw the bob
Draw_BOB(&rocks[index],lpddsback);
// animate the bob
Animate_BOB2(&rocks[index]);
// test if animation is done
if (rocks[index].anim_state == BOB_STATE_ANIM_DONE)
{
// kill the rock
rocks[index].state = ROCK_STATE_DEAD;
rocks[index].anim_state = 0;
// send message to add up score
//...
// increment number of rocks dropped
if (++rocks[0].varsI[8] == ROCKS_DROP_FOR_PRIZE)
Init_Prize(rand()%NUM_PRIZES,PRIZE_DISPLAY_TIME);
} // end if
} break;
default: break;
} // end switch
} // end for index
// return success
return(1);
} // end Draw_Rocks
///////////////////////////////////////////////////////////////
int Init_Prize(int prize_index, int count)
{
// this function initializes a prize to be displayed
// prize 0 is the control bob and the remaining prize bobs are slaves
prizes[0].state = PRIZE_STATE_ON;
prizes[0].counter_1 = count;
prizes[0].varsI[0] = prize_index; // store this for later use
// make sound
Play_Sound(prize_out_snd_id);
// return success
return(1);
} // end Init_Prize
////////////////////////////////////////////////////////////////
int Process_Prize(void)
{
// this function processes a prize and tests if it is picked up by
// the player
// is prize out?
if (prizes[0].state == PRIZE_STATE_OFF)
return(0);
// test for collision with player
if (Collision_BOBS(&dug, &prizes[0]))
{
// add in score and display
dug.varsI[DUG_INDEX_SCORE]+=prizes[prizes[0].varsI[0]].varsI[1];
// display a score
Start_Score(prizes[0].x+16,prizes[0].y+16, prizes[prizes[0].varsI[0]].varsI[1]);
// play win prize sound
Play_Sound(prize_win_snd_id);
// terminate the prize
prizes[0].state = PRIZE_STATE_OFF;
prizes[0].counter_1 = 0;
prizes[0].varsI[0] = 0;
// return terminate
return(1);
} // end if
// update and terminate?
if (--prizes[0].counter_1 < 0)
{
// terminate the prize -- too bad!
prizes[0].state = PRIZE_STATE_OFF;
prizes[0].counter_1 = 0;
prizes[0].varsI[0] = 0;
// return terminate
return(0);
} // end if
// return success
return(1);
} // end Process_Prize
///////////////////////////////////////////////////////////////
int Draw_Prize(void)
{
// this function draws the prize (if there is one)
// is prize out?
if (prizes[0].state == PRIZE_STATE_OFF)
return(0);
// extract the active prize
int active_prize = prizes[0].varsI[0];
// draw the prize
Draw_BOB(&prizes[active_prize], lpddsback);
// animate the prize
Animate_BOB(&prizes[active_prize]);
// return success
return(1);
} // end Draw_Prize
////////////////////////////////////////////////////////////
int Start_Fball(int x, int y, int dir, int fball_type = FBALL_TYPE_RED)
{
// this function starts a fire ball from the given position and direction
// scan for an unused fire ball
for (int index=0; index < NUM_FBALLS; index++)
{
// test if this fire ball is usuable
if (fballs[index].state==FBALL_STATE_DEAD)
{
// set the fire ball up
fballs[index].state = FBALL_STATE_MOVING;
fballs[index].anim_state = 0;
fballs[index].x = x;
fballs[index].y = y;
// play sound
Play_Sound_From_Pool(fball_snd_ids,4);
// talk shit
if (rand()%10==1)
Play_Sound(puff_talk_snd_ids[rand()%4]);
// select velocity and animation based on direction
switch(dir)
{
case DIR_RIGHT:
{
// set velocity
fballs[index].xv = FBALL_SPEED;
fballs[index].yv = 0;
// set animation
Set_Animation_BOB2(&fballs[index], fball_type*2);
} break;
case DIR_LEFT:
{
// set velocity
fballs[index].xv = -FBALL_SPEED;
fballs[index].yv = 0;
// set animation
Set_Animation_BOB2(&fballs[index], fball_type*2);
} break;
case DIR_UP:
{
// set velocity
fballs[index].xv = 0;
fballs[index].yv = -FBALL_SPEED;
// set animation
Set_Animation_BOB2(&fballs[index], fball_type*2);
} break;
case DIR_DOWN:
{
// set velocity
fballs[index].xv = 0;
fballs[index].yv = FBALL_SPEED;
// set animation
Set_Animation_BOB2(&fballs[index], fball_type*2);
} break;
default:break;
} // end switch
// return success
return(1);
} // end if
} // end for index
// return failure
return(0);
} // end Start_Fball
///////////////////////////////////////////////////////////////
int Process_Fballs(void)
{
// this functions processes all the fballs, moves, and tests for collisions
// process all fire balls
for (int index=0; index < NUM_FBALLS; index++)
{
// test if this fire ball is active
if (fballs[index].state==FBALL_STATE_MOVING)
{
// move fire ball
Move_BOB(&fballs[index]);
// test for gravity
if ((int)fballs[index].yv==0 && (((int)fballs[index].y-2) % DUG_X_INTERVAL))
fballs[index].y++;
// test for hit with offscreen
if (fballs[index].x > SCREEN_WIDTH-16 || fballs[index].x <= 0 ||
fballs[index].y > SCREEN_HEIGHT-16 || fballs[index].y <= 0 ) // DUG_MIN_ROCK_LINE)
{
// put fireball into dying state and switch animation sequence
fballs[index].state = FBALL_STATE_EXPLODING;
// play explosion sound
Play_Sound_From_Pool(expl_snd_ids,4);
// set animation
Set_Animation_BOB2(&fballs[index], fballs[index].curr_animation+1);
// reset animation state
fballs[index].anim_state = 0;
// process next
continue;
} // end if
// only test in lower region
if (fballs[index].y >= DUG_MIN_ROCK_LINE)
{
// test for material hit
int sx = fballs[index].x+8;
int sy = fballs[index].y+8;
// test sample
if (Get_Pixel(sx,sy,background_bmp.buffer,background_bmp.width)!=COLOR_INDEX_HOLE)
{
// put fireball into dying state and switch animation sequence
fballs[index].state = FBALL_STATE_EXPLODING;
// play explosion sound
Play_Sound_From_Pool(expl_snd_ids,4);
// set animation
Set_Animation_BOB2(&fballs[index], fballs[index].curr_animation+1);
// reset animation state
fballs[index].anim_state = 0;
// process next
continue;
} // end if
} // end if
// test for collisions here
if (dug.state == DUG_STATE_ALIVE)
{
if (Collision_BOBS(&dug,&fballs[index]))
{
// start the death sequence
Start_Dug_Death();
// put fireball into dying state and switch animation sequence
fballs[index].state = FBALL_STATE_EXPLODING;
// play explosion sound
Play_Sound_From_Pool(expl_snd_ids,4);
// set animation
Set_Animation_BOB2(&fballs[index], fballs[index].curr_animation+1);
// reset animation state
fballs[index].anim_state = 0;
} // end if
} // end if dug alive
} // end if alive
} // end for index
// return sucess
return(1);
} // end Process_Fballs
////////////////////////////////////////////////////////////////
int Draw_Fballs(void)
{
// this function draws and animates all the fballs
static int blasting = 0;
// process all fire balls
for (int index=0; index < NUM_FBALLS; index++)
{
// test if this fire ball is usuable
if (fballs[index].state!=FBALL_STATE_DEAD)
{
// draw the bob first
Draw_BOB(&fballs[index], lpddsback);
// animate the bob
Animate_BOB2(&fballs[index]);
// eat rock away
if (fballs[index].state==FBALL_STATE_EXPLODING) // && fballs[index].y>=DUG_MIN_ROCK_LINE)
{
int fcx = fballs[index].x;
int fcy = fballs[index].y;
int num_chunks = 6 + rand()%6;
// destruction
for (int chunks=0; chunks < num_chunks; chunks++)
{
int blast_shape = rand()%NUM_FBLASTS;
fblasts[blast_shape].x = fcx - 8 + rand()%17;
fblasts[blast_shape].y = fcy - 8 + rand()%17;
// clip blast coords
if (fblasts[blast_shape].x >= SCREEN_WIDTH - 16)
fblasts[blast_shape].x = SCREEN_WIDTH - 16;
else
if (fblasts[blast_shape].x < 2)
fblasts[blast_shape].x = 2;
if (fblasts[blast_shape].y < DUG_MIN_ROCK_LINE)
fblasts[blast_shape].y = DUG_MIN_ROCK_LINE;
else
if (fblasts[blast_shape].y >= SCREEN_HEIGHT - 16)
fblasts[blast_shape].y = SCREEN_HEIGHT - 16;
// draw the damage
Draw_Bitmap(&fblasts[blast_shape],background_bmp.buffer,background_bmp.width,1);
} // end for chunks
} // end if
// test if in dying state
if (fballs[index].state==FBALL_STATE_EXPLODING &&
fballs[index].anim_state==BOB_STATE_ANIM_DONE)
{
// your terminated fucker!
fballs[index].state=FBALL_STATE_DEAD;
} // end if
} // end if
} // end for index
// return sucess
return(1);
} // end Draw_Fballs
/////////////////////////////////////////////////////////////////
int Start_Gpump(int x, int y, int dir)
{
// this function starts a grappling pump from the given position and direction
// scan for an unused pump
for (int index=0; index < NUM_GPUMPS; index++)
{
// test if this pump is usuable
if (gpumps[index].state==GPUMP_STATE_DEAD)
{
// set the pump up
gpumps[index].state = GPUMP_STATE_MOVING;
gpumps[index].anim_state = 0;
gpumps[index].x = x;
gpumps[index].y = y;
// select velocity and animation based on direction
switch(dir)
{
case DIR_RIGHT:
{
// set velocity
gpumps[index].xv = GPUMP_SPEED;
gpumps[index].yv = 0;
// set animation
Set_Animation_BOB2(&gpumps[index], dir);
} break;
case DIR_LEFT:
{
// set velocity
gpumps[index].xv = -GPUMP_SPEED;
gpumps[index].yv = 0;
// set animation
Set_Animation_BOB2(&gpumps[index], dir);
} break;
case DIR_UP:
{
// set velocity
gpumps[index].xv = 0;
gpumps[index].yv = -GPUMP_SPEED;
// set animation
Set_Animation_BOB2(&gpumps[index], dir);
} break;
case DIR_DOWN:
{
// set velocity
gpumps[index].xv = 0;
gpumps[index].yv = GPUMP_SPEED;
// set animation
Set_Animation_BOB2(&gpumps[index], dir);
} break;
default:break;
} // end switch
// start sound
Play_Sound_From_Pool(gpump_snd_ids, 4);
// return success
return(1);
} // end if
} // end for index
// return failure
return(0);
} // end Start_Gpump
///////////////////////////////////////////////////////////////
int Process_Gpumps(void)
{
// this functions processes all the gpumps, moves, and tests for collisions
// process all pumps
for (int index=0; index < NUM_GPUMPS; index++)
{
// test if this pump is usuable
if (gpumps[index].state!=GPUMP_STATE_DEAD)
{
// move pump
Move_BOB(&gpumps[index]);
// test for hit with offscreen
if (gpumps[index].x > SCREEN_WIDTH || gpumps[index].x < -16 ||
gpumps[index].y > SCREEN_HEIGHT || gpumps[index].y < -16)
{
// kill the pump
gpumps[index].state = GPUMP_STATE_DEAD;
} // end if
// only test in lower region
if (gpumps[index].y >= DUG_MIN_ROCK_LINE)
{
// test for material hit
int sx = gpumps[index].x+8;
int sy = gpumps[index].y+8;
// test sample
if (Get_Pixel(sx,sy,background_bmp.buffer,background_bmp.width)!=COLOR_INDEX_HOLE)
{
// kill the pump
gpumps[index].state = GPUMP_STATE_DEAD;
} // end if
} // end if
} // end if alive
} // end for index
// return sucess
return(1);
} // end Process_Gpumps
////////////////////////////////////////////////////////////////
int Draw_Gpumps(void)
{
// this function draws and animates all the gpumps
// process all pumps
for (int index=0; index < NUM_GPUMPS; index++)
{
// test if this pump is usuable
if (gpumps[index].state!=GPUMP_STATE_DEAD)
{
// draw the bob first
Draw_BOB(&gpumps[index], lpddsback);
// animate the bob
Animate_BOB(&gpumps[index]);
} // end if
} // end for index
// return sucess
return(1);
} // end Draw_Gpumps
///////////////////////////////////////////////////////////////
int Start_Poo(int x, int y, int dir)
{
// this function attempts to start a poo up with the desired
// position and direction
int index; // looping index
// find an unused poo
for (index=0; index < NUM_POOS; index++)
{
// is poo this available
if (poos[index].state == POO_STATE_DEAD)
{
// set poo up
poos[index].state = POO_STATE_ALIVE;
poos[index].varsI[POO_INDEX_AI_STATE] = POO_AI_STATE_EXPLORE;
poos[index].varsI[POO_INDEX_ANIM_STATE] = POO_ANIM_STATE_BOUNCE;
poos[index].varsI[POO_INDEX_CURR_DIR] = dir;
poos[index].varsI[POO_INDEX_LAST_DIR] = dir;
poos[index].varsI[POO_INDEX_DESIRED_DIR] = dir;
poos[index].varsI[POO_INDEX_PSI_COUNT] = 0;
poos[index].max_count_2 = 0;
poos[index].varsI[POO_INDEX_EXPLORE_COUNTER] = 2*POO_EXPLORE_TIME + rand()%POO_EXPLORE_TIME;
// reset averaging vars
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
if ((poos[index].varsI[POO_INDEX_BOUNCE_MAX] = (6 + rand()%6) - dug.varsI[DUG_INDEX_LEVEL]/2) < 2)
poos[index].varsI[POO_INDEX_BOUNCE_MAX] = 2;
// general counters
poos[index].counter_1 = 0;
poos[index].counter_2 = 0;
// set position
poos[index].x = x;
poos[index].y = y;
// save for restart
poos[index].varsI[POO_INDEX_SAVED_X] = x;
poos[index].varsI[POO_INDEX_SAVED_Y] = y;
poos[index].varsI[POO_INDEX_SAVED_DIR] = dir;
// the the current animation of poo
if (dir==DIR_LEFT || dir==DIR_UP)
{
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_LEFT);
poos[index].varsI[POO_INDEX_ANIM_DIR] = DIR_LEFT;
} // end if
else
if (dir==DIR_RIGHT || dir==DIR_DOWN)
{
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_RIGHT);
poos[index].varsI[POO_INDEX_ANIM_DIR] = DIR_RIGHT;
} // end if
// return success
return(1);
} // end if
} // end for index
// return failure
return(0);
} // end Start_Poo
//////////////////////////////////////////////////////////////
int Process_Poos(void)
{
// this function processes and controls the ai for al the poos
int index, // looping variable
pdx,pdy, // velocity
sx,sy; // sample points
static int poo_counter_1 = 0; // used to initiate random events
static char *state_names[] = {"fire","explore","chase","evade","burrow","crush","inflating","popped"};
// loop and process all poos
//mono.set_cursor(0,1);
//mono.print("Poo System States");
// draw each poo
for (index=0; index < NUM_POOS; index++)
{
// is poo this available
if (poos[index].state != POO_STATE_DEAD)
{
// sprintf(buffer,"\nPoo %d, AI State = %s, XB = %d, YB=%d, PSI = %d , count_2 = %d ",index,
// state_names[poos[index].varsI[POO_INDEX_AI_STATE]],
// poos[index].varsI[POO_INDEX_SUM_X],
// poos[index].varsI[POO_INDEX_SUM_Y],
// poos[index].varsI[POO_INDEX_PSI_COUNT],
// poos[index].max_count_2);
// mono.print(buffer);
// talk shit
if (rand()%750==100)
Play_Sound(dyclops_talk_snd_ids[rand()%4]);
// test for collisions here
if (dug.state == DUG_STATE_ALIVE &&
poos[index].varsI[POO_INDEX_AI_STATE] != POO_AI_STATE_CRUSHED &&
poos[index].varsI[POO_INDEX_AI_STATE] != POO_AI_STATE_INFLATING)
{
if (Collision_BOBS(&dug,&poos[index]))
{
// start the death sequence
Start_Dug_Death();
} // end if
} // end if
// test for being crushed by rock
for (int rindex=0; rindex < NUM_ROCKS; rindex++)
{
// test if rock is alive
if (rocks[rindex].state==ROCK_STATE_FALLING)
{
// rock is alive, so test for collision with poo
if (Collision_BOBS(&rocks[rindex],&poos[index]) && poos[index].varsI[POO_INDEX_AI_STATE] != POO_AI_STATE_CRUSHED)
{
// first reset all state information of poo
//poos[index].state = POO_STATE_DYING;
poos[index].varsI[POO_INDEX_AI_STATE] = POO_AI_STATE_CRUSHED;
poos[index].varsI[POO_INDEX_ANIM_STATE] = POO_ANIM_STATE_CRUSHED;
// start crunch sound
Play_Sound_From_Pool(crunch_snd_ids,4);
// tag rock
poos[index].varsI[POO_INDEX_OBJECT_PTR] = rindex;
// set animation
if (poos[index].varsI[POO_INDEX_CURR_DIR] == DIR_RIGHT ||
poos[index].varsI[POO_INDEX_CURR_DIR] == DIR_UP)
{
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_CRUSH_RIGHT);
} // end if
else
{
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_CRUSH_LEFT);
} // end if
// that's it
break;
} // end if
} // end if
} // end for rindex
// check for hit with pumps
for (int gindex=0; gindex < NUM_GPUMPS; gindex++)
{
// test if this pump is usuable
if (gpumps[gindex].state!=GPUMP_STATE_DEAD &&
poos[index].max_count_2==0 &&
poos[index].varsI[POO_INDEX_AI_STATE] != POO_AI_STATE_CRUSHED )
{
if (Collision_BOBS(&gpumps[gindex],&poos[index]))
{
// kill the pump
gpumps[gindex].state=GPUMP_STATE_DEAD;
// make pump sound
Play_Sound_From_Pool(air_snd_ids, 4);
// change to inflate mode
poos[index].varsI[POO_INDEX_AI_STATE] = POO_AI_STATE_INFLATING;
poos[index].varsI[POO_INDEX_ANIM_STATE] = POO_ANIM_STATE_INFLATING;
if (poos[index].varsI[POO_INDEX_PSI_COUNT] < 3*GPUMP_INJECTION)
{
poos[index].varsI[POO_INDEX_PSI_COUNT] += (GPUMP_INJECTION-1);
if (poos[index].varsI[POO_INDEX_PSI_COUNT] > 3*GPUMP_INJECTION)
poos[index].varsI[POO_INDEX_PSI_COUNT] = 3*GPUMP_INJECTION;
} // end if
// this is a pump poo!
break;
} // end if
} // end if
} // end gindex
// what is the ai state of the poo
// C R U S H E D L O G I C //////////////////////////////////////////////////
if (poos[index].varsI[POO_INDEX_AI_STATE] == POO_AI_STATE_CRUSHED)
{
// the poo is getting crushed, simple track tagged rock
poos[index].x = rocks[poos[index].varsI[POO_INDEX_OBJECT_PTR]].x;
poos[index].y = rocks[poos[index].varsI[POO_INDEX_OBJECT_PTR]].y+8;
// test if rock is complete and in crumble mode
if (rocks[poos[index].varsI[POO_INDEX_OBJECT_PTR]].state==ROCK_STATE_DEAD)
{
// terminate poo
poos[index].state = POO_STATE_DEAD;
// one more for the gipper
dug.varsI[DUG_INDEX_KILLS]++;
int score = 100+100*(poos[index].y/100);
// start up score object
Start_Score(poos[index].x+16 - 4 + rand()%8,poos[index].y+16 - 4+rand()%8,score);
dug.varsI[DUG_INDEX_SCORE]+=score;
} // end if
} // end if
else
//// S T O P L O G I C /////////////////////////////////////////////////////
if (poos[index].varsI[POO_INDEX_AI_STATE]==POO_AI_STATE_STOP)
{
// the poo is stopped to think
if (--poos[index].counter_1 <= 0)
{
// select new state
} // end if
} // end if
//// I N F L A T I O N S T A T E /////////////////////////////////////////////
if (poos[index].varsI[POO_INDEX_AI_STATE]==POO_AI_STATE_INFLATING)
{
if (poos[index].varsI[POO_INDEX_PSI_COUNT] < 3*GPUMP_INJECTION)
{
// decrease inflation
if (--poos[index].varsI[POO_INDEX_PSI_COUNT] <= 0)
{
// switch to chase mode
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
poos[index].max_count_2 = 0;
// change modes
poos[index].varsI[POO_INDEX_AI_STATE] = POO_AI_STATE_CHASE;
// set animation correctly
// the the current animation of poo
if (poos[index].varsI[POO_INDEX_CURR_DIR]==DIR_LEFT || poos[index].varsI[POO_INDEX_CURR_DIR]==DIR_UP)
{
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_LEFT);
poos[index].varsI[POO_INDEX_ANIM_STATE] = POO_ANIM_STATE_BOUNCE;
} // end if
else
{
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_RIGHT);
poos[index].varsI[POO_INDEX_ANIM_STATE] = POO_ANIM_STATE_BOUNCE;
} // end if
} // end if
} // end if
else
if (++poos[index].varsI[POO_INDEX_PSI_COUNT] > (3*GPUMP_INJECTION + GPUMP_INJECTION/2))
{
// kill the poo
poos[index].state = POO_STATE_DEAD;
poos[index].max_count_2 = 0;
// one more for the gipper
dug.varsI[DUG_INDEX_KILLS]++;
int score = 100+100*(poos[index].y/100);
if (dug.varsI[DUG_INDEX_DIR] == DIR_LEFT || dug.varsI[DUG_INDEX_DIR] == DIR_RIGHT)
score+=50;
// start up score object
Start_Score(poos[index].x+16 - 4 + rand()%8,poos[index].y+16 - 4+rand()%8,score);
dug.varsI[DUG_INDEX_SCORE]+=score;
} // end if
} // end if
else // E X P L O R E L O G I C ///////////////////////////////////////////////////
if (poos[index].varsI[POO_INDEX_AI_STATE]==POO_AI_STATE_EXPLORE)
{
// this is the general exploration ai
// test the current direction of the poo
switch(poos[index].varsI[POO_INDEX_CURR_DIR])
{
case DIR_LEFT:
{
// compute velocity changes
pdx = -POO_SPEED;
pdy = 0;
// move poo
poos[index].x+=pdx;
poos[index].y+=pdy;
// compute sample position
sx = poos[index].x;
sy = poos[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
poos[index].x <= 0)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_RIGHT;
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_RIGHT);
// increment x-axis bounce counter
poos[index].varsI[POO_INDEX_SUM_X]++;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} break;
case DIR_RIGHT:
{
// compute velocity changes
pdx = POO_SPEED;
pdy = 0;
// move poo
poos[index].x+=pdx;
poos[index].y+=pdy;
// compute sample position
sx = poos[index].x + 31;
sy = poos[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
poos[index].x >= (SCREEN_WIDTH-32))
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_LEFT;
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_LEFT);
// increment x-axis bounce counter
poos[index].varsI[POO_INDEX_SUM_X]++;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} break;
case DIR_UP:
{
// compute velocity changes
pdy = -POO_SPEED;
pdx = 0;
// move poo
poos[index].x+=pdx;
poos[index].y+=pdy;
// compute sample position
sx = poos[index].x + 16;
sy = poos[index].y;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
poos[index].y <= DUG_MIN_ROCK_LINE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_DOWN;
// increment x-axis bounce counter
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y]++;
} // end if
} break;
case DIR_DOWN:
{
// compute velocity changes
pdy = POO_SPEED;
pdx = 0;
// move poo
poos[index].x+=pdx;
poos[index].y+=pdy;
// compute sample position
sx = poos[index].x + 16;
sy = poos[index].y + 31;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
poos[index].y >= (SCREEN_HEIGHT-32))
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_UP;
// increment x-axis bounce counter
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y]++;
} // end if
} break;
default:break;
} // end switch
// at this point the poo has moved, let's test if we can make a turn
if (poos[index].varsI[POO_INDEX_CURR_DIR] == DIR_LEFT ||
poos[index].varsI[POO_INDEX_CURR_DIR] == DIR_RIGHT)
{
// try for up or down turn
if (!((int)poos[index].x % DUG_X_INTERVAL))
{
// it legal to make a turn
// select a direction
if ((rand()%2) == 1)
{
// try and turn up
sx = poos[index].x + 16;
sy = poos[index].y - 1;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy-2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_UP;
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
}
else
{
// try and turn down
sx = poos[index].x + 16;
sy = poos[index].y + 32;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy+2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_DOWN;
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end else
} // end if
} // end if
else
if (poos[index].varsI[POO_INDEX_CURR_DIR] == DIR_UP ||
poos[index].varsI[POO_INDEX_CURR_DIR] == DIR_DOWN)
{
// try for up or down turn
if (!(((int)poos[index].y + 8) % DUG_X_INTERVAL))
{
// it legal to make a turn
// select a direction
if ((rand()%2)==1)
{
// try and turn right
sx = poos[index].x + 32;
sy = poos[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx + 2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_RIGHT;
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_RIGHT);
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end if
else
{
// try and turn down
sx = poos[index].x - 1;
sy = poos[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx - 2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_LEFT;
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_LEFT);
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end else
} // end if
} // end if
// test for state exits
if (--poos[index].varsI[POO_INDEX_EXPLORE_COUNTER] <=0)
{
// set state to chase
poos[index].varsI[POO_INDEX_AI_STATE]=POO_AI_STATE_CHASE;
// reset counter
poos[index].varsI[POO_INDEX_EXPLORE_COUNTER] = POO_EXPLORE_TIME;
} // end if
// test for switch into burrow mode
if (poos[index].varsI[POO_INDEX_SUM_X] > poos[index].varsI[POO_INDEX_BOUNCE_MAX] ||
poos[index].varsI[POO_INDEX_SUM_Y] > poos[index].varsI[POO_INDEX_BOUNCE_MAX])
{
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
// change modes to burrow
poos[index].varsI[POO_INDEX_AI_STATE] = POO_AI_STATE_BURROW;
Set_Animation_BOB2(&poos[index],POO_ANIM_BURROW);
poos[index].varsI[POO_INDEX_ANIM_STATE] = POO_ANIM_STATE_BURROW;
// start directional rescan
poos[index].counter_2 = 0;
// set maximum burrow time
//poos[index].varsI[POO_INDEX_EXPLORE_COUNTER] = (POO_EXPLORE_TIME >> 2) + (rand()%POO_EXPLORE_TIME);
} // end if
} // end if explore
else /// C H A S E L O G I C ///////////////////////////////////////////////////
if (poos[index].varsI[POO_INDEX_AI_STATE]==POO_AI_STATE_CHASE)
{
int desired_taken = 0; // used to track if desired was taken
// test the current direction of the poo
switch(poos[index].varsI[POO_INDEX_CURR_DIR])
{
case DIR_LEFT:
{
// compute velocity changes
pdx = -POO_SPEED;
pdy = 0;
// move poo
poos[index].x+=pdx;
poos[index].y+=pdy;
// compute sample position
sx = poos[index].x;
sy = poos[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
poos[index].x <= 0)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_RIGHT;
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_RIGHT);
// increment x-axis bounce counter
poos[index].varsI[POO_INDEX_SUM_X]++;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} break;
case DIR_RIGHT:
{
// compute velocity changes
pdx = POO_SPEED;
pdy = 0;
// move poo
poos[index].x+=pdx;
poos[index].y+=pdy;
// compute sample position
sx = poos[index].x + 31;
sy = poos[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
poos[index].x >= (SCREEN_WIDTH-32))
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_LEFT;
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_LEFT);
// increment x-axis bounce counter
poos[index].varsI[POO_INDEX_SUM_X]++;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} break;
case DIR_UP:
{
// compute velocity changes
pdy = -POO_SPEED;
pdx = 0;
// move poo
poos[index].x+=pdx;
poos[index].y+=pdy;
// compute sample position
sx = poos[index].x + 16;
sy = poos[index].y;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
poos[index].y <= (DUG_MIN_ROCK_LINE))
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_DOWN;
// increment y-axis bounce counter
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y]++;
} // end if
} break;
case DIR_DOWN:
{
// compute velocity changes
pdy = POO_SPEED;
pdx = 0;
// move poo
poos[index].x+=pdx;
poos[index].y+=pdy;
// compute sample position
sx = poos[index].x + 16;
sy = poos[index].y + 31;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
poos[index].y >= (SCREEN_HEIGHT-32))
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_UP;
// increment y-axis bounce counter
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y]++;
} // end if
} break;
default:break;
} // end switch
// at this point the poo has moved, let's test if we can make a turn
// compute the desired new direction
// compute dx and dy
int dx = dug.x - poos[index].x;
int dy = dug.y - poos[index].y;
// decide which way we want to go
if (abs(dx) > abs(dy))
{
// set primary desired direction to minimize dx
if (dx > 0)
poos[index].varsI[POO_INDEX_DESIRED_DIR] = DIR_RIGHT;
else
poos[index].varsI[POO_INDEX_DESIRED_DIR] = DIR_LEFT;
// set secondary direction only if delta is > 16
if (abs(dy) > 16)
{
if (dy > 0)
poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] = DIR_DOWN;
else
poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] = DIR_UP;
} // end if
else
poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] = DIR_NULL;
} // end if
else
{
// set primary desired direction to minimize dy
if (dy > 0)
poos[index].varsI[POO_INDEX_DESIRED_DIR] = DIR_DOWN;
else
poos[index].varsI[POO_INDEX_DESIRED_DIR] = DIR_UP;
// set secondary desired direction to minimize dx, only if dx > 16
if (abs(dx) > 16)
{
if (dx > 0)
poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] = DIR_RIGHT;
else
poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] = DIR_LEFT;
} // end if
else
poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] = DIR_NULL;
} // end if
// once in a blue moon swap primary and secondary
if ((rand()%10)==1)
{
// swap
int temp = poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR];
poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] = poos[index].varsI[POO_INDEX_DESIRED_DIR];
poos[index].varsI[POO_INDEX_DESIRED_DIR] = temp;
} // end if
// make sure we don't want to go the same way
if ((poos[index].varsI[POO_INDEX_DESIRED_DIR] >> 1) != (poos[index].varsI[POO_INDEX_CURR_DIR] >> 1))
{
// test for desired right turn
if (poos[index].varsI[POO_INDEX_DESIRED_DIR] == DIR_RIGHT &&
!(((int)poos[index].y+8) % DUG_X_INTERVAL))
{
// try and turn up
sx = poos[index].x + 32;
sy = poos[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx+2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_RIGHT;
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_RIGHT);
// set taken flag
desired_taken = 1;
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end if
// test for desired right turn
else
if (poos[index].varsI[POO_INDEX_DESIRED_DIR] == DIR_LEFT &&
!(((int)poos[index].y+8) % DUG_X_INTERVAL))
{
// try and turn up
sx = poos[index].x - 1;
sy = poos[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx - 2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_LEFT;
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_LEFT);
// set taken flag
desired_taken = 1;
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end if
else
if (poos[index].varsI[POO_INDEX_DESIRED_DIR] == DIR_UP &&
!(((int)poos[index].x) % DUG_X_INTERVAL))
{
// try and turn up
sx = poos[index].x + 16;
sy = poos[index].y - 1;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy - 2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_UP;
// set taken flag
desired_taken = 1;
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end if
else
if (poos[index].varsI[POO_INDEX_DESIRED_DIR] == DIR_DOWN &&
!(((int)poos[index].x) % DUG_X_INTERVAL))
{
// try and turn up
sx = poos[index].x + 16;
sy = poos[index].y + 32;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy+2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_DOWN;
// set taken flag
desired_taken = 1;
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end if
} // end if primary valid
///////////////////////////////////////////////////////////////////////
// test for secondary turns
if (!desired_taken &&
(poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR]!=DIR_NULL) &&
(poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] >> 1) != (poos[index].varsI[POO_INDEX_CURR_DIR] >> 1) )
{
// test for desired right turn
if (poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] == DIR_RIGHT &&
!(((int)poos[index].y+8) % DUG_X_INTERVAL))
{
// try and turn up
sx = poos[index].x + 32;
sy = poos[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx+2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_RIGHT;
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_RIGHT);
// set taken flag
desired_taken = 1;
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end if
// test for desired right turn
else
if (poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] == DIR_LEFT &&
!(((int)poos[index].y+8) % DUG_X_INTERVAL))
{
// try and turn up
sx = poos[index].x - 1;
sy = poos[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx - 2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_LEFT;
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_LEFT);
// set taken flag
desired_taken = 1;
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end if
else
if (poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] == DIR_UP &&
!(((int)poos[index].x) % DUG_X_INTERVAL))
{
// try and turn up
sx = poos[index].x + 16;
sy = poos[index].y - 1;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy - 2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_UP;
// set taken flag
desired_taken = 1;
} // end if
} // end if
else
if (poos[index].varsI[POO_INDEX_2ND_DESIRED_DIR] == DIR_DOWN &&
!(((int)poos[index].x) % DUG_X_INTERVAL))
{
// try and turn up
sx = poos[index].x + 16;
sy = poos[index].y + 32;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy+2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
poos[index].varsI[POO_INDEX_LAST_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_DOWN;
// set taken flag
desired_taken = 1;
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end if
} // end else 2nd desired
// test for global randomness ////////////////////////////////////////////////////
if (++poo_counter_1 > 200)
poo_counter_1 = 0;
// test for random event
if ((poo_counter_1 == 0) &&
((rand()%3)==1) &&
(Fast_Distance(poos[index].x-dug.x, poos[index].y-dug.y) > 300))
{
// reverse direction
switch(poos[index].varsI[POO_INDEX_CURR_DIR])
{
case DIR_LEFT:
{
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_RIGHT;
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_RIGHT);
} break;
case DIR_RIGHT:
{
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_LEFT;
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_LEFT);
} break;
case DIR_UP: poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_DOWN; break;
case DIR_DOWN: poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_UP; break;
default:break;
} // end switch
} // end if
///////////////////////////////////////////////////////////////////////////
// test for pre-emptive state transitions
if (poos[index].varsI[POO_INDEX_SUM_X] > POO_BOUNCES_PREMPT || poos[index].varsI[POO_INDEX_SUM_Y] > POO_BOUNCES_PREMPT)
{
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
// change modes
poos[index].varsI[POO_INDEX_AI_STATE] = POO_AI_STATE_EXPLORE;
poos[index].varsI[POO_INDEX_EXPLORE_COUNTER] = (POO_EXPLORE_TIME >> 2) + (rand()%POO_EXPLORE_TIME);
} // end if
} // end if chase
else //////////////////////////////////////////////////////////////////////////
if (poos[index].varsI[POO_INDEX_AI_STATE]==POO_AI_STATE_EVADE)
{
} // end if
else /////////////////////////////////////////////////////////////////////////
if (poos[index].varsI[POO_INDEX_AI_STATE]==POO_AI_STATE_BURROW)
{
// select tracking direction
int burst_speed = 1;
// compute added velocity due to level
if ((rand()%(100-dug.varsI[DUG_INDEX_LEVEL]))==1)
burst_speed = 2;
// x tracking
if (rand()%3==1)
{
if (dug.x > poos[index].x)
poos[index].x+=(burst_speed );
else
if (dug.x < poos[index].x)
poos[index].x-=(burst_speed );
} // end if
// y tracking
if (rand()%3==1)
{
if (dug.y < poos[index].y)
poos[index].y-=(burst_speed );
else
if (dug.y > poos[index].y)
poos[index].y+=(burst_speed );
} // end if
// test for clip
if (poos[index].y < DUG_MIN_ROCK_LINE)
poos[index].y+=(1);
int sx = poos[index].x,
sy = poos[index].y;
// test if done burrowing
if (Get_Pixel(sx, sy, background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx+31,sy, background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx, sy+31,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx+31,sy+31,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// set state to chase
poos[index].varsI[POO_INDEX_AI_STATE]=POO_AI_STATE_CHASE;
poos[index].varsI[POO_INDEX_ANIM_STATE] = POO_ANIM_STATE_BOUNCE;
// reset counter
poos[index].varsI[POO_INDEX_EXPLORE_COUNTER] = POO_EXPLORE_TIME;
// reset bounce counters
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
// reset bounce master
if ((poos[index].varsI[POO_INDEX_BOUNCE_MAX] = (3 + (rand()%3) - dug.varsI[DUG_INDEX_LEVEL]/2) < 3))
poos[index].varsI[POO_INDEX_BOUNCE_MAX] = 3;
// make a final decision on direction
// lock coords
int gdx = ((int)poos[index].x % DUG_X_INTERVAL);
int gdy = (((int)poos[index].y+8) % DUG_X_INTERVAL);
// find the smaller of the two and align
if (gdx <= gdy)
{
// align x axis, find closest interval
if (gdx <= 19)
{
poos[index].x-=gdx;
} // end if
else
{
poos[index].x+=(DUG_X_INTERVAL - gdx);
} // end else
// align y axis on even boundary
poos[index].y = (int)poos[index].y & (0xfffffffe);
} // end if
else
{
// align y axis, find closest interval
if (gdy <= 19)
{
poos[index].y-=gdy;
} // end if
else
{
poos[index].y+=(DUG_X_INTERVAL - gdy);
} // end else
// align x axis on even boundary
poos[index].x = (int)poos[index].x & (0xfffffffe);
} // end else
// compute most desired direction
int dx = dug.x - poos[index].x;
int dy = dug.y - poos[index].y;
// decide which way we want to go
if (abs(dx) > abs(dy))
{
// set primary desired direction to minimize dx
if (dx > 0)
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_RIGHT;
else
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_LEFT;
} // end if
else
{
// set primary desired direction to minimize dy
if (dy > 0)
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_DOWN;
else
poos[index].varsI[POO_INDEX_CURR_DIR] = DIR_UP;
} // end if
// set animation direction
poos[index].varsI[POO_INDEX_ANIM_DIR] = poos[index].varsI[POO_INDEX_CURR_DIR];
// set animation
if (poos[index].varsI[POO_INDEX_ANIM_DIR]==DIR_LEFT ||
poos[index].varsI[POO_INDEX_ANIM_DIR]==DIR_UP)
{
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_LEFT);
} // end if
else
if (poos[index].varsI[POO_INDEX_ANIM_DIR]==DIR_RIGHT ||
poos[index].varsI[POO_INDEX_ANIM_DIR]==DIR_DOWN)
{
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_RIGHT);
} // end if
} // end if
} // end if
} // end if alive
} // end for index
// return success
return(1);
} // end Process_Poos
///////////////////////////////////////////////////////////////
int Draw_Poos(void)
{
// this function animates and draws all the poos
int index; // looping index
// draw each poo
for (index=0; index < NUM_POOS; index++)
{
// is poo this available
if (poos[index].state != POO_STATE_DEAD)
{
// what is the animation state?
switch(poos[index].varsI[POO_INDEX_ANIM_STATE])
{
case POO_ANIM_STATE_BOUNCE:
{
// the poo is just bouncing up and down
Draw_BOB(&poos[index],lpddsback);
// animate the poo
Animate_BOB2(&poos[index]);
} break;
case POO_ANIM_STATE_CRUSHED:
{
// the poo is being crushed
// draw the poo
Draw_BOB(&poos[index],lpddsback);
if (poos[index].anim_state != BOB_STATE_ANIM_DONE)
{
// animate the poo
Animate_BOB2(&poos[index]);
} // end if
#if 0
bob->anim_index = 2;
bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
#endif
} break;
case POO_ANIM_STATE_BURROW:
{
// the poo is just bouncing up and down
Draw_BOB(&poos[index],lpddsback);
// animate the poo
Animate_BOB2(&poos[index]);
} break;
case POO_ANIM_STATE_INFLATING:
{
// set the position of the puffy
puffy.x = poos[index].x-12;
puffy.y = poos[index].y-20;
// compute frame offset
int frame = (poos[index].varsI[POO_INDEX_PSI_COUNT]/50);
if (frame >= 3)
{
frame = 3;
// make pop sound
if (poos[index].max_count_2==0)
{
// make pop sound
Play_Sound_From_Pool(pop_snd_ids, 4);
poos[index].max_count_2=1;
} // end if
} // end if
// set frame
puffy.curr_frame = 4*(poos[index].varsI[POO_INDEX_CURR_DIR]%2) + frame;
// draw the puffy
Draw_BOB(&puffy,lpddsback);
} break;
default:break;
} // end switch
} // end if
} // end for index
// return success
return(1);
} // end Draw_Poos
////////////////////////////////////////////////////////////////
int Start_Puff(int x, int y, int dir)
{
// this function attempts to start a puff up with the desired
// position and direction
int index; // looping index
// find an unused puff
for (index=0; index < NUM_PUFFS; index++)
{
// is puff this available
if (puffs[index].state == PUFF_STATE_DEAD)
{
// set puff up
puffs[index].state = PUFF_STATE_ALIVE;
puffs[index].varsI[PUFF_INDEX_AI_STATE] = PUFF_AI_STATE_EXPLORE;
puffs[index].varsI[PUFF_INDEX_ANIM_STATE] = PUFF_ANIM_STATE_BOUNCE;
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = dir;
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = dir;
puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] = dir;
puffs[index].varsI[PUFF_INDEX_PSI_COUNT] = 0;
puffs[index].max_count_2 = 0;
puffs[index].varsI[PUFF_INDEX_EXPLORE_COUNTER] = 2*PUFF_EXPLORE_TIME + rand()%PUFF_EXPLORE_TIME;
// reset averaging vars
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
puffs[index].varsI[PUFF_INDEX_BOUNCE_MAX] = 12 + rand()%20; // + f(level)
// general counters
puffs[index].counter_1 = 0;
puffs[index].counter_2 = 0;
// set position
puffs[index].x = x;
puffs[index].y = y;
// save for restart
puffs[index].varsI[PUFF_INDEX_SAVED_X] = x;
puffs[index].varsI[PUFF_INDEX_SAVED_Y] = y;
puffs[index].varsI[PUFF_INDEX_SAVED_DIR] = dir;
// the the current animation of puff
if (dir==DIR_LEFT || dir==DIR_UP)
{
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_LEFT);
puffs[index].varsI[PUFF_INDEX_ANIM_DIR] = DIR_LEFT;
} // end if
else
if (dir==DIR_RIGHT || dir==DIR_DOWN)
{
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_RIGHT);
puffs[index].varsI[PUFF_INDEX_ANIM_DIR] = DIR_RIGHT;
} // end if
// return success
return(1);
} // end if
} // end for index
// return failure
return(0);
} // end Start_Puff
//////////////////////////////////////////////////////////////
int Process_Puffs(void)
{
// this function processes and controls the ai for al the puffs
int index, // looping variable
pdx,pdy, // velocity
sx,sy; // sample points
static int puff_counter_1 = 0; // used to initiate random events
static char *state_names[] = {"stop","explore","chase","evade","burrow","crushed","inflating", "popped"};
// loop and process all puffs
//mono.set_cursor(0,15);
//mono.print("Puff System States");
// draw each puff
for (index=0; index < NUM_PUFFS; index++)
{
// is puff this available
if (puffs[index].state != PUFF_STATE_DEAD)
{
// sprintf(buffer,"\nPuff %d, AI State = %s, XB = %d, YB=%d, PSI = %d, count_2 = %d ",index,
// state_names[puffs[index].varsI[PUFF_INDEX_AI_STATE]],
// puffs[index].varsI[PUFF_INDEX_SUM_X],
// puffs[index].varsI[PUFF_INDEX_SUM_Y],
// puffs[index].varsI[PUFF_INDEX_PSI_COUNT],
// puffs[index].max_count_2);
// mono.print(buffer);
// test for collisions here
if (dug.state == DUG_STATE_ALIVE &&
puffs[index].varsI[PUFF_INDEX_AI_STATE] != PUFF_AI_STATE_CRUSHED &&
puffs[index].varsI[PUFF_INDEX_AI_STATE] != PUFF_AI_STATE_INFLATING)
{
if (Collision_BOBS(&dug,&puffs[index]))
{
// start the death sequence
Start_Dug_Death();
} // end if
} // end if
// test for being crushed by rock
for (int rindex=0; rindex < NUM_ROCKS; rindex++)
{
// test if rock is alive
if (rocks[rindex].state==ROCK_STATE_FALLING)
{
// rock is alive, so test for collision with puff
if (Collision_BOBS(&rocks[rindex],&puffs[index]) && puffs[index].varsI[PUFF_INDEX_AI_STATE] != PUFF_AI_STATE_CRUSHED)
{
// first reset all state information of puff
//puffs[index].state = PUFF_STATE_DYING;
puffs[index].varsI[PUFF_INDEX_AI_STATE] = PUFF_AI_STATE_CRUSHED;
puffs[index].varsI[PUFF_INDEX_ANIM_STATE] = PUFF_ANIM_STATE_CRUSHED;
// start crunch sound
Play_Sound_From_Pool(crunch_snd_ids,4);
// tag rock
puffs[index].varsI[PUFF_INDEX_OBJECT_PTR] = rindex;
// set animation
if (puffs[index].varsI[PUFF_INDEX_CURR_DIR] == DIR_RIGHT ||
puffs[index].varsI[PUFF_INDEX_CURR_DIR] == DIR_UP)
{
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_CRUSH_RIGHT);
} // end if
else
{
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_CRUSH_LEFT);
} // end if
// that's it
break;
} // end if
} // end if
} // end for rindex
// check for hit with pumps
for (int gindex=0; gindex < NUM_GPUMPS; gindex++)
{
// test if this pump is usuable
if (gpumps[gindex].state!=GPUMP_STATE_DEAD &&
puffs[index].max_count_2==0 &&
puffs[index].varsI[PUFF_INDEX_AI_STATE] != PUFF_AI_STATE_CRUSHED )
{
if (Collision_BOBS(&gpumps[gindex],&puffs[index]))
{
// kill the pump
gpumps[gindex].state=GPUMP_STATE_DEAD;
// make pump sound
Play_Sound_From_Pool(air_snd_ids, 4);
// change to inflate mode
puffs[index].varsI[PUFF_INDEX_AI_STATE] = PUFF_AI_STATE_INFLATING;
puffs[index].varsI[PUFF_INDEX_ANIM_STATE] = PUFF_ANIM_STATE_INFLATING;
if (puffs[index].varsI[PUFF_INDEX_PSI_COUNT] < 3*GPUMP_INJECTION)
{
puffs[index].varsI[PUFF_INDEX_PSI_COUNT] += (GPUMP_INJECTION-1);
if (puffs[index].varsI[PUFF_INDEX_PSI_COUNT] > 3*GPUMP_INJECTION)
puffs[index].varsI[PUFF_INDEX_PSI_COUNT] = 3*GPUMP_INJECTION;
} // end if
// this is a pump puff!
break;
} // end if
} // end if
} // end gindex
// what is the ai state of the puff
// C R U S H E D L O G I C //////////////////////////////////////////////////
if (puffs[index].varsI[PUFF_INDEX_AI_STATE] == PUFF_AI_STATE_CRUSHED)
{
// the puff is getting crushed, simple track tagged rock
puffs[index].x = rocks[puffs[index].varsI[PUFF_INDEX_OBJECT_PTR]].x;
puffs[index].y = rocks[puffs[index].varsI[PUFF_INDEX_OBJECT_PTR]].y+8;
// test if rock is complete and in crumble mode
if (rocks[puffs[index].varsI[PUFF_INDEX_OBJECT_PTR]].state==ROCK_STATE_DEAD)
{
// terminate puff
puffs[index].state = PUFF_STATE_DEAD;
// one more for the gipper
dug.varsI[DUG_INDEX_KILLS]++;
int score = 100+100*(puffs[index].y/100);
// start up score object
dug.varsI[DUG_INDEX_SCORE]+=score;
// start up score object
Start_Score(puffs[index].x+16 - 4 + rand()%8,puffs[index].y+16 - 4+rand()%8, score);
} // end if
} // end if
else
//// F I R E L O G I C /////////////////////////////////////////////////////
if (puffs[index].varsI[PUFF_INDEX_AI_STATE]==PUFF_AI_STATE_FIRE)
{
// the puff is stopped to fire
if (--puffs[index].counter_1 == 15)
{
// test for totally random shot
if ((puffs[index].varsI[PUFF_INDEX_SUM_X] >= 3) ||
(puffs[index].varsI[PUFF_INDEX_SUM_Y] >= 3) &&
((rand()%10)==1) )
{
// if up/down then fire right/left
if ((puffs[index].varsI[PUFF_INDEX_CURR_DIR]==DIR_UP) ||
(puffs[index].varsI[PUFF_INDEX_CURR_DIR]==DIR_DOWN) )
{
Start_Fball(puffs[index].x+8, puffs[index].y+2,
((rand()%2) ? (DIR_RIGHT) : (DIR_LEFT)),
rand()%2);
} // end if
else
{
// up down
Start_Fball(puffs[index].x+8, puffs[index].y+8,
((rand()%2) ? (DIR_UP) : (DIR_DOWN)),
rand()%2);
} // end else
} // end if rand
else
if ((puffs[index].varsI[PUFF_INDEX_CURR_DIR]==DIR_LEFT) ||
(puffs[index].varsI[PUFF_INDEX_CURR_DIR]==DIR_RIGHT) )
{
Start_Fball(puffs[index].x+8, puffs[index].y+2,
puffs[index].varsI[PUFF_INDEX_CURR_DIR],
rand()%2);
} // end if
else
if ((puffs[index].varsI[PUFF_INDEX_CURR_DIR]==DIR_UP) ||
(puffs[index].varsI[PUFF_INDEX_CURR_DIR]==DIR_DOWN) )
{
// vertical
Start_Fball(puffs[index].x+8, puffs[index].y+8,
puffs[index].varsI[PUFF_INDEX_CURR_DIR],
rand()%2);
} // end if
} // end if
else
if (puffs[index].counter_1 <= 0)
{
// set state back to chase
puffs[index].varsI[PUFF_INDEX_AI_STATE]=PUFF_AI_STATE_CHASE;
} // end if
} // end if
else
//// I N F L A T I O N S T A T E /////////////////////////////////////////////
if (puffs[index].varsI[PUFF_INDEX_AI_STATE]==PUFF_AI_STATE_INFLATING)
{
if (puffs[index].varsI[PUFF_INDEX_PSI_COUNT] < 3*GPUMP_INJECTION)
{
// decrease inflation
if (--puffs[index].varsI[PUFF_INDEX_PSI_COUNT] <= 0)
{
// switch to chase mode
// reset bounce counters
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
puffs[index].max_count_2 = 0;
// change modes
puffs[index].varsI[PUFF_INDEX_AI_STATE] = PUFF_AI_STATE_CHASE;
// set animation correctly
// the the current animation of puff
if (puffs[index].varsI[PUFF_INDEX_CURR_DIR]==DIR_LEFT || puffs[index].varsI[PUFF_INDEX_CURR_DIR]==DIR_UP)
{
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_LEFT);
puffs[index].varsI[PUFF_INDEX_ANIM_STATE] = PUFF_ANIM_STATE_BOUNCE;
} // end if
else
{
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_RIGHT);
puffs[index].varsI[PUFF_INDEX_ANIM_STATE] = PUFF_ANIM_STATE_BOUNCE;
} // end if
} // end if
} // end if
else
if (++puffs[index].varsI[PUFF_INDEX_PSI_COUNT] > (3*GPUMP_INJECTION + GPUMP_INJECTION/2))
{
// kill the puff
puffs[index].state = PUFF_STATE_DEAD;
puffs[index].max_count_2 = 0;
// one more for the gipper
dug.varsI[DUG_INDEX_KILLS]++;
int score = 100+100*(puffs[index].y/100);
if (dug.varsI[DUG_INDEX_DIR] == DIR_LEFT || dug.varsI[DUG_INDEX_DIR] == DIR_RIGHT)
score+=50;
// start up score object
Start_Score(puffs[index].x+16 - 4 + rand()%8,puffs[index].y+16 - 4+rand()%8,score);
dug.varsI[DUG_INDEX_SCORE]+=score;
} // end if
} // end if
else // E X P L O R E L O G I C ///////////////////////////////////////////////
if (puffs[index].varsI[PUFF_INDEX_AI_STATE]==PUFF_AI_STATE_EXPLORE)
{
// this is the general exploration ai
// test the current direction of the puff
switch(puffs[index].varsI[PUFF_INDEX_CURR_DIR])
{
case DIR_LEFT:
{
// compute velocity changes
pdx = -PUFF_SPEED;
pdy = 0;
// move puff
puffs[index].x+=pdx;
puffs[index].y+=pdy;
// compute sample position
sx = puffs[index].x;
sy = puffs[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
puffs[index].x <= 0)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_RIGHT;
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_RIGHT);
} // end if
} break;
case DIR_RIGHT:
{
// compute velocity changes
pdx = PUFF_SPEED;
pdy = 0;
// move puff
puffs[index].x+=pdx;
puffs[index].y+=pdy;
// compute sample position
sx = puffs[index].x + 31;
sy = puffs[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
puffs[index].x >= (SCREEN_WIDTH - 32))
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_LEFT;
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_LEFT);
} // end if
} break;
case DIR_UP:
{
// compute velocity changes
pdy = -PUFF_SPEED;
pdx = 0;
// move puff
puffs[index].x+=pdx;
puffs[index].y+=pdy;
// compute sample position
sx = puffs[index].x + 16;
sy = puffs[index].y;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
puffs[index].y <= (DUG_MIN_ROCK_LINE))
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_DOWN;
} // end if
} break;
case DIR_DOWN:
{
// compute velocity changes
pdy = PUFF_SPEED;
pdx = 0;
// move puff
puffs[index].x+=pdx;
puffs[index].y+=pdy;
// compute sample position
sx = puffs[index].x + 16;
sy = puffs[index].y + 31;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
puffs[index].y >= (SCREEN_HEIGHT-32))
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_UP;
} // end if
} break;
default:break;
} // end switch
// at this point the puff has moved, let's test if we can make a turn
if (puffs[index].varsI[PUFF_INDEX_CURR_DIR] == DIR_LEFT ||
puffs[index].varsI[PUFF_INDEX_CURR_DIR] == DIR_RIGHT)
{
// try for up or down turn
if (!((int)puffs[index].x % DUG_X_INTERVAL))
{
// it legal to make a turn
// select a direction
if ((rand()%2) == 1)
{
// try and turn up
sx = puffs[index].x + 16;
sy = puffs[index].y - 1;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy-2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_UP;
} // end if
}
else
{
// try and turn down
sx = puffs[index].x + 16;
sy = puffs[index].y + 32;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy+2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_DOWN;
} // end if
} // end else
} // end if
} // end if
else
if (puffs[index].varsI[PUFF_INDEX_CURR_DIR] == DIR_UP ||
puffs[index].varsI[PUFF_INDEX_CURR_DIR] == DIR_DOWN)
{
// try for up or down turn
if (!(((int)puffs[index].y + 8) % DUG_X_INTERVAL))
{
// it legal to make a turn
// select a direction
if ((rand()%2)==1)
{
// try and turn right
sx = puffs[index].x + 32;
sy = puffs[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx + 2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_RIGHT;
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_RIGHT);
} // end if
} // end if
else
{
// try and turn down
sx = puffs[index].x - 1;
sy = puffs[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx - 2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_LEFT;
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_LEFT);
} // end if
} // end else
} // end if
} // end if
// test for fire
if ( ((rand()%(200-dug.varsI[DUG_INDEX_LEVEL]))==1))
{
// set timer
puffs[index].counter_1 = 30;
// set new state
puffs[index].varsI[PUFF_INDEX_AI_STATE] = PUFF_AI_STATE_FIRE;
} // end if
// test for state exit
if (--puffs[index].varsI[PUFF_INDEX_EXPLORE_COUNTER] <=0)
{
// set state to chase
puffs[index].varsI[PUFF_INDEX_AI_STATE]=PUFF_AI_STATE_CHASE;
// reset counter
puffs[index].varsI[PUFF_INDEX_EXPLORE_COUNTER] = PUFF_EXPLORE_TIME;
} // end if
} // end if
else /// C H A S E L O G I C ///////////////////////////////////////////////////
if (puffs[index].varsI[PUFF_INDEX_AI_STATE]==PUFF_AI_STATE_CHASE)
{
int desired_taken = 0; // used to track if desired was taken
// test the current direction of the puff
switch(puffs[index].varsI[PUFF_INDEX_CURR_DIR])
{
case DIR_LEFT:
{
// compute velocity changes
pdx = -PUFF_SPEED;
pdy = 0;
// move puff
puffs[index].x+=pdx;
puffs[index].y+=pdy;
// compute sample position
sx = puffs[index].x;
sy = puffs[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
puffs[index].x <= 0)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_RIGHT;
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_RIGHT);
// increment x-axis bounce counter
puffs[index].varsI[PUFF_INDEX_SUM_X]++;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
} // end if
} break;
case DIR_RIGHT:
{
// compute velocity changes
pdx = PUFF_SPEED;
pdy = 0;
// move puff
puffs[index].x+=pdx;
puffs[index].y+=pdy;
// compute sample position
sx = puffs[index].x + 31;
sy = puffs[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
puffs[index].x >= (SCREEN_WIDTH - 32))
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_LEFT;
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_LEFT);
// increment x-axis bounce counter
puffs[index].varsI[PUFF_INDEX_SUM_X]++;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
} // end if
} break;
case DIR_UP:
{
// compute velocity changes
pdy = -PUFF_SPEED;
pdx = 0;
// move puff
puffs[index].x+=pdx;
puffs[index].y+=pdy;
// compute sample position
sx = puffs[index].x + 16;
sy = puffs[index].y;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
puffs[index].y <= (DUG_MIN_ROCK_LINE))
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_DOWN;
// increment y-axis bounce counter
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y]++;
} // end if
} break;
case DIR_DOWN:
{
// compute velocity changes
pdy = PUFF_SPEED;
pdx = 0;
// move puff
puffs[index].x+=pdx;
puffs[index].y+=pdy;
// compute sample position
sx = puffs[index].x + 16;
sy = puffs[index].y + 31;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)!=COLOR_INDEX_HOLE ||
puffs[index].y >= (SCREEN_HEIGHT-32))
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_UP;
// increment y-axis bounce counter
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y]++;
} // end if
} break;
default:break;
} // end switch
// at this point the puff has moved, let's test if we can make a turn
// compute the desired new direction
// compute dx and dy
int dx = dug.x - puffs[index].x;
int dy = dug.y - puffs[index].y;
// decide which way we want to go
if (abs(dx) > abs(dy))
{
// set primary desired direction to minimize dx
if (dx > 0)
puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] = DIR_RIGHT;
else
puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] = DIR_LEFT;
// set secondary direction only if delta is > 16
if (abs(dy) > 16)
{
if (dy > 0)
puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] = DIR_DOWN;
else
puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] = DIR_UP;
} // end if
else
puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] = DIR_NULL;
} // end if
else
{
// set primary desired direction to minimize dy
if (dy > 0)
puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] = DIR_DOWN;
else
puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] = DIR_UP;
// set secondary desired direction to minimize dx, only if dx > 16
if (abs(dx) > 16)
{
if (dx > 0)
puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] = DIR_RIGHT;
else
puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] = DIR_LEFT;
} // end if
else
puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] = DIR_NULL;
} // end if
// once in a blue moon swap primary and secondary
if ((rand()%10)==1)
{
// swap
int temp = puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR];
puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] = puffs[index].varsI[PUFF_INDEX_DESIRED_DIR];
puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] = temp;
} // end if
// make sure we don't want to go the same way
if ( (puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] >> 1) != (puffs[index].varsI[PUFF_INDEX_CURR_DIR] >> 1))
{
// test for desired right turn
if (puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] == DIR_RIGHT &&
!(((int)puffs[index].y+8) % DUG_X_INTERVAL))
{
// try and turn up
sx = puffs[index].x + 32;
sy = puffs[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx+2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_RIGHT;
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_RIGHT);
// set taken flag
desired_taken = 1;
// reset bounce counters
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
} // end if
} // end if
// test for desired right turn
else
if (puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] == DIR_LEFT &&
!(((int)puffs[index].y+8) % DUG_X_INTERVAL))
{
// try and turn up
sx = puffs[index].x - 1;
sy = puffs[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx - 2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_LEFT;
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_LEFT);
// set taken flag
desired_taken = 1;
// reset bounce counters
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
} // end if
} // end if
else
if (puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] == DIR_UP &&
!(((int)puffs[index].x) % DUG_X_INTERVAL))
{
// try and turn up
sx = puffs[index].x + 16;
sy = puffs[index].y - 1;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy - 2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_UP;
// set taken flag
desired_taken = 1;
// reset bounce counters
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
} // end if
} // end if
else
if (puffs[index].varsI[PUFF_INDEX_DESIRED_DIR] == DIR_DOWN &&
!(((int)puffs[index].x) % DUG_X_INTERVAL))
{
// try and turn up
sx = puffs[index].x + 16;
sy = puffs[index].y + 32;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy+2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_DOWN;
// set taken flag
desired_taken = 1;
// reset bounce counters
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
} // end if
} // end if
} // end if primary valid
///////////////////////////////////////////////////////////////////////
// test for secondary turns
if (!desired_taken &&
(puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR]!=DIR_NULL) &&
(puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] >> 1) != (puffs[index].varsI[PUFF_INDEX_CURR_DIR] >> 1) )
{
// test for desired right turn
if (puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] == DIR_RIGHT &&
!(((int)puffs[index].y+8) % DUG_X_INTERVAL))
{
// try and turn up
sx = puffs[index].x + 32;
sy = puffs[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx+2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_RIGHT;
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_RIGHT);
// set taken flag
desired_taken = 1;
// reset bounce counters
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
} // end if
} // end if
// test for desired right turn
else
if (puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] == DIR_LEFT &&
!(((int)puffs[index].y+8) % DUG_X_INTERVAL))
{
// try and turn up
sx = puffs[index].x - 1;
sy = puffs[index].y + 16;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx - 2,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_LEFT;
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_LEFT);
// set taken flag
desired_taken = 1;
// reset bounce counters
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
} // end if
} // end if
else
if (puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] == DIR_UP &&
!(((int)puffs[index].x) % DUG_X_INTERVAL))
{
// try and turn up
sx = puffs[index].x + 16;
sy = puffs[index].y - 1;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy - 2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_UP;
// set taken flag
desired_taken = 1;
} // end if
} // end if
else
if (puffs[index].varsI[PUFF_INDEX_2ND_DESIRED_DIR] == DIR_DOWN &&
!(((int)puffs[index].x) % DUG_X_INTERVAL))
{
// try and turn up
sx = puffs[index].x + 16;
sy = puffs[index].y + 32;
// check for collision
if (Get_Pixel(sx,sy,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE &&
Get_Pixel(sx,sy+2,background_bmp.buffer, background_bmp.width)==COLOR_INDEX_HOLE)
{
// reverse the direction of motion
puffs[index].varsI[PUFF_INDEX_LAST_DIR] = puffs[index].varsI[PUFF_INDEX_CURR_DIR];
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_DOWN;
// set taken flag
desired_taken = 1;
// reset bounce counters
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
} // end if
} // end if
} // end else 2nd desired
// test for global randomness ////////////////////////////////////////////////////
if (++puff_counter_1 > 200)
puff_counter_1 = 0;
// test for random event
if ((puff_counter_1 == 0) &&
((rand()%3)==1) &&
(Fast_Distance(puffs[index].x-dug.x, puffs[index].y-dug.y) > 300))
{
// reverse direction
switch(puffs[index].varsI[PUFF_INDEX_CURR_DIR])
{
case DIR_LEFT:
{
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_RIGHT;
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_RIGHT);
} break;
case DIR_RIGHT:
{
puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_LEFT;
// set new animation
Set_Animation_BOB2(&puffs[index],PUFF_ANIM_BOUNCE_LEFT);
} break;
case DIR_UP: puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_DOWN; break;
case DIR_DOWN: puffs[index].varsI[PUFF_INDEX_CURR_DIR] = DIR_UP; break;
default:break;
} // end switch
} // end if
///////////////////////////////////////////////////////////////////////////
// test for pre-emptive state transitions
if (puffs[index].varsI[PUFF_INDEX_SUM_X] > 3 || puffs[index].varsI[PUFF_INDEX_SUM_Y] > 3)
{
// reset bounce counters
puffs[index].varsI[PUFF_INDEX_SUM_X] = 0;
puffs[index].varsI[PUFF_INDEX_SUM_Y] = 0;
// change modes
puffs[index].varsI[PUFF_INDEX_AI_STATE] = PUFF_AI_STATE_EXPLORE;
puffs[index].varsI[PUFF_INDEX_EXPLORE_COUNTER] = (PUFF_EXPLORE_TIME >> 2) + (rand()%PUFF_EXPLORE_TIME);
} // end if
// test for weapons fire, add in level here for prob
if (
//(puffs[index].varsI[PUFF_INDEX_CURR_DIR] == DIR_LEFT || puffs[index].varsI[PUFF_INDEX_CURR_DIR] == DIR_RIGHT) &&
((rand()%(100-dug.varsI[DUG_INDEX_LEVEL]))==1))
// && (Fast_Distance(dug.x - puffs[index].x,dug.y - puffs[index].y) < 300))
{
// set timer
puffs[index].counter_1 = 30;
// set new state
puffs[index].varsI[PUFF_INDEX_AI_STATE] = PUFF_AI_STATE_FIRE;
} // end if
} // end if chase
else //////////////////////////////////////////////////////////////////////////
if (puffs[index].varsI[PUFF_INDEX_AI_STATE]==PUFF_AI_STATE_EVADE)
{
} // end if
else /////////////////////////////////////////////////////////////////////////
if (puffs[index].varsI[PUFF_INDEX_AI_STATE]==PUFF_AI_STATE_BURROW)
{
} // end if
} // end if alive
} // end for index
// return success
return(1);
} // end Process_Puffs
///////////////////////////////////////////////////////////////
int Draw_Puffs(void)
{
// this function animates and draws all the puffs
int index; // looping index
// draw each puff
for (index=0; index < NUM_PUFFS; index++)
{
// is puff this available
if (puffs[index].state != PUFF_STATE_DEAD)
{
// what is the animation state?
switch(puffs[index].varsI[PUFF_INDEX_ANIM_STATE])
{
case PUFF_ANIM_STATE_BOUNCE:
{
// the puff is just bouncing up and down
Draw_BOB(&puffs[index],lpddsback);
// animate the puff
Animate_BOB(&puffs[index]);
} break;
case PUFF_ANIM_STATE_CRUSHED:
{
// draw the puff
Draw_BOB(&puffs[index],lpddsback);
if (puffs[index].anim_state != BOB_STATE_ANIM_DONE)
{
// animate the puff
Animate_BOB2(&puffs[index]);
} // end if
} break;
case PUFF_ANIM_STATE_BURROW:
{
// the puff is just bouncing up and down
Draw_BOB(&puffs[index],lpddsback);
// animate the puff
Animate_BOB(&puffs[index]);
} break;
case PUFF_ANIM_STATE_INFLATING:
{
// set the position of the puffy
puffy.x = puffs[index].x-12;
puffy.y = puffs[index].y-20;
// compute frame offset
int frame = (puffs[index].varsI[PUFF_INDEX_PSI_COUNT]/50);
if (frame >= 3)
{
frame = 3;
// make pop sound
if (puffs[index].max_count_2==0)
{
// make pop sound
Play_Sound_From_Pool(pop_snd_ids, 4);
puffs[index].max_count_2=1;
} // end if
} // end if
// set frame
puffy.curr_frame = 8+4*(puffs[index].varsI[PUFF_INDEX_CURR_DIR]%2) + frame;
// draw the puffy
Draw_BOB(&puffy,lpddsback);
} break;
default:break;
} // end switch
} // end if
} // end for index
// return success
return(1);
} // end Draw_Puffs
///////////////////////////////////////////////////////////////
int Start_Score(int x, int y, int score)
{
// this function starts a score at the given position and direction
// scan for an unused pump
for (int index=0; index < NUM_SCORES; index++)
{
// test if this score is usuable
if (scores[index].state==SCORE_OFF)
{
// set the score up
scores[index].state = SCORE_ON;
scores[index].x = x-16;
scores[index].y = y-16;
scores[index].max_count_1 = SCORE_DISPLAY_COUNT + rand()%25;
scores[index].counter_1 = 0;
// select proper frame
if (score < 1000)
scores[index].curr_frame = (score/100 - 1);
else
scores[index].curr_frame = ((score % 11000)/1000) + 8;
// return success
return(1);
} // end if
} // end for index
// return failure
return(0);
} // end Start_Score
///////////////////////////////////////////////////////////////
int Process_Scores(void)
{
// this functions processes all the scores
// process all pumps
for (int index=0; index < NUM_SCORES; index++)
{
// test if this score is usuable
if (scores[index].state!=SCORE_OFF)
{
// decrement counter
if (++scores[index].counter_1 > scores[index].max_count_1)
{
// kill score
scores[index].state=SCORE_OFF;
} // end if
// move a bit
if (scores[index].counter_1 > SCORE_DISPLAY_COUNT/2)
scores[index].y--;
} // end if alive
} // end for index
// return sucess
return(1);
} // end Process_Scores
////////////////////////////////////////////////////////////////
int Draw_Scores(void)
{
// this function draws and animates all the scores
// process all scores
for (int index=0; index < NUM_SCORES; index++)
{
// test if this scores is usuable
if (scores[index].state!=SCORE_OFF)
{
// draw the bob
Draw_BOB(&scores[index], lpddsback);
} // end if
} // end for index
// return sucess
return(1);
} // end Draw_Scores
////////////////////////////////////////////////////////
void Start_Dug_Death(void)
{
// this function starts the death sequence for the dug
int index; // looping index
// set initial animation sequence
Set_Animation_BOB2(&dug, DUG_ANIM_DEATH);
Set_Anim_Speed_BOB(&dug, 5);
// change states
dug.state = DUG_STATE_DYING;
dug.anim_state = 0;
// start sound
Play_Sound(dug_die_snd_id);
// reset all creatures to explore mode
for (index=0; index < NUM_POOS; index++)
{
// is poo this available
if (poos[index].state != POO_STATE_DEAD &&
poos[index].varsI[POO_INDEX_AI_STATE] != POO_AI_STATE_BURROW &&
poos[index].varsI[POO_INDEX_AI_STATE] != POO_AI_STATE_INFLATING)
{
// set state to explore
poos[index].varsI[POO_INDEX_AI_STATE] = POO_AI_STATE_EXPLORE;
poos[index].varsI[POO_INDEX_ANIM_STATE] = POO_ANIM_STATE_BOUNCE;
// set animation
if (poos[index].varsI[POO_INDEX_CURR_DIR] == DIR_RIGHT ||
poos[index].varsI[POO_INDEX_CURR_DIR] == DIR_UP)
{
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_RIGHT);
} // end if
else
{
// set new animation
Set_Animation_BOB2(&poos[index],POO_ANIM_BOUNCE_LEFT);
} // end if
// reset counters
poos[index].varsI[POO_INDEX_EXPLORE_COUNTER] = POO_EXPLORE_TIME + (rand()%POO_EXPLORE_TIME);
poos[index].varsI[POO_INDEX_SUM_X] = 0;
poos[index].varsI[POO_INDEX_SUM_Y] = 0;
} // end if
} // end for index
// add in dragon stuff
} // end Start_Dug_Death
// WINX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
int Game_Init(void *parms)
{
// this function is where you do all the initialization
// for your game
int index; // looping var
char filename[80]; // used to build up files names
//mono.clear();
//mono.print("\ndebugger on-line\n");
// open the error file
Open_Error_File("Error.dat");
screen_width = 640;
screen_height = 480;
screen_bpp = 8;
// start up DirectDraw (replace the parms as you desire)
DD_Init(screen_width, screen_height, screen_bpp);
// let user knows whats up
Draw_Text_GDI("L O A D I N G . . .",
(SCREEN_WIDTH/2) - 3*strlen("L O A D I N G . . ."),
(SCREEN_HEIGHT/2 - 32),
RGB(0,0,255),lpddsprimary);
// initialize directsound
DSound_Init();
// initialize Directinput
DInput_Init();
// initialize all input devices
DI_Init_Keyboard();
DI_Init_Joystick(-16,16,-16,16);
DI_Init_Mouse();
// load all the sound and music
Load_Sound_Music();
// LOAD BACKGROUND ////////////////////////////////////////////
// create background image
Create_Bitmap(&background_bmp,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
// LOAD DUG ///////////////////////////////////////////////////
// load master dug bitmap
Load_Bitmap_File(&bitmap8bit, "UNDART/UNDDUMB.BMP");
// set the palette to background image palette
Set_Palette(bitmap8bit.palette);
// let user knows whats up
Draw_Text_GDI("L O A D I N G . . .",
(SCREEN_WIDTH/2) - 3*strlen("L O A D I N G . . ."),
(SCREEN_HEIGHT/2 - 32),
RGB(0,255,0),lpddsprimary);
// fix the hole
bitmap8bit.palette[COLOR_INDEX_HOLE].peRed = 0;
bitmap8bit.palette[COLOR_INDEX_HOLE].peGreen = 0;
bitmap8bit.palette[COLOR_INDEX_HOLE].peBlue = 0;
Set_Palette_Entry(COLOR_INDEX_HOLE,&bitmap8bit.palette[COLOR_INDEX_HOLE]);
// create dug bob
Create_BOB(&dug,0,0,32,32,44,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM,
DDSCAPS_SYSTEMMEMORY);
// load frames for left, right, up down, (walk, dig, fire)
for (index=0; index < 32; index++)
Load_Frame_BOB(&dug,&bitmap8bit,index,index%8,2+index/8,BITMAP_EXTRACT_MODE_CELL);
// death sequence on last row
for (index=32; index < 44; index++)
Load_Frame_BOB(&dug,&bitmap8bit,index,(index-32),6,BITMAP_EXTRACT_MODE_CELL);
// load animations
// left
Load_Animation_BOB(&dug,0,4,dug_anims[0]);
Load_Animation_BOB(&dug,1,4,dug_anims[1]);
Load_Animation_BOB(&dug,2,2,dug_anims[2]);
// right
Load_Animation_BOB(&dug,3,4,dug_anims[3]);
Load_Animation_BOB(&dug,4,4,dug_anims[4]);
Load_Animation_BOB(&dug,5,2,dug_anims[5]);
// up
Load_Animation_BOB(&dug,6,4,dug_anims[6]);
Load_Animation_BOB(&dug,7,4,dug_anims[7]);
Load_Animation_BOB(&dug,8,2,dug_anims[8]);
// down
Load_Animation_BOB(&dug,9,4,dug_anims[9]);
Load_Animation_BOB(&dug,10,4,dug_anims[10]);
Load_Animation_BOB(&dug,11,2,dug_anims[11]);
// death
Load_Animation_BOB(&dug,12,10,dug_anims[12]);
Load_Animation_BOB(&dug,13,8,dug_anims[13]);
// crushing
Load_Animation_BOB(&dug,14,3,dug_anims[14]);
// initialize state variables in register file
dug.varsI[DUG_INDEX_SCORE] = 0;
dug.varsI[DUG_INDEX_LIVES] = 3;
dug.varsI[DUG_INDEX_LEVEL] = 1;
dug.varsI[DUG_INDEX_DAMAGE] = 0;
dug.varsI[DUG_INDEX_KILLS] = 0;
dug.varsI[DUG_INDEX_PUMP_PSI] = 0;
dug.varsI[DUG_INDEX_ANIM_MODE] = DUG_ANIM_WALK;
// set state to alive
dug.state = DUG_STATE_ALIVE;
// set direction to left
dug.varsI[DUG_INDEX_DIR] = DIR_LEFT;
// set initial animation sequence
Set_Animation_BOB2(&dug, DUG_ANIM_WALK + dug.varsI[DUG_INDEX_DIR]*3);
// set position
Set_Pos_BOB(&dug,320,32);
// set animation speed
Set_Anim_Speed_BOB(&dug,3);
// make demo clone
Clone_BOBX(&dug,&dug_demo);
// create digging holes
for (index=0; index < 10; index++)
{
// create the hole bitmap
Create_Bitmap(&dug_holes[index],0,0,32,32);
// scan it out
Load_Image_Bitmap(&dug_holes[index],&bitmap8bit,index,10,BITMAP_EXTRACT_MODE_CELL);
} // end for index
// LOAD MUSHROOMS //////////////////////////////////////////
// create mushroom bob
Create_BOB(&mushroom,0,0,32,32,2,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,
DDSCAPS_SYSTEMMEMORY);
// load frames for small and big
for (index=0; index < 2; index++)
Load_Frame_BOB(&mushroom,&bitmap8bit,index,index,8,BITMAP_EXTRACT_MODE_CELL);
// LOAD ROCKS ///////////////////////////////////////////////
// create master rock bob
Create_BOB(&rocks[0],0,0,32,32,5,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,
DDSCAPS_SYSTEMMEMORY);
// set state to dead
rocks[0].state = ROCK_STATE_DEAD;
// set animation speed
Set_Anim_Speed_BOB(&rocks[0],3);
// load frames in
for (index=0; index < 5; index++)
Load_Frame_BOB(&rocks[0],&bitmap8bit,index,index,9,BITMAP_EXTRACT_MODE_CELL);
// now clone bob
for (index=1; index<NUM_ROCKS; index++)
{
// clone the bob
Clone_BOBX(&rocks[0], &rocks[index]);
} // end for index
// LOAD THE POOS ////////////////////////////////////////////////
// create master poo bob
Create_BOB(&poos[0],0,0,32,32,11,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM,
DDSCAPS_SYSTEMMEMORY);
// set state to dead
poos[0].state = POO_STATE_DEAD;
// set animation speed
Set_Anim_Speed_BOB(&poos[0],6);
// load animations in
Load_Animation_BOB(&poos[0],POO_ANIM_BOUNCE_LEFT, 2,poo_anims[0]);
Load_Animation_BOB(&poos[0],POO_ANIM_BOUNCE_RIGHT,2,poo_anims[1]);
Load_Animation_BOB(&poos[0],POO_ANIM_CRUSH_LEFT, 2,poo_anims[2]);
Load_Animation_BOB(&poos[0],POO_ANIM_CRUSH_RIGHT, 2,poo_anims[3]);
Load_Animation_BOB(&poos[0],POO_ANIM_BURROW, 4,poo_anims[4]);
// set current animation
Set_Animation_BOB2(&poos[0], POO_ANIM_BOUNCE_LEFT);
// load frames in
for (index=0; index < 11; index++)
Load_Frame_BOB(&poos[0],&bitmap8bit,index,index,1,BITMAP_EXTRACT_MODE_CELL);
// now clone bob
for (index=1; index < NUM_POOS; index++)
{
// clone the bob
Clone_BOBX(&poos[0], &poos[index]);
// load animations in
Load_Animation_BOB(&poos[index],POO_ANIM_BOUNCE_LEFT, 2,poo_anims[0]);
Load_Animation_BOB(&poos[index],POO_ANIM_BOUNCE_RIGHT,2,poo_anims[1]);
Load_Animation_BOB(&poos[index],POO_ANIM_CRUSH_LEFT, 2,poo_anims[2]);
Load_Animation_BOB(&poos[index],POO_ANIM_CRUSH_RIGHT, 2,poo_anims[3]);
Load_Animation_BOB(&poos[index],POO_ANIM_BURROW, 4,poo_anims[4]);
// set current animation
Set_Animation_BOB2(&poos[index], POO_ANIM_BOUNCE_LEFT);
} // end for index
// make demo clone
Clone_BOBX(&poos[0], &poo_demo);
// LOAD THE PUFFS ////////////////////////////////////////////////
// create master puff bob
Create_BOB(&puffs[0],0,0,32,32,13,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM,
DDSCAPS_SYSTEMMEMORY);
// set state to dead
puffs[0].state = PUFF_STATE_DEAD;
// set animation speed
Set_Anim_Speed_BOB(&puffs[0],4);
// load animations in
Load_Animation_BOB(&puffs[0],PUFF_ANIM_BOUNCE_LEFT, 4,puff_anims[0]);
Load_Animation_BOB(&puffs[0],PUFF_ANIM_BOUNCE_RIGHT,4,puff_anims[1]);
Load_Animation_BOB(&puffs[0],PUFF_ANIM_CRUSH_LEFT, 2,puff_anims[2]);
Load_Animation_BOB(&puffs[0],PUFF_ANIM_CRUSH_RIGHT, 2,puff_anims[3]);
Load_Animation_BOB(&puffs[0],PUFF_ANIM_BURROW, 4,puff_anims[4]);
// set current animation
Set_Animation_BOB2(&puffs[0], PUFF_ANIM_BOUNCE_LEFT);
// load frames in
for (index=0; index < 13; index++)
Load_Frame_BOB(&puffs[0],&bitmap8bit,index,index,0,BITMAP_EXTRACT_MODE_CELL);
// now clone bob
for (index=1; index < NUM_PUFFS; index++)
{
// clone the bob
Clone_BOBX(&puffs[0], &puffs[index]);
// load animations in
Load_Animation_BOB(&puffs[index],PUFF_ANIM_BOUNCE_LEFT, 4,puff_anims[0]);
Load_Animation_BOB(&puffs[index],PUFF_ANIM_BOUNCE_RIGHT,4,puff_anims[1]);
Load_Animation_BOB(&puffs[index],PUFF_ANIM_CRUSH_LEFT, 2,puff_anims[2]);
Load_Animation_BOB(&puffs[index],PUFF_ANIM_CRUSH_RIGHT, 2,puff_anims[3]);
Load_Animation_BOB(&puffs[index],PUFF_ANIM_BURROW, 4,puff_anims[4]);
// set current animation
Set_Animation_BOB2(&puffs[index], PUFF_ANIM_BOUNCE_LEFT);
} // end for index
// make demo clone
Clone_BOBX(&puffs[0], &puff_demo);
// LOAD SCORE BITMAPS ///////////////////////////////////////////
// create master score
Create_BOB(&scores[0],0,0,32,32,19,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,
DDSCAPS_SYSTEMMEMORY);
//set state to off
scores[0].state = SCORE_OFF;
// load frames in
for (index=0; index < 19; index++)
Load_Frame_BOB(&scores[0],&bitmap8bit,index,index,11,BITMAP_EXTRACT_MODE_CELL);
// now clone bob
for (index=1; index < NUM_SCORES; index++)
{
// clone the bob
Clone_BOBX(&scores[0], &scores[index]);
} // end for index
// unload master bitmap file
Unload_Bitmap_File(&bitmap8bit);
// LOAD WEAPONS /////////////////////////////////////////////
// load object bitmap
Load_Bitmap_File(&bitmap8bit, "UNDART/UNDOBJ.BMP");
// fireballs
// create master fireball
Create_BOB(&fballs[0],0,0,16,16,16,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM ,
DDSCAPS_SYSTEMMEMORY);
// set state of gpump
fballs[0].state = FBALL_STATE_DEAD;
// load the animations in
Load_Animation_BOB(&fballs[0],FBALL_ANIM_RED_FLY, 5,fball_anims[0]);
Load_Animation_BOB(&fballs[0],FBALL_ANIM_RED_EXPLODE, 3,fball_anims[1]);
Load_Animation_BOB(&fballs[0],FBALL_ANIM_GREEN_FLY, 5,fball_anims[2]);
Load_Animation_BOB(&fballs[0],FBALL_ANIM_GREEN_EXPLODE,3,fball_anims[3]);
// set animation speed
Set_Anim_Speed_BOB(&fballs[0],4);
// load frames in
for (index=0; index < 16; index++)
Load_Frame_BOB(&fballs[0],&bitmap8bit,index,index%8,index/8,BITMAP_EXTRACT_MODE_CELL);
// now clone bob
for (index=1; index < NUM_FBALLS; index++)
{
// clone the bob
Clone_BOBX(&fballs[0], &fballs[index]);
// load the animation in
// cloning doesn't clone animation, sorry!
Load_Animation_BOB(&fballs[index],FBALL_ANIM_RED_FLY, 5,fball_anims[0]);
Load_Animation_BOB(&fballs[index],FBALL_ANIM_RED_EXPLODE, 3,fball_anims[1]);
Load_Animation_BOB(&fballs[index],FBALL_ANIM_GREEN_FLY, 5,fball_anims[2]);
Load_Animation_BOB(&fballs[index],FBALL_ANIM_GREEN_EXPLODE,3,fball_anims[3]);
} // end for index
// create fireball holes
for (index=0; index < NUM_FBLASTS; index++)
{
// create the hole bitmap
Create_Bitmap(&fblasts[index],0,0,16,16);
// scan it out
Load_Image_Bitmap(&fblasts[index],&bitmap8bit,8+index,0,BITMAP_EXTRACT_MODE_CELL);
} // end for index
// pumps
// create master pump
Create_BOB(&gpumps[0],0,0,16,16,12,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM ,
DDSCAPS_SYSTEMMEMORY);
// set state of gpump
gpumps[0].state = GPUMP_STATE_DEAD;
// load the animations in
Load_Animation_BOB(&gpumps[0],0,4,gpump_anims[0]);
Load_Animation_BOB(&gpumps[0],1,4,gpump_anims[1]);
Load_Animation_BOB(&gpumps[0],2,4,gpump_anims[2]);
Load_Animation_BOB(&gpumps[0],3,4,gpump_anims[3]);
// set animation speed
Set_Anim_Speed_BOB(&gpumps[0],4);
// load frames in
for (index=0; index < 12; index++)
Load_Frame_BOB(&gpumps[0],&bitmap8bit,index,index,2,BITMAP_EXTRACT_MODE_CELL);
// now clone bob
for (index=1; index < NUM_GPUMPS; index++)
{
// clone the bob
Clone_BOBX(&gpumps[0], &gpumps[index]);
// load the animation in
// cloning doesn't clone animation, sorry!
Load_Animation_BOB(&gpumps[index],0,3,gpump_anims[0]);
Load_Animation_BOB(&gpumps[index],1,3,gpump_anims[1]);
Load_Animation_BOB(&gpumps[index],2,3,gpump_anims[2]);
Load_Animation_BOB(&gpumps[index],3,3,gpump_anims[3]);
} // end for index
// create small dug bob
Create_BOB(&small_dug,0,0,16,16,1,
BOB_ATTR_VISIBLE | BOB_ATTR_SINGLE_FRAME,
DDSCAPS_SYSTEMMEMORY);
// load in small dug
Load_Frame_BOB(&small_dug,&bitmap8bit,0,0,3,BITMAP_EXTRACT_MODE_CELL);
// unload object bitmap
Unload_Bitmap_File(&bitmap8bit);
// L O A D P U F F Y V E R S I O N S ////////////////////////
// load object bitmap
Load_Bitmap_File(&bitmap8bit, "UNDART/UNDBLOW8.BMP");
// create master fireball
Create_BOB(&puffy,0,0,56,56,16,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME ,
DDSCAPS_SYSTEMMEMORY);
// load frames in
for (index=0; index < 16; index++)
Load_Frame_BOB(&puffy,&bitmap8bit,index,index%4,index/4,BITMAP_EXTRACT_MODE_CELL);
// create andre image
Create_Bitmap(&andre,320-32,260,56,56);
Load_Image_Bitmap(&andre,&bitmap8bit,0,4,BITMAP_EXTRACT_MODE_CELL);
// unload object bitmap
Unload_Bitmap_File(&bitmap8bit);
// LOAD PRIZES /////////////////////////////////////////////
// load prize bitmap
Load_Bitmap_File(&bitmap8bit, "UNDART/UNDCASH.BMP");
for (index=0; index < NUM_PRIZES; index++)
{
// create and load all the prizes
Create_BOB(&prizes[index],280,232,32,32,8,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,
DDSCAPS_SYSTEMMEMORY);
// set animation speed
Set_Anim_Speed_BOB(&prizes[index],3);
// set prize value in varsI[1]
prizes[index].varsI[1] = (index+1)*1000;
// load in prize frame
for (int frame=0; frame < 8; frame++)
Load_Frame_BOB(&prizes[index],&bitmap8bit,frame,frame,index,BITMAP_EXTRACT_MODE_CELL);
} // end for index
// unload object bitmap
Unload_Bitmap_File(&bitmap8bit);
// LOAD MENU bitmaps /////////////////////////////////////////
// create background image
Create_Bitmap(&menu_bmp,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
// load image
Load_Bitmap_File(&bitmap8bit, "UNDART/UNDMENU8.BMP");
// scan image into bitmap
Load_Image_Bitmap(&menu_bmp,&bitmap8bit,0,0,BITMAP_EXTRACT_MODE_ABS);
// unload object bitmap
Unload_Bitmap_File(&bitmap8bit);
// LOAD TORCHES /////////////////////////////////////////////
// load image
Load_Bitmap_File(&bitmap8bit, "UNDART/UNDFIRE8.BMP");
// create mushroom bob
Create_BOB(&torch,0,0,88,88,6,
BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,
DDSCAPS_SYSTEMMEMORY);
// set animation speed
Set_Anim_Speed_BOB(&torch,3);
// load frames for torch
for (index=0; index < 6; index++)
Load_Frame_BOB(&torch,&bitmap8bit,index,index,0,BITMAP_EXTRACT_MODE_CELL);
// unload object bitmap
Unload_Bitmap_File(&bitmap8bit);
// LOAD FONT ////////////////////////////////////////////////
// load image
Load_Bitmap_File(&bitmap8bit, "UNDART/UNDFONT8.BMP");
// create font bitmaps
for (index=0; index < FONT_NUM_CHARS; index++)
{
// create the font bitmap
Create_Bitmap(&font[index],0,0,16,16);
// scan it out
Load_Image_Bitmap(&font[index],&bitmap8bit,index%16,index/16,BITMAP_EXTRACT_MODE_CELL);
} // end for index
// unload object bitmap
Unload_Bitmap_File(&bitmap8bit);
///////////////////////////////////////////////////////////////
// set clipping rectangle to screen extents so objects dont
// mess up at edges
RECT screen_rect = {0,0,screen_width,screen_height};
lpddclipper = DD_Attach_Clipper(lpddsback,1,&screen_rect);
// seed random number generate
srand(Start_Clock());
// load all the levels in
if (!Load_Levels("UNDLEV.DAT"))
{
// file is jacked up
MessageBox(main_window_handle,
"Level File 'UNDLEV.DAT' -- Data Invalid or Corrupt.",
"DigDumb Startup Error",
MB_ICONERROR);
// get out of here
PostMessage(main_window_handle, WM_DESTROY,0,0);
return(0);
} // end if
// hide the mouse
ShowCursor(FALSE);
// return success
return(1);
} // end Game_Init
///////////////////////////////////////////////////////////
int Game_Reset(void)
{
// this function resets all the system variables in preparation to run a level
int index; // looping counter
// reset number of levels
num_creatures_on_level = 0;
// reset end level counter
end_level_counter = 0;
// reset radiation level
radiation_message_played = 0;
// reset dug
dug.varsI[DUG_INDEX_DAMAGE] = 0;
dug.varsI[DUG_INDEX_PUMP_PSI] = 100;
dug.varsI[DUG_INDEX_KILLS] = 0;
dug.varsI[DUG_INDEX_ANIM_MODE] = DUG_ANIM_WALK;
// set state to alive
dug.state = DUG_STATE_ALIVE;
// set direction to left
dug.varsI[DUG_INDEX_DIR] = DIR_LEFT;
// set initial animation sequence
Set_Animation_BOB2(&dug, DUG_ANIM_WALK + dug.varsI[DUG_INDEX_DIR]*3);
// set position
Set_Pos_BOB(&dug,320,32);
// set animation speed
Set_Anim_Speed_BOB(&dug,3);
// reset poos
for (index=0; index < NUM_POOS; index++)
{
poos[index].state = POO_STATE_DEAD;
} // end for index
// reset puffs
for (index=0; index < NUM_PUFFS; index++)
{
puffs[index].state = PUFF_STATE_DEAD;
} // end for index
// reset scores
for (index=0; index < NUM_SCORES; index++)
{
// test if this score is usuable
scores[index].state = SCORE_OFF;
} // end for index
// reset gpumps
for (index=0; index < NUM_GPUMPS; index++)
{
// test if this pump is usuable
gpumps[index].state = GPUMP_STATE_DEAD;
} // end for index
// reset gpumps
for (index=0; index < NUM_ROCKS; index++)
{
// is this rock dead?
rocks[index].state = ROCK_STATE_DEAD;
} // end if
// reset fire balls
for (index=0; index < NUM_FBALLS; index++)
{
// test if this fire ball is usuable
fballs[index].state=FBALL_STATE_DEAD;
} // end if
// reset the prize
prizes[0].state = PRIZE_STATE_OFF;
// return
return(1);
} // end Game_Reset
///////////////////////////////////////////////////////////
int Game_Shutdown(void *parms)
{
// this function is where you shutdown your game and
// release all resources that you allocated
int index; // looping variable
// kill individual bobs
Destroy_BOBX(&dug);
Destroy_BOBX(&small_dug);
Destroy_BOBX(&puffy);
Destroy_BOBX(&mushroom);
Destroy_BOBX(&torch);
Destroy_BOBX(&dug_demo);
Destroy_BOBX(&poo_demo);
Destroy_BOBX(&puff_demo);
// kill rocks
for (index=0; index<NUM_ROCKS; index++)
Destroy_BOBX(&rocks[index]);
// kill puffs
for (index=0; index < NUM_PUFFS; index++)
Destroy_BOBX(&puffs[index]);
// kill poos
for (index=0; index < NUM_POOS; index++)
Destroy_BOBX(&poos[index]);
// kill prizes
for (index=0; index<NUM_PRIZES; index++)
Destroy_BOBX(&prizes[index]);
// kill weapons
for (index=0; index<NUM_GPUMPS; index++)
Destroy_BOBX(&gpumps[index]);
for (index=0; index<NUM_FBALLS; index++)
Destroy_BOBX(&fballs[index]);
// kill holes
for (index=0; index<NUM_HOLE_BITMAPS; index++)
Destroy_Bitmap(&dug_holes[index]);
// kill font
for (index=0; index<FONT_NUM_CHARS; index++)
Destroy_Bitmap(&font[index]);
// kill scores
for (index=0; index<NUM_SCORES; index++)
Destroy_BOBX(&scores[index]);
// kill all bitmaps
Destroy_Bitmap(&background_bmp);
Destroy_Bitmap(&menu_bmp);
Destroy_Bitmap(&andre);
// shutdown directdraw
DD_Shutdown();
// unload sounds
Delete_All_Sounds();
// shutdown directsound
DSound_Shutdown();
// release all input devices
DI_Release_Keyboard();
DI_Release_Joystick();
DI_Release_Mouse();
// close the error file
Close_Error_File();
// hide the mouse
ShowCursor(TRUE);
// return success
return(1);
} // end Game_Shutdown
///////////////////////////////////////////////////////////
int Game_Main(void *parms)
{
// this is the workhorse of your game it will be called
// continuously in real-time this is like main() in C
// all the calls for you game go here!
static int fire_deb = 0, // used to debounce fire key
fireb_deb = 0, // debounceces joystick fire buttons
esc_deb = 0, // debounce esc key
pause_deb = 0; // debounce pause key
static int rock_push = 0, // tracks if rock is being pushed
demo_reset = 0, // used to create demo mode
pump_valve = 0, // used to control psi pressure rate
heal_count = 0; // used in healing
int dug_dx = 0, // used in collision algorithm
dug_dy = 0;
// what state is game in?
if (game_state == GAME_STATE_INIT)
{
// reset everything
Game_Reset();
// start first level
Start_Level(STARTING_LEVEL_NUMBER);
// reset number of lives
dug.varsI[DUG_INDEX_LIVES] = 3;
dug.varsI[DUG_INDEX_LEVEL] = 0;
dug.varsI[DUG_INDEX_SCORE] = 0;
// reset new man tracker
new_man_tracker = POINTS_NEW_MAN;
// transition to running
game_state = GAME_STATE_MENU;
} // end if
else
if (game_state == GAME_STATE_MENU)
{
// user is entering menu mode
// test for demo reset
if (demo_reset == 0)
{
// reset all the demo objects
// dug
// set initial animation sequence
Set_Animation_BOB2(&dug_demo, DUG_ANIM_WALK + DIR_RIGHT*3);
// set position
Set_Pos_BOB(&dug_demo,DUG_DEMO_X,DUG_DEMO_Y);
// set animation speed
Set_Anim_Speed_BOB(&dug_demo,4);
// poo
// set initial animation sequence
Set_Animation_BOB2(&poo_demo, POO_ANIM_BOUNCE_RIGHT);
// set position
Set_Pos_BOB(&poo_demo,POO_DEMO_X,POO_DEMO_Y);
// set animation speed
Set_Anim_Speed_BOB(&poo_demo,4);
// puff
// set initial animation sequence
Set_Animation_BOB2(&puff_demo, PUFF_ANIM_BOUNCE_RIGHT);
// set position
Set_Pos_BOB(&puff_demo,PUFF_DEMO_X,PUFF_DEMO_Y);
// set animation speed
Set_Anim_Speed_BOB(&puff_demo,4);
// reset demo
demo_reset = 1;
// start music
Play_Sound(intro_music_id, DSBPLAY_LOOPING);
} // end if
// display menu
// start the timing clock
Start_Clock();
// clear the drawing surface
DD_Lock_Back_Surface();
Draw_Bitmap2(&menu_bmp, back_buffer, back_lpitch,0);
DD_Unlock_Back_Surface();
// read all input devices
DI_Read_Keyboard();
DI_Read_Mouse();
DI_Read_Joystick();
// draw all objects
// animate the torch
Animate_BOB2(&torch);
// animate poo
Animate_BOB2(&poo_demo);
// animate puff
Animate_BOB2(&puff_demo);
// animate dug
Animate_BOB2(&dug_demo);
// draw the 2 torches
torch.x = 24;
torch.y = 60;
Draw_BOB(&torch, lpddsback);
torch.x = 524;
torch.y = 60;
Draw_BOB(&torch, lpddsback);
// draw puff
Draw_BOB(&puff_demo,lpddsback);
// draw poo
Draw_BOB(&poo_demo,lpddsback);
// draw dug
Draw_BOB(&dug_demo,lpddsback);
// display the next frame
DD_Flip();
// sync to 30ish fps
Wait_Clock(30);
// check of user is trying to exit
if (!esc_deb && keyboard_state[DIK_ESCAPE])
{
// out of here
game_state = GAME_STATE_EXIT;
// set debounce
esc_deb = 1;
Stop_Sound(intro_music_id);
} // end if
else
if (!keyboard_state[DIK_ESCAPE])
esc_deb = 0;
// test for restart
if (keyboard_state[DIK_RETURN])
{
// transition to running
// reset all the vars
Game_Reset();
Stop_Sound(intro_music_id);
// start first level
Start_Level(STARTING_LEVEL_NUMBER);
dug.varsI[DUG_INDEX_LEVEL] = 0;
// reset lives
dug.varsI[DUG_INDEX_LIVES] = 3;
// reset score
dug.varsI[DUG_INDEX_SCORE] = 0;
// reset new man tracker
new_man_tracker = POINTS_NEW_MAN;
///////////////////
// reset counter for rebirth
dug.counter_1 = 0;
// reset state
dug.state=DUG_STATE_REBIRTH;
// reset vars
dug.varsI[DUG_INDEX_ANIM_MODE] = DUG_ANIM_WALK;
// set direction to left
dug.varsI[DUG_INDEX_DIR] = DIR_LEFT;
// set initial animation sequence
Set_Animation_BOB2(&dug,DUG_ANIM_REBIRTH);
///////////////
// transition to running state
game_state = GAME_STATE_RUNNING;
Save_Palette(save_palette);
Screen_Transitions(SCREEN_REDNESS, primary_buffer, primary_lpitch);
Set_Palette(save_palette);
// play rebirth/trans sound
Play_Sound(dug_trans_snd_id);
} // end if
// test for resume
if (keyboard_state[DIK_SPACE])
{
// transition back to running state
game_state = GAME_STATE_RUNNING;
Stop_Sound(intro_music_id);
} // end if
} // end if
else
if (game_state == GAME_STATE_NEXT_LEVEL)
{
// move to next level
if (++curr_level >= num_levels)
{
// set state to game won
game_state = GAME_STATE_WIN;
} // end if
else
{
// reset all the vars
Game_Reset();
// load the next level
Start_Level(curr_level);
// wait a sec
Sleep(1000);
// play the next level sound
Play_Sound(level_snd_id);
//DD_Lock_Primary_Surface();
Save_Palette(save_palette);
Screen_Transitions(SCREEN_WHITENESS, primary_buffer, primary_lpitch);
Set_Palette(save_palette);
//DD_Unlock_Primary_Surface();
// transition to running state
game_state = GAME_STATE_RUNNING;
} // end if didn't win
} // end if
else
if (game_state == GAME_STATE_RUNNING)
{
// reset all vars
demo_reset = 0;
// start the timing clock
Start_Clock();
// clear the drawing surface
// DD_Fill_Surface(lpddsback, 0);
DD_Lock_Back_Surface();
Draw_Bitmap2(&background_bmp, back_buffer, back_lpitch,0);
DD_Unlock_Back_Surface();
// read all input devices
DI_Read_Keyboard();
DI_Read_Mouse();
DI_Read_Joystick();
// what state is dug in
if (dug.state==DUG_STATE_ALIVE)
{
// test desired direction, and artificially set motions based on valid intervals
if ((joy_state.lY || keyboard_state[DIK_UP] || keyboard_state[DIK_DOWN]) && ((int)dug.x % DUG_X_INTERVAL))
{
// dug is trying to make an upward or downward turn, but isn't at a
// valid turning interval
if (dug.varsI[DUG_INDEX_DIR] == DIR_RIGHT)
keyboard_state[DIK_RIGHT] |= 1;
else
if (dug.varsI[DUG_INDEX_DIR] == DIR_LEFT)
keyboard_state[DIK_LEFT] |= 1;
} // end if
// test desired direction, and artificially set motions based on valid intervals
if ((joy_state.lX || keyboard_state[DIK_RIGHT] || keyboard_state[DIK_LEFT]) && (((int)dug.y+8) % DUG_Y_INTERVAL))
{
// dug is trying to make an upward or downward turn, but isn't at a
// valid turning interval
if (dug.varsI[DUG_INDEX_DIR] == DIR_UP)
keyboard_state[DIK_UP] |= 1;
else
if (dug.varsI[DUG_INDEX_DIR] == DIR_DOWN)
keyboard_state[DIK_DOWN] |= 1;
} // end if
// process final motion
if ( (keyboard_state[DIK_LEFT] || joy_state.lX < 0)&& !(((int)dug.y+8) % DUG_Y_INTERVAL))
{
// first test if there is any rock ahead
Dug_Dig_Test(dug.x-1,dug.y+16);
// test what the current direction is
if (dug.varsI[DUG_INDEX_DIR]!=DIR_LEFT)
{
// set direction to left
dug.varsI[DUG_INDEX_DIR] = DIR_LEFT;
// set animation sequence to left
Set_Animation_BOB2(&dug, dug.varsI[DUG_INDEX_ANIM_MODE] + dug.varsI[DUG_INDEX_DIR]*3);
} // end if
// animate dug
Animate_BOB(&dug);
// dig hole
Dig_Hole();
// move dug
dug.x-=DUG_SPEED;
dug_dx = -DUG_SPEED;
dug_dy = 0;
} // end if
else
if ((keyboard_state[DIK_RIGHT] || joy_state.lX > 0) && !(((int)dug.y+8) % DUG_Y_INTERVAL))
{
// first test if there is any rock ahead
Dug_Dig_Test(dug.x+32,dug.y+16);
// test what the current direction is
if (dug.varsI[DUG_INDEX_DIR]!=DIR_RIGHT)
{
// set direction to left
dug.varsI[DUG_INDEX_DIR] = DIR_RIGHT;
// set animation sequence to right
Set_Animation_BOB2(&dug, dug.varsI[DUG_INDEX_ANIM_MODE] + dug.varsI[DUG_INDEX_DIR]*3);
} // end if
// animate dug
Animate_BOB(&dug);
// dig hole
Dig_Hole();
// move dug
dug.x+=DUG_SPEED;
dug_dx = DUG_SPEED;
dug_dy = 0;
} // end if
else
if ((keyboard_state[DIK_UP] || joy_state.lY < 0)&& !((int)dug.x % DUG_X_INTERVAL))
{
// first test if there is any rock ahead
Dug_Dig_Test(dug.x+16,dug.y-1);
// test what the current direction is
if (dug.varsI[DUG_INDEX_DIR]!=DIR_UP)
{
// set direction to left
dug.varsI[DUG_INDEX_DIR] = DIR_UP;
// set animation sequence to left
Set_Animation_BOB2(&dug, dug.varsI[DUG_INDEX_ANIM_MODE] + dug.varsI[DUG_INDEX_DIR]*3);
} // end if
// animate dug
Animate_BOB(&dug);
// dig hole
Dig_Hole();
// move dug
dug.y-=DUG_SPEED;
dug_dy = -DUG_SPEED;
dug_dx = 0;
} // end if
else
if ((keyboard_state[DIK_DOWN] || joy_state.lY > 0) && !((int)dug.x % DUG_X_INTERVAL))
{
// first test if there is any rock ahead
Dug_Dig_Test(dug.x+16,dug.y+32);
// test what the current direction is
if (dug.varsI[DUG_INDEX_DIR]!=DIR_DOWN)
{
// set direction to left
dug.varsI[DUG_INDEX_DIR] = DIR_DOWN;
// set animation sequence to left
Set_Animation_BOB2(&dug, dug.varsI[DUG_INDEX_ANIM_MODE] + dug.varsI[DUG_INDEX_DIR]*3);
} // end if
// animate dug
Animate_BOB(&dug);
// dig hole
Dig_Hole();
// move dug
dug.y+=DUG_SPEED;
dug_dy = DUG_SPEED;
dug_dx = 0;
} // end if
// check for collisions with rock
if (dug_dx || dug_dy)
{
// scan thru rock list
for (int rindex=0; rindex < NUM_ROCKS; rindex++)
{
// test for collision
if (rocks[rindex].state!=ROCK_STATE_DEAD && Collision_BOBS(&dug, &rocks[rindex]))
{
// move dug back
dug.x-=dug_dx;
dug.y-=dug_dy;
// push rock over a bit
if (dug_dx && (rand()%2)==1)
{
// knudge rock a bit
rocks[rindex].x+=(dug_dx/DUG_SPEED);
// make sure it stays on screen
if (rocks[rindex].x >= SCREEN_WIDTH-32)
rocks[rindex].x = SCREEN_WIDTH-32-1;
else
if (rocks[rindex].x < 0)
rocks[rindex].x = 0;
} // end if
// enable this for vertical push
// rocks[rindex].y+=(dug_dy/DUG_SPEED);
// start pushing sound
ULONG status;
sound_fx[dug_push_snd_id].dsbuffer->GetStatus(&status);
if (status!=DSBSTATUS_LOOPING && status!=DSBSTATUS_PLAYING)
Resume_Sound(dug_push_snd_id,DSBPLAY_LOOPING);
// set flag
rock_push = 4;
// no need to process any more rocks
break;
} // end if
} // end for rindex
} // end if
// decrement rock push event
if (--rock_push < 0)
rock_push = 0;
// need to turn off rock sound
if (rock_push==0)
Pause_Sound(dug_push_snd_id);
// ??? this code doesn't need to execute unless dug moves
// clip dug to screen
if (dug.x < 0)
dug.x=0;
else
if (dug.x > (SCREEN_WIDTH-8-dug.width))
dug.x = (SCREEN_WIDTH-8-dug.width);
if (dug.y < 32)
{
// reset position and rotate 90 deg
dug.y = 32;
// set direction to right
dug.varsI[DUG_INDEX_DIR] = DIR_RIGHT;
// set animation sequence to right
Set_Animation_BOB2(&dug, dug.varsI[DUG_INDEX_ANIM_MODE] + dug.varsI[DUG_INDEX_DIR]*3);
} // end if
else
if (dug.y > (SCREEN_HEIGHT-16-dug.height))
dug.y = (SCREEN_HEIGHT-16-dug.height);
// test for being crushed by rock, redundant loop
for (int rindex=0; rindex < NUM_ROCKS; rindex++)
{
// test if rock is alive
if (rocks[rindex].state==ROCK_STATE_FALLING)
{
// rock is alive, so test for collision with dug
if (Collision_BOBS(&rocks[rindex],&dug))
{
// first reset all state information of dug
dug.state = DUG_STATE_CRUSHED;
dug.anim_state = 0;
// start crunch sound
Play_Sound_From_Pool(crunch_snd_ids,4);
// tag rock
dug.varsI[DUG_INDEX_OBJECT_PTR] = rindex;
// set animation
Set_Animation_BOB2(&dug,DUG_ANIM_CRUSHED);
// set animation speed
Set_Anim_Speed_BOB(&dug,4);
// that's it
break;
} // end if
} // end if
} // end for rindex
// process all state vars of dug ?? might want to make different
if (++pump_valve >= (1+(dug.varsI[DUG_INDEX_LEVEL] >> 4)))
{
if (++dug.varsI[DUG_INDEX_PUMP_PSI] > DUG_MAX_PSI)
dug.varsI[DUG_INDEX_PUMP_PSI] = DUG_MAX_PSI;
// reset
pump_valve = 0;
} // end if
// animate dug in fire mode
if (dug.varsI[DUG_INDEX_ANIM_MODE]==DUG_ANIM_FIRE)
Animate_BOB(&dug);
if (keyboard_state[DIK_SPACE])
draw_on=-draw_on;
// test if dug is upstairs
if (dug.y <= DUG_MIN_ROCK_LINE)
{
//?? is dug dead, used to be 3
if ((dug.varsI[DUG_INDEX_DAMAGE] += ( 1 + (dug.varsI[DUG_INDEX_LEVEL] >> 4))) > DUG_MAX_RADIATION)
{
// ouch
Start_Dug_Death();
} // end if
} // end if
else
{
// cool radiation down
if (dug.varsI[DUG_INDEX_DAMAGE] > 0)
if (++heal_count > 2)
{
dug.varsI[DUG_INDEX_DAMAGE]--;
heal_count=0;
} // end if
} // end if
// test for radiation poisoning
if (!radiation_message_played && dug.varsI[DUG_INDEX_DAMAGE] >= DUG_CRITICAL_RADIATION)
{
// set flag
radiation_message_played = 1;
// play warning sound
Play_Sound(radiation_snd_id);
} // end if
else
if (dug.varsI[DUG_INDEX_DAMAGE] < DUG_CRITICAL_RADIATION)
radiation_message_played = 0;
// test for new man
if (dug.varsI[DUG_INDEX_SCORE] > new_man_tracker)
{
// give player another life
dug.varsI[DUG_INDEX_LIVES]++;
// increase threshold for a new man
new_man_tracker+=POINTS_NEW_MAN;
// play sound
Play_Sound(dug_life_snd_id);
} // end if
// test for weapons fire keyboard
if ((keyboard_state[DIK_LCONTROL]) && (!fire_deb) && (dug.varsI[DUG_INDEX_PUMP_PSI] > DUG_MIN_PSI))
{
// fire the pump
if (dug.varsI[DUG_INDEX_DIR]==DIR_LEFT || dug.varsI[DUG_INDEX_DIR]==DIR_RIGHT)
Start_Gpump(dug.x+12, dug.y+12,dug.varsI[DUG_INDEX_DIR]);
else
Start_Gpump(dug.x+12, dug.y+12,dug.varsI[DUG_INDEX_DIR]);
// take some of dugs air out
dug.varsI[DUG_INDEX_PUMP_PSI]-=16; //?? used to be 20
// set debounce
fire_deb=1;
// check animation mode of dug
if (dug.varsI[DUG_INDEX_ANIM_MODE] != DUG_ANIM_FIRE)
{
// set mode to fire
dug.varsI[DUG_INDEX_ANIM_MODE] = DUG_ANIM_FIRE;
// set animation sequence to left
Set_Animation_BOB2(&dug, dug.varsI[DUG_INDEX_ANIM_MODE] + dug.varsI[DUG_INDEX_DIR]*3);
} // end if
} // end if
// debounce fire button keyboard
if (!keyboard_state[DIK_LCONTROL])
fire_deb = 0;
// test for weapons fire joystick
if ((joy_state.rgbButtons[0]) && (!fireb_deb) && (dug.varsI[DUG_INDEX_PUMP_PSI] > DUG_MIN_PSI))
{
// fire the pump
if (dug.varsI[DUG_INDEX_DIR]==DIR_LEFT || dug.varsI[DUG_INDEX_DIR]==DIR_RIGHT)
Start_Gpump(dug.x+12, dug.y+12,dug.varsI[DUG_INDEX_DIR]);
else
Start_Gpump(dug.x+12, dug.y+12,dug.varsI[DUG_INDEX_DIR]);
// take some of dugs air out
dug.varsI[DUG_INDEX_PUMP_PSI]-=16; //?? used to be 20
// set debounce
fireb_deb=1;
// check animation mode of dug
if (dug.varsI[DUG_INDEX_ANIM_MODE] != DUG_ANIM_FIRE)
{
// set mode to fire
dug.varsI[DUG_INDEX_ANIM_MODE] = DUG_ANIM_FIRE;
// set animation sequence to left
Set_Animation_BOB2(&dug, dug.varsI[DUG_INDEX_ANIM_MODE] + dug.varsI[DUG_INDEX_DIR]*3);
} // end if
} // end if
// debounce fire button keyboard
if (!joy_state.rgbButtons[0])
fireb_deb = 0;
} // end if dug is alive
else
{
// not alive
// turn anything off
Pause_Sound(dug_push_snd_id);
} // end if
// test of other states
if (dug.state==DUG_STATE_DYING)
{
// animate the death sequence
Animate_BOB2(&dug);
// test for done sequence
if (dug.anim_state == BOB_STATE_ANIM_DONE)
{
// set state to dead
dug.state = DUG_STATE_DEAD;
dug.anim_state = 0;
dug.counter_1 = 100;
Set_Anim_Speed_BOB(&dug, 3);
// one less life
if (--dug.varsI[DUG_INDEX_LIVES] < 0)
{
// dug is dead
game_state = GAME_STATE_OVER;
} // end if
} // end if
} // end if
else
if (dug.state==DUG_STATE_CRUSHED)
{
// dug is getting crushed, simple track tagged rock
dug.x = rocks[dug.varsI[DUG_INDEX_OBJECT_PTR]].x;
dug.y = rocks[dug.varsI[DUG_INDEX_OBJECT_PTR]].y+8;
// test for done sequence
if (dug.anim_state != BOB_STATE_ANIM_DONE)
{
// animate the rebirth sequence
Animate_BOB2(&dug);
// test if animation is complete
if (dug.anim_state == BOB_STATE_ANIM_DONE)
dug.curr_frame = dug.animations[DUG_ANIM_CRUSHED][2];
} // end if
// test if rock is complete and in crumble mode
if (rocks[dug.varsI[DUG_INDEX_OBJECT_PTR]].state==ROCK_STATE_DEAD)
{
// set state to dead
dug.state = DUG_STATE_DEAD;
dug.anim_state = 0;
dug.counter_1 = 100;
Set_Anim_Speed_BOB(&dug, 2);
// one less life
if (--dug.varsI[DUG_INDEX_LIVES] < 0)
{
// dug is dead
game_state = GAME_STATE_OVER;
} // end if
// start up score object
} // end if
} // end if
else
if (dug.state==DUG_STATE_DEAD)
{
// test if death is over
if (--dug.counter_1 < 0)
{
// reset counter
dug.counter_1 = 0;
// reset state
dug.state=DUG_STATE_REBIRTH;
dug.varsI[DUG_INDEX_DAMAGE] = 0;
// reset vars
dug.varsI[DUG_INDEX_ANIM_MODE] = DUG_ANIM_WALK;
// set direction to left
dug.varsI[DUG_INDEX_DIR] = DIR_LEFT;
// set initial animation sequence
//Set_Animation_BOB2(&dug, DUG_ANIM_WALK + dug.varsI[DUG_INDEX_DIR]*3);
Set_Animation_BOB2(&dug,DUG_ANIM_REBIRTH);
// set position
Set_Pos_BOB(&dug,320,32);
// start rebirth sound
Play_Sound(dug_trans_snd_id);
} // end if
} // end if
else
if (dug.state==DUG_STATE_REBIRTH)
{
// animate the rebirth sequence
Animate_BOB2(&dug);
// test for done sequence
if (dug.anim_state == BOB_STATE_ANIM_DONE)
{
// set state to dead
dug.state = DUG_STATE_ALIVE;
// set animation sequence to walk
Set_Animation_BOB2(&dug, DUG_ANIM_WALK + dug.varsI[DUG_INDEX_DIR]*3);
} // end if
} // end if
// process gpumps
Process_Gpumps();
// process prize
Process_Prize();
// process score
Process_Scores();
//mono.clear();
// process poos
Process_Poos();
// process puffs
Process_Puffs();
// process fire balls
Process_Fballs();
// process all rocks
Process_Rocks();
// draw all rocks
Draw_Rocks();
// draw pumps
Draw_Gpumps();
// draw poos
Draw_Poos();
// draw fire balls
Draw_Fballs();
// draw puffs
Draw_Puffs();
// draw digdumb
if (dug.state!=DUG_STATE_DEAD)
Draw_BOB(&dug,lpddsback);
// draw prize
Draw_Prize();
// draw scores
Draw_Scores();
// update high score
if (dug.varsI[DUG_INDEX_SCORE] > high_score)
{
// reset high score
high_score = dug.varsI[DUG_INDEX_SCORE];
} // end if
// draw information
Draw_Info();
// draw all foreground objects
// flip the surfaces
DD_Flip();
// sync to 40ish fps
Wait_Clock(24);
// test if dug is done with level
if (dug.varsI[DUG_INDEX_KILLS] >= num_creatures_on_level && ++end_level_counter >= END_LEVEL_DELAY)
{
// transition to next level
game_state = GAME_STATE_NEXT_LEVEL;
// reset counter
end_level_counter = 0;
// increment level number
dug.varsI[DUG_INDEX_LEVEL]++;
} // end if
// test for exit to menu
if (!esc_deb && keyboard_state[DIK_ESCAPE])
{
game_state = GAME_STATE_MENU;
esc_deb = 1;
} // end if
else
if (!keyboard_state[DIK_ESCAPE])
esc_deb = 0;
// check for pause mode
if (!pause_deb && keyboard_state[DIK_P])
{
game_state = GAME_STATE_PAUSED;
pause_deb = 1;
// display paused in primary buffer
Draw_Text_GDI("Game Paused - Press <P> to Continue...",
SCREEN_WIDTH/2 - 4*strlen("Game Paused - Press <P> to Continue..."), SCREEN_HEIGHT/2,
RGB(0,255,0),lpddsprimary);
} // end if
else
if (!keyboard_state[DIK_P])
pause_deb = 0;
#if 0
// diagnostic printing area
sprintf(buffer,"curr_anim=%d curr_frame=%d ",dug.curr_animation, dug.curr_frame);
mono.set_cursor(0,1);
mono.print(buffer);
sprintf(buffer,"draw_on=%d ",draw_on);
mono.set_cursor(0,2);
mono.print(buffer);
sprintf(buffer,"dug x=%d y=%d ",dug.x, dug.y);
mono.set_cursor(0,3);
mono.print(buffer);
sprintf(buffer,"dug psi=%d ",dug.varsI[DUG_INDEX_PUMP_PSI]);
mono.set_cursor(0,4);
mono.print(buffer);
sprintf(buffer,"dug kills=%d ",dug.varsI[DUG_INDEX_KILLS]);
mono.set_cursor(0,5);
mono.print(buffer);
sprintf(buffer,"num_creatures_on_level=%d ",num_creatures_on_level);
mono.set_cursor(0,6);
mono.print(buffer);
#endif
} // end if
else
if (game_state == GAME_STATE_PAUSED)
{
// get input
DI_Read_Keyboard();
//DI_Read_Mouse();
//DI_Read_Joystick();
// the game is paused, wait for player to hit pause key again
if (!pause_deb && keyboard_state[DIK_P])
{
game_state = GAME_STATE_RUNNING;
pause_deb = 1;
} // end if
else
if (!keyboard_state[DIK_P])
pause_deb = 0;
} // end if
else
if (game_state == GAME_STATE_WIN)
{
// clear out back surface
DD_Fill_Surface(lpddsback, 0);
// wait a sec
//Sleep(2000);
// play game over animation
if ((rand()%2)==1)
{
DD_Lock_Primary_Surface();
Screen_Transitions(SCREEN_DISOLVE, primary_buffer, primary_lpitch);
DD_Unlock_Primary_Surface();
// clear out primary surface
DD_Fill_Surface(lpddsprimary, 0);
}
else
{
Save_Palette(save_palette);
Screen_Transitions(SCREEN_DARKNESS, primary_buffer, primary_lpitch);
// clear out primary surface
DD_Fill_Surface(lpddsprimary, 0);
Set_Palette(save_palette);
} // end if
// draw in game over screen
Load_Bitmap_File(&bitmap8bit, "UNDART/UNDWIN8.BMP");
// play sound
Play_Sound(win_snd_id);
// copy the bitmap to primary buffer
DD_Lock_Primary_Surface();
Copy_Screen(bitmap8bit.buffer,primary_buffer, primary_lpitch, 0);
DD_Unlock_Primary_Surface();
// unload the bitmap
Unload_Bitmap_File(&bitmap8bit);
// wait for sound to stop
while(1)
{
// is music done yet
ULONG status;
sound_fx[win_snd_id].dsbuffer->GetStatus(&status);
if (status==0)
break;
} // end while
// wait a sec
Sleep(1000);
// fade away
Save_Palette(save_palette);
Screen_Transitions(SCREEN_DARKNESS, primary_buffer, primary_lpitch);
// clear out primary surface
DD_Fill_Surface(lpddsprimary, 0);
Set_Palette(save_palette);
// set state to menu
game_state = GAME_STATE_INIT;
} // end if
else
if (game_state == GAME_STATE_OVER)
{
// clear out back surface
DD_Fill_Surface(lpddsback, 0);
// wait a sec
Sleep(2000);
// play game over animation
if ((rand()%2)==1)
{
DD_Lock_Primary_Surface();
Screen_Transitions(SCREEN_DISOLVE, primary_buffer, primary_lpitch);
DD_Unlock_Primary_Surface();
// clear out primary surface
DD_Fill_Surface(lpddsprimary, 0);
}
else
{
Save_Palette(save_palette);
Screen_Transitions(SCREEN_DARKNESS, primary_buffer, primary_lpitch);
// clear out primary surface
DD_Fill_Surface(lpddsprimary, 0);
Set_Palette(save_palette);
} // end if
// play sound
Play_Sound(game_over_snd_id);
// draw in game over screen
Load_Bitmap_File(&bitmap8bit, "UNDART/UNDOVER8.BMP");
// copy the bitmap to primary buffer
DD_Lock_Primary_Surface();
Copy_Screen(bitmap8bit.buffer,primary_buffer, primary_lpitch, 0);
DD_Unlock_Primary_Surface();
// unload the bitmap
Unload_Bitmap_File(&bitmap8bit);
// wait a sec
Sleep(4000);
// fade away
Save_Palette(save_palette);
Screen_Transitions(SCREEN_DARKNESS, primary_buffer, primary_lpitch);
// clear out primary surface
DD_Fill_Surface(lpddsprimary, 0);
Set_Palette(save_palette);
// set state to menu
game_state = GAME_STATE_INIT;
} // end if
else
if (game_state == GAME_STATE_EXIT)
{
// this is the exit state, runs exactly once
// play the ending music
Play_Sound(credits_snd_id);
// clear out back surface
DD_Fill_Surface(lpddsback, 0);
// perform screen transition
DD_Lock_Primary_Surface();
Screen_Transitions(SCREEN_DISOLVE, primary_buffer, primary_lpitch);
DD_Unlock_Primary_Surface();
//mono.print("\nin exit");
// draw in credits screen
Load_Bitmap_File(&bitmap8bit, "UNDART/UNDCRED8.BMP");
// copy the bitmap to primary buffer
DD_Lock_Primary_Surface();
Copy_Screen(bitmap8bit.buffer,primary_buffer, primary_lpitch, 0);
DD_Unlock_Primary_Surface();
// unload bitmap file
Unload_Bitmap_File(&bitmap8bit);
// wait for key board hit
while(1)
{
// read the keyboard
DI_Read_Keyboard();
// the game is paused, wait for player to hit pause key again
if (keyboard_state[DIK_RETURN] || keyboard_state[DIK_SPACE] || keyboard_state[DIK_ESCAPE])
break;
// is music done yet
ULONG status;
sound_fx[credits_snd_id].dsbuffer->GetStatus(&status);
if (status==0)
break;
} // end if
// wait a sec
//Sleep(7500);
// fade away
Save_Palette(save_palette);
Screen_Transitions(SCREEN_DARKNESS, primary_buffer, primary_lpitch);
// clear out primary surface
DD_Fill_Surface(lpddsprimary, 0);
Set_Palette(save_palette);
// turn off credits sound
Stop_Sound(credits_snd_id);
// exit windows
PostMessage(main_window_handle, WM_DESTROY,0,0);
// set terminal wait state
game_state = GAME_STATE_WAIT_FOR_TERMINATION;
} // end if
else
if (game_state == GAME_STATE_WAIT_FOR_TERMINATION)
{
// just chill, there are a few messages in the queue...
//mono.print("\nterminal state");
} // end
// return success
return(1);
} // end Game_Main
//////////////////////////////////////////////////////////