home *** CD-ROM | disk | FTP | other *** search
/ Teach Yourself Game Programming in 21 Days / TYGAMES_R.ISO / source / day_18 / simpizza.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-07  |  105.5 KB  |  4,423 lines

  1.  
  2. // I N C L U D E S ///////////////////////////////////////////////////////////
  3.  
  4. #include <io.h>
  5. #include <conio.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include <fcntl.h>
  11. #include <memory.h>
  12. #include <malloc.h>
  13. #include <math.h>
  14. #include <string.h>
  15.  
  16. #include "graph3.h"   // include our graphics stuff
  17. #include "graph4.h"
  18. #include "graph6.h"
  19. #include "graph8.h"   // fixed point library
  20. #include "graph9.h"   // sound library
  21. #include "graph11.h"  // multitasking and keyboard interrupt driver
  22.  
  23. // P R O T O T Y P E S ///////////////////////////////////////////////////////
  24.  
  25. void Show_Stats();
  26.  
  27. void Age_Orders(void);
  28.  
  29. void Order_Pizza(void);
  30.  
  31. void Blink_House(int house_number);
  32.  
  33. void Start_Pizza(int x,
  34.                  int y,
  35.                  int xv,
  36.                  int yv,
  37.                  int direction);
  38.  
  39. void Erase_Pizzas(void);
  40.  
  41. void Behind_Pizzas(void);
  42.  
  43. void Draw_Pizzas(void);
  44.  
  45. void Move_Pizzas(void);
  46.  
  47. void Init_Pizzas(void);
  48.  
  49. void Load_Death(void);
  50.  
  51. void Start_Boy_Death(void);
  52.  
  53. void Erase_Boy_Death(void);
  54.  
  55. void Behind_Boy_Death(void);
  56.  
  57. void Draw_Boy_Death(void);
  58.  
  59. void Animate_Boy_Death(void);
  60.  
  61. void Init_Messages(void);
  62.  
  63. int Insert_Message(char *string,int preempt);
  64.  
  65. void Start_Message(int index);
  66.  
  67. void Display_Message(void);
  68.  
  69. void Send_Message(void);
  70.  
  71. void Start_Splat(int x,int y,int speed,int color);
  72.  
  73. void Behind_Splats(void);
  74.  
  75. void Erase_Splats(void);
  76.  
  77. void Draw_Splats(void);
  78.  
  79. void Animate_Splats(void);
  80.  
  81. void Init_Splats(void);
  82.  
  83. void Erase_Humans(void);
  84.  
  85. void Behind_Humans(void);
  86.  
  87. void Draw_Humans(void);
  88.  
  89. int Start_Human(void);
  90.  
  91. void Move_Humans(void);
  92.  
  93. void Init_Humans(void);
  94.  
  95. void Erase_Cars(void);
  96.  
  97. void Behind_Cars(void);
  98.  
  99. void Draw_Cars(void);
  100.  
  101. void Move_Cars(void);
  102.  
  103. void Init_Cars(void);
  104.  
  105. unsigned char Get_Pixel_DB(int x,int y);
  106.  
  107. int Initialize_Sound_System(void);
  108.  
  109. void Close_Sound_System(void);
  110.  
  111. void Play_Sound(int sound);
  112.  
  113. void Do_Intro(void);
  114.  
  115. void Load_Environment(void);
  116.  
  117. void Load_Background(void);
  118.  
  119. void Draw_Gauages(void);
  120.  
  121. // D E F I N E S /////////////////////////////////////////////////////////////
  122.  
  123. #define DEBUG           0   // turns on/off debug information
  124.  
  125. #define FP_SHIFT_D64    12  // converts a fixed point to an int and divides
  126.                             // by 16 in one operation
  127.  
  128. #define END_MOPEDS            1 // game ended because player used up mopeds
  129. #define END_TIME              2 // game ended because it's past 5:00pm
  130.  
  131. // defines for pizzas
  132.  
  133. #define PIZZA_ALIVE           1 // state of a live Pizza
  134. #define PIZZA_DEAD            0 // state of a dead Pizza
  135. #define NUM_PIZZAS            3 // number of Pizzas that can be fired
  136. #define NUM_PIZZA_FRAMES      8 // number of frames in pizza animation
  137.  
  138. #define START_NUM_COLOR (14*16)
  139.  
  140. #define END_NUM_COLOR   (14*16+23)
  141.  
  142.  
  143. #define START_SPEEDO_COLOR  (10*16)
  144. #define END_SPEEDO_COLOR    (10*16+5)
  145.  
  146. #define ROOF_COLOR_REG  204      // the roofs color register
  147.  
  148. #define MAX_HOUSES      32  // the maximum number of houses in the city
  149.  
  150. #define HOUSE_NO_ORDER  0   // this house has not ordered
  151. #define HOUSE_ORDERED   1   // this house is waiting for a pizza
  152.  
  153. // game area defines
  154.  
  155. #define CELL_COLUMNS    20  // number of columns in the cell world
  156. #define CELL_ROWS       11  // number of rows in the cell world
  157.  
  158. // general Splats
  159.  
  160. #define NUM_SPLATS       4  // number of Splats that can run at once
  161.  
  162. #define SPLAT_DEAD       0   // state of a dead Splat
  163. #define SPLAT_ALIVE      1   // state of a live Splat
  164.  
  165. // human defines
  166.  
  167. #define NUM_HUMAN_FRAMES 16  // number of animation frames
  168. #define NUM_HUMANS        8  // maximum number of humans
  169.  
  170. #define HUMAN_DEAD        0  // states of humans
  171. #define HUMAN_NORTH       1
  172. #define HUMAN_SOUTH       2
  173. #define HUMAN_WEST        3
  174. #define HUMAN_EAST        4
  175.  
  176. // player defines
  177.  
  178. #define NUM_BOY_FRAMES    16 // number of animation cells for players moped
  179.  
  180. #define BOY_DEAD          0  // states for vinnie
  181. #define BOY_ALIVE         1
  182. #define BOY_DYING         2
  183.  
  184. // car defines
  185.  
  186. #define NUM_CARS          8  // number of cars in the simulation
  187. #define NUM_CAR_FRAMES    20 // number of animation cells for cars
  188.  
  189. #define CAR_COLOR_1       0  // base offsets for different colors
  190. #define CAR_COLOR_2       4
  191. #define CAR_COLOR_3       8
  192. #define CAR_COLOR_4       12
  193.  
  194. #define CAR_DEAD          0  // states of cars
  195. #define CAR_STARTING      1
  196. #define CAR_DRIVING       2
  197. #define CAR_SLOWING       3
  198. #define CAR_STOPPED       4
  199.  
  200. #define CAR_NORTH         1  // directions of cars
  201. #define CAR_SOUTH         2
  202. #define CAR_WEST          3
  203. #define CAR_EAST          4
  204.  
  205. // player defines for vinnie
  206.  
  207. #define PLAYER_DEAD       0
  208. #define PLAYER_ALIVE      1
  209. #define PLAYER_DYING      2
  210.  
  211. // direction of player
  212.  
  213. #define PLAYER_EAST       0
  214. #define PLAYER_WEST       1
  215. #define PLAYER_NORTH      2
  216. #define PLAYER_SOUTH      3
  217.  
  218. // define bitmap id's
  219.  
  220. #define STOP_NORTH_ID     9     // a stop sign on a north bound street
  221. #define STOP_SOUTH_ID     8     // a stop sign on an east bound street
  222.  
  223. #define HOUSE_WEST_1_ID   33    // id's for the 4 bitmaps that make up a west
  224. #define HOUSE_WEST_2_ID   34    // facing house
  225. #define HOUSE_WEST_3_ID   35
  226. #define HOUSE_WEST_4_ID   36
  227.  
  228. #define HOUSE_EAST_1_ID   37    // id's for the 4 bitmaps that make up a east
  229. #define HOUSE_EAST_2_ID   38    // facing house
  230. #define HOUSE_EAST_3_ID   39
  231. #define HOUSE_EAST_4_ID   40
  232.  
  233. #define NUM_MESSAGES      8  // maximum number of pending messages
  234.  
  235. // states of a message
  236.  
  237. #define MESS_DEAD         0  // this message is dead
  238. #define MESS_WAIT         1  // this message is waiting
  239.  
  240. // sound system defines
  241.  
  242. #define NUM_SOUNDS           14   // number of sounds in system
  243.  
  244. #define SOUND_CAR_STOP       0  // a car stopping
  245. #define SOUND_CAR_START      1  // a car starting
  246. #define SOUND_MOPED_HORN     2  // the mopeds horn
  247. #define SOUND_CAR_HORN       3  // a cars horn
  248. #define SOUND_MOPED_HIT      4  // the moped being hit
  249. #define SOUND_HUMAN_HIT      5  // a human being hit
  250. #define SOUND_YO_VINNIE      6  // here's an order
  251. #define SOUND_LOST_ORDER     7  // you lost an order
  252. #define SOUND_THANK_YOU_B    8  // thank you from the customer  (boy)
  253. #define SOUND_THANK_YOU_G    9  // thank you from the customer  (girl)
  254. #define SOUND_TOO_LONG       10 // delivery took too long
  255. #define SOUND_COME_HOME      11 // days over
  256. #define SOUND_CAR_SOUND      12 // backgronud car sound
  257. #define SOUND_START          13 // start of game
  258.  
  259.  
  260. #define SOUND_DEFAULT_PORT   0x220  // default sound port for sound blaster
  261. #define SOUND_DEFAULT_INT    5      // default interrupt
  262.  
  263. // M A C R O S //////////////////////////////////////////////////////////////
  264.  
  265. #define SET_SPRITE_SIZE(w,h) {sprite_width=w; sprite_height=h;}
  266.  
  267. // S T R U C T U R E S ///////////////////////////////////////////////////////
  268.  
  269. // this is the structure used to database all the house positions in the city
  270.  
  271. typedef struct house_typ
  272.         {
  273.         int x;      // position of house
  274.         int y;
  275.         int type;   // type of house i.e. east or west front door
  276.         int num;    // house number
  277.  
  278.         int state;  // is there an order pending
  279.  
  280.         int timer;  // the current time left to deliver the pizza
  281.  
  282.         } house, *house_ptr;
  283.  
  284. // typedef for the car
  285.  
  286. typedef struct car_typ
  287.         {
  288.         int x;                   // x position
  289.         int y;                   // y position
  290.         int curr_xv;             // x velocity
  291.         int curr_yv;             // y velocity
  292.  
  293.         int max_xv;              // max x velocity
  294.         int max_yv;              // max y velocity
  295.  
  296.         int state;               // the state of the car
  297.         int direction;
  298.         int counter_1;           // use for counting
  299.         int threshold_1;         // the counters threshold
  300.  
  301.         int counter_2;
  302.         int threshold_2;
  303.  
  304.         int counter_3;
  305.         int threshold_3;
  306.  
  307.         int color;              // color of car
  308.  
  309.         sprite object;          // the sprite
  310.  
  311.         } car, *car_ptr;
  312.  
  313.  
  314. // typedef for the player
  315.  
  316. typedef struct player_typ
  317.         {
  318.         fixed x;                   // x position
  319.         fixed y;                   // y position
  320.  
  321.         fixed xv;                  // x velocity
  322.         fixed yv;                  // y velocity
  323.  
  324.         fixed curr_xv;             // x velocity
  325.         fixed curr_yv;             // y velocity
  326.  
  327.         fixed max_xv;              // max x velocity
  328.         fixed max_yv;              // max y velocity
  329.  
  330.  
  331.         fixed throttle;            // current throttle position
  332.         fixed hp;                  // horse power
  333.         fixed friction;            // the friction of the air, bike, ...
  334.         fixed brakes;              // the braking friction
  335.  
  336.         fixed max_throttle;        // maximum throttle position
  337.  
  338.         int state;               // the state of the player
  339.         int direction;
  340.         int counter_1;           // use for counting
  341.         int threshold_1;         // the counters threshold
  342.  
  343.         int counter_2;
  344.  
  345.         int threshold_2;
  346.  
  347.         int counter_3;
  348.         int threshold_3;
  349.  
  350.         sprite object;          // the sprite
  351.  
  352.         } player, *player_ptr;
  353.  
  354. // typedef for a projectile
  355.  
  356. typedef struct projectile_typ
  357.         {
  358.         int x;                   // x position
  359.         int y;                   // y position
  360.         int xv;                  // x velocity
  361.         int yv;                  // y velocity
  362.         int state;               // the state of the particle
  363.         int counter_1;           // use for counting
  364.         int threshold_1;         // the counters threshold
  365.  
  366.         int counter_2;
  367.         int threshold_2;
  368.  
  369.         sprite object;           // the projectile sprite
  370.  
  371.         } projectile, *projectile_ptr;
  372.  
  373. // this structure holds the message data
  374.  
  375. typedef struct message_type
  376.         {
  377.  
  378.         char string[64];   // holds the message
  379.  
  380.         int state;         // state of message waiting, playing, dead
  381.  
  382.         } message, *message_ptr;
  383.  
  384. // G L O B A L S  ////////////////////////////////////////////////////////////
  385.  
  386. pcx_picture imagery_pcx,      // the game imagery
  387.             background_pcx,   // the backdrop
  388.             intro_pcx;        // the introduction screen
  389.  
  390. // the sprites used in the game
  391.  
  392. sprite roads,                 // the road bitmaps
  393.        builds,                // the building and house bitmaps
  394.        numbers,               // the house numbers
  395.        humans[NUM_HUMANS],    // the humans on the streets
  396.        splats[NUM_SPLATS],    // the array of Splats
  397.        boy_death;             // the death sequence sprite for the boy
  398.  
  399. projectile pizzas[NUM_PIZZAS];  // the array of pizzas in the world
  400.  
  401. player boy;                     // vinnie the pizza boy
  402.  
  403. // statistics of boy
  404.  
  405. int boy_mopeds    = 3,          // number of mopeds
  406.     boy_pizzas    = 0,          // number of pizzas on moped rack
  407.     boy_xpeds     = 0,          // number of peds player has killed
  408.     boy_tips      = 0,          // current tips
  409.     boy_time      = 540,        // the time in minutes
  410.     orders_filled = 0,          // how many orders have been filled
  411.     total_orders  = 0;          // total pizzas ordered
  412.  
  413.  
  414. int throttle_on=0;            // flags if the pizza boy has the throttle on
  415.  
  416. car cars[NUM_CARS];           // the cars in the game
  417.  
  418. house house_pos[MAX_HOUSES];  // the houses in the city
  419.  
  420. int curr_house;               // the last house entered into database
  421.  
  422. RGB_color roof_color,                // used to hold roof color
  423.           alert_color = {63,63,63};  // used as the house wants a pizza color!
  424.  
  425. int lite_house =  0;      // debuging var used to light houses up
  426.  
  427. int difficulty=75;        // difficulty of game, 100 is easy 1 is hardest
  428.  
  429. long players_score = 0;    // initial score
  430.  
  431. int players_dir    = PLAYER_SOUTH;  // initial direction of player
  432.  
  433. message messages[NUM_MESSAGES];   // the array of messages which is really a
  434.                                   // circular queue
  435.  
  436. int mess_head=-1,                 // head of message queue
  437.     mess_tail=-1;                 // tail of message queue
  438.  
  439. int message_index  = 0,           // current string index of message
  440.     message_length = 0,           // overall length of message
  441.     message_done   = 1;           // is the message done playing
  442.  
  443. char message_string[128];         // global message string
  444.  
  445. // the sound system variables
  446.  
  447. char far *sound_fx[NUM_SOUNDS];           // pointers to the voc files
  448. unsigned char sound_lengths[NUM_SOUNDS];  // lengths of the voc files
  449.  
  450. int sound_available = 0;                  // flags if sound is available
  451.  
  452. int sound_port = SOUND_DEFAULT_PORT;      // default sound port
  453. int sound_int  = SOUND_DEFAULT_INT;       // default sound interrupt
  454.  
  455.  
  456. // data structures
  457.  
  458. // the city that pizza boy delivers to
  459.  
  460. char *city_1[CELL_ROWS] = { "..45[]0145[]{.45[]01",
  461.                             "..76[]3276[]0176[]32",
  462.                             "..45[]01.}[]3245[]01",
  463.                             "..76s]32.}s]{.76s]32",
  464.                             "^^^^##^^^^##^^^^##^^",
  465.                             "vvvv##vvvv##vvvv##vv",
  466.                             "..45[S{.45[S0145[S{.",
  467.                             "..76[]0176[]3276[]01",
  468.                             "cd89[]3245[]{..}[]32",
  469.                             "feba[]0176[]0145[]01",
  470.                             "...}[]32.}[]3276[]32",};
  471.  
  472.  
  473. // velocities used to compute trajectory vector of moped
  474.  
  475. fixed boy_xv[NUM_BOY_FRAMES] =
  476.  
  477.                     {(fixed)(1.000000*FP_SHIFT_2N),
  478.                      (fixed)(0.923880*FP_SHIFT_2N),
  479.                      (fixed)(0.707107*FP_SHIFT_2N),
  480.                      (fixed)(0.382684*FP_SHIFT_2N),
  481.                      (fixed)(0.000001*FP_SHIFT_2N),
  482.                     (fixed)(-0.382682*FP_SHIFT_2N),
  483.                     (fixed)(-0.707105*FP_SHIFT_2N),
  484.                     (fixed)(-0.923879*FP_SHIFT_2N),
  485.                     (fixed)(-1.000000*FP_SHIFT_2N),
  486.                     (fixed)(-0.923881*FP_SHIFT_2N),
  487.                     (fixed)(-0.707109*FP_SHIFT_2N),
  488.                     (fixed)(-0.382687*FP_SHIFT_2N),
  489.                     (fixed)(-0.000004*FP_SHIFT_2N),
  490.                     (fixed)(0.382679*FP_SHIFT_2N),
  491.                     (fixed)(0.707103*FP_SHIFT_2N),
  492.                     (fixed)(0.923878*FP_SHIFT_2N)};
  493.  
  494.  
  495. fixed boy_yv[NUM_BOY_FRAMES] =
  496.  
  497.                    {(fixed)(0.000000 *FP_SHIFT_2N),
  498.                     (fixed)(-0.382683*FP_SHIFT_2N),
  499.                     (fixed)(-0.707106*FP_SHIFT_2N),
  500.                     (fixed)(-0.923879*FP_SHIFT_2N),
  501.                     (fixed)(-1.000000*FP_SHIFT_2N),
  502.                     (fixed)(-0.923880*FP_SHIFT_2N),
  503.                     (fixed)(-0.707108*FP_SHIFT_2N),
  504.                     (fixed)(-0.382686*FP_SHIFT_2N),
  505.                     (fixed)(-0.000003*FP_SHIFT_2N),
  506.                     (fixed)(0.382681 *FP_SHIFT_2N),
  507.                     (fixed)(0.707104 *FP_SHIFT_2N),
  508.                     (fixed)(0.923878 *FP_SHIFT_2N),
  509.                     (fixed)(1.000000 *FP_SHIFT_2N),
  510.                     (fixed)(0.923881 *FP_SHIFT_2N),
  511.                     (fixed)(0.707110 *FP_SHIFT_2N),
  512.                     (fixed)(0.382688 *FP_SHIFT_2N)};
  513.  
  514.  
  515. // an integer version of the fixed point tables used to throw the pizzas with
  516.  
  517. int pizza_xv[] ={3,
  518.                  3,
  519.                  2,
  520.                  1,
  521.                  0,
  522.                  0,
  523.                 -1,
  524.                 -2,
  525.                 -2,
  526.                 -2,
  527.                 -1,
  528.                  0,
  529.                  0,
  530.                  1,
  531.                  2,
  532.                  3,};
  533.  
  534. int pizza_yv[] = {0,
  535.                   0,
  536.                  -1,
  537.                  -2,
  538.                  -2,
  539.                  -2,
  540.                  -1,
  541.                   0,
  542.                   0,
  543.                   1,
  544.                   2,
  545.                   3,
  546.                   3,
  547.                   3,
  548.                   2,
  549.                   1,};
  550.  
  551.  
  552. // F U N C T I O N S //////////////////////////////////////////////////////////
  553.  
  554. void Erase_Boy_Death(void)
  555. {
  556.  
  557. // this function erases the flying moped
  558.  
  559.  
  560. // test if the boy is dying
  561.  
  562. if (boy.state == BOY_DYING)
  563.    {
  564.  
  565.    // set sprite size for engine
  566.  
  567.    SET_SPRITE_SIZE(32,30);
  568.  
  569.    // erase the sprite
  570.  
  571.    Erase_Sprite_DB((sprite_ptr)&boy_death);
  572.  
  573.    } // end if boy is dying
  574.  
  575. } // end Erase_Boy_Death
  576.  
  577. //////////////////////////////////////////////////////////////////////////////
  578.  
  579. void Draw_Boy_Death(void)
  580. {
  581.  
  582. // this function draws the flying moped
  583.  
  584.  
  585. // test if the boy is dying
  586.  
  587. if (boy.state == BOY_DYING)
  588.    {
  589.  
  590.    // set sprite size for engine
  591.  
  592.    SET_SPRITE_SIZE(32,30);
  593.  
  594.    // draw the sprite
  595.  
  596.    Draw_Sprite_DB((sprite_ptr)&boy_death);
  597.  
  598.    } // end if boy is dying
  599.  
  600. } // end Draw_Boy_Death
  601.  
  602. ///////////////////////////////////////////////////////////////////////////////
  603.  
  604. void Behind_Boy_Death(void)
  605. {
  606.  
  607. // this function scans under the flying moped
  608.  
  609.  
  610. // test if the boy is dying
  611.  
  612. if (boy.state == BOY_DYING)
  613.    {
  614.  
  615.    // set sprite size for engine
  616.  
  617.    SET_SPRITE_SIZE(32,30);
  618.  
  619.    // erase the sprite
  620.  
  621.    Behind_Sprite_DB((sprite_ptr)&boy_death);
  622.  
  623.    } // end if boy is dying
  624.  
  625. } // end Behind_Boy_Death
  626.  
  627. //////////////////////////////////////////////////////////////////////////////
  628.  
  629. void Animate_Boy_Death(void)
  630. {
  631.  
  632. // this function moves and animates the flying moped
  633.  
  634. if (boy.state==BOY_DYING)
  635.    {
  636.  
  637.    // test if we are moving up or down
  638.  
  639.    if (boy_death.motion_clock==1) // going up i.e. toward center of screen
  640.       {
  641.       // move player toward center of screen to make it look 3-D
  642.  
  643.       // x - tracking
  644.  
  645.       if (boy_death.x<160)
  646.           boy_death.x+=4;
  647.       else
  648.       if  (boy_death.x>160+4)
  649.            boy_death.x-=4;
  650.  
  651.       // y - tracking
  652.  
  653.       if (boy_death.y<100)
  654.           boy_death.y+=4;
  655.       else
  656.       if  (boy_death.y>100+4)
  657.            boy_death.y-=4;
  658.  
  659.       } // end if going up
  660.    else
  661.       {
  662.       // must be falling back to earth
  663.  
  664.       // move player toward where he was hit
  665.  
  666.       // x - tracking
  667.  
  668.       if (boy_death.x<boy_death.x_old)
  669.           boy_death.x+=4;
  670.       else
  671.       if  (boy_death.x>boy_death.x_old+4)
  672.            boy_death.x-=4;
  673.  
  674.       // y - tracking
  675.  
  676.       if (boy_death.y<boy_death.y_old )
  677.           boy_death.y+=4;
  678.       else
  679.       if  (boy_death.y>boy_death.y_old+4)
  680.            boy_death.y-=4;
  681.  
  682.       } // end else
  683.  
  684.    // do a boundary test to make sure sprite stays on screen
  685.  
  686.    // x - tests
  687.  
  688.    if (boy_death.x>320-32)
  689.        boy_death.x=320-32;
  690.    else
  691.    if (boy_death.x<0)
  692.        boy_death.x=0;
  693.  
  694.    // y - tests
  695.  
  696.    if (boy_death.y>200-32)
  697.        boy_death.y=200-32;
  698.    else
  699.    if (boy_death.y<0)
  700.        boy_death.y=0;
  701.  
  702.    // test if it's time to animate
  703.  
  704.    if (++boy_death.anim_clock==boy_death.anim_speed)
  705.       {
  706.  
  707.       // reset clock
  708.  
  709.       boy_death.anim_clock = 0;
  710.  
  711.       // move to next frame in sequence
  712.  
  713.       ++boy_death.curr_frame;
  714.  
  715.       // test if it's time to end death or change direction of motion
  716.  
  717.       if (boy_death.curr_frame==7)
  718.          {
  719.          // make player fall back down
  720.  
  721.          boy_death.motion_clock=-1;
  722.  
  723.          } // end if start player back to earth
  724.       else
  725.       if (boy_death.curr_frame==16)
  726.          {
  727.  
  728.          // player has gone through death sequence so start him back at
  729.          // the pizza hut
  730.  
  731.          // set up state information
  732.  
  733.          boy.state             = BOY_ALIVE;
  734.          boy_death.state       = BOY_ALIVE;
  735.  
  736.          boy.x                 = Assign_Integer(48);
  737.          boy.y                 = Assign_Integer(144);
  738.          boy.curr_xv           = 0;
  739.          boy.curr_yv           = 0;
  740.          boy.max_xv            = 0;
  741.          boy.max_yv            = 0;
  742.          boy.xv                = 0;
  743.          boy.yv                = 0;
  744.  
  745.  
  746.          boy.throttle          = 0;
  747.          boy.hp                = Assign_Float((float).4);
  748.          boy.friction          = Assign_Float((float)-.10);
  749.          boy.brakes            = Assign_Integer(1);
  750.  
  751.          boy.max_throttle      = Assign_Integer(3);
  752.  
  753.          boy.counter_1         = 0;
  754.          boy.threshold_1       = 2;
  755.  
  756.          boy.object.curr_frame = 0;
  757.          boy.direction         = 0;
  758.  
  759.          } // end if it's all over
  760.  
  761.       } // end if time to change frames
  762.  
  763.    } // end if boy is dying
  764.  
  765. } // end Animate_Boy_Death
  766.  
  767. /////////////////////////////////////////////////////////////////////////////
  768.  
  769. void Start_Boy_Death(void)
  770.  
  771. {
  772.  
  773. // this function starts the animation sequence for the boy being hit by a car
  774.  
  775. boy.state                = BOY_DYING;
  776.  
  777. boy_death.state          = BOY_DYING;
  778. boy_death.x              = (int)(boy.x >> FP_SHIFT)+3-16;
  779. boy_death.y              = (int)(boy.y >> FP_SHIFT)+3-16;
  780.  
  781. boy_death.x_old          = boy_death.x;
  782. boy_death.y_old          = boy_death.y;
  783.  
  784. boy_death.anim_clock     = 0;
  785. boy_death.anim_speed     = 2;
  786. boy_death.motion_clock   = 1; // use this to mean going up
  787.  
  788. // make sure proper animation cell is selected
  789.  
  790. boy_death.curr_frame = 0;
  791.  
  792. // set sprite size for engine
  793.  
  794. SET_SPRITE_SIZE(32,30);
  795.  
  796. Behind_Sprite_DB((sprite_ptr)&boy_death);
  797.  
  798. // send a message
  799.  
  800. Insert_Message("ARRRRGGGGG!!!!!",1);
  801.  
  802. } // end Start_Boy_Death
  803.  
  804. /////////////////////////////////////////////////////////////////////////////
  805.  
  806. void Erase_Pizzas(void)
  807. {
  808.  
  809. // this function indexes through all the pizzas and if they are active
  810. // erases them by replacing the background color that was under them
  811.  
  812. int index;
  813.  
  814. // set sprite size for engine
  815.  
  816. SET_SPRITE_SIZE(6,6);
  817.  
  818. for (index=0; index<NUM_PIZZAS; index++)
  819.     {
  820.  
  821.     // is this pizza active
  822.  
  823.     if (pizzas[index].state == PIZZA_ALIVE)
  824.        {
  825.  
  826.        // extract proper parameters
  827.  
  828.        pizzas[index].object.x = pizzas[index].x;
  829.        pizzas[index].object.y = pizzas[index].y;
  830.  
  831.        // erase the sprite
  832.  
  833.        Erase_Sprite_DB((sprite_ptr)&pizzas[index].object);
  834.  
  835.        } // end if alive
  836.  
  837.     } // end for index
  838.  
  839. } // end Erase_Pizzas
  840.  
  841. /////////////////////////////////////////////////////////////////////////////
  842.  
  843. void Behind_Pizzas(void)
  844. {
  845.  
  846. // this function indexes through all the pizzas and if they are active
  847. // scans the background color that is behind them so it can be replaced later
  848.  
  849. int index;
  850.  
  851. // set sprite size for engine
  852.  
  853. SET_SPRITE_SIZE(6,6);
  854.  
  855. for (index=0; index<NUM_PIZZAS; index++)
  856.     {
  857.  
  858.     // is this pizza active
  859.  
  860.     if (pizzas[index].state == PIZZA_ALIVE)
  861.        {
  862.  
  863.        // extract proper parameters
  864.  
  865.        pizzas[index].object.x = pizzas[index].x;
  866.        pizzas[index].object.y = pizzas[index].y;
  867.  
  868.        // scan begind the sprite
  869.  
  870.        Behind_Sprite_DB((sprite_ptr)&pizzas[index].object);
  871.  
  872.        } // end if alive
  873.  
  874.     } // end for index
  875.  
  876. } // end Behind_Pizzas
  877.  
  878. /////////////////////////////////////////////////////////////////////////////
  879.  
  880. void Draw_Pizzas(void)
  881. {
  882.  
  883. // this function indexes through all the pizzas and if they are active
  884. // draws the missile as a bright white pixel on the screen
  885.  
  886. int index;
  887.  
  888. // set sprite size for engine
  889.  
  890. SET_SPRITE_SIZE(6,6);
  891.  
  892. for (index=0; index<NUM_PIZZAS; index++)
  893.     {
  894.  
  895.     // is this pizza active
  896.  
  897.     if (pizzas[index].state == PIZZA_ALIVE)
  898.        {
  899.  
  900.        // extract proper parameters
  901.  
  902.        pizzas[index].object.x = pizzas[index].x;
  903.        pizzas[index].object.y = pizzas[index].y;
  904.  
  905.        // draw the sprite
  906.  
  907.        Draw_Sprite_DB((sprite_ptr)&pizzas[index].object);
  908.  
  909.        } // end if alive
  910.  
  911.     } // end for index
  912.  
  913. } // end Draw_Pizzas
  914.  
  915. /////////////////////////////////////////////////////////////////////////////
  916.  
  917. void Move_Pizzas(void)
  918. {
  919.  
  920. // this function moves the pizzas and does all the collision detection
  921.  
  922. int index,              // used for loops
  923.     hindex,             // used to index through houses
  924.     pizza_x,            // position of pizza
  925.     pizza_y,
  926.     pizza_x_center,     // center of pizza
  927.     pizza_y_center,
  928.     cell_x,cell_y,cell_id;  // used to test if pizza has hit a background cell
  929.  
  930. float tip;              // used to compute tip
  931.  
  932. char buffer[128];  // used to build up strings
  933.  
  934. // loop thru all pizzas and perform a lot of tests
  935.  
  936. for (index=0; index<NUM_PIZZAS; index++)
  937.     {
  938.  
  939.     // is missile active
  940.  
  941.     if (pizzas[index].state == PIZZA_ALIVE)
  942.        {
  943.  
  944.        // move the pizza
  945.  
  946.        pizza_x = (pizzas[index].x += pizzas[index].xv);
  947.        pizza_y = (pizzas[index].y += pizzas[index].yv);
  948.  
  949.        // animate the pizza
  950.  
  951.        if (++pizzas[index].object.curr_frame>=NUM_PIZZA_FRAMES)
  952.           pizzas[index].object.curr_frame = 0;
  953.  
  954.        // compute center of pizza for ease of computations
  955.  
  956.        pizza_x_center = pizza_x+3;
  957.        pizza_y_center = pizza_y+3;
  958.  
  959.        // comment this stuff out for now
  960.        // cell_x = pizza_x_center  >> 4;  // divide by 16 since cells are 16x16 pixels
  961.        // cell_y = pizza_y_center  >> 4;
  962.        // what is the cell at this location
  963.        // cell_id =
  964.  
  965.  
  966.        // test if pizza has entered into a house that has ordered space
  967.  
  968.        for (hindex=0; hindex<=curr_house; hindex++)
  969.            {
  970.  
  971.            // test if this house has a pending order
  972.  
  973.            if (house_pos[hindex].state == HOUSE_ORDERED)
  974.               {
  975.  
  976.               // test if pizza has hit it taking into consideration direction
  977.               // house is facing
  978.  
  979.               if (house_pos[hindex].type == 1 ) // west facing house
  980.                  {
  981.                  // do collision test for west facing
  982.  
  983.                  if (pizza_x_center>=house_pos[hindex].x+5 &&
  984.                      pizza_x_center<=house_pos[hindex].x+17 &&
  985.                      pizza_y_center>=house_pos[hindex].y+3 &&
  986.                      pizza_y_center<=house_pos[hindex].y+20 )
  987.                     {
  988.                     // pizza boy made the delivery!
  989.  
  990.                     // kill pizza
  991.  
  992.                     pizzas[index].state = PIZZA_DEAD;
  993.  
  994.                     // increase number of orders filled
  995.  
  996.                     orders_filled++;
  997.  
  998.                     // take house off delivery list
  999.  
  1000.                     house_pos[hindex].state = HOUSE_NO_ORDER;
  1001.  
  1002.                     // compute tip based on elapsed time
  1003.  
  1004.                     tip = 5*((float)house_pos[hindex].timer/(float)500);
  1005.  
  1006.                     boy_tips+=(int)tip;
  1007.  
  1008.                     // build up message depending on amount of time
  1009.  
  1010.                     if (house_pos[hindex].timer<100)
  1011.                        {
  1012.  
  1013.                        sprintf(buffer,"It took long enough!");
  1014.  
  1015.                        // send it
  1016.  
  1017.                        Insert_Message(buffer,1);
  1018.  
  1019.                        // play sound
  1020.  
  1021.                        Play_Sound(SOUND_TOO_LONG);
  1022.  
  1023.                        } // end if took too long
  1024.                     else
  1025.                        {
  1026.  
  1027.                        sprintf(buffer,"Thank you!");
  1028.  
  1029.                        // send it
  1030.  
  1031.                        Insert_Message(buffer,1);
  1032.  
  1033.                        if (rand()%2==1)
  1034.                           Play_Sound(SOUND_THANK_YOU_B );
  1035.                        else
  1036.                           Play_Sound(SOUND_THANK_YOU_G );
  1037.  
  1038.  
  1039.  
  1040.                        } // end else good service
  1041.  
  1042.                     } // end if we have a winner
  1043.  
  1044.                  } // end if house facing west
  1045.               else
  1046.                  {
  1047.                  // house is facing east
  1048.  
  1049.                  // do collision test for east facing
  1050.  
  1051.                  if (pizza_x_center>=house_pos[hindex].x-1 &&
  1052.                      pizza_x_center<=house_pos[hindex].x+11 &&
  1053.                      pizza_y_center>=house_pos[hindex].y+3 &&
  1054.                      pizza_y_center<=house_pos[hindex].y+19 )
  1055.                     {
  1056.                     // pizza boy made the delivery!
  1057.  
  1058.                     // kill pizza
  1059.  
  1060.                     pizzas[index].state = PIZZA_DEAD;
  1061.  
  1062.                     // increase number of orders filled
  1063.  
  1064.                     orders_filled++;
  1065.  
  1066.                     // take house off delivery list
  1067.  
  1068.                     house_pos[hindex].state = HOUSE_NO_ORDER;
  1069.  
  1070.                     // compute tip based on elapsed time
  1071.  
  1072.                     tip = 5*((float)house_pos[hindex].timer/(float)500);
  1073.  
  1074.                     boy_tips+=(int)tip;
  1075.  
  1076.                     // build up message depending on amount of time
  1077.  
  1078.                     if (house_pos[hindex].timer<100)
  1079.                        {
  1080.  
  1081.                        sprintf(buffer,"It took long enough!");
  1082.  
  1083.                        // send it with urgency
  1084.  
  1085.                        Insert_Message(buffer,0);
  1086.  
  1087.                        Play_Sound(SOUND_TOO_LONG );
  1088.  
  1089.                        } // end if took too long
  1090.                     else
  1091.                        {
  1092.  
  1093.                        sprintf(buffer,"Thank you!");
  1094.  
  1095.                        // send it with urgency
  1096.  
  1097.                        Insert_Message(buffer,0);
  1098.  
  1099.                        if (rand()%2==1)
  1100.                           Play_Sound(SOUND_THANK_YOU_B );
  1101.                        else
  1102.                           Play_Sound(SOUND_THANK_YOU_G );
  1103.  
  1104.  
  1105.                        } // end else good service
  1106.  
  1107.                     } // end if we have a winner
  1108.  
  1109.                  } // end else house facing east
  1110.  
  1111.               } // end if house has ordered
  1112.  
  1113.            } // end for hindex
  1114.  
  1115.        // test if it's hit the edge of the screen or a wall
  1116.  
  1117.        if ( (pizza_x >= 320-8) || (pizza_x <= 0) ||
  1118.             (pizza_y > (176-8)) || (pizza_y <= 0) )
  1119.           {
  1120.  
  1121.           // kill pizza
  1122.  
  1123.           pizzas[index].state = PIZZA_DEAD;
  1124.  
  1125.           } // end if off edge of screen
  1126.  
  1127.        // test if pizza has timed out
  1128.  
  1129.        if (++pizzas[index].counter_1>=pizzas[index].threshold_1)
  1130.           {
  1131.  
  1132.           // kill pizza
  1133.  
  1134.           pizzas[index].state = PIZZA_DEAD;
  1135.  
  1136.           } // end if timed out
  1137.  
  1138.        } // end if pizza alive
  1139.  
  1140.     } // end for index
  1141.  
  1142. } // end Move_Pizzas
  1143.  
  1144. /////////////////////////////////////////////////////////////////////////////
  1145.  
  1146. void Start_Pizza(int x,
  1147.                  int y,
  1148.                  int xv,
  1149.                  int yv,
  1150.                  int direction)
  1151.  
  1152. {
  1153.  
  1154. // this function scans through the pizzas array and tries to find one that
  1155. // isn't being used.  this function could be more efficient.
  1156.  
  1157. int index;
  1158.  
  1159. // scan for a useable pizza
  1160.  
  1161. for (index=0; index<NUM_PIZZAS; index++)
  1162.     {
  1163.     // is this pizza free?
  1164.  
  1165.     if (pizzas[index].state == PIZZA_DEAD)
  1166.        {
  1167.  
  1168.        // set up fields
  1169.  
  1170.        pizzas[index].state       = PIZZA_ALIVE;
  1171.        pizzas[index].x           = x;
  1172.        pizzas[index].y           = y;
  1173.        pizzas[index].xv          = xv;
  1174.        pizzas[index].yv          = yv;
  1175.        pizzas[index].counter_1   = 0;
  1176.        pizzas[index].threshold_1 = 25;
  1177.  
  1178.        // make sure proper animation cell is selected
  1179.  
  1180.        pizzas[index].object.curr_frame = 0;
  1181.  
  1182.        // extract proper parameters
  1183.  
  1184.        pizzas[index].object.x = x;
  1185.        pizzas[index].object.y = y;
  1186.  
  1187.        // set sprite size for engine
  1188.  
  1189.        SET_SPRITE_SIZE(6,6);
  1190.  
  1191.        Behind_Sprite_DB((sprite_ptr)&pizzas[index].object);
  1192.  
  1193.        break; // exit loop
  1194.  
  1195.        } // end if found a good one
  1196.  
  1197.     } // end for index
  1198.  
  1199. } // end Start_Pizza
  1200.  
  1201. /////////////////////////////////////////////////////////////////////////////
  1202.  
  1203. void Init_Pizzas(void)
  1204. {
  1205. // this function just makes sure all the "state" fields of the pizzas are
  1206. // dead so that we don't get any strays on start up.  Remember never assume
  1207. // that variables are zeroed on instantiation!
  1208.  
  1209. int index;
  1210.  
  1211. for (index=0; index<NUM_PIZZAS; index++)
  1212.     pizzas[index].state = PIZZA_DEAD;
  1213.  
  1214. } // Init_Pizzas
  1215.  
  1216. //////////////////////////////////////////////////////////////////////////////
  1217.  
  1218. void Init_Messages(void)
  1219. {
  1220. // this function initializes the messages data structure
  1221.  
  1222. int index;  // loop index
  1223.  
  1224. for (index=0; index<NUM_MESSAGES; index++)
  1225.     {
  1226.  
  1227.     strcpy(messages[index].string,"");
  1228.  
  1229.     // set state to dead
  1230.  
  1231.     messages[index].state = MESS_DEAD;
  1232.  
  1233.     } // end for index
  1234.  
  1235. } // end Init_Messages
  1236.  
  1237. ///////////////////////////////////////////////////////////////////////////////
  1238.  
  1239. int Insert_Message(char *string,int preempt)
  1240. {
  1241. // this function inserts a message into the message queue, but doesn't guarantee
  1242. // that it will be played right now unless the preempt flag is true
  1243.  
  1244. // test for preempt
  1245.  
  1246. if (preempt)
  1247.    {
  1248.  
  1249.    // force feed message into display
  1250.  
  1251.    message_index=0;
  1252.  
  1253.    message_done=0;
  1254.  
  1255.    strcpy(message_string,"...........");
  1256.    strcat(message_string,string);
  1257.  
  1258.    // compute length before adding on the end dots
  1259.  
  1260.    message_length = strlen(message_string);
  1261.  
  1262.    strcat(message_string,"...........");
  1263.  
  1264.    return(1);
  1265.  
  1266.    } // end if preempt
  1267.  
  1268. // advance message index
  1269.  
  1270. if (++mess_head >= NUM_MESSAGES)
  1271.    mess_head=0;
  1272.  
  1273. // insert message into array
  1274.  
  1275. strcpy(messages[mess_head].string,string);
  1276.  
  1277. // set state of message to waiting
  1278.  
  1279. messages[mess_head].state = MESS_WAIT;
  1280.  
  1281. return(1);
  1282.  
  1283. } // end Insert_Message
  1284.  
  1285. ///////////////////////////////////////////////////////////////////////////////
  1286.  
  1287. void Start_Message(int index)
  1288. {
  1289. // this message conditions the new message to be played and resets all the
  1290. // appropriate variables
  1291.  
  1292. message_index=0;
  1293.  
  1294. message_done=0;
  1295.  
  1296. strcpy(message_string,"...........");
  1297. strcat(message_string,messages[index].string);
  1298.  
  1299. // compute length before adding on the end dots
  1300.  
  1301. message_length = strlen(message_string);
  1302.  
  1303. strcat(message_string,"...........");
  1304.  
  1305. } // end Start_Message
  1306.  
  1307. /////////////////////////////////////////////////////////////////////////////
  1308.  
  1309. void Display_Message(void)
  1310. {
  1311.  
  1312. static int counter=0,   // used as a time reference to slow scrolling of mess.
  1313.            entered=0;   // standard first time entered flag
  1314.  
  1315. char buffer[128];       // working buffer
  1316.  
  1317. // this is an autonomous function that is called every cycle to update
  1318. // the message center
  1319.  
  1320. if (!entered)
  1321.    {
  1322.  
  1323.    // set flag
  1324.  
  1325.    entered = 1;
  1326.  
  1327.    // do any initialization chores
  1328.  
  1329.    } // end if first time
  1330.  
  1331.  
  1332. // test fi it's time to process
  1333.  
  1334. if (++counter>1)
  1335.    {
  1336.  
  1337.    // reset counter
  1338.  
  1339.    counter=0;
  1340.  
  1341.    // test if message is not done
  1342.  
  1343.    if (!message_done)
  1344.       {
  1345.  
  1346.       // update display
  1347.       // we need to copy the proper number of bytes from the message string to the
  1348.       // buffer string
  1349.  
  1350.       memcpy((char *)buffer,(char *)&message_string[message_index],11);
  1351.  
  1352.       // set the null character
  1353.  
  1354.       buffer[11] = 0;
  1355.  
  1356.       Blit_String_DB(142,190,15,buffer,0);
  1357.  
  1358.       // update index and test for completion of message
  1359.  
  1360.       if (++message_index>message_length)
  1361.          {
  1362.  
  1363.          // send message to system that message is done
  1364.  
  1365.          message_done=1;
  1366.  
  1367.          } // end if message complete
  1368.  
  1369.  
  1370.       } // end if message not done
  1371.  
  1372.    } // end if it's time to process
  1373.  
  1374. } // end Display_Message
  1375.  
  1376. ///////////////////////////////////////////////////////////////////////////////
  1377.  
  1378. void Send_Message(void)
  1379. {
  1380. // this function will be called every cycle and will try to send the message
  1381. // display another if it can
  1382.  
  1383. int index; // loop variable
  1384.  
  1385. // first test if current message in display is complete
  1386.  
  1387. if (message_done)
  1388.    {
  1389.  
  1390.    // is there another message
  1391.  
  1392.    while(mess_head!=mess_tail)
  1393.       {
  1394.       // advance tail
  1395.  
  1396.       if (++mess_tail>=NUM_MESSAGES)
  1397.          mess_tail=0;
  1398.  
  1399.       // test if this message is a good one
  1400.  
  1401.       if (messages[mess_tail].state!=MESS_DEAD)
  1402.          {
  1403.          // start the message
  1404.  
  1405.          Start_Message(mess_tail);
  1406.  
  1407.          // set state of message to dead since it is now being played
  1408.  
  1409.          messages[mess_tail].state = MESS_DEAD;
  1410.  
  1411.          // blaze!!!
  1412.  
  1413.          return;
  1414.  
  1415.          } // end if we found a live one
  1416.  
  1417.       } // end while there is a message waiting
  1418.  
  1419.    } // end if message_done
  1420.  
  1421. } // end Send_Message
  1422.  
  1423. /////////////////////////////////////////////////////////////////////////////
  1424.  
  1425. void Start_Splat(int x,int y,int speed,int color)
  1426. {
  1427. // this function stars a generic Splat
  1428.  
  1429. int index;
  1430.  
  1431. SET_SPRITE_SIZE(10,10);
  1432.  
  1433. // scan for a useable Splat
  1434.  
  1435. for (index=0; index<NUM_SPLATS; index++)
  1436.     {
  1437.  
  1438.     if (splats[index].state == SPLAT_DEAD)
  1439.        {
  1440.  
  1441.        // set up fields
  1442.  
  1443.        splats[index].state        = SPLAT_ALIVE;
  1444.        splats[index].x            = x;
  1445.        splats[index].y            = y;
  1446.        splats[index].curr_frame   = 0+color;
  1447.        splats[index].anim_speed   = speed;
  1448.        splats[index].anim_clock   = 0;
  1449.        splats[index].motion_speed = 0;
  1450.  
  1451.        // scan background to be safe
  1452.  
  1453.        Behind_Sprite_DB((sprite_ptr)&splats[index]);
  1454.  
  1455.        break; // exit loop
  1456.  
  1457.        } // end if found a good one
  1458.  
  1459.     } // end for index
  1460.  
  1461. } // end Start_Splat
  1462.  
  1463. /////////////////////////////////////////////////////////////////////////////
  1464.  
  1465. void Behind_Splats(void)
  1466. {
  1467.  
  1468. // this function scans under the Splats
  1469.  
  1470. int index;
  1471.  
  1472. SET_SPRITE_SIZE(10,10);
  1473.  
  1474. // scan for a running Splats
  1475.  
  1476. for (index=0; index<NUM_SPLATS; index++)
  1477.     {
  1478.  
  1479.     if (splats[index].state == SPLAT_ALIVE)
  1480.        {
  1481.        Behind_Sprite_DB((sprite_ptr)&splats[index]);
  1482.  
  1483.        } // end if found a good one
  1484.  
  1485.     } // end for index
  1486.  
  1487. } // end Behind_Splats
  1488.  
  1489. /////////////////////////////////////////////////////////////////////////////
  1490.  
  1491. void Erase_Splats(void)
  1492. {
  1493. // this function erases all the current Splats
  1494.  
  1495. int index;
  1496.  
  1497. SET_SPRITE_SIZE(10,10);
  1498.  
  1499. // scan for a useable Splat
  1500.  
  1501. for (index=0; index<NUM_SPLATS; index++)
  1502.     {
  1503.  
  1504.     if (splats[index].state == SPLAT_ALIVE)
  1505.        {
  1506.        Erase_Sprite_DB((sprite_ptr)&splats[index]);
  1507.  
  1508.        } // end if found a good one
  1509.  
  1510.     } // end for index
  1511.  
  1512. } // end Erase_Splats
  1513.  
  1514. /////////////////////////////////////////////////////////////////////////////
  1515.  
  1516. void Draw_Splats(void)
  1517. {
  1518. // this function draws the Splat
  1519.  
  1520. int index;
  1521.  
  1522. SET_SPRITE_SIZE(10,10);
  1523.  
  1524. // scan for a useable Splat
  1525.  
  1526. for (index=0; index<NUM_SPLATS; index++)
  1527.     {
  1528.  
  1529.     // make sure this Splat is alive
  1530.  
  1531.     if (splats[index].state == SPLAT_ALIVE)
  1532.        {
  1533.  
  1534.        Draw_Sprite_DB((sprite_ptr)&splats[index]);
  1535.  
  1536.        } // end if found a good one
  1537.  
  1538.     } // end for index
  1539.  
  1540. } // end Draw_Splats
  1541.  
  1542. /////////////////////////////////////////////////////////////////////////////
  1543.  
  1544. void Animate_Splats(void)
  1545. {
  1546. // this function steps the Splat thru the frames of animation
  1547. int index;
  1548.  
  1549. // scan for a useable Splat
  1550.  
  1551. for (index=0; index<NUM_SPLATS; index++)
  1552.     {
  1553.     // test if Splat is alive
  1554.     if (splats[index].state == SPLAT_ALIVE)
  1555.        {
  1556.        // test if it's time to change frames
  1557.  
  1558.        if (++splats[index].anim_clock == splats[index].anim_speed)
  1559.           {
  1560.           // is the Splat over?
  1561.  
  1562.           ++splats[index].curr_frame;
  1563.  
  1564.           if (++splats[index].motion_speed == 4)
  1565.              splats[index].state = SPLAT_DEAD;
  1566.  
  1567.           // reset animation clock for future
  1568.  
  1569.           splats[index].anim_clock = 0;
  1570.  
  1571.           } // end if time ti change frames
  1572.  
  1573.        } // end if found a good one
  1574.  
  1575.     } // end for index
  1576.  
  1577. } // end Animate_Splats
  1578.  
  1579. //////////////////////////////////////////////////////////////////////////////
  1580.  
  1581. void Init_Splats(void)
  1582. {
  1583. // reset all Splats
  1584.  
  1585. int index;
  1586.  
  1587. for (index=0; index<NUM_SPLATS; index++)
  1588.     splats[index].state = SPLAT_DEAD;
  1589.  
  1590. } // Init_Splats
  1591.  
  1592. //////////////////////////////////////////////////////////////////////////////
  1593.  
  1594. void Erase_Cars(void)
  1595. {
  1596.  
  1597. // this function indexes through all the Cars and if they are active
  1598. // erases them by replacing the background color that was under them
  1599.  
  1600. int index;
  1601.  
  1602. // set sprite size for engine
  1603.  
  1604. SET_SPRITE_SIZE(12,12);
  1605.  
  1606. for (index=0; index<NUM_CARS; index++)
  1607.     {
  1608.  
  1609.     // is this Car alive
  1610.  
  1611.     if (cars[index].state != CAR_DEAD)
  1612.        {
  1613.  
  1614.        // copy position to sprite structure
  1615.  
  1616.        cars[index].object.x = cars[index].x;
  1617.        cars[index].object.y = cars[index].y;
  1618.  
  1619.        // erase the sprite
  1620.  
  1621.        Erase_Sprite_DB((sprite_ptr)&cars[index].object);
  1622.  
  1623.        } // end if alive
  1624.  
  1625.     } // end for index
  1626.  
  1627. } // end Erase_Cars
  1628.  
  1629. /////////////////////////////////////////////////////////////////////////////
  1630.  
  1631. void Draw_Cars(void)
  1632. {
  1633.  
  1634. // this function indexes through all the Cars and if they are active
  1635. // draws them
  1636.  
  1637. int index;
  1638.  
  1639. // set sprite size for engine
  1640.  
  1641. SET_SPRITE_SIZE(12,12);
  1642.  
  1643. for (index=0; index<NUM_CARS; index++)
  1644.     {
  1645.  
  1646.     // is this Car alive
  1647.  
  1648.     if (cars[index].state != CAR_DEAD)
  1649.        {
  1650.  
  1651.        // copy position to sprite structure
  1652.  
  1653.        cars[index].object.x = cars[index].x;
  1654.        cars[index].object.y = cars[index].y;
  1655.  
  1656.        // erase the sprite
  1657.  
  1658.        Draw_Sprite_DB((sprite_ptr)&cars[index].object);
  1659.  
  1660.        } // end if alive
  1661.  
  1662.     } // end for index
  1663.  
  1664. } // end Draw_Cars
  1665.  
  1666. /////////////////////////////////////////////////////////////////////////////
  1667.  
  1668. void Behind_Cars(void)
  1669. {
  1670.  
  1671. // this function indexes through all the Cars and if they are active
  1672. // scan under them
  1673.  
  1674. int index;
  1675.  
  1676. // set sprite size for engine
  1677.  
  1678. SET_SPRITE_SIZE(12,12);
  1679.  
  1680. for (index=0; index<NUM_CARS; index++)
  1681.     {
  1682.  
  1683.     // is this Car alive
  1684.  
  1685.     if (cars[index].state != CAR_DEAD)
  1686.        {
  1687.  
  1688.        // copy position to sprite structure
  1689.  
  1690.        cars[index].object.x = cars[index].x;
  1691.        cars[index].object.y = cars[index].y;
  1692.  
  1693.        // erase the sprite
  1694.  
  1695.        Behind_Sprite_DB((sprite_ptr)&cars[index].object);
  1696.  
  1697.        } // end if alive
  1698.  
  1699.     } // end for index
  1700.  
  1701. } // end Behind_Cars
  1702.  
  1703. /////////////////////////////////////////////////////////////////////////////
  1704.  
  1705. void Init_Cars(void)
  1706. {
  1707. // this function sets the state of all Cars to dead
  1708.  
  1709. int index;
  1710.  
  1711. for (index=0; index<NUM_CARS; index++)
  1712.     {
  1713.     cars[index].state             = CAR_DEAD;
  1714.     cars[index].object.curr_frame = 0;
  1715.     cars[index].object.x          = 0;
  1716.     cars[index].object.y          = 0;
  1717.     } // end for
  1718.  
  1719. } // end Init_Cars
  1720.  
  1721. //////////////////////////////////////////////////////////////////////////////
  1722.  
  1723. void Move_Cars(void)
  1724. {
  1725. // this function moves the Cars
  1726.  
  1727. int index,           // loop var
  1728.     cx,cy,           // used for quick variable access i.e. aliasing
  1729.     cell_x,cell_y,   // position of Car in cell world
  1730.     cell_id,         // id of cell bitmap
  1731.     tx,ty,           // used to hold position of test object
  1732.     new_state = 0,   // the next state
  1733.     state_change = 0;// has a state change occured
  1734.  
  1735.  
  1736. // traverse list and move all of the live ones
  1737.  
  1738. for (index=0; index<NUM_CARS; index++)
  1739.     {
  1740.  
  1741.     // test if Car is alive
  1742.  
  1743.     if (cars[index].state!=CAR_DEAD)
  1744.        {
  1745.  
  1746.        // select animation and motion based on direction if it's time to
  1747.        // process object
  1748.  
  1749.        if (++cars[index].counter_1==cars[index].threshold_1)
  1750.           {
  1751.  
  1752.           // reset state change variable
  1753.  
  1754.           state_change=0;
  1755.  
  1756.           // first reset animation counter
  1757.  
  1758.           cars[index].counter_1=0;
  1759.  
  1760.           // which state is the car in ?
  1761.  
  1762.           switch(cars[index].state)
  1763.                 {
  1764.  
  1765.                 case CAR_STARTING:
  1766.                      {
  1767.  
  1768.                      // move the car
  1769.  
  1770.                      cars[index].x+=cars[index].curr_xv;
  1771.                      cars[index].y+=cars[index].curr_yv;
  1772.  
  1773.                      // which way are we accelerating the car
  1774.  
  1775.                      switch(cars[index].direction)
  1776.                            {
  1777.  
  1778.                            case CAR_NORTH:
  1779.                                 {
  1780.  
  1781.                                 // press the pedal until desired speed
  1782.  
  1783.                                 if (--cars[index].curr_yv <= cars[index].max_yv)
  1784.                                    cars[index].curr_yv = cars[index].max_yv;
  1785.  
  1786.  
  1787.                                    // test if we are done
  1788.  
  1789.                                 if (++cars[index].counter_3 >= cars[index].threshold_3)
  1790.                                    {
  1791.                                    // now we are driving
  1792.  
  1793.                                    state_change = 1;
  1794.                                    new_state    = CAR_DRIVING;
  1795.  
  1796.                                    } // end if reached max speed
  1797.  
  1798.                                 } break;
  1799.  
  1800.                            case CAR_SOUTH:
  1801.                                 {
  1802.  
  1803.                                 // press the pedal until desired speed
  1804.  
  1805.                                 if (++cars[index].curr_yv >= cars[index].max_yv)
  1806.                                     cars[index].curr_yv = cars[index].max_yv;
  1807.  
  1808.  
  1809.                                 if (++cars[index].counter_3 >= cars[index].threshold_3)
  1810.                                    {
  1811.                                    // now we are driving
  1812.  
  1813.                                    state_change = 1;
  1814.                                    new_state    = CAR_DRIVING;
  1815.  
  1816.                                    } // end if reached max speed
  1817.  
  1818.                                 } break;
  1819.  
  1820.                            case CAR_WEST:
  1821.                                 {
  1822.                                 // not implemented currently
  1823.  
  1824.  
  1825.                                 } break;
  1826.  
  1827.                            case CAR_EAST:
  1828.                                 {
  1829.                                 // not implemented currently
  1830.  
  1831.  
  1832.                                 } break;
  1833.  
  1834.                            default:break;
  1835.  
  1836.                            } // end switch direction
  1837.  
  1838.                      } break;
  1839.  
  1840.                 case CAR_DRIVING:
  1841.                      {
  1842.  
  1843.                      // test if we should play sound
  1844.  
  1845.                      if (rand()%500==1)
  1846.                         Play_Sound(SOUND_CAR_SOUND);
  1847.  
  1848.                      if (rand()%500==2)
  1849.                         Play_Sound(SOUND_CAR_HORN);
  1850.  
  1851.                      // move the car
  1852.  
  1853.                      cars[index].x+=cars[index].curr_xv;
  1854.                      cars[index].y+=cars[index].curr_yv;
  1855.  
  1856.                      // test for a stop sign
  1857.  
  1858.                      // which way is the car going
  1859.  
  1860.                      switch(cars[index].direction)
  1861.                            {
  1862.  
  1863.                            case CAR_NORTH:
  1864.                                 {
  1865.  
  1866.                                 // compute bitmap in front of car
  1867.  
  1868.                                 cell_x = (cars[index].x+6) >> 4;
  1869.                                 cell_y = (cars[index].y+10) >> 4;
  1870.  
  1871.                                 // get bitmap id
  1872.  
  1873.                                 cell_id = city_1[cell_y][cell_x];
  1874.  
  1875.                                 // is this a stop sign
  1876.  
  1877.                                 if (cell_id == STOP_NORTH_ID)
  1878.                                    {
  1879.                                    state_change = 1;
  1880.                                    new_state    = CAR_SLOWING;
  1881.  
  1882.                                    } // end if hit a stop sigh
  1883.  
  1884.                                 } break;
  1885.  
  1886.                            case CAR_SOUTH:
  1887.                                 {
  1888.  
  1889.                                 // compute bitmap in front of car
  1890.  
  1891.                                 cell_x = (cars[index].x+6) >> 4;
  1892.                                 cell_y = (cars[index].y+0) >> 4;
  1893.  
  1894.                                 // get bitmap id
  1895.  
  1896.                                 cell_id = city_1[cell_y][cell_x];
  1897.  
  1898.                                 // is this a stop sign
  1899.  
  1900.                                 if (cell_id == STOP_SOUTH_ID)
  1901.                                    {
  1902.                                    state_change = 1;
  1903.                                    new_state    = CAR_SLOWING;
  1904.  
  1905.                                    } // end if hit a stop sigh
  1906.  
  1907.                                 } break;
  1908.  
  1909.                            case CAR_WEST:
  1910.                                 {
  1911.                                 // not implemented currently
  1912.                                 } break;
  1913.  
  1914.                            case CAR_EAST:
  1915.                                 {
  1916.                                 // not implemented currently
  1917.                                 } break;
  1918.  
  1919.                            default:break;
  1920.  
  1921.                            } // end switch direction
  1922.  
  1923.  
  1924.                      } break;
  1925.  
  1926.  
  1927.                 case CAR_SLOWING:
  1928.                      {
  1929.                      // continue hitting breaks
  1930.  
  1931.  
  1932.                      // which way is the car going
  1933.  
  1934.                      switch(cars[index].direction)
  1935.                            {
  1936.  
  1937.                            case CAR_NORTH:
  1938.                                 {
  1939.                                 // enage breaks
  1940.  
  1941.                                 if (++cars[index].curr_yv>=0)
  1942.                                    {
  1943.  
  1944.                                    state_change=1;
  1945.                                    new_state   = CAR_STOPPED;
  1946.  
  1947.                                    } // end if stopped
  1948.  
  1949.                                 } break;
  1950.  
  1951.                            case CAR_SOUTH:
  1952.                                 {
  1953.  
  1954.                                 // enage breaks
  1955.  
  1956.                                 if (--cars[index].curr_yv<=0)
  1957.                                    {
  1958.  
  1959.                                    state_change=1;
  1960.                                    new_state   = CAR_STOPPED;
  1961.  
  1962.                                    } // end if stopped
  1963.  
  1964.                                 } break;
  1965.  
  1966.                            case CAR_WEST:
  1967.                                 {
  1968.                                 // not implemented currently
  1969.  
  1970.  
  1971.                                 } break;
  1972.  
  1973.                            case CAR_EAST:
  1974.                                 {
  1975.                                 // not implemented currently
  1976.  
  1977.  
  1978.                                 } break;
  1979.  
  1980.                            default:break;
  1981.  
  1982.                            } // end switch direction
  1983.  
  1984.                      } break;
  1985.  
  1986.                 case CAR_STOPPED:
  1987.                      {
  1988.  
  1989.                      // have we looked both ways?
  1990.  
  1991.                      if (++cars[index].counter_2 > cars[index].threshold_2)
  1992.                         {
  1993.  
  1994.                         // start car back up
  1995.  
  1996.                         state_change = 1;
  1997.                         new_state    = CAR_STARTING;
  1998.  
  1999.                         } // end if sat for long enough
  2000.  
  2001.                      } break;
  2002.  
  2003.                 default:break;
  2004.  
  2005.                 } // end switch
  2006.  
  2007.          // test for a state change
  2008.  
  2009.          if (state_change)
  2010.             {
  2011.  
  2012.             // what is the new state
  2013.  
  2014.             switch(new_state)
  2015.                   {
  2016.  
  2017.                   case CAR_STARTING:
  2018.                        {
  2019.  
  2020.                        cars[index].state       = CAR_STARTING;
  2021.                        cars[index].counter_3   = 0;
  2022.                        cars[index].threshold_3 = 8;
  2023.  
  2024.                        // play the sound
  2025.  
  2026.                        Play_Sound(SOUND_CAR_START);
  2027.  
  2028.                        } break;
  2029.  
  2030.                   case CAR_DRIVING:
  2031.                        {
  2032.  
  2033.                        cars[index].state = CAR_DRIVING;
  2034.  
  2035.                        } break;
  2036.  
  2037.                   case CAR_SLOWING:
  2038.                        {
  2039.  
  2040.                        cars[index].state = CAR_SLOWING;
  2041.  
  2042.                        // play the sound
  2043.  
  2044.                        Play_Sound(SOUND_CAR_STOP);
  2045.  
  2046.                        } break;
  2047.  
  2048.                   case CAR_STOPPED:
  2049.                        {
  2050.  
  2051.                        cars[index].counter_2   = 0;
  2052.                        cars[index].threshold_2 = 20 + rand()%50;
  2053.                        cars[index].state       = CAR_STOPPED;
  2054.  
  2055.                        } break;
  2056.  
  2057.                   default: break;
  2058.  
  2059.                   } // end switch new state
  2060.  
  2061.             } // end if
  2062.  
  2063.           } // end if time to process
  2064.  
  2065.        // do collision detection with borders
  2066.  
  2067.        if (cars[index].x > 320-12 || cars[index].x < 0 ||
  2068.            cars[index].y > 163    || cars[index].y < 0 )
  2069.           {
  2070.           // kill ther car
  2071.  
  2072.           cars[index].state = CAR_DEAD;
  2073.  
  2074.           } // end if car off screen
  2075.       else
  2076.          {
  2077.          // see if car has hit pizza boy
  2078.          // only if car is moving fast
  2079.  
  2080.          if (cars[index].state==CAR_DRIVING && boy.state==BOY_ALIVE)
  2081.             {
  2082.  
  2083.             // convert pizza boys position to integer space
  2084.  
  2085.             tx = ((int)(boy.x >> FP_SHIFT))+6;
  2086.             ty = ((int)(boy.y >> FP_SHIFT))+8;
  2087.  
  2088.             // perform standard collision test
  2089.  
  2090.             if (tx>cars[index].x+2 && tx<cars[index].x+9 &&
  2091.                 ty>cars[index].y+2 && ty<cars[index].y+9)
  2092.                {
  2093.  
  2094.                // one less moped
  2095.  
  2096.                --boy_mopeds;
  2097.  
  2098.                // start death sequence
  2099.  
  2100.                Start_Boy_Death();
  2101.  
  2102.                Play_Sound(SOUND_MOPED_HIT);
  2103.  
  2104.                } // end if car hit moped
  2105.  
  2106.             } // end if car could posscible hit pizza boy
  2107.  
  2108.          } // end else test cars against moped
  2109.  
  2110.        } // end if alive
  2111.  
  2112.     } // end for index
  2113.  
  2114. } // end Move_Cars
  2115.  
  2116. //////////////////////////////////////////////////////////////////////////////
  2117.  
  2118. int Start_Car(void)
  2119. {
  2120.  
  2121. // this function is used to start a Car up
  2122.  
  2123. int index;
  2124.  
  2125. // look up tables for starting positions of Cars
  2126.  
  2127. static int x_south_start[] = {64,160,257}; // south bound
  2128. static int x_north_start[] = {84,180,277}; // north bound
  2129. static int y_west_start[]  = {66};         // west bound
  2130. static int y_east_start[]  = {84};         // east bound
  2131.  
  2132. // find a Car that isn't being used
  2133.  
  2134. for (index=0; index<NUM_CARS; index++)
  2135.     {
  2136.  
  2137.     // try and find a Car to start
  2138.  
  2139.     if (cars[index].state == CAR_DEAD)
  2140.        {
  2141.  
  2142.        // select direction Car will be traveling in
  2143.  
  2144.        switch(1+rand()%4)
  2145.              {
  2146.  
  2147.              case CAR_NORTH:
  2148.                   {
  2149.  
  2150.                   // set up fields
  2151.  
  2152.                   cars[index].x          = x_north_start[rand()%3];
  2153.                   cars[index].y          = 163;
  2154.                   cars[index].curr_xv    = 0;
  2155.                   cars[index].curr_yv    = -4;
  2156.                   cars[index].max_xv     = 0;
  2157.                   cars[index].max_yv     = -2-(rand()%2);
  2158.                   cars[index].direction  = CAR_NORTH;
  2159.                   cars[index].object.curr_frame = 0+4*(rand()%5);
  2160.  
  2161.                   } break;
  2162.  
  2163.              case CAR_SOUTH:
  2164.                   {
  2165.  
  2166.                   // set up fields
  2167.  
  2168.                   cars[index].x          = x_south_start[rand()%3];
  2169.                   cars[index].y          = 0;
  2170.                   cars[index].curr_xv    = 0;
  2171.                   cars[index].curr_yv    = 4;
  2172.                   cars[index].max_xv     = 0;
  2173.                   cars[index].max_yv     = 4+(rand()%2);
  2174.                   cars[index].direction  = CAR_SOUTH;
  2175.                   cars[index].object.curr_frame = 1+(4*(rand()%5));
  2176.  
  2177.                   } break;
  2178.  
  2179.              case CAR_WEST:
  2180.                   {
  2181.  
  2182.                   // set up fields
  2183.  
  2184.                   cars[index].x          = 320-12;
  2185.                   cars[index].y          = y_west_start[0];
  2186.                   cars[index].curr_xv    = -4;
  2187.                   cars[index].curr_yv    = 0;
  2188.                   cars[index].max_xv     = -4-(rand()%2);
  2189.                   cars[index].max_yv     = 0;
  2190.                   cars[index].direction  = CAR_WEST;
  2191.                   cars[index].object.curr_frame = 2+(4*(rand()%5));
  2192.  
  2193.                   } break;
  2194.  
  2195.              case CAR_EAST:
  2196.                   {
  2197.  
  2198.                   // set up fields
  2199.  
  2200.                   cars[index].x          = 0;
  2201.                   cars[index].y          = y_east_start[0];
  2202.                   cars[index].curr_xv    = 4;
  2203.                   cars[index].curr_yv    = 0;
  2204.                   cars[index].max_xv     = 4+(rand()%2);
  2205.                   cars[index].max_yv     = 0;
  2206.                   cars[index].direction  = CAR_EAST;
  2207.                   cars[index].object.curr_frame = 3+(4*(rand()%5));
  2208.  
  2209.                   } break;
  2210.  
  2211.              } // end switch
  2212.  
  2213.        // set common fields (mostly counters)
  2214.  
  2215.        cars[index].state       = CAR_DRIVING;
  2216.  
  2217.        cars[index].counter_1   = 0;
  2218.        cars[index].threshold_1 = 1;
  2219.  
  2220.        cars[index].counter_2   = 0;
  2221.        cars[index].threshold_2 = 0;
  2222.  
  2223.        cars[index].counter_3   = 0;
  2224.        cars[index].threshold_3 = 0;
  2225.  
  2226.        // color field isn't really being used at this time
  2227.  
  2228.        cars[index].color       = 0;
  2229.  
  2230.        // set the sprite size properly
  2231.  
  2232.        SET_SPRITE_SIZE(12,12);
  2233.  
  2234.        // scan under the sprite
  2235.  
  2236.        Behind_Sprite_DB((sprite_ptr)&cars[index].object);
  2237.  
  2238.        // break out of loop
  2239.  
  2240.        return(1);
  2241.  
  2242.        } // end if dead
  2243.  
  2244.     } // end for index
  2245.  
  2246. return(0);
  2247.  
  2248. } // end Start_Car
  2249.  
  2250. /////////////////////////////////////////////////////////////////////////////
  2251.  
  2252. void Erase_Humans(void)
  2253. {
  2254.  
  2255. // this function indexes through all the humans and if they are active
  2256. // erases them by replacing the background color that was under them
  2257.  
  2258. int index;
  2259.  
  2260. // set sprite size for engine
  2261.  
  2262. SET_SPRITE_SIZE(6,10);
  2263.  
  2264. for (index=0; index<NUM_HUMANS; index++)
  2265.     {
  2266.  
  2267.     // is this human alive
  2268.  
  2269.     if (humans[index].state != HUMAN_DEAD)
  2270.        {
  2271.  
  2272.        // erase the sprite
  2273.  
  2274.        Erase_Sprite_DB((sprite_ptr)&humans[index]);
  2275.  
  2276.        } // end if alive
  2277.  
  2278.     } // end for index
  2279.  
  2280. } // end Erase_Humans
  2281.  
  2282. /////////////////////////////////////////////////////////////////////////////
  2283.  
  2284. void Draw_Humans(void)
  2285. {
  2286.  
  2287. // this function indexes through all the humans and if they are active
  2288. // draws them
  2289.  
  2290. int index;
  2291.  
  2292. // set sprite size for engine
  2293.  
  2294. SET_SPRITE_SIZE(6,10);
  2295.  
  2296. for (index=0; index<NUM_HUMANS; index++)
  2297.     {
  2298.  
  2299.     // is this human alive
  2300.  
  2301.     if (humans[index].state != HUMAN_DEAD)
  2302.        {
  2303.  
  2304.        // erase the sprite
  2305.  
  2306.        Draw_Sprite_DB((sprite_ptr)&humans[index]);
  2307.  
  2308.        } // end if alive
  2309.  
  2310.     } // end for index
  2311.  
  2312. } // end Draw_Humans
  2313.  
  2314. /////////////////////////////////////////////////////////////////////////////
  2315.  
  2316. void Behind_Humans(void)
  2317. {
  2318.  
  2319. // this function indexes through all the humans and if they are active
  2320. // scan under them
  2321.  
  2322. int index;
  2323.  
  2324. // set sprite size for engine
  2325.  
  2326. SET_SPRITE_SIZE(6,10);
  2327.  
  2328. for (index=0; index<NUM_HUMANS; index++)
  2329.     {
  2330.  
  2331.     // is this human alive
  2332.  
  2333.     if (humans[index].state != HUMAN_DEAD)
  2334.        {
  2335.  
  2336.        // erase the sprite
  2337.  
  2338.        Behind_Sprite_DB((sprite_ptr)&humans[index]);
  2339.  
  2340.        } // end if alive
  2341.  
  2342.     } // end for index
  2343.  
  2344. } // end Behind_Humans
  2345.  
  2346. /////////////////////////////////////////////////////////////////////////////
  2347.  
  2348. void Init_Humans(void)
  2349. {
  2350. // this function sets the state of all humans to dead
  2351.  
  2352. int index;
  2353.  
  2354. for (index=0; index<NUM_HUMANS; index++)
  2355.     humans[index].state = HUMAN_DEAD;
  2356.  
  2357. } // end Init_Humans
  2358.  
  2359. //////////////////////////////////////////////////////////////////////////////
  2360.  
  2361. void Move_Humans(void)
  2362. {
  2363. // this function moves the humans
  2364.  
  2365. int index,           // loop var
  2366.     index_2,
  2367.     hx,hy,           // used for quick variable access i.e. aliasing
  2368.     cell_x,cell_y,   // position of human in cell world
  2369.     cell_id,         // id of cell bitmap
  2370.     tx,ty;           // used for temporary position vars
  2371.  
  2372. // traverse list and move all of the live ones
  2373.  
  2374. for (index=0; index<NUM_HUMANS; index++)
  2375.     {
  2376.  
  2377.     // test if human is alive
  2378.  
  2379.     if (humans[index].state!=HUMAN_DEAD)
  2380.        {
  2381.  
  2382.        // select animation and motion based on direction if it's time to
  2383.        // process object
  2384.  
  2385.        if (++humans[index].anim_clock==humans[index].anim_speed)
  2386.           {
  2387.           // first reset animation counter
  2388.  
  2389.           humans[index].anim_clock=0;
  2390.  
  2391.           // now move and animate human
  2392.  
  2393.           switch(humans[index].state)
  2394.                 {
  2395.  
  2396.                 case HUMAN_NORTH:
  2397.                      {
  2398.  
  2399.                      // do translation
  2400.  
  2401.                      humans[index].y-=2;
  2402.  
  2403.                      // do animation
  2404.  
  2405.                      if (++humans[index].curr_frame>3)
  2406.                         humans[index].curr_frame = 0;
  2407.  
  2408.                      } break;
  2409.  
  2410.                 case HUMAN_SOUTH:
  2411.                      {
  2412.  
  2413.                      // do translation
  2414.  
  2415.                      humans[index].y+=2;
  2416.  
  2417.                      // do animation
  2418.  
  2419.                      if (++humans[index].curr_frame>7)
  2420.                         humans[index].curr_frame = 4;
  2421.  
  2422.                      } break;
  2423.  
  2424.                 case HUMAN_WEST:
  2425.                      {
  2426.  
  2427.                      // do translation
  2428.  
  2429.                      humans[index].x-=2;
  2430.  
  2431.                      // do animation
  2432.  
  2433.                      if (++humans[index].curr_frame>11)
  2434.                         humans[index].curr_frame = 8;
  2435.  
  2436.                      } break;
  2437.  
  2438.                 case HUMAN_EAST:
  2439.                      {
  2440.  
  2441.                      // do translation
  2442.  
  2443.                      humans[index].x+=2;
  2444.  
  2445.                      // do animation
  2446.  
  2447.                      if (++humans[index].curr_frame>15)
  2448.                         humans[index].curr_frame = 12;
  2449.  
  2450.                      } break;
  2451.  
  2452.                 default:break;
  2453.  
  2454.                 } // end switch direction
  2455.  
  2456.           // do collision detection
  2457.  
  2458.           // boundary detection
  2459.  
  2460.           hx = humans[index].x;
  2461.           hy = humans[index].y;
  2462.  
  2463.           // test if human has walked into a house
  2464.  
  2465.           switch(humans[index].state)
  2466.                 {
  2467.  
  2468.                 case HUMAN_NORTH:
  2469.                      {
  2470.                      // compute test point on sprite
  2471.  
  2472.                      cell_x = (hx + 3) >> 4;
  2473.                      cell_y = (hy + 10) >> 4;
  2474.  
  2475.                      } break;
  2476.  
  2477.                 case HUMAN_SOUTH:
  2478.                      {
  2479.                      // compute test point on sprite
  2480.  
  2481.                      cell_x = (hx + 3) >> 4;
  2482.                      cell_y = (hy) >> 4;
  2483.  
  2484.  
  2485.                      } break;
  2486.  
  2487.                 case HUMAN_WEST:
  2488.                      {
  2489.                      // compute test point on sprite
  2490.  
  2491.                      cell_x = (hx + 6) >> 4;
  2492.                      cell_y = (hy + 5) >> 4;
  2493.  
  2494.                      } break;
  2495.  
  2496.                 case HUMAN_EAST:
  2497.                      {
  2498.                      // compute test point on sprite
  2499.  
  2500.                      cell_x = (hx) >> 4;
  2501.                      cell_y = (hy + 5) >> 4;
  2502.  
  2503.                      } break;
  2504.  
  2505.                 default:break;
  2506.  
  2507.                 } // end switch
  2508.  
  2509.            // extract cell from world
  2510.  
  2511.            cell_id = city_1[cell_y][cell_x];
  2512.  
  2513.            // test for house
  2514.  
  2515.            if (cell_id==HOUSE_WEST_2_ID || cell_id==HOUSE_EAST_1_ID)
  2516.               humans[index].state = HUMAN_DEAD;
  2517.  
  2518.           // test against screen borders
  2519.           else
  2520.           if (hx>320-8 || hx<0 || hy>200-24-8 || hy<0)
  2521.              {
  2522.              // kill the human
  2523.  
  2524.              humans[index].state = HUMAN_DEAD;
  2525.  
  2526.              } // end if hit edge
  2527.  
  2528.           else
  2529.              {
  2530.  
  2531.              // test human against cars
  2532.  
  2533.              for (index_2=0; index_2<NUM_CARS; index_2++)
  2534.                  {
  2535.  
  2536.                  // test if the car is alive
  2537.  
  2538.                  if (cars[index_2].state!=CAR_DEAD && cars[index_2].state!=CAR_STOPPED)
  2539.                     {
  2540.  
  2541.                     // test if humans center is within bounding box of car
  2542.  
  2543.                     if ( (hx+3 > cars[index_2].x) && (hx+3 < cars[index_2].x+11) &&
  2544.                          (hy+5 > cars[index_2].y) && (hy+5 < cars[index_2].y+11))
  2545.                        {
  2546.                        // kill the human
  2547.  
  2548.                        humans[index].state = HUMAN_DEAD;
  2549.  
  2550.                        // start an splat
  2551.  
  2552.                        Start_Splat(hx,hy,2+rand()%2,humans[index].motion_clock);
  2553.  
  2554.                        // play the sound
  2555.  
  2556.                        Play_Sound(SOUND_HUMAN_HIT);
  2557.  
  2558.                        break;
  2559.  
  2560.                        } // end if human is hit
  2561.  
  2562.                     } // end if car active
  2563.  
  2564.                  } // end for index_2
  2565.  
  2566.                  // test human against moped
  2567.  
  2568.  
  2569.                  if (humans[index].state != HUMAN_DEAD && boy.throttle>128 &&
  2570.                     boy.state==BOY_ALIVE)
  2571.                     {
  2572.  
  2573.                     // extract position of boy (convert to int)
  2574.  
  2575.                     tx = (int)(boy.x >> FP_SHIFT);
  2576.                     ty = (int)(boy.y >> FP_SHIFT);
  2577.  
  2578.                     if ( (hx+3 > tx+2) && (hx+3 < tx+9) &&
  2579.                          (hy+5 > ty+2) && (hy+5 < ty+9))
  2580.                        {
  2581.                        // kill the human
  2582.  
  2583.                        humans[index].state = HUMAN_DEAD;
  2584.  
  2585.                        // one more dead ped
  2586.  
  2587.                        boy_xpeds++;
  2588.  
  2589.                        // start a splat
  2590.  
  2591.                        Start_Splat(hx,hy,2+rand()%2,humans[index].motion_clock);
  2592.  
  2593.                        Play_Sound(SOUND_HUMAN_HIT);
  2594.  
  2595.                        } // end if human is hit
  2596.  
  2597.                     } // end if test human against moped
  2598.  
  2599.               } // end else test for human hit car
  2600.  
  2601.           } // end if time to process
  2602.  
  2603.        } // end if alive
  2604.  
  2605.     } // end for index
  2606.  
  2607. } // end Move_Humans
  2608.  
  2609. //////////////////////////////////////////////////////////////////////////////
  2610.  
  2611. int Start_Human(void)
  2612. {
  2613.  
  2614. // this function is used to start a human up
  2615.  
  2616. int index;
  2617.  
  2618. // look up tables for starting positions of humans
  2619.  
  2620. static int x_start[] = {2,14,26,59,97,155,192,250,287};
  2621. static int y_start[] = {22,52,90,136,164};
  2622.  
  2623. // find a human that isn't being used
  2624.  
  2625. for (index=0; index<NUM_HUMANS; index++)
  2626.     {
  2627.  
  2628.     // try and find a human to start
  2629.  
  2630.     if (humans[index].state == HUMAN_DEAD)
  2631.        {
  2632.  
  2633.  
  2634.        // select direction human will be traveling in
  2635.  
  2636.        switch(1+rand()%4)
  2637.              {
  2638.  
  2639.              case HUMAN_NORTH:
  2640.                   {
  2641.  
  2642.                   // set up fields
  2643.  
  2644.                   humans[index].x          = x_start[rand()%9];
  2645.                   humans[index].y          = 170;
  2646.                   humans[index].state      = HUMAN_NORTH;
  2647.                   humans[index].curr_frame = 0;
  2648.  
  2649.                   } break;
  2650.  
  2651.              case HUMAN_SOUTH:
  2652.                   {
  2653.  
  2654.                   // set up fields
  2655.  
  2656.                   humans[index].x          = x_start[rand()%9];
  2657.                   humans[index].y          = 0;
  2658.                   humans[index].state      = HUMAN_SOUTH;
  2659.                   humans[index].curr_frame = 4;
  2660.  
  2661.                   } break;
  2662.  
  2663.              case HUMAN_WEST:
  2664.                   {
  2665.  
  2666.                   // set up fields
  2667.  
  2668.                   humans[index].x          = 320-8;
  2669.                   humans[index].y          = y_start[rand()%5];
  2670.                   humans[index].state      = HUMAN_WEST;
  2671.                   humans[index].curr_frame = 8;
  2672.  
  2673.                   } break;
  2674.  
  2675.              case HUMAN_EAST:
  2676.                   {
  2677.  
  2678.                   // set up fields
  2679.  
  2680.                   humans[index].x          = 0;
  2681.                   humans[index].y          = y_start[rand()%5];
  2682.                   humans[index].state      = HUMAN_EAST;
  2683.                   humans[index].curr_frame = 12;
  2684.  
  2685.                   } break;
  2686.  
  2687.              } // end switch
  2688.  
  2689.        // set common fields
  2690.  
  2691.        humans[index].anim_clock=0;
  2692.        humans[index].anim_speed=1+rand()%3;
  2693.  
  2694.        SET_SPRITE_SIZE(6,10);
  2695.  
  2696.        // scan under the sprite
  2697.  
  2698.        Behind_Sprite_DB((sprite_ptr)&humans[index]);
  2699.  
  2700.        // break out of loop
  2701.  
  2702.        return(1);
  2703.  
  2704.        } // end if dead
  2705.  
  2706.     } // end for index
  2707.  
  2708. return(0);
  2709.  
  2710. } // end Start_Human
  2711.  
  2712. /////////////////////////////////////////////////////////////////////////////
  2713.  
  2714. void Draw_Screen(char **screen)
  2715. {
  2716. // this function draws a screen by using the data in the universe array
  2717. // each element in the universe array is a 2-D matrix of cells, these
  2718. // cells are ASCII characters that represent the requested bitmap that
  2719. // should be placed in the cell location
  2720.  
  2721. char *curr_row;
  2722.  
  2723. int index,
  2724.     index_x,        // index vars
  2725.     index_y,
  2726.     cell_id;        // the bitmap id
  2727.  
  2728. // translation table for screen database used to convert the ASCII
  2729. // characters into id numbers
  2730.  
  2731. static char ascii_to_id[128] =
  2732.  
  2733. //    !  "  #  $  %  &  '  (  )  *  +  ,  -  .  /
  2734.  
  2735.   {0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,32,0 ,
  2736.  
  2737. // 0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?
  2738.    33,34,35,36,37,38,39,40,45,46,0 ,0 ,0 ,0 ,0 ,0 ,
  2739.  
  2740. // @  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O
  2741.    0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
  2742.  
  2743.  
  2744. // P  Q  R  S  T  U  V  W  X  Y  Z  [  \  ]  ^  _
  2745.    0 ,0 ,0 ,9 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,4 ,0 ,5 ,6 ,0 ,
  2746.  
  2747.  
  2748. // `  a  b  c  d  e  f  g  h  i  j  k  l  m  n  o
  2749.    0 ,47,48,41,42,43,44,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
  2750.  
  2751. // p  q  r  s  t  u  v  w  x  y  z  {  |  }  ~  DEL
  2752.   0  ,0 ,0 ,8 ,0 ,0 ,7 ,0 ,0 ,0 ,0 ,49,0 ,50,0  ,0 ,};
  2753.  
  2754. // clear out the double buffer
  2755.  
  2756. // Fill_Double_Buffer(0);
  2757.  
  2758. SET_SPRITE_SIZE(16,16);
  2759.  
  2760. // now draw the screen row by row
  2761.  
  2762. for (index_y = 0; index_y<CELL_ROWS; index_y++)
  2763.     {
  2764.  
  2765.     // get the current row for speed
  2766.  
  2767.     curr_row = screen[index_y];
  2768.  
  2769.     // do the row
  2770.  
  2771.     for (index_x = 0; index_x<CELL_COLUMNS; index_x++)
  2772.         {
  2773.         // extract cell out of data structure and blit it onto screen
  2774.  
  2775.         cell_id = ascii_to_id[curr_row[index_x]-32];
  2776.  
  2777.         // write id number into data structure
  2778.  
  2779.         curr_row[index_x] = cell_id;
  2780.  
  2781.         // test which sprite should be used, either roads or building?
  2782.  
  2783.         if (cell_id <32) // use roads
  2784.            {
  2785.  
  2786.            // compute proper sprite position
  2787.  
  2788.            roads.x = index_x * sprite_width;
  2789.            roads.y = index_y * sprite_height;
  2790.  
  2791.            // set current frame to bitmap id
  2792.  
  2793.            roads.curr_frame = cell_id;
  2794.  
  2795.            // draw the bitmap
  2796.  
  2797.            Draw_Sprite_DB((sprite_ptr)&roads);
  2798.  
  2799.            } // end if road sprite
  2800.  
  2801.         else
  2802.            {
  2803.            // use building sprite
  2804.  
  2805.            // compute proper sprite position
  2806.  
  2807.            builds.x = index_x * sprite_width;
  2808.            builds.y = index_y * sprite_height;
  2809.  
  2810.            // set current frame to bitmap id
  2811.  
  2812.            cell_id-=32;
  2813.  
  2814.            builds.curr_frame = cell_id;
  2815.  
  2816.            // draw the bitmap
  2817.  
  2818.            Draw_Sprite_DB((sprite_ptr)&builds);
  2819.  
  2820.            // test if this is a house, if so insert house position into
  2821.            // database and draw house number
  2822.  
  2823.            if (cell_id==1 || cell_id==6)
  2824.               {
  2825.               // 1 is westward front door and 6 is eastward fron door
  2826.  
  2827.               // insert house position into database
  2828.  
  2829.               house_pos[curr_house].x    = index_x*sprite_width;
  2830.               house_pos[curr_house].y    = index_y*sprite_height;
  2831.               house_pos[curr_house].type = cell_id;
  2832.               house_pos[curr_house].num  = curr_house;
  2833.  
  2834.               house_pos[curr_house].state=HOUSE_NO_ORDER;
  2835.               house_pos[curr_house].timer=0;
  2836.  
  2837.               // we are on the next house
  2838.  
  2839.               curr_house++;
  2840.  
  2841.               } // end if front of house
  2842.  
  2843.            } // end else
  2844.  
  2845.         } // end for index_x
  2846.  
  2847.     } // end for index_y
  2848.  
  2849. // now that the entire city has been drawn, let's draw the house numbers
  2850. // on top of the houses
  2851.  
  2852. for (index=0; index<curr_house; index++)
  2853.     {
  2854.     // what kind of house is it?
  2855.  
  2856.     if (house_pos[index].type == 1)
  2857.        {
  2858.  
  2859.        // extract position data and blit proper numerical bitmap
  2860.  
  2861.        numbers.x          = (house_pos[index].x)+16;
  2862.        numbers.y          = (house_pos[index].y);
  2863.        numbers.curr_frame = house_pos[index].num;
  2864.  
  2865.        Draw_Sprite_DB((sprite_ptr)&numbers);
  2866.  
  2867.        } // end if westward pointing
  2868.     else
  2869.        {
  2870.        // must be an eastward pointing house
  2871.  
  2872.        // extract position data and blit proper numerical bitmap
  2873.  
  2874.        numbers.x          = (house_pos[index].x)-8;
  2875.        numbers.y          = (house_pos[index].y);
  2876.        numbers.curr_frame = house_pos[index].num;
  2877.  
  2878.        Draw_Sprite_DB((sprite_ptr)&numbers);
  2879.  
  2880.        } // end else eastward
  2881.  
  2882.     } // end for index
  2883.  
  2884. // remap the color registers for the house numbers so that they are white
  2885.  
  2886. Get_Palette_Register(ROOF_COLOR_REG,(RGB_color_ptr)&roof_color);
  2887.  
  2888. for (index=START_NUM_COLOR; index<=END_NUM_COLOR; index++)
  2889.     {
  2890.     Set_Palette_Register(index,(RGB_color_ptr)&roof_color);
  2891.  
  2892.     } // end for index
  2893.  
  2894. // make curr_house reflect array bounds
  2895.  
  2896. curr_house--;
  2897.  
  2898. } // end Draw_Screen
  2899.  
  2900. /////////////////////////////////////////////////////////////////////////////
  2901.  
  2902. int Initialize_Sound_System(void)
  2903. {
  2904.  
  2905. // this function loads in the ct-voice.drv driver and the configuration file
  2906. // and sets up the sound driver appropriately
  2907.  
  2908. FILE *fp;
  2909.  
  2910. // test if driver is on disk
  2911.  
  2912. if ( (fp=fopen("ct-voice.drv","rb"))==NULL)
  2913.    {
  2914.    return(0);
  2915.    } // end if not file
  2916.  
  2917. fclose(fp);
  2918.  
  2919. // load up sound configuration file
  2920.  
  2921. if ( (fp=fopen("simpizza.cfg","r"))==NULL )
  2922.    {
  2923.    printf("\nSound configuration file not found...");
  2924.    printf("\nUsing default values of port 220h and interrupt 5.");
  2925.  
  2926.    } // end if open sound configuration file
  2927. else
  2928.    {
  2929.  
  2930.    fscanf(fp,"%d %d",&sound_port, &sound_int);
  2931.    printf("\nSetting sound system to port %d decimal with interrupt %d.",
  2932.                                                     sound_port, sound_int);
  2933.  
  2934.    } // end else
  2935.  
  2936. // start up the whole sound system and load everything
  2937.  
  2938. Voc_Load_Driver();
  2939.  
  2940. Voc_Set_Port(sound_port);
  2941. Voc_Set_IRQ(sound_int);
  2942. Voc_Init_Driver();
  2943. Voc_Get_Version();
  2944. Voc_Set_Status_Addr((char far *)&ct_voice_status);
  2945.  
  2946. // load in sounds
  2947.  
  2948. sound_fx[SOUND_CAR_STOP   ]  = Voc_Load_Sound("SMCSTOP.VOC ",&sound_lengths[SOUND_CAR_STOP   ]);
  2949. sound_fx[SOUND_CAR_START  ]  = Voc_Load_Sound("SMCSTART.VOC",&sound_lengths[SOUND_CAR_START  ]);
  2950. sound_fx[SOUND_MOPED_HORN ]  = Voc_Load_Sound("SMMHORN.VOC ",&sound_lengths[SOUND_MOPED_HORN ]);
  2951. sound_fx[SOUND_CAR_HORN   ]  = Voc_Load_Sound("SMCHORN.VOC ",&sound_lengths[SOUND_CAR_HORN   ]);
  2952. sound_fx[SOUND_MOPED_HIT  ]  = Voc_Load_Sound("SMMHIT.VOC  ",&sound_lengths[SOUND_MOPED_HIT  ]);
  2953. sound_fx[SOUND_HUMAN_HIT  ]  = Voc_Load_Sound("SMHHIT.VOC  ",&sound_lengths[SOUND_HUMAN_HIT  ]);
  2954. sound_fx[SOUND_YO_VINNIE  ]  = Voc_Load_Sound("SMYO.VOC    ",&sound_lengths[SOUND_YO_VINNIE  ]);
  2955. sound_fx[SOUND_LOST_ORDER ]  = Voc_Load_Sound("SMLOST.VOC  ",&sound_lengths[SOUND_LOST_ORDER ]);
  2956. sound_fx[SOUND_THANK_YOU_B]  = Voc_Load_Sound("SMTHANK1.VOC",&sound_lengths[SOUND_THANK_YOU_B]);
  2957. sound_fx[SOUND_THANK_YOU_G]  = Voc_Load_Sound("SMTHANK2.VOC",&sound_lengths[SOUND_THANK_YOU_G]);
  2958. sound_fx[SOUND_TOO_LONG   ]  = Voc_Load_Sound("SMTOO.VOC   ",&sound_lengths[SOUND_TOO_LONG   ]);
  2959. sound_fx[SOUND_COME_HOME  ]  = Voc_Load_Sound("SMCOME.VOC  ",&sound_lengths[SOUND_COME_HOME  ]);
  2960. sound_fx[SOUND_CAR_SOUND  ]  = Voc_Load_Sound("SMCAR.VOC   ",&sound_lengths[SOUND_CAR_SOUND  ]);
  2961. sound_fx[SOUND_START      ]  = Voc_Load_Sound("SMSTART.VOC ",&sound_lengths[SOUND_START      ]);
  2962.  
  2963. // turn on speaker
  2964.  
  2965. Voc_Set_Speaker(1);
  2966.  
  2967. // success
  2968.  
  2969. return(1);
  2970.  
  2971. } // end Initialize_Sound_System
  2972.  
  2973. /////////////////////////////////////////////////////////////////////////////
  2974.  
  2975. void Close_Sound_System(void)
  2976. {
  2977.  
  2978. // this function closes down the sound system
  2979.  
  2980. // make sure there is sound
  2981.  
  2982. if (sound_available)
  2983.    {
  2984.    // turn off speaker
  2985.  
  2986.    Voc_Set_Speaker(0);
  2987.  
  2988.    // unload sounds
  2989.  
  2990.    Voc_Unload_Sound(sound_fx[SOUND_CAR_STOP   ]);
  2991.    Voc_Unload_Sound(sound_fx[SOUND_CAR_START  ]);
  2992.    Voc_Unload_Sound(sound_fx[SOUND_MOPED_HORN ]);
  2993.    Voc_Unload_Sound(sound_fx[SOUND_CAR_HORN   ]);
  2994.    Voc_Unload_Sound(sound_fx[SOUND_MOPED_HIT  ]);
  2995.    Voc_Unload_Sound(sound_fx[SOUND_HUMAN_HIT  ]);
  2996.    Voc_Unload_Sound(sound_fx[SOUND_YO_VINNIE  ]);
  2997.    Voc_Unload_Sound(sound_fx[SOUND_LOST_ORDER ]);
  2998.    Voc_Unload_Sound(sound_fx[SOUND_THANK_YOU_B]);
  2999.    Voc_Unload_Sound(sound_fx[SOUND_THANK_YOU_G]);
  3000.    Voc_Unload_Sound(sound_fx[SOUND_TOO_LONG   ]);
  3001.    Voc_Unload_Sound(sound_fx[SOUND_COME_HOME  ]);
  3002.    Voc_Unload_Sound(sound_fx[SOUND_CAR_SOUND  ]);
  3003.    Voc_Unload_Sound(sound_fx[SOUND_START      ]);
  3004.  
  3005.    Voc_Terminate_Driver();
  3006.  
  3007.    } // end if sound
  3008.  
  3009. } // end Close_Sound_System
  3010.  
  3011. /////////////////////////////////////////////////////////////////////////////
  3012.  
  3013. void Play_Sound(int sound)
  3014. {
  3015. // this function plays a sound by turning off one if there is a sound playing
  3016. // and then playing the sent sound
  3017.  
  3018. // make sure there is a sound system first
  3019.  
  3020. if (sound_available)
  3021.    {
  3022.  
  3023.    // stop the current sound (if there is one)
  3024.  
  3025.    Voc_Stop_Sound();
  3026.  
  3027.    // play sent sound
  3028.  
  3029.    Voc_Play_Sound(sound_fx[sound] , sound_lengths[sound]);
  3030.  
  3031.    } // end if sound available
  3032.  
  3033. } // end Play_Sound
  3034.  
  3035. ///////////////////////////////////////////////////////////////////////////////
  3036.  
  3037. unsigned char Get_Pixel_DB(int x,int y)
  3038. {
  3039.  
  3040. // gets the color value of pixel at (x,y) from the double buffer
  3041.  
  3042. return double_buffer[((y<<8) + (y<<6)) + x];
  3043.  
  3044. } // end Get_Pixel_DB
  3045.  
  3046. //////////////////////////////////////////////////////////////////////////////
  3047.  
  3048. void Do_Intro(void)
  3049. {
  3050. // this function displays the introduction screen and then melts it
  3051.  
  3052. // load intro screen and display for a few secs.
  3053.  
  3054. PCX_Init((pcx_picture_ptr)&intro_pcx);
  3055.  
  3056. PCX_Load("simint.pcx", (pcx_picture_ptr)&intro_pcx,1);
  3057.  
  3058. PCX_Show_Buffer((pcx_picture_ptr)&intro_pcx);
  3059.  
  3060. // let user see it
  3061.  
  3062. Delay(50);
  3063.  
  3064. Fade_Lights();
  3065.  
  3066. PCX_Delete((pcx_picture_ptr)&intro_pcx);
  3067.  
  3068. } // end Do_Intro
  3069.  
  3070. ///////////////////////////////////////////////////////////////////////////////
  3071.  
  3072. void Load_Environment(void)
  3073. {
  3074. // this function loads the imagery for the environment
  3075.  
  3076. int index;  // loop variables
  3077.  
  3078. // load in imagery
  3079.  
  3080. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  3081.  
  3082. PCX_Load("simimg.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  3083.  
  3084. // initialize the road and building sprites
  3085.  
  3086. SET_SPRITE_SIZE(16,16);
  3087.  
  3088. Sprite_Init((sprite_ptr)&roads,0,0,0,0,0,0);
  3089. Sprite_Init((sprite_ptr)&builds,0,0,0,0,0,0);
  3090. Sprite_Init((sprite_ptr)&numbers,0,0,0,0,0,0);
  3091.  
  3092. // load in frames for roads
  3093.  
  3094. for (index=0; index<10; index++)
  3095.     {
  3096.  
  3097.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3098.                     (sprite_ptr)&roads,index,index,0);
  3099.  
  3100.     } // end for
  3101.  
  3102. // now load the buildings
  3103.  
  3104. for (index=0; index<17; index++)
  3105.     {
  3106.  
  3107.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3108.                     (sprite_ptr)&builds,index,index,1);
  3109.     } // end for
  3110.  
  3111. // load last two sidewalk bitmaps
  3112.  
  3113. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3114.                 (sprite_ptr)&builds,index,0,2);
  3115.  
  3116. index++;
  3117.  
  3118. PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3119.                 (sprite_ptr)&builds,index,1,2);
  3120.  
  3121. // now load the house numbers
  3122.  
  3123. for (index=0; index<16; index++)
  3124.     {
  3125.  
  3126.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3127.                     (sprite_ptr)&numbers,index,index,4);
  3128.     } // end for
  3129.  
  3130. for (index=0; index<8; index++)
  3131.     {
  3132.  
  3133.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3134.                     (sprite_ptr)&numbers,index+16,index,5);
  3135.     } // end for
  3136.  
  3137. // delete the pcx file
  3138.  
  3139. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  3140.  
  3141. } // end Load_Environment
  3142.  
  3143. ///////////////////////////////////////////////////////////////////////////////
  3144.  
  3145. void Load_Humans(void)
  3146. {
  3147. // this function loads the imagery for the humans
  3148.  
  3149. int index,    // loop indices
  3150.     index_2,
  3151.     color;    // used to select color of human which is reall the row in the
  3152.               // pcx file
  3153. // load in the human imagery
  3154.  
  3155. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  3156.  
  3157. PCX_Load("simimg3.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  3158.  
  3159. // set the proper sprite size
  3160.  
  3161. SET_SPRITE_SIZE(6,10);
  3162.  
  3163. // load in the humans
  3164.  
  3165. for (index=0; index<NUM_HUMANS; index++)
  3166.     {
  3167.  
  3168.     Sprite_Init((sprite_ptr)&humans[index],0,0,0,0,0,0);
  3169.  
  3170.     color = rand()%2;
  3171.  
  3172.     for (index_2=0; index_2<NUM_HUMAN_FRAMES; index_2++)
  3173.          {
  3174.          PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3175.                         (sprite_ptr)&humans[index],index_2,index_2,color);
  3176.  
  3177.          // set color field (use the motion_clock field in the structure)
  3178.  
  3179.          humans[index].motion_clock = color*4;
  3180.  
  3181.          } // end for index_2
  3182.  
  3183.     // set up state information
  3184.  
  3185.     humans[index].state      = HUMAN_DEAD;
  3186.     humans[index].x          = 0;
  3187.     humans[index].y          = 0;
  3188.     humans[index].curr_frame = 0;
  3189.  
  3190.     } // end for
  3191.  
  3192. // delete the pcx file
  3193.  
  3194. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  3195.  
  3196. } // end Load_Humans
  3197.  
  3198. //////////////////////////////////////////////////////////////////////////////
  3199.  
  3200. void Load_Cars(void)
  3201. {
  3202. // this function loads the imagery for the cars
  3203.  
  3204. int index,    // loop indices
  3205.     index_2;
  3206.  
  3207. // load in the human imagery
  3208.  
  3209. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  3210.  
  3211. PCX_Load("simimg2.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  3212.  
  3213. // set the proper sprite size
  3214.  
  3215. SET_SPRITE_SIZE(12,12);
  3216.  
  3217. // load in the cars
  3218.  
  3219. for (index=0; index<NUM_CARS; index++)
  3220.     {
  3221.  
  3222.     Sprite_Init((sprite_ptr)&cars[index].object,0,0,0,0,0,0);
  3223.  
  3224.     for (index_2=0; index_2<NUM_CAR_FRAMES; index_2++)
  3225.          PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3226.                         (sprite_ptr)&cars[index].object,index_2,index_2,0);
  3227.  
  3228.     // set up state information
  3229.  
  3230.     cars[index].state             = CAR_DEAD;
  3231.     cars[index].x                 = 0;
  3232.     cars[index].y                 = 0;
  3233.     cars[index].object.curr_frame = 0;
  3234.  
  3235.     } // end for
  3236.  
  3237.  
  3238. // load in the frames for the pizza boy's moped
  3239.  
  3240. Sprite_Init((sprite_ptr)&boy.object,0,0,0,0,0,0);
  3241.  
  3242. for (index=0; index<NUM_BOY_FRAMES; index++)
  3243.      PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3244.                     (sprite_ptr)&boy.object,index,15-index,2);
  3245.  
  3246. // set up state information
  3247.  
  3248. boy.state             = BOY_ALIVE;
  3249. boy.x                 = Assign_Integer(48);
  3250. boy.y                 = Assign_Integer(144);
  3251. boy.curr_xv           = 0;
  3252. boy.curr_yv           = 0;
  3253. boy.max_xv            = 0;
  3254. boy.max_yv            = 0;
  3255. boy.xv                = 0;
  3256. boy.yv                = 0;
  3257.  
  3258.  
  3259. boy.throttle          = 0;
  3260. boy.hp                = Assign_Float((float).4);
  3261. boy.friction          = Assign_Float((float)-.10);
  3262. boy.brakes            = Assign_Integer(1);
  3263.  
  3264. boy.max_throttle      = Assign_Integer(3);
  3265.  
  3266. boy.counter_1         = 0;
  3267. boy.threshold_1       = 2;
  3268.  
  3269. boy.object.curr_frame = 0;
  3270. boy.direction         = 0;
  3271.  
  3272. // delete the pcx file
  3273.  
  3274. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  3275.  
  3276. } // end Load_Cars
  3277.  
  3278. ////////////////////////////////////////////////////////////////////////////////
  3279.  
  3280. void Load_Splats(void)
  3281. {
  3282. // this function loads the splats
  3283.  
  3284. int index,  // loop var
  3285.     index_2;
  3286.  
  3287. // load in imagery for explosions
  3288.  
  3289. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  3290.  
  3291. PCX_Load("simimg4.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  3292.  
  3293. // initialize the splats and extract bitmaps
  3294.  
  3295. SET_SPRITE_SIZE(10,10);
  3296.  
  3297. // load in frames for splats
  3298.  
  3299. for (index=0; index<NUM_SPLATS; index++)
  3300.     {
  3301.  
  3302.     Sprite_Init((sprite_ptr)&splats[index],0,0,0,0,0,0);
  3303.  
  3304.     for (index_2=0; index_2<8; index_2++)
  3305.         PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3306.                         (sprite_ptr)&splats[index],index_2,index_2,0);
  3307.  
  3308.     } // end for
  3309.  
  3310. // delete the pcx file
  3311.  
  3312. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  3313.  
  3314. } // end Load_Splats
  3315.  
  3316. ////////////////////////////////////////////////////////////////////////////////
  3317.  
  3318. void Load_Death(void)
  3319. {
  3320. // this function loads the death frames
  3321.  
  3322. int index;  // loop var
  3323.  
  3324. // load in imagery for death frames
  3325.  
  3326. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  3327.  
  3328. PCX_Load("simimg6.pcx",(pcx_picture_ptr)&imagery_pcx,1);
  3329.  
  3330. // initialize the death sprite and extract bitmaps
  3331.  
  3332. SET_SPRITE_SIZE(32,30);
  3333.  
  3334. // load in frames for death sequence
  3335.  
  3336. Sprite_Init((sprite_ptr)&boy_death,0,0,0,0,0,0);
  3337.  
  3338. for (index=0; index<16; index++)
  3339.     PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3340.                     (sprite_ptr)&boy_death,index,index%8,index/8);
  3341.  
  3342. // delete the pcx file
  3343.  
  3344. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  3345.  
  3346. } // end Load_Death
  3347.  
  3348. ////////////////////////////////////////////////////////////////////////////////
  3349.  
  3350. void Load_Pizzas(void)
  3351. {
  3352. // this function loads the pizzas
  3353.  
  3354. int index,  // loop var
  3355.     index_2;
  3356.  
  3357. // load in imagery for explosions
  3358.  
  3359. PCX_Init((pcx_picture_ptr)&imagery_pcx);
  3360.  
  3361. PCX_Load("simimg5.pcx", (pcx_picture_ptr)&imagery_pcx,1);
  3362.  
  3363. // initialize the splats and extract bitmaps
  3364.  
  3365. SET_SPRITE_SIZE(6,6);
  3366.  
  3367. // load in frames for pizzas
  3368.  
  3369. for (index=0; index<NUM_PIZZAS; index++)
  3370.     {
  3371.  
  3372.     Sprite_Init((sprite_ptr)&pizzas[index].object,0,0,0,0,0,0);
  3373.  
  3374.     for (index_2=0; index_2<8; index_2++)
  3375.         PCX_Grab_Bitmap((pcx_picture_ptr)&imagery_pcx,
  3376.                         (sprite_ptr)&pizzas[index].object,index_2,index_2,0);
  3377.  
  3378.     } // end for
  3379.  
  3380. // delete the pcx file
  3381.  
  3382. PCX_Delete((pcx_picture_ptr)&imagery_pcx);
  3383.  
  3384. } // end Load_Pizzas
  3385.  
  3386. //////////////////////////////////////////////////////////////////////////////
  3387.  
  3388. void Load_Background(void)
  3389. {
  3390.  
  3391. // load in the background image into the double buffer
  3392.  
  3393. PCX_Init((pcx_picture_ptr)&background_pcx);
  3394.  
  3395. PCX_Load("simbak.pcx", (pcx_picture_ptr)&background_pcx,1);
  3396.  
  3397. // copy the background into the double buffer
  3398.  
  3399. _fmemcpy((char far *)double_buffer,
  3400.          (char far *)(background_pcx.buffer),
  3401.          SCREEN_WIDTH*SCREEN_HEIGHT);
  3402.  
  3403. PCX_Delete((pcx_picture_ptr)&background_pcx);
  3404.  
  3405. } // Load_Background
  3406.  
  3407. ///////////////////////////////////////////////////////////////////////////////
  3408.  
  3409. void Show_Instructions(void)
  3410. {
  3411. // this function displays the instructions and then disolves them
  3412.  
  3413. // load instruction screen and display it until a key press
  3414.  
  3415. PCX_Init((pcx_picture_ptr)&intro_pcx);
  3416.  
  3417. PCX_Load("simins.pcx", (pcx_picture_ptr)&intro_pcx,1);
  3418.  
  3419. PCX_Show_Buffer((pcx_picture_ptr)&intro_pcx);
  3420.  
  3421. // let user see it
  3422.  
  3423. while(!kbhit()){};
  3424.  
  3425. getch();
  3426.  
  3427. // let's try this screen transition
  3428.  
  3429. Sheer();
  3430.  
  3431. PCX_Delete((pcx_picture_ptr)&intro_pcx);
  3432.  
  3433. } // end Show_Instructions
  3434.  
  3435. ///////////////////////////////////////////////////////////////////////////////
  3436.  
  3437. void Draw_Gauges(void)
  3438. {
  3439.  
  3440. static int time_counter=0,         // track virtual time
  3441.            seconds_counter=0,      // tracks virtual seconds indicator
  3442.            difficulty_counter=0;   // tracks virtual hours to modify difficulty
  3443.  
  3444. // this function draws the players statistics in the display module
  3445.  
  3446. char buffer[128],min_string[8];
  3447.  
  3448. int hours, minutes;
  3449.  
  3450. // show the number of mopeds
  3451.  
  3452. sprintf(buffer,"%d",boy_mopeds);
  3453.  
  3454. Blit_String_DB(76,179,15,buffer,0);
  3455.  
  3456.  
  3457. // show the number of pizzas in rack
  3458.  
  3459. sprintf(buffer,"%d ",boy_pizzas);
  3460.  
  3461. Blit_String_DB(76,189,15,buffer,0);
  3462.  
  3463. // show the number of dead peds
  3464.  
  3465. sprintf(buffer,"%d",boy_xpeds);
  3466.  
  3467. Blit_String_DB(267+10,179,15,buffer,0);
  3468.  
  3469. // show the tips
  3470.  
  3471. sprintf(buffer,"$%d",boy_tips);
  3472.  
  3473. Blit_String_DB(251+10,189,15,buffer,0);
  3474.  
  3475.  
  3476. // show the time of day
  3477.  
  3478. // first convert minutes to hours:mins
  3479.  
  3480. hours   = boy_time / 60;
  3481.  
  3482. minutes = boy_time % 60;
  3483.  
  3484. // make sure not to display military time
  3485.  
  3486. if (hours>12)
  3487.     hours-=12;
  3488.  
  3489. // test if it's time to clean the display up
  3490.  
  3491. if (boy_time==780) // 12:00 pm
  3492.    Blit_String_DB(184,179,12,"     ",0);
  3493.  
  3494. // advance time
  3495.  
  3496. if (++time_counter==25)
  3497.    {
  3498.    // reset counter
  3499.  
  3500.    time_counter=0;
  3501.  
  3502.    // increment time
  3503.  
  3504.    boy_time++;
  3505.  
  3506.    // adjust difficulty as day progreses
  3507.  
  3508.    if (++difficulty_counter==60)
  3509.       {
  3510.       // make game a little harder
  3511.  
  3512.       difficulty-=3;
  3513.  
  3514.       // reset counter
  3515.  
  3516.       difficulty_counter = 0;
  3517.  
  3518.       } // end if it's the end of an hour
  3519.  
  3520.    } // end if one virtual minute
  3521.  
  3522. // format minutes ...this sucks!
  3523.  
  3524. if (minutes<10)
  3525.    sprintf(min_string,"0%d",minutes);
  3526. else
  3527.    sprintf(min_string,"%d",minutes);
  3528.  
  3529. // make little digital separator blink
  3530.  
  3531. if (++seconds_counter <= 25)
  3532.    sprintf(buffer,"%d %s",hours,min_string);
  3533. else
  3534. if (seconds_counter > 25 && seconds_counter<50)
  3535.    sprintf(buffer,"%d:%s",hours,min_string);
  3536. else
  3537.    {
  3538.    seconds_counter = 0;
  3539.    sprintf(buffer,"%d:%s",hours,min_string);
  3540.    } // end else reset
  3541.  
  3542. // draw the time
  3543.  
  3544. Blit_String_DB(184,179,12,buffer,0);
  3545.  
  3546.  
  3547. } // end Draw_Gauges
  3548.  
  3549. ///////////////////////////////////////////////////////////////////////////////
  3550.  
  3551. void Animate_Speedo(void)
  3552. {
  3553. // this function does the color palette animation for the speedometer
  3554.  
  3555. static int entered=0;                    // used to track first call to function
  3556. static RGB_color color_dark,color_light; // used as working colors
  3557.  
  3558. int index;                               // looping index
  3559.  
  3560. fixed speed;                             // holds percentage of maximum power
  3561.  
  3562. // test if this is first time in function
  3563.  
  3564. if (!entered)
  3565.    {
  3566.    // set flag
  3567.  
  3568.    entered = 1;
  3569.  
  3570.    // create a dark blue
  3571.  
  3572.    color_dark.red   = 0;
  3573.    color_dark.green = 0;
  3574.    color_dark.blue  = 30;
  3575.  
  3576.  
  3577.    // create a dark blue
  3578.  
  3579.    color_light.red   = 0;
  3580.    color_light.green = 0;
  3581.    color_light.blue  = 63;
  3582.  
  3583.    // set all speedo colors to dark blue
  3584.  
  3585.    for (index=START_SPEEDO_COLOR; index<=END_SPEEDO_COLOR; index++)
  3586.        {
  3587.  
  3588.        Set_Palette_Register(index,(RGB_color_ptr)&color_dark);
  3589.  
  3590.        } // end for
  3591.  
  3592.    } // end if first time
  3593. else
  3594.    {
  3595.    // do normal processing
  3596.  
  3597.    // based on throttle position illuminate speedo
  3598.  
  3599.    // convert fixed point ratio of max throttle/current throttle to
  3600.    // speed
  3601.  
  3602.    speed =  (((boy.throttle << FP_SHIFT)/boy.max_throttle)*(fixed)6) >> FP_SHIFT;
  3603.  
  3604.    // illumninate lights on dash
  3605.  
  3606.    for (index=START_SPEEDO_COLOR; index<START_SPEEDO_COLOR+speed; index++)
  3607.        {
  3608.  
  3609.        Set_Palette_Register(index,(RGB_color_ptr)&color_light);
  3610.  
  3611.        } // end for
  3612.  
  3613.     // turn the rest off
  3614.  
  3615.     for (; index<=END_SPEEDO_COLOR; index++)
  3616.         {
  3617.  
  3618.         Set_Palette_Register(index,(RGB_color_ptr)&color_dark);
  3619.  
  3620.         } // end for
  3621.  
  3622.    } // end else normal processing
  3623.  
  3624. } // end Animate_Speedo
  3625.  
  3626. ///////////////////////////////////////////////////////////////////////////////
  3627.  
  3628. void Order_Pizza(void)
  3629. {
  3630. // this function orders a pizza
  3631.  
  3632. int index,
  3633.     house_number;
  3634.  
  3635. char buffer[64];
  3636.  
  3637. // select a home that hasn't ordered yet
  3638.  
  3639. while(1)
  3640.      {
  3641.      // select a random house
  3642.  
  3643.      house_number = rand()%(curr_house+1);
  3644.  
  3645.      // test if this one hasn't ordered
  3646.  
  3647.      if (house_pos[house_number].state==HOUSE_NO_ORDER)
  3648.         {
  3649.         // this is the order and set up house as ordered
  3650.  
  3651.         house_pos[house_number].state  = HOUSE_ORDERED;
  3652.         house_pos[house_number].timer  = 500+5*rand()%25; // about 30 virtual mins.
  3653.  
  3654.         // build up message
  3655.  
  3656.         sprintf(buffer,"Yo Vinnie...take a pizza to house %d",house_number+1);
  3657.  
  3658.         // send it
  3659.  
  3660.         Insert_Message(buffer,0);
  3661.  
  3662.         // play sound
  3663.  
  3664.         Play_Sound(SOUND_YO_VINNIE);
  3665.  
  3666.         // increase number of pizzas ordered
  3667.  
  3668.         total_orders++;
  3669.  
  3670.         // tell the house to blink
  3671.  
  3672.         Blink_House(house_number);
  3673.  
  3674.         break;
  3675.  
  3676.         } // end if
  3677.  
  3678.      } // end while
  3679.  
  3680. } // end Order_Pizza
  3681.  
  3682. ///////////////////////////////////////////////////////////////////////////////
  3683.  
  3684. void Age_Orders(void)
  3685. {
  3686. // this function traverses the pending orders and decrements their timers
  3687. // if a timer expires then the pizza order is nullified and a message is sent
  3688.  
  3689. int index;        // loop index
  3690. char buffer[64];  // used to build up message string
  3691.  
  3692. // traverse pizza order list for each house
  3693.  
  3694. for (index=0; index<=curr_house; index++)
  3695.     {
  3696.     // test if there is an order for this house
  3697.  
  3698.     if (house_pos[index].state==HOUSE_ORDERED)
  3699.        {
  3700.        // decrement timer
  3701.  
  3702.        if (--house_pos[index].timer <= 0)
  3703.           {
  3704.           // took too long, forget it!
  3705.  
  3706.           house_pos[index].state = HOUSE_NO_ORDER;
  3707.  
  3708.           // send a nasty message
  3709.  
  3710.           // build up message
  3711.  
  3712.           sprintf(buffer,"Vinnie!..we just lost number %d",index+1);
  3713.  
  3714.           // play sound
  3715.  
  3716.           Play_Sound(SOUND_LOST_ORDER);
  3717.  
  3718.           // send it with urgency
  3719.  
  3720.           Insert_Message(buffer,1);
  3721.  
  3722.           } // end if time has ran out
  3723.  
  3724.        } // end if house is waiting for a pizza
  3725.  
  3726.     } // end for index
  3727.  
  3728. } // end Age_Orders
  3729.  
  3730. ////////////////////////////////////////////////////////////////////////////////
  3731.  
  3732. void Blink_House(int house_number)
  3733. {
  3734.  
  3735. static int counter   = 0,   // internal timer
  3736.            the_house = -1;  // the house being blinked (if any)
  3737.  
  3738. // this function will blink the house that it is sent
  3739.  
  3740. // test if house number is -1, this means do normal processing
  3741.  
  3742. if (house_number==-1)
  3743.    {
  3744.  
  3745.    // test if there is currently a blinking house
  3746.  
  3747.    if (the_house!=-1)
  3748.       {
  3749.  
  3750.       // increment timer
  3751.  
  3752.       ++counter;
  3753.  
  3754.       // see if it's time to change color
  3755.       // this sequence will blink the house 4 times
  3756.  
  3757.       if (counter==15)
  3758.          Set_Palette_Register(the_house+START_NUM_COLOR,
  3759.                              (RGB_color_ptr)&roof_color);
  3760.       else
  3761.       if (counter==25)
  3762.          Set_Palette_Register(the_house+START_NUM_COLOR,
  3763.                              (RGB_color_ptr)&alert_color);
  3764.       else
  3765.       if (counter==40)
  3766.          Set_Palette_Register(the_house+START_NUM_COLOR,
  3767.                              (RGB_color_ptr)&roof_color);
  3768.       else
  3769.       if (counter==50)
  3770.          Set_Palette_Register(the_house+START_NUM_COLOR,
  3771.                              (RGB_color_ptr)&alert_color);
  3772.       else
  3773.       if (counter==65)
  3774.          Set_Palette_Register(the_house+START_NUM_COLOR,
  3775.                              (RGB_color_ptr)&roof_color);
  3776.       else
  3777.       if (counter==75)
  3778.          Set_Palette_Register(the_house+START_NUM_COLOR,
  3779.                              (RGB_color_ptr)&alert_color);
  3780.       else
  3781.       if (counter==90)
  3782.          {
  3783.          Set_Palette_Register(the_house+START_NUM_COLOR,
  3784.                              (RGB_color_ptr)&roof_color);
  3785.  
  3786.  
  3787.          // reset system
  3788.  
  3789.          the_house=-1;
  3790.  
  3791.          } // end if end of road
  3792.  
  3793.       } // end if there is a blinking house
  3794.  
  3795.    } // end if do normal processing
  3796. else
  3797.    {
  3798.    // user is bliking a new house so set up the variables appropriately
  3799.  
  3800.    // test if there is a house being blinked and if so preempt it
  3801.  
  3802.    if (the_house!=-1)
  3803.       Set_Palette_Register(the_house+START_NUM_COLOR,
  3804.                           (RGB_color_ptr)&roof_color);
  3805.  
  3806.    // set the house to on
  3807.  
  3808.    the_house = house_number;
  3809.  
  3810.    // reset the counter
  3811.  
  3812.    counter   = 0;
  3813.  
  3814.    // turn the color register on
  3815.  
  3816.    Set_Palette_Register(the_house+START_NUM_COLOR,
  3817.                        (RGB_color_ptr)&alert_color);
  3818.  
  3819.    } // send else
  3820.  
  3821. } // end Blink_House
  3822.  
  3823. /////////////////////////////////////////////////////////////////////////////
  3824.  
  3825. void Show_Stats(void)
  3826. {
  3827. // this function displays the stats screen
  3828.  
  3829.  
  3830. float hours,         // hours worked
  3831.       pay,           // pay due to salary
  3832.       cost_mopeds,   // cost of breaking mopeds
  3833.       cost_lost,     // cost due to lost orders
  3834.       cost_injuries, // cost of hurting peds
  3835.       gross,         // gross pay
  3836.       net,           // net pay after taxes and deductions
  3837.       final;         // total finally pay
  3838.  
  3839. char buffer[64];  // used to build up stat strings
  3840.  
  3841. // load instruction screen and display it until a key press
  3842.  
  3843. PCX_Init((pcx_picture_ptr)&intro_pcx);
  3844.  
  3845. PCX_Load("simstats.pcx", (pcx_picture_ptr)&intro_pcx,1);
  3846.  
  3847. PCX_Show_Buffer((pcx_picture_ptr)&intro_pcx);
  3848.  
  3849. // display stats
  3850.  
  3851. // hours worked
  3852.  
  3853. hours = (float)(boy_time-540)/(float)60;
  3854.  
  3855. sprintf(buffer,"%.2f",hours);
  3856.  
  3857. Blit_String(202,48,15,buffer,1);
  3858.  
  3859. // total pay
  3860.  
  3861. pay = 4.25*hours;
  3862.  
  3863. sprintf(buffer,"$%.2f",pay);
  3864.  
  3865. Blit_String(202,59,15,buffer,1);
  3866.  
  3867. // crashed mopeds
  3868.  
  3869. cost_mopeds = 50*(3-boy_mopeds);
  3870.  
  3871. sprintf(buffer,"$%.2f",cost_mopeds);
  3872.  
  3873. Blit_String(202,95,15,buffer,1);
  3874.  
  3875. // injuries
  3876.  
  3877. cost_injuries = 100*boy_xpeds;
  3878.  
  3879. sprintf(buffer,"$%.2f",cost_injuries);
  3880.  
  3881. Blit_String(202,107,15,buffer,1);
  3882.  
  3883. // lost orders
  3884.  
  3885. cost_lost = 3*(total_orders-orders_filled);
  3886.  
  3887. sprintf(buffer,"$%.2f",cost_lost);
  3888.  
  3889. Blit_String(202,119,15,buffer,1);
  3890.  
  3891. // gross pay
  3892.  
  3893. gross = pay - cost_mopeds - cost_injuries - cost_lost;
  3894.  
  3895. if (gross<0)
  3896.     gross=0;
  3897.  
  3898. sprintf(buffer,"$%.2f",gross);
  3899.  
  3900. Blit_String(230,143,15,buffer,1);
  3901.  
  3902. // after taxes
  3903.  
  3904. net = gross*.7;
  3905.  
  3906. sprintf(buffer,"$%.2f",net);
  3907.  
  3908. Blit_String(230,155,15,buffer,1);
  3909.  
  3910. // plus tips
  3911.  
  3912. final = net+boy_tips;
  3913.  
  3914. sprintf(buffer,"$%.2f",final);
  3915.  
  3916. Blit_String(230,167,15,buffer,1);
  3917.  
  3918. // wait for exit
  3919.  
  3920. while(kbhit())
  3921.       getch();
  3922.  
  3923. // let user see it
  3924.  
  3925. while(!kbhit()){};
  3926.  
  3927. getch();
  3928.  
  3929. PCX_Delete((pcx_picture_ptr)&intro_pcx);
  3930.  
  3931. } // end Show_Stats
  3932.  
  3933. // M A I N ////////////////////////////////////////////////////////////////////
  3934.  
  3935. void main(void)
  3936. {
  3937.  
  3938. int done=0,         // main event loop exit flag
  3939.     sent=0,         // used to flag end sequence has been initiated
  3940.     cell_x,         // cell x position
  3941.     cell_y,         // cell y position
  3942.     cell_id,        // bitmap id
  3943.     tx,ty,          // test position
  3944.     direction;      // temporary direction variable
  3945.  
  3946. char buffer[128]; // used for string printing
  3947.  
  3948. // begin the program
  3949.  
  3950. printf("\nStarting SIM-Pizza...");
  3951.  
  3952. // initialize sound system
  3953.  
  3954. sound_available = Initialize_Sound_System();
  3955.  
  3956. // let user think the computer is working hard
  3957.  
  3958. Delay(50);
  3959.  
  3960. // set video mode to 320x200 256 color mode
  3961.  
  3962. Set_Video_Mode(VGA256);
  3963.  
  3964. // create a double buffer
  3965.  
  3966. if (!Create_Double_Buffer(SCREEN_HEIGHT))
  3967.    {
  3968.  
  3969.    printf("\nNot enough memory to create double buffer.");
  3970.  
  3971.    } // end if
  3972.  
  3973. // clear the double buffer
  3974.  
  3975. Fill_Double_Buffer(0);
  3976.  
  3977. // impress user (at least try to)
  3978.  
  3979. Do_Intro();
  3980.  
  3981. // show the instructions
  3982.  
  3983. Show_Instructions();
  3984.  
  3985. // load imagery for game
  3986.  
  3987. Load_Environment();
  3988.  
  3989. Load_Humans();
  3990.  
  3991. Load_Cars();
  3992.  
  3993. Load_Splats();
  3994.  
  3995. Load_Pizzas();
  3996.  
  3997. Load_Death();
  3998.  
  3999. Load_Background();
  4000.  
  4001. // initialize everything
  4002.  
  4003. Init_Humans();
  4004.  
  4005. Init_Cars();
  4006.  
  4007. Init_Pizzas();
  4008.  
  4009. Init_Messages();
  4010.  
  4011. Insert_Message("Boda Boom! Bada Bing!",0);
  4012.  
  4013. // install the new keyboard driver
  4014.  
  4015. Install_Keyboard();
  4016.  
  4017. // draw the screen
  4018.  
  4019. Draw_Screen((char **)city_1);
  4020.  
  4021. // scan under player first time before loop
  4022.  
  4023. SET_SPRITE_SIZE(12,12);
  4024.  
  4025. boy.object.x = (int)(boy.x >> FP_SHIFT);
  4026. boy.object.y = (int)(boy.y >> FP_SHIFT);
  4027.  
  4028. Behind_Sprite_DB((sprite_ptr)&boy.object);
  4029.  
  4030. // say what's up
  4031.  
  4032. Play_Sound(SOUND_START);
  4033.  
  4034. // begin main event loop
  4035.  
  4036. while(!done)
  4037.      {
  4038.      // erase everything
  4039.  
  4040.      if (boy.state==BOY_ALIVE)
  4041.      {
  4042.  
  4043.      SET_SPRITE_SIZE(12,12);
  4044.      boy.object.x = (int)(boy.x >> FP_SHIFT);
  4045.      boy.object.y = (int)(boy.y >> FP_SHIFT);
  4046.      Erase_Sprite_DB((sprite_ptr)&boy.object);
  4047.      } // end if boy alive
  4048.  
  4049.      Erase_Humans();
  4050.  
  4051.      Erase_Cars();
  4052.  
  4053.      Erase_Splats();
  4054.  
  4055.      Erase_Pizzas();
  4056.  
  4057.      Erase_Boy_Death();
  4058.  
  4059.      // reset throttle flag
  4060.  
  4061.      throttle_on = 0;
  4062.  
  4063.      // is user pressing a key
  4064.  
  4065.      if ((key_table[INDEX_RIGHT] || key_table[INDEX_LEFT] ||
  4066.           key_table[INDEX_UP]    || key_table[INDEX_DOWN] ||
  4067.           key_table[INDEX_ALT]   ||
  4068.           key_table[INDEX_SPACE] || key_table[INDEX_ESC] ) &&
  4069.           (boy.state==BOY_ALIVE))
  4070.         {
  4071.         // which key?
  4072.  
  4073.               if (key_table[INDEX_ESC]) // exit game
  4074.                  {
  4075.                  // exit system
  4076.  
  4077.                  done=1;
  4078.  
  4079.                  } // end if
  4080.  
  4081.               if (key_table[INDEX_RIGHT])  // move right
  4082.                  {
  4083.                    // turn moped right
  4084.  
  4085.                    if (++boy.counter_1==boy.threshold_1)
  4086.                       {
  4087.                       // reset counter
  4088.  
  4089.                       boy.counter_1 = 0;
  4090.  
  4091.                       // turn moped right
  4092.  
  4093.                       if (--boy.direction<0)
  4094.                             boy.direction=15;
  4095.  
  4096.                       boy.object.curr_frame = boy.direction;
  4097.  
  4098.                       } // end if time to process
  4099.  
  4100.                   } // end if right
  4101.               else
  4102.               if (key_table[INDEX_LEFT])  // move left
  4103.                    {
  4104.                    // turn moped left
  4105.  
  4106.                    if (++boy.counter_1==boy.threshold_1)
  4107.                    {
  4108.                    // reset counter
  4109.  
  4110.                    boy.counter_1 = 0;
  4111.  
  4112.                    // turn moped left
  4113.  
  4114.                    if (++boy.direction>15)
  4115.                          boy.direction=0;
  4116.  
  4117.                    boy.object.curr_frame = boy.direction;
  4118.  
  4119.                    } // end if time to process
  4120.  
  4121.                    } // end if left
  4122.  
  4123.               if (key_table[INDEX_ALT]) // blast horn
  4124.                  {
  4125.  
  4126.                  Play_Sound(SOUND_MOPED_HORN);
  4127.  
  4128.                  } // end if horn
  4129.  
  4130.               if (key_table[INDEX_UP])  // move up
  4131.                  {
  4132.                  // accelerate
  4133.  
  4134.                  boy.throttle+=boy.hp;
  4135.  
  4136.                  // test we are at maximum speed
  4137.  
  4138.                  if (boy.throttle>boy.max_throttle)
  4139.                      boy.throttle = boy.max_throttle;
  4140.  
  4141.                  // set flag to denote that throttle is engaged
  4142.  
  4143.                  throttle_on = 1;
  4144.  
  4145.                  } // end if up
  4146.  
  4147.               else
  4148.               if (key_table[INDEX_DOWN]) // brakes
  4149.                  {
  4150.                  // hit the brakes!
  4151.  
  4152.                  boy.throttle-=boy.brakes;
  4153.  
  4154.                  // test if we have stopped
  4155.  
  4156.                  if (boy.throttle<0)
  4157.                      boy.throttle = 0;
  4158.  
  4159.                  } // end if brakes
  4160.  
  4161.  
  4162.               if (key_table[INDEX_SPACE]) // throw pizza
  4163.                  {
  4164.                  // throw a pizza
  4165.  
  4166.                  // are there any pizzas to throw
  4167.  
  4168.                  if (--boy_pizzas<0)
  4169.                     boy_pizzas = 0;
  4170.                  else
  4171.                     {
  4172.                     // send message
  4173.  
  4174.                     Insert_Message("Here's your pizza mister!",1);
  4175.  
  4176.                     // rotate pizza direction 90 CC
  4177.  
  4178.                     direction = boy.direction - 4;
  4179.  
  4180.                     if (direction<0)
  4181.                         direction+=16;
  4182.  
  4183.                     // send a pizza sailing
  4184.  
  4185.                     Start_Pizza(((int)(boy.x >> FP_SHIFT)+5),
  4186.                                 ((int)(boy.y >> FP_SHIFT)+5),
  4187.                                 pizza_xv[direction],
  4188.                                 pizza_yv[direction],
  4189.                                 0);
  4190.  
  4191.                     } // end else
  4192.  
  4193.                  } // end if throw a pizza
  4194.  
  4195.         } // end if kbhit
  4196.  
  4197.      // translate moped
  4198.  
  4199.      boy.x=boy.x + ((boy.throttle * boy_xv[boy.direction])>>FP_SHIFT);
  4200.      boy.y=boy.y + ((boy.throttle * boy_yv[boy.direction])>>FP_SHIFT);
  4201.  
  4202.      // test if not on road
  4203.  
  4204.      cell_x = ((int)(boy.x >> FP_SHIFT)+6)>>4;
  4205.      cell_y = ((int)(boy.y >> FP_SHIFT)+6)>>4;
  4206.  
  4207.      // extract bitmap id
  4208.  
  4209.      cell_id = cell_id = city_1[cell_y][cell_x];
  4210.  
  4211.      // test if cell is not road
  4212.  
  4213.      if ((cell_id>=32 && cell_id<=46) ||
  4214.          (cell_id>=49 && cell_id<=50) )
  4215.         {
  4216.         // back moped up
  4217.  
  4218.         boy.x=boy.x - ((boy.throttle * boy_xv[boy.direction])>>FP_SHIFT);
  4219.         boy.y=boy.y - ((boy.throttle * boy_yv[boy.direction])>>FP_SHIFT);
  4220.  
  4221.         // turn off throttle
  4222.  
  4223.         boy.throttle = 0;
  4224.  
  4225.         } // end if moped on property
  4226.  
  4227.      // do edge tests
  4228.  
  4229.      if (boy.x > (fixed)(320-12)<<FP_SHIFT)
  4230.         boy.x = 0;
  4231.      else
  4232.      if (boy.x < 0)
  4233.         boy.x = (fixed)(320-12)<<FP_SHIFT;
  4234.  
  4235.      if (boy.y > (fixed)(176-12)<<FP_SHIFT)
  4236.         boy.y = 0;
  4237.      else
  4238.      if (boy.y < 0)
  4239.         boy.y = (fixed)(176-12)<<FP_SHIFT;
  4240.  
  4241.      // test if throttle is disengaged, if so, activate friction
  4242.  
  4243.      if (!throttle_on)
  4244.         {
  4245.         // decrease throttle
  4246.  
  4247.         boy.throttle+=boy.friction;
  4248.  
  4249.         // test we are at maximum speed
  4250.  
  4251.         if (boy.throttle < 0)
  4252.             boy.throttle = 0;
  4253.  
  4254.         } // end if throttle off
  4255.  
  4256.  
  4257.      // test if moped has got a new load from the pizza hut
  4258.  
  4259.      tx = ((int)(boy.x >> FP_SHIFT))+6;
  4260.      ty = ((int)(boy.y >> FP_SHIFT))+8;
  4261.  
  4262.      if (tx>=40 && tx<=52 && ty>=136 && ty<=150)
  4263.         boy_pizzas = 5;
  4264.  
  4265.      // move everything
  4266.  
  4267.      Move_Humans();
  4268.  
  4269.      Move_Cars();
  4270.  
  4271.      Move_Pizzas();
  4272.  
  4273.      Animate_Splats();
  4274.  
  4275.      Animate_Boy_Death();
  4276.  
  4277.      Age_Orders();
  4278.  
  4279.      // start objects here
  4280.  
  4281.      if (rand()%(difficulty)==1)
  4282.         Start_Human();
  4283.  
  4284.      if (rand()%(difficulty)==1)
  4285.         Start_Car();
  4286.  
  4287.      if (rand()%(difficulty*5)==1)
  4288.         Order_Pizza();
  4289.  
  4290.      // test if it's close to quiting time
  4291.  
  4292.      if (boy_time==1010 && !sent) // 4:50 pm
  4293.         {
  4294.         Insert_Message("Vinnie!...time to go home",1);
  4295.         Play_Sound(SOUND_COME_HOME);
  4296.         // set a flag so this doesn't happen any more
  4297.         sent=1;
  4298.  
  4299.         }
  4300.  
  4301.      // scan under objects
  4302.  
  4303.      if (boy.state==BOY_ALIVE)
  4304.      {
  4305.  
  4306.      SET_SPRITE_SIZE(12,12);
  4307.  
  4308.      boy.object.x = (int)(boy.x >> FP_SHIFT);
  4309.      boy.object.y = (int)(boy.y >> FP_SHIFT);
  4310.  
  4311.      Behind_Sprite_DB((sprite_ptr)&boy.object);
  4312.      } // end if boy alive
  4313.  
  4314.      Behind_Humans();
  4315.  
  4316.      Behind_Cars();
  4317.  
  4318.      Behind_Splats();
  4319.  
  4320.      Behind_Pizzas();
  4321.  
  4322.      Behind_Boy_Death();
  4323.  
  4324.      // draw objects
  4325.  
  4326.      Draw_Cars();
  4327.  
  4328.      Draw_Humans();
  4329.  
  4330.      Draw_Boy_Death();
  4331.  
  4332.      if (boy.state==BOY_ALIVE)
  4333.      {
  4334.  
  4335.      SET_SPRITE_SIZE(12,12);
  4336.  
  4337.      // boy.object.x = (int)(boy.x >> FP_SHIFT);
  4338.      // boy.object.y = (int)(boy.y >> FP_SHIFT);
  4339.  
  4340.      Draw_Sprite_DB((sprite_ptr)&boy.object);
  4341.      } // end if boy alive
  4342.  
  4343.      Draw_Splats();
  4344.  
  4345.      Draw_Pizzas();
  4346.  
  4347.      // draw all instrumentation
  4348.  
  4349.      Draw_Gauges();
  4350.  
  4351.      Send_Message();
  4352.  
  4353.      Display_Message();
  4354.  
  4355.      Animate_Speedo();
  4356.  
  4357.      Blink_House(-1); // note: -1 means do normal processing i.e. it's a command
  4358.  
  4359.      // display double buffer
  4360.  
  4361.      Show_Double_Buffer((char far *)double_buffer);
  4362.  
  4363.      // wait a sec
  4364.  
  4365.      Delay(1);
  4366.  
  4367.      // test if it's time to bail
  4368.  
  4369.      if (boy_mopeds==0 && boy.state==BOY_ALIVE)
  4370.         {
  4371.  
  4372.         done=END_MOPEDS;   // end game because out of mopeds
  4373.  
  4374.         } // end if ran out of mopeds
  4375.      else
  4376.      if (boy_time>1020)  // if it's after 5:00, let's end game also
  4377.         {
  4378.  
  4379.         done=END_TIME;   // end game because of time
  4380.  
  4381.         } // end if ran out of time
  4382.  
  4383.      } // end while
  4384.  
  4385. // wait a second
  4386.  
  4387. Delay(50);
  4388.  
  4389. // do a screen transition
  4390.  
  4391. Fade_Lights();
  4392.  
  4393. // remove keyboard driver
  4394.  
  4395. Delete_Keyboard();
  4396.  
  4397. // let user see what he did
  4398.  
  4399. Show_Stats();
  4400.  
  4401. // exit system with a cool transition
  4402.  
  4403. Melt();
  4404.  
  4405. // reset the video mode back to text
  4406.  
  4407. Set_Video_Mode(TEXT_MODE);
  4408.  
  4409. // free the double buffer
  4410.  
  4411. Delete_Double_Buffer();
  4412.  
  4413. // close sound system
  4414.  
  4415. Close_Sound_System();
  4416.  
  4417. printf("\nSIM-Pizza shutting down...");
  4418. printf("\nAll resources released...exiting back to DOS.\n");
  4419.  
  4420. } // end main
  4421.  
  4422.  
  4423.