home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / Source / GPCHAP23 / PROG23_5.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2002-05-01  |  26.7 KB  |  907 lines

  1. // PROG23_5.CPP - pattern demo with tracking instruction
  2. // to compile make sure to include DDRAW.LIB, DSOUND.LIB,
  3. // DINPUT.LIB, WINMM.LIB, and of course GPDUMB I and II files.
  4.  
  5. // INCLUDES ///////////////////////////////////////////////
  6.  
  7. #define WIN32_LEAN_AND_MEAN  
  8. #define INITGUID
  9.  
  10. #include <windows.h>   // include important windows stuff
  11. #include <windowsx.h> 
  12. #include <mmsystem.h>
  13. #include <iostream.h> // include important C/C++ stuff
  14. #include <conio.h>
  15. #include <stdlib.h>
  16. #include <malloc.h>
  17. #include <memory.h>
  18. #include <string.h>
  19. #include <stdarg.h>
  20. #include <stdio.h> 
  21. #include <math.h>
  22. #include <io.h>
  23. #include <fcntl.h>
  24.  
  25. #include <ddraw.h>  // directX includes
  26. #include <dsound.h>
  27. #include <dinput.h>
  28. #include "gpdumb1.h" // game library includes
  29. #include "gpdumb2.h"
  30.  
  31. // DEFINES ////////////////////////////////////////////////
  32.  
  33. // defines for windows 
  34. #define WINDOW_CLASS_NAME "WINXCLASS"  // class name
  35.  
  36. #define WINDOW_WIDTH    320   // size of window
  37. #define WINDOW_HEIGHT   240
  38.  
  39. #define NUM_PATTERNS    4     // number of patterns in system
  40.  
  41. // pattern instruction opcodes for skelaton
  42.  
  43. // directional instructions
  44. #define OPC_E    0  // move west
  45. #define OPC_NE   1  // move northeast
  46. #define OPC_N    2  // move north
  47. #define OPC_NW   3  // move northwest
  48. #define OPC_W    4  // move west
  49. #define OPC_SW   5  // move southwest
  50. #define OPC_S    6  // move south
  51. #define OPC_SE   7  // move southeast
  52.  
  53. // special instructions
  54. #define OPC_STOP        8  // stop for a moment
  55. #define OPC_RAND        9  // select a random direction
  56. #define OPC_TEST_DIST   10 // test distance 
  57. #define OPC_END        -1  // end pattern
  58.  
  59.  
  60. #define MIN_LONELYNESS  100 // minimum distance before skelaton
  61.                             // gets lonely for its pet bat
  62.  
  63. // PROTOTYPES /////////////////////////////////////////////
  64.  
  65. // game console
  66. int Game_Init(void *parms=NULL);
  67. int Game_Shutdown(void *parms=NULL);
  68. int Game_Main(void *parms=NULL);
  69.  
  70. // GLOBALS ////////////////////////////////////////////////
  71.  
  72. HWND main_window_handle           = NULL; // save the window handle
  73. HINSTANCE main_instance           = NULL; // save the instance
  74. char buffer[80];                          // used to print text
  75.  
  76. BITMAP_IMAGE background_bmp;   // holds the background
  77. BOB          skelaton;         // the AI skelaton
  78.  
  79. BOB          bat;                // this time your the bat
  80. int          bat_sound_id  = -1; // sound of bat flapping wings
  81.  
  82. // animation sequences for bob
  83. int skelaton_anims[8][4] = { {0,1,0,2},
  84.                              {0+4,1+4,0+4,2+4},
  85.                              {0+8,1+8,0+8,2+8},
  86.                              {0+12,1+12,0+12,2+12},
  87.                              {0+16,1+16,0+16,2+16},
  88.                              {0+20,1+20,0+20,2+20},
  89.                              {0+24,1+24,0+24,2+24},
  90.                              {0+28,1+28,0+28,2+28}, };
  91.  
  92.  
  93. // patterns in opcode operand format
  94. int pattern_1[] = {OPC_W, 10, OPC_NW, 10, OPC_N, 10, OPC_NE, 10, 
  95.                    OPC_TEST_DIST, 50, // a distance test
  96.                    OPC_E, 10, OPC_SE, 10, OPC_S, 10, OPC_SW, 10, 
  97.                    OPC_W, 10, OPC_RAND, 10,
  98.                    OPC_TEST_DIST, 50, // a distance test                   
  99.                    OPC_W, 20, OPC_NW, 10, OPC_N, 20, OPC_NE, 10, 
  100.                    OPC_E, 20, OPC_SE, 10, OPC_S, 20, OPC_SW, 10, 
  101.                    OPC_TEST_DIST, 50, // a distance test
  102.                    OPC_W, 10, OPC_END,0};
  103.                    
  104.  
  105. int pattern_2[] = {OPC_E, 20, OPC_W, 20, OPC_STOP, 20, OPC_NE, 10, 
  106.                    OPC_TEST_DIST, 50, // a distance test                   
  107.                    OPC_W, 10, OPC_NW, 10, OPC_SW, 20, OPC_NW, 20, 
  108.                    OPC_TEST_DIST, 50, // a distance test
  109.                    OPC_SW, 20, OPC_NW, 30, OPC_SW, 10, OPC_S, 50,  
  110.                    OPC_TEST_DIST, 50, // a distance test                   
  111.                    OPC_W, 2, OPC_NW, 2, OPC_N, 2, OPC_NE, 50,  OPC_TEST_DIST, 50, // a distance test
  112.                    OPC_E,2, OPC_SE,2, OPC_S,2, OPC_RAND, 10, OPC_END,0};
  113.  
  114.  
  115.  
  116. int pattern_3[] = { OPC_N, 10, OPC_S, 10, OPC_N, 10, OPC_S, 10, 
  117.                     OPC_TEST_DIST, 50, // a distance test                    
  118.                     OPC_E, 10, OPC_W, 10, OPC_E, 10, OPC_W, 10,
  119.                     OPC_TEST_DIST, 50, // a distance test
  120.                     OPC_NW, 10, OPC_N, 10, OPC_NE, 10, OPC_N, 10, 
  121.                     OPC_TEST_DIST, 60, // a distance test
  122.                     OPC_STOP, 20, OPC_RAND, 5, OPC_E, 50, OPC_S, 50, OPC_W, 50, 
  123.                     OPC_TEST_DIST, 50, // a distance test                    
  124.                     OPC_E, 10, OPC_E, 10, OPC_E, 10, OPC_NW, 100,   OPC_TEST_DIST, 60, // a distance test
  125.                     OPC_STOP, 10, OPC_END,0};
  126.  
  127.  
  128. int pattern_4[] = {OPC_W, 100, 
  129.                    OPC_NW, 2,OPC_N, 2,OPC_NE, 2,
  130.                    OPC_E, 100, 
  131.                    OPC_NE, 2,OPC_N, 2,OPC_NW, 2,
  132.                    OPC_TEST_DIST, 50, // a distance test                    
  133.                    OPC_W, 100, 
  134.                    OPC_NW, 2,OPC_N, 2,OPC_NE, 2,
  135.                    OPC_E, 100, 
  136.                    OPC_NE, 2,OPC_N, 2,OPC_NW, 2,
  137.                    OPC_TEST_DIST, 50, // a distance test                    
  138.                    OPC_W, 100, 
  139.                    OPC_NW, 2,OPC_N, 2,OPC_NE, 2,
  140.                    OPC_E, 100, 
  141.                    OPC_NE, 2,OPC_N, 2,OPC_NW, 2,
  142.                    OPC_TEST_DIST, 50, // a distance test
  143.                    OPC_RAND, 10, OPC_RAND, 5,
  144.  
  145.                    OPC_SW, 2,OPC_S, 2,OPC_SE, 2,
  146.                    OPC_E, 100, 
  147.                    OPC_TEST_DIST, 50, // a distance test
  148.                    OPC_SE, 2,OPC_S, 2,OPC_SW, 2,
  149.                    OPC_W, 100,
  150.                    OPC_TEST_DIST, 50, // a distance test
  151.                    OPC_SW, 2,OPC_S, 2,OPC_SE, 2,
  152.                    OPC_E, 100, 
  153.                    OPC_SE, 2,OPC_S, 2,OPC_SW, 2,
  154.                    OPC_W, 100,
  155.                    OPC_TEST_DIST, 50, // a distance test
  156.                    OPC_SW, 2,OPC_S, 2,OPC_SE, 2,
  157.                    OPC_E, 100, 
  158.                    OPC_TEST_DIST, 50, // a distance test
  159.                    OPC_SE, 2,OPC_S, 2,OPC_SW, 2,
  160.                    OPC_W, 100, OPC_END,0};
  161.  
  162. // master pattern array
  163. int *patterns[NUM_PATTERNS] = {pattern_1, pattern_2, pattern_3, pattern_4};
  164.  
  165. int *curr_pattern=NULL;  // current pattern being processed
  166.  
  167. int opcode,                   // general opcode
  168.     operand,                  // general operand
  169.     skelaton_ip     =0,       // pattern instruction pointer for skelaton
  170.     skelaton_counter=0,       // counter of pattern control
  171.     skelaton_pattern_index;   // the current pattern being executed
  172.  
  173. // used as a index to string lookup to help print out
  174. char *opcode_names[] = {"OPC_E",
  175.                         "OPC_NE", 
  176.                         "OPC_N",    
  177.                         "OPC_NW",   
  178.                         "OPC_W",    
  179.                         "OPC_SW",   
  180.                         "OPC_S",    
  181.                         "OPC_SE",   
  182.                         "OPC_STOP", 
  183.                         "OPC_RAND", 
  184.                         "OPC_TEST_DIST"};  
  185. // sound stuff
  186.  
  187. // FUNCTIONS //////////////////////////////////////////////
  188.  
  189. LRESULT CALLBACK WindowProc(HWND hwnd, 
  190.                             UINT msg, 
  191.                             WPARAM wparam, 
  192.                             LPARAM lparam)
  193. {
  194. // this is the main message handler of the system
  195. PAINTSTRUCT    ps;           // used in WM_PAINT
  196. HDC            hdc;       // handle to a device context
  197.  
  198. // what is the message 
  199. switch(msg)
  200.     {    
  201.     case WM_CREATE: 
  202.         {
  203.         // do initialization stuff here
  204.         return(0);
  205.         } break;
  206.  
  207.     case WM_PAINT:
  208.          {
  209.          // start painting
  210.          hdc = BeginPaint(hwnd,&ps);
  211.  
  212.          // end painting
  213.          EndPaint(hwnd,&ps);
  214.          return(0);
  215.         } break;
  216.  
  217.     case WM_DESTROY: 
  218.         {
  219.         // kill the application            
  220.         PostQuitMessage(0);
  221.         return(0);
  222.         } break;
  223.  
  224.     default:break;
  225.  
  226.     } // end switch
  227.  
  228. // process any messages that we didn't take care of 
  229. return (DefWindowProc(hwnd, msg, wparam, lparam));
  230.  
  231. } // end WinProc
  232.  
  233. // WINMAIN ////////////////////////////////////////////////
  234.  
  235. int WINAPI WinMain(    HINSTANCE hinstance,
  236.                     HINSTANCE hprevinstance,
  237.                     LPSTR lpcmdline,
  238.                     int ncmdshow)
  239. {
  240. // this is the winmain function
  241.  
  242. WNDCLASS winclass;    // this will hold the class we create
  243. HWND     hwnd;        // generic window handle
  244. MSG         msg;        // generic message
  245. HDC      hdc;       // generic dc
  246. PAINTSTRUCT ps;     // generic paintstruct
  247.  
  248. // first fill in the window class stucture
  249. winclass.style            = CS_DBLCLKS | CS_OWNDC | 
  250.                           CS_HREDRAW | CS_VREDRAW;
  251. winclass.lpfnWndProc    = WindowProc;
  252. winclass.cbClsExtra        = 0;
  253. winclass.cbWndExtra        = 0;
  254. winclass.hInstance        = hinstance;
  255. winclass.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
  256. winclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  257. winclass.hbrBackground    = (HBRUSH)GetStockObject(BLACK_BRUSH);
  258. winclass.lpszMenuName    = NULL; 
  259. winclass.lpszClassName    = WINDOW_CLASS_NAME;
  260.  
  261. // register the window class
  262. if (!RegisterClass(&winclass))
  263.     return(0);
  264.  
  265. // create the window, note the use of WS_POPUP
  266. if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
  267.                           "WinX Game Console",     // title
  268.                           WS_POPUP | WS_VISIBLE,
  269.                            0,0,       // x,y
  270.                           WINDOW_WIDTH,  // width
  271.                           WINDOW_HEIGHT, // height
  272.                           NULL,       // handle to parent 
  273.                           NULL,       // handle to menu
  274.                           hinstance,// instance
  275.                           NULL)))    // creation parms
  276. return(0);
  277.  
  278. // save the window handle and instance in a global
  279. main_window_handle = hwnd;
  280. main_instance      = hinstance;
  281.  
  282. // perform all game console specific initialization
  283. Game_Init();
  284.  
  285. // enter main event loop
  286. while(1)
  287.     {
  288.     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  289.         { 
  290.         // test if this is a quit
  291.         if (msg.message == WM_QUIT)
  292.            break;
  293.     
  294.         // translate any accelerator keys
  295.         TranslateMessage(&msg);
  296.  
  297.         // send the message to the window proc
  298.         DispatchMessage(&msg);
  299.         } // end if
  300.     
  301.     // main game processing goes here
  302.     Game_Main();
  303.  
  304.     } // end while
  305.  
  306. // shutdown game and release all resources
  307. Game_Shutdown();
  308.  
  309. // return to Windows like this
  310. return(msg.wParam);
  311.  
  312. } // end WinMain
  313.  
  314. // WINX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
  315.  
  316. int Game_Init(void *parms)
  317. {
  318. // this function is where you do all the initialization 
  319. // for your game
  320.  
  321. int index; // looping variable
  322. int skelaton_anim[2];
  323.  
  324. char filename[80]; // used to build up filenames
  325.  
  326. // start up DirectDraw (replace the parms as you desire)
  327. DD_Init(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP);
  328.  
  329. // load background image
  330. Load_Bitmap_File(&bitmap8bit, "DUNGEON.BMP");
  331. Create_Bitmap(&background_bmp,0,0,640,480);
  332. Load_Image_Bitmap(&background_bmp, &bitmap8bit,0,0,BITMAP_EXTRACT_MODE_ABS);
  333. Set_Palette(bitmap8bit.palette);
  334. Unload_Bitmap_File(&bitmap8bit);
  335.  
  336. // load the bat bitmaps
  337. Load_Bitmap_File(&bitmap8bit, "BATS8.BMP");
  338.  
  339. // create bat bob
  340. Create_BOB(&bat,320,200, 16,16, 5, BOB_ATTR_MULTI_FRAME | BOB_ATTR_VISIBLE, DDSCAPS_SYSTEMMEMORY);
  341. Set_Anim_Speed_BOB(&bat, 2);
  342.  
  343. // load the bat in 
  344. for (index=0; index < 5; index++)
  345.     Load_Frame_BOB(&bat, &bitmap8bit, index, index, 0, BITMAP_EXTRACT_MODE_CELL);
  346.  
  347. // unload bat
  348. Unload_Bitmap_File(&bitmap8bit);
  349.  
  350.  
  351. // create skelaton bob
  352. if (!Create_BOB(&skelaton,0,0,56,72,32,
  353.            BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM,DDSCAPS_SYSTEMMEMORY))
  354.    return(0);
  355.  
  356. // load the frames in 8 directions, 4 frames each
  357. // each set of frames has a walk and a fire, frame sets
  358. // are loaded in counter clockwise order looking down
  359. // from a birds eys view or the x-z plane
  360. for (int direction = 0; direction < 8; direction++)
  361.     { 
  362.     // build up file name
  363.     sprintf(filename,"SKELSP%d.BMP",direction);
  364.  
  365.     // load in new bitmap file
  366.     Load_Bitmap_File(&bitmap8bit,filename);
  367.  
  368.     Load_Frame_BOB(&skelaton,&bitmap8bit,0+direction*4,0,0,BITMAP_EXTRACT_MODE_CELL);  
  369.     Load_Frame_BOB(&skelaton,&bitmap8bit,1+direction*4,1,0,BITMAP_EXTRACT_MODE_CELL);  
  370.     Load_Frame_BOB(&skelaton,&bitmap8bit,2+direction*4,2,0,BITMAP_EXTRACT_MODE_CELL);  
  371.     Load_Frame_BOB(&skelaton,&bitmap8bit,3+direction*4,0,1,BITMAP_EXTRACT_MODE_CELL);  
  372.  
  373.     // unload the bitmap file
  374.     Unload_Bitmap_File(&bitmap8bit);
  375.  
  376.     // set the animation sequences for skelaton
  377.     Load_Animation_BOB(&skelaton,direction,4,skelaton_anims[direction]);
  378.  
  379.     } // end for direction
  380.  
  381. // set up stating state of skelaton
  382. Set_Animation_BOB(&skelaton, 0);
  383. Set_Anim_Speed_BOB(&skelaton, 4);
  384. Set_Vel_BOB(&skelaton, 0,0);
  385. Set_Pos_BOB(&skelaton, 0, 128);
  386.  
  387. // initialize directinput
  388. DInput_Init();
  389.  
  390. // acquire the keyboard only
  391. DI_Init_Keyboard();
  392.  
  393. // initilize DirectSound
  394. DSound_Init();
  395.  
  396. // load background sounds
  397. bat_sound_id = Load_WAV("BAT.WAV");
  398.  
  399. // start the sounds
  400. Play_Sound(bat_sound_id, DSBPLAY_LOOPING);
  401.  
  402. // set clipping rectangle to screen extents so objects dont
  403. // mess up at edges
  404. RECT screen_rect = {0,0,screen_width,screen_height};
  405. lpddclipper = DD_Attach_Clipper(lpddsback,1,&screen_rect);
  406.  
  407. // hide the mouse
  408. ShowCursor(FALSE);
  409.  
  410. // seed random number generate
  411. srand(Start_Clock());
  412.  
  413. // return success
  414. return(1);
  415.  
  416. } // end Game_Init
  417.  
  418. ///////////////////////////////////////////////////////////
  419.  
  420. int Game_Shutdown(void *parms)
  421. {
  422. // this function is where you shutdown your game and
  423. // release all resources that you allocated
  424.  
  425. // shut everything down
  426.  
  427. // kill all the bobs
  428. Destroy_BOBX(&skelaton);
  429. Destroy_BOBX(&bat);
  430.  
  431. // shutdown directdraw last
  432. DD_Shutdown();
  433.  
  434. // now directsound
  435. Stop_All_Sounds();
  436. DSound_Shutdown();
  437.  
  438. // shut down directinput
  439. DInput_Shutdown();
  440.  
  441. // return success
  442. return(1);
  443. } // end Game_Shutdown
  444.  
  445. //////////////////////////////////////////////////////////
  446.  
  447. void Skelaton_AI(void)
  448. {
  449. // this function controls the ai of the skelaton and the pattern
  450. // processing
  451.  
  452.  
  453. // these are local defines to help compute the direction to move the
  454. // skelaton if it needs to hunt down bat, note they are all in power
  455. // of 2 order, hence, they are mutually exclusive
  456.  
  457. #define WEST_BIT     1
  458. #define EAST_BIT     2
  459. #define NORTH_BIT    4 
  460. #define SOUTH_BIT    8 
  461.  
  462. // test if it's time to process a new instruction
  463. if (curr_pattern==NULL)
  464.    {
  465.    // select a random pattern in pattern bank
  466.    skelaton_pattern_index = rand()%NUM_PATTERNS;
  467.    curr_pattern = patterns[skelaton_pattern_index];
  468.    
  469.    // now reset instuction pointer
  470.    skelaton_ip = 0;
  471.  
  472.    // reset counter
  473.    skelaton_counter = 0;
  474.  
  475.    } // end if
  476.  
  477. // process next instruction if it's time
  478. if (--skelaton_counter <= 0)
  479.     {
  480.     // get next instruction
  481.     opcode  = curr_pattern[skelaton_ip++];
  482.     operand = curr_pattern[skelaton_ip++];
  483.  
  484.     // test what the opcode is
  485.     switch(opcode)
  486.         {
  487.         case OPC_E:
  488.             {
  489.             // set direction to east
  490.             Set_Vel_BOB(&skelaton,3,0);
  491.   
  492.             // set animation to east
  493.             Set_Animation_BOB(&skelaton,opcode);
  494.             
  495.             // set counter to instuction operand
  496.             skelaton_counter = operand;
  497.  
  498.             } break;
  499.  
  500.         case OPC_NE:
  501.             {
  502.             // set direction to northeast
  503.             Set_Vel_BOB(&skelaton,3,-3);
  504.   
  505.             // set animation to northeast
  506.             Set_Animation_BOB(&skelaton,opcode);
  507.             
  508.             // set counter to instuction operand
  509.             skelaton_counter = operand;
  510.  
  511.             } break;
  512.  
  513.         case OPC_N: 
  514.             {
  515.             // set direction to north
  516.             Set_Vel_BOB(&skelaton,0,-3);
  517.   
  518.             // set animation to north
  519.             Set_Animation_BOB(&skelaton,opcode);
  520.             
  521.             // set counter to instuction operand
  522.             skelaton_counter = operand;
  523.  
  524.             } break;            
  525.  
  526.         case OPC_NW:
  527.             {
  528.             // set direction to northwest
  529.             Set_Vel_BOB(&skelaton,-3,-3);
  530.   
  531.             // set animation to northwest
  532.             Set_Animation_BOB(&skelaton,opcode);
  533.             
  534.             // set counter to instuction operand
  535.             skelaton_counter = operand;
  536.  
  537.             } break;            
  538.  
  539.         case OPC_W: 
  540.             {
  541.             // set direction to west
  542.             Set_Vel_BOB(&skelaton,-3,0);
  543.   
  544.             // set animation to west
  545.             Set_Animation_BOB(&skelaton,opcode);
  546.             
  547.             // set counter to instuction operand
  548.             skelaton_counter = operand;
  549.              
  550.             } break;            
  551.  
  552.         case OPC_SW:
  553.             {
  554.             // set direction to southwest
  555.             Set_Vel_BOB(&skelaton,-3,3);
  556.   
  557.             // set animation to southwest
  558.             Set_Animation_BOB(&skelaton,opcode);
  559.             
  560.             // set counter to instuction operand
  561.             skelaton_counter = operand;
  562.  
  563.             } break;            
  564.  
  565.         case OPC_S: 
  566.             {
  567.             // set direction to south
  568.             Set_Vel_BOB(&skelaton,0,3);
  569.   
  570.             // set animation to south
  571.             Set_Animation_BOB(&skelaton,opcode);
  572.             
  573.             // set counter to instuction operand
  574.             skelaton_counter = operand;
  575.  
  576.             } break;            
  577.  
  578.         case OPC_SE:
  579.             {
  580.             // set direction to southeast
  581.             Set_Vel_BOB(&skelaton,3,3);
  582.   
  583.             // set animation to southeast
  584.             Set_Animation_BOB(&skelaton,opcode);
  585.             
  586.             // set counter to instuction operand
  587.             skelaton_counter = operand;
  588.  
  589.             } break;            
  590.  
  591.         case OPC_STOP: 
  592.             {
  593.             // stop motion
  594.             Set_Vel_BOB(&skelaton,0,0);
  595.             
  596.             // set counter to instuction operand
  597.             skelaton_counter = operand;
  598.  
  599.             } break;
  600.  
  601.         case OPC_RAND:
  602.             {
  603.             // set counter to instuction operand
  604.             skelaton_counter = 0;
  605.  
  606.             } break;
  607.  
  608.         case OPC_TEST_DIST:
  609.              {
  610.              // test distance between bat and skelaton
  611.              // if bat is too far, then move toward bat
  612.  
  613.              int dx = (bat.x - skelaton.x);
  614.              int dy = (bat.y - skelaton.y);
  615.  
  616.              // test distance against minimum lonelyness
  617.              if (sqrt((dx*dx) + (dy*dy)) > MIN_LONELYNESS)
  618.                 {
  619.                 // the skelaton needs to be pointed toward the bat (player)
  620.                 // this is a bit hard because we need to point the skelaton
  621.                 // in 1 of 8 directions, instead of just giving him a velocity
  622.                 // to solve the problem well break it up into a dx and a dy and then
  623.                 // use a look up table to set everything up right
  624.    
  625.                 int direction = 0; // the bit encoded direction
  626.  
  627.                 // first east-west
  628.                 if (bat.x > skelaton.x)
  629.                    direction|=EAST_BIT;
  630.                 else
  631.                 if (bat.x < skelaton.x)
  632.                    direction|=WEST_BIT;
  633.                 
  634.                 // now north-south
  635.                 if (bat.y > skelaton.y)
  636.                    direction|=SOUTH_BIT;
  637.                 else
  638.                 if (bat.y < skelaton.y)
  639.                    direction|=NORTH_BIT;
  640.           
  641.                 // test final direction, note this could be compressed into
  642.                 // another look up table, but this is simpler 
  643.                 switch(direction)
  644.                         {
  645.                         case WEST_BIT:
  646.                             {
  647.                             // set motion
  648.                             Set_Vel_BOB(&skelaton,-3,0);
  649.   
  650.                             // set animation 
  651.                             Set_Animation_BOB(&skelaton,OPC_W);
  652.             
  653.                             // set counter to instuction operand
  654.                             skelaton_counter = operand;
  655.  
  656.                             } break;
  657.  
  658.                         case EAST_BIT:     
  659.                              {
  660.                             // set motion
  661.                             Set_Vel_BOB(&skelaton,3,0);
  662.   
  663.                             // set animation 
  664.                             Set_Animation_BOB(&skelaton,OPC_E);
  665.             
  666.                             // set counter to instuction operand
  667.                             skelaton_counter = operand;
  668.  
  669.                              } break;
  670.  
  671.                         case NORTH_BIT:     
  672.                             {
  673.                             // set motion
  674.                             Set_Vel_BOB(&skelaton,0,-3);
  675.   
  676.                             // set animation 
  677.                             Set_Animation_BOB(&skelaton,OPC_N);
  678.             
  679.                             // set counter to instuction operand
  680.                             skelaton_counter = operand;
  681.  
  682.                             } break;
  683.  
  684.                         case SOUTH_BIT:     
  685.                             {
  686.                             // set motion
  687.                             Set_Vel_BOB(&skelaton,0,3);
  688.   
  689.                             // set animation 
  690.                             Set_Animation_BOB(&skelaton,OPC_S);
  691.             
  692.                             // set counter to instuction operand
  693.                             skelaton_counter = operand;
  694.                             } break;
  695.  
  696.                         case (NORTH_BIT | WEST_BIT):
  697.                             {
  698.                             // set motion
  699.                             Set_Vel_BOB(&skelaton,-3,-3);
  700.   
  701.                             // set animation 
  702.                             Set_Animation_BOB(&skelaton,OPC_NW);
  703.             
  704.                             // set counter to instuction operand
  705.                             skelaton_counter = operand;
  706.                             } break;
  707.  
  708.                         case (NORTH_BIT | EAST_BIT):
  709.                             {
  710.                             // set motion
  711.                             Set_Vel_BOB(&skelaton,3,-3);
  712.   
  713.                             // set animation 
  714.                             Set_Animation_BOB(&skelaton,OPC_NE);
  715.             
  716.                             // set counter to instuction operand
  717.                             skelaton_counter = operand;
  718.                             } break;
  719.  
  720.                         case (SOUTH_BIT | WEST_BIT):
  721.                             {
  722.                             // set motion
  723.                             Set_Vel_BOB(&skelaton,-3,3);
  724.   
  725.                             // set animation 
  726.                             Set_Animation_BOB(&skelaton,OPC_SW);
  727.             
  728.                             // set counter to instuction operand
  729.                             skelaton_counter = operand;
  730.                             } break;
  731.  
  732.                         case (SOUTH_BIT | EAST_BIT):
  733.                             {
  734.                             // set motion
  735.                             Set_Vel_BOB(&skelaton,3,3);
  736.   
  737.                             // set animation 
  738.                             Set_Animation_BOB(&skelaton,OPC_SE);
  739.             
  740.                             // set counter to instuction operand
  741.                             skelaton_counter = operand;
  742.                             } break;
  743.  
  744.                         default: break;
  745.  
  746.                         } // end switch 
  747.                
  748.                 } // end if
  749.  
  750.              } break;
  751.  
  752.         case OPC_END: 
  753.             {
  754.             // stop motion
  755.             Set_Vel_BOB(&skelaton,0,0);
  756.             
  757.             // select a random pattern in pattern bank
  758.             skelaton_pattern_index = rand()%NUM_PATTERNS;
  759.             curr_pattern = patterns[skelaton_pattern_index];
  760.    
  761.             // now reset instuction pointer
  762.             skelaton_ip = 0;
  763.  
  764.             // reset counter
  765.             skelaton_counter = 0;
  766.  
  767.             } break;
  768.         
  769.         default: break;
  770.  
  771.         } // end switch
  772.  
  773.     } // end if
  774.  
  775.  
  776. // draw stats
  777. sprintf(buffer,"Pattern #%d",skelaton_pattern_index);
  778. Draw_Text_GDI(buffer,10, 400,RGB(0,255,0), lpddsback);
  779.  
  780. sprintf(buffer,"Opcode=%s Operand=%d",opcode_names[opcode],operand);
  781. Draw_Text_GDI(buffer,10, 416,RGB(0,255,0), lpddsback);
  782.  
  783. sprintf(buffer,"Instruction Ptr=%d ", skelaton_ip);
  784. Draw_Text_GDI(buffer,10, 432,RGB(0,255,0), lpddsback);
  785.  
  786. sprintf(buffer,"Counter=%d ", skelaton_counter);
  787. Draw_Text_GDI(buffer,10, 448,RGB(0,255,0), lpddsback);
  788.  
  789. } // end skelaton_AI
  790.  
  791. //////////////////////////////////////////////////////////
  792.  
  793. int Game_Main(void *parms)
  794. {
  795. // this is the workhorse of your game it will be called
  796. // continuously in real-time this is like main() in C
  797. // all the calls for you game go here!
  798.  
  799. int index; // looping var
  800.  
  801. // start the timing clock
  802. Start_Clock();
  803.  
  804. // clear the drawing surface
  805. DD_Fill_Surface(lpddsback, 0);
  806.  
  807. // lock back buffer and copy background into it
  808. DD_Lock_Back_Surface();
  809.  
  810. // draw background
  811. Draw_Bitmap(&background_bmp, back_buffer, back_lpitch,0);
  812.  
  813. // unlock back surface
  814. DD_Unlock_Back_Surface();
  815.  
  816. // read keyboard
  817. DI_Read_Keyboard();
  818.  
  819. // do the ai on skelaton
  820. Skelaton_AI();
  821.  
  822. // animate the bat
  823. Animate_BOB(&bat);
  824.  
  825. // the animate the skelaton unless its stopped
  826. if (opcode!=OPC_STOP)
  827.    Animate_BOB(&skelaton);
  828.  
  829. // move skelaton
  830. Move_BOB(&skelaton);
  831.  
  832. // test if skelaton is off screen, if so wrap around
  833. if (skelaton.x >= SCREEN_WIDTH)
  834.    skelaton.x = -skelaton.width;
  835. else
  836. if (skelaton.x < -skelaton.width)
  837.    skelaton.x = SCREEN_WIDTH;
  838.  
  839. if (skelaton.y >= SCREEN_HEIGHT)
  840.    skelaton.y = -skelaton.height;
  841. else
  842. if (skelaton.y < -skelaton.height)
  843.    skelaton.y = SCREEN_HEIGHT;
  844.  
  845. // let player move the bat
  846. // allow player to move
  847. if (keyboard_state[DIK_RIGHT])
  848.    bat.x+=4;
  849. else
  850. if (keyboard_state[DIK_LEFT])
  851.    bat.x-=4;
  852.  
  853. if (keyboard_state[DIK_UP])
  854.    bat.y-=4;
  855. else
  856. if (keyboard_state[DIK_DOWN])
  857.    bat.y+=4;
  858.  
  859.  
  860. // test if bat is off screen, if so wrap around
  861. if (bat.x >= SCREEN_WIDTH)
  862.    bat.x = -bat.width;
  863. else
  864. if (bat.x < -bat.width)
  865.    bat.x = SCREEN_WIDTH;
  866.  
  867. if (bat.y >= SCREEN_HEIGHT)
  868.    bat.y = -bat.height;
  869. else
  870. if (bat.y < -bat.height)
  871.    bat.y = SCREEN_HEIGHT;
  872.  
  873. // draw the skelaton
  874. Draw_BOB(&skelaton, lpddsback);
  875.  
  876. // draw the bat
  877. Draw_BOB(&bat, lpddsback);
  878.  
  879. // draw title
  880. Draw_Text_GDI("Skelaton Pattern Demo With Tracking",10, 10,RGB(0,255,255), lpddsback);
  881.  
  882. // flip the surfaces
  883. DD_Flip();
  884.  
  885. // sync to 30ish fps
  886. Wait_Clock(30);
  887.  
  888. // check of user is trying to exit
  889. if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE])
  890.     {
  891.     PostMessage(main_window_handle, WM_DESTROY,0,0);
  892.  
  893.     // stop all sounds
  894.     Stop_All_Sounds();
  895.  
  896.     // do a screen transition
  897.     Screen_Transitions(SCREEN_DARKNESS,NULL,0);
  898.  
  899.     } // end if
  900.  
  901. // return success
  902. return(1);
  903.  
  904. } // end Game_Main
  905.  
  906. //////////////////////////////////////////////////////////
  907.