home *** CD-ROM | disk | FTP | other *** search
/ NEXT Generation 27 / NEXT27.iso / pc / demos / emperor / dx3.exe / SDK / SAMPLES / IKLOWNS / CGKRUSTY.CPP < prev    next >
C/C++ Source or Header  |  1996-08-28  |  50KB  |  1,477 lines

  1. /*===========================================================================*\
  2. |
  3. |  File:        cgkrusty.cpp
  4. |
  5. |  Description: 
  6. |       
  7. |-----------------------------------------------------------------------------
  8. |
  9. |  Copyright (C) 1995-1996 Microsoft Corporation.  All Rights Reserved.
  10. |
  11. |  Written by Moss Bay Engineering, Inc. under contract to Microsoft Corporation
  12. |
  13. \*===========================================================================*/
  14.  
  15. /**************************************************************************
  16.  
  17.     (C) Copyright 1995-1996 Microsoft Corp.  All rights reserved.
  18.  
  19.     You have a royalty-free right to use, modify, reproduce and 
  20.     distribute the Sample Files (and/or any modified version) in 
  21.     any way you find useful, provided that you agree that 
  22.     Microsoft has no warranty obligations or liability for any 
  23.     Sample Application Files which are modified. 
  24.  
  25.     we do not recomend you base your game on IKlowns, start with one of
  26.     the other simpler sample apps in the GDK
  27.  
  28.  **************************************************************************/
  29.  
  30. #include <windows.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #ifdef __WATCOMC__
  35. #include <mem.h>
  36. #else
  37. #include <memory.h>
  38. #endif
  39. #include "cgchdll.h"
  40. #include "cgchar.h"
  41. #include "cgtimer.h"
  42. #include "cginput.h"
  43.  
  44. char inifile [260];
  45. int gFastKlown;
  46. int gFastVel;
  47. int gDebugOut;
  48. int gPieSpeed;
  49. int gPieRange;
  50. int gKlownHits;
  51. int gAgression;
  52. int gMobility;
  53. int SENSITIVITY  = 33;
  54. int RUN_THRESHOLD  = 66;
  55.  
  56. static DWORD gTimeout=30000;
  57. static DWORD gUpdateInterval=1000;
  58.  
  59. #define MIN_MOUSE_MOVE  3
  60. #define BIG_MOUSE_MOVE  30
  61. #define CenterX 320
  62. #define CenterY 240
  63.  
  64. #define BREAK_IF(x) if (x) _asm int 3;
  65.  
  66. #define WALK_VELOCITY 60
  67. #define RUN_VELOCITY 180
  68.  
  69. #define rand timeGetTime
  70. // klown states:
  71. typedef enum eKLOWN_STATES 
  72. {
  73.   STAND_RIGHT, STAND_LEFT,      //0,1
  74.   WALK_RIGHT, WALK_LEFT,        //2
  75.   RUN_RIGHT, RUN_LEFT,          //4
  76.   R2L_TURN, L2R_TURN,           //6
  77.   THROW_RIGHT, THROW_LEFT,         //8
  78.   THROW_RIGHT_WALK, THROW_LEFT_WALK,  //10  
  79.   THROW_RIGHT_RUN, THROW_LEFT_RUN,    //12
  80.   IN_RIGHT, IN_LEFT,                  //14
  81.   OUT_RIGHT, OUT_LEFT,                //16
  82.   DUCK_RIGHT, DUCK_LEFT,              //18
  83.   BLOCK_RIGHT, BLOCK_LEFT,            //20
  84.   POKE_RIGHT, POKE_LEFT,              //22
  85.   HIT_FACE_L, HIT_FACE_R,             //24
  86.   HIT_BACK_L, HIT_BACK_R,             //26
  87.   POKED_L, POKED_R,                   //28
  88.   IS_DEAD,                            //30
  89.   GAME_OVER,                          //31
  90.   // insert new states here, before next NUM_STATES:
  91.  
  92.   NUM_STATES,
  93.  
  94. // INTERNAL USE ONLY: don't use these for things which will have sequences, 
  95. // and DONT!!! return them  to the level object:
  96.   INT_THROW_RIGHT,
  97.   INT_THROW_LEFT,
  98.   INT_THROW_RIGHT_WALK,
  99.   INT_THROW_LEFT_WALK,
  100.   INT_THROW_RIGHT_RUN,
  101.   INT_THROW_LEFT_RUN,
  102.   INT_COLLIDED_ON_LEFT,
  103.   INT_COLLIDED_ON_RIGHT,
  104.   
  105.   INT_NUM_STATES
  106. }
  107. #ifdef __WATCOMC__
  108. xx1
  109. #endif
  110. ;
  111.  
  112. typedef enum eKLOWN_SEQ
  113. {
  114.     EOS, NOTHING, DUCK, THROW, BLOCK, POKE, GO_IN, GO_OUT, 
  115.     WALK_L, WALK_R, RUN_L, RUN_R, GOT_HIT_L, GOT_HIT_R,
  116.     GOT_POKED_L, GOT_POKED_R
  117. }
  118. #ifdef __WATCOMC__
  119. xx2
  120. #endif
  121. ;
  122.  
  123. typedef struct
  124. {
  125.     int start;
  126.     int end;
  127.     int transition;
  128. } STATE;
  129.  
  130. // 
  131. // klown info - flag if sequence needs to run till finished or not...
  132. #define MUST_FINISH 1
  133. int klown_state_flags[NUM_STATES] =
  134. {
  135.   0,    //STAND_RIGHT, 
  136.   0,    // STAND_LEFT,
  137.   0,    // WALK_RIGHT, 
  138.   0,    //WALK_LEFT,
  139.   0,    //RUN_RIGHT, 
  140.   0,    //RUN_LEFT,
  141.   MUST_FINISH,  //R2L_TURN, 
  142.   MUST_FINISH,  //L2R_TURN,
  143.   MUST_FINISH,  //THROW_RIGHT, 
  144.   MUST_FINISH,  //THROW_LEFT, 
  145.   MUST_FINISH,  //THROW_RIGHT_WALK, 
  146.   MUST_FINISH,  //THROW_LEFT_WALK,  
  147.   MUST_FINISH,  //THROW_RIGHT_RUN, 
  148.   MUST_FINISH,  //THROW_LEFT_RUN,   
  149.   0,    //IN_RIGHT, 
  150.   0,    //IN_LEFT,
  151.   0,    //OUT_RIGHT, 
  152.   0,    //OUT_LEFT,
  153.   MUST_FINISH,  //DUCK_RIGHT, 
  154.   MUST_FINISH,  //DUCK_LEFT,
  155.   MUST_FINISH,  //BLOCK_RIGHT, 
  156.   MUST_FINISH,  //BLOCK_LEFT,
  157.   MUST_FINISH,  //POKE_RIGHT, 
  158.   MUST_FINISH,  //POKE_LEFT,
  159.   MUST_FINISH,  //HIT_FACE_L, 
  160.   MUST_FINISH,  //HIT_FACE_R,
  161.   MUST_FINISH,  //HIT_BACK_L, 
  162.   MUST_FINISH,  //HIT_BACK_R,
  163.   MUST_FINISH,  //POKED_L, 
  164.   MUST_FINISH,  //POKED_R,
  165.   MUST_FINISH,  //IS_DEAD   
  166.   MUST_FINISH               // GAME_OVER
  167. };
  168.  
  169. int klown_states_index [INT_NUM_STATES];
  170. // klown state machine - triplets describing all possible transitions:
  171. STATE klown_states[] =
  172. {
  173.     { STAND_RIGHT, WALK_RIGHT, WALK_R },
  174.     { STAND_RIGHT, RUN_RIGHT,  RUN_R },
  175.     { STAND_RIGHT, BLOCK_RIGHT,  BLOCK },
  176.     { STAND_RIGHT, POKE_RIGHT,  POKE },
  177.     { STAND_RIGHT, DUCK_RIGHT,  DUCK },
  178.     { STAND_RIGHT, IN_RIGHT,  GO_IN },
  179.     { STAND_RIGHT, OUT_RIGHT,  GO_OUT },
  180.     { STAND_RIGHT, THROW_RIGHT,  THROW },
  181.     { STAND_RIGHT, R2L_TURN,  WALK_L },
  182.     { STAND_RIGHT, R2L_TURN,  RUN_L },
  183.     { STAND_RIGHT, HIT_FACE_R,  GOT_HIT_R },
  184.     { STAND_RIGHT, HIT_BACK_R,  GOT_HIT_L },
  185.     { STAND_RIGHT, POKED_R,  GOT_POKED_R },
  186.  
  187.     { STAND_LEFT, WALK_LEFT, WALK_L },
  188.     { STAND_LEFT, RUN_LEFT,  RUN_L },
  189.     { STAND_LEFT, BLOCK_LEFT,  BLOCK },
  190.     { STAND_LEFT, POKE_LEFT,  POKE },
  191.     { STAND_LEFT, DUCK_LEFT,  DUCK },
  192.     { STAND_LEFT, IN_LEFT,  GO_IN },
  193.     { STAND_LEFT, OUT_LEFT,  GO_OUT },
  194.     { STAND_LEFT, THROW_LEFT,  THROW },
  195.     { STAND_LEFT, L2R_TURN,  WALK_R },
  196.     { STAND_LEFT, L2R_TURN,  RUN_R },
  197.     { STAND_LEFT, HIT_FACE_L,  GOT_HIT_L },
  198.     { STAND_LEFT, HIT_BACK_L,  GOT_HIT_R },
  199.     { STAND_LEFT, POKED_L,  GOT_POKED_L },
  200.  
  201.     { WALK_RIGHT, WALK_RIGHT, WALK_R },
  202.     { WALK_RIGHT, RUN_RIGHT, RUN_R },
  203.     { WALK_RIGHT, THROW_RIGHT_WALK, THROW },
  204.     { WALK_RIGHT, R2L_TURN, RUN_L },
  205.     { WALK_RIGHT, R2L_TURN, WALK_L },
  206.     { WALK_RIGHT, IN_RIGHT,  GO_IN },
  207.     { WALK_RIGHT, OUT_RIGHT,  GO_OUT },
  208.     { WALK_RIGHT, STAND_RIGHT, NOTHING },
  209.  
  210.     { WALK_LEFT, WALK_LEFT, WALK_L },
  211.     { WALK_LEFT, RUN_LEFT, RUN_L },
  212.     { WALK_LEFT, THROW_LEFT_WALK, THROW },
  213.     { WALK_LEFT, L2R_TURN, RUN_R },
  214.     { WALK_LEFT, L2R_TURN, WALK_R },
  215.     { WALK_LEFT, IN_LEFT,  GO_IN },
  216.     { WALK_LEFT, OUT_LEFT,  GO_OUT },
  217.     { WALK_LEFT, STAND_LEFT, NOTHING },
  218.  
  219.     { RUN_RIGHT, RUN_RIGHT, RUN_R },
  220.     { RUN_RIGHT, WALK_RIGHT, WALK_R },
  221.     { RUN_RIGHT, THROW_RIGHT_RUN, THROW },
  222.     { RUN_RIGHT, R2L_TURN, RUN_L },
  223.     { RUN_RIGHT, R2L_TURN, WALK_L },
  224.     { RUN_RIGHT, IN_RIGHT,  GO_IN },
  225.     { RUN_RIGHT, OUT_RIGHT,  GO_OUT },
  226.     { RUN_RIGHT, STAND_RIGHT, NOTHING },
  227.  
  228.     { RUN_LEFT, RUN_LEFT, RUN_L },
  229.     { RUN_LEFT, WALK_LEFT, WALK_L },
  230.     { RUN_LEFT, THROW_LEFT_RUN, THROW },
  231.     { RUN_LEFT, L2R_TURN, RUN_R },
  232.     { RUN_LEFT, L2R_TURN, WALK_R },
  233.     { RUN_LEFT, IN_LEFT,  GO_IN },
  234.     { RUN_LEFT, OUT_LEFT,  GO_OUT },
  235.     { RUN_LEFT, STAND_LEFT, NOTHING },
  236.  
  237.     { R2L_TURN, STAND_LEFT, EOS },
  238.  
  239.     { L2R_TURN, STAND_RIGHT, EOS },
  240.  
  241.     { DUCK_RIGHT, STAND_RIGHT, EOS },
  242.  
  243.     { DUCK_LEFT, STAND_LEFT, EOS },
  244.  
  245.     { BLOCK_RIGHT, STAND_RIGHT, EOS },
  246.  
  247.     { BLOCK_LEFT, STAND_LEFT, EOS },
  248.  
  249.     { POKE_RIGHT, STAND_RIGHT, EOS },
  250.  
  251.     { POKE_LEFT, STAND_LEFT, EOS },
  252.  
  253.     { IN_RIGHT, WALK_RIGHT, WALK_R },
  254.     { IN_RIGHT, R2L_TURN, WALK_L },
  255.     { IN_RIGHT, OUT_RIGHT, GO_OUT },
  256.     { IN_RIGHT, STAND_RIGHT, EOS },
  257.     { IN_RIGHT, STAND_RIGHT, NOTHING },
  258.  
  259.     { IN_LEFT, WALK_LEFT, WALK_L },
  260.     { IN_LEFT, L2R_TURN, WALK_R },
  261.     { IN_LEFT, OUT_LEFT, GO_OUT },
  262.     { IN_LEFT, STAND_LEFT, EOS },
  263.     { IN_LEFT, STAND_LEFT, NOTHING },
  264.  
  265.     { OUT_RIGHT, WALK_RIGHT, WALK_R },
  266.     { OUT_RIGHT, R2L_TURN, WALK_L },
  267.     { OUT_RIGHT, IN_RIGHT, GO_IN },
  268.     { OUT_RIGHT, STAND_RIGHT, EOS },
  269.     { OUT_RIGHT, STAND_RIGHT, NOTHING},
  270.  
  271.     { OUT_LEFT, WALK_LEFT, WALK_L },
  272.     { OUT_LEFT, L2R_TURN, WALK_R },
  273.     { OUT_LEFT, IN_LEFT, GO_IN },
  274.     { OUT_LEFT, STAND_LEFT, EOS },
  275.     { OUT_LEFT, STAND_LEFT, NOTHING },
  276.  
  277.     { HIT_FACE_L, STAND_LEFT, EOS },
  278.  
  279.     { HIT_FACE_R, STAND_RIGHT, EOS },
  280.  
  281.     { HIT_BACK_L, STAND_LEFT, EOS },
  282.  
  283.     { HIT_BACK_R, STAND_RIGHT, EOS },
  284.  
  285.     { POKED_L, STAND_LEFT, EOS },
  286.  
  287.     { POKED_R, STAND_RIGHT, EOS },
  288.  
  289.     { THROW_RIGHT, INT_THROW_RIGHT, EOS },
  290.     { THROW_LEFT, INT_THROW_LEFT, EOS },
  291.     { THROW_RIGHT_WALK, INT_THROW_RIGHT_WALK, EOS },
  292.     { THROW_LEFT_WALK, INT_THROW_LEFT_WALK, EOS },
  293.     { THROW_RIGHT_RUN, INT_THROW_RIGHT_RUN, EOS },
  294.     { THROW_LEFT_RUN, INT_THROW_LEFT_RUN, EOS },
  295.     
  296.     { IS_DEAD, GAME_OVER, EOS },
  297.  
  298. // HEY!  PAY ATTENTION!  States listed here on out MUST NOT be returned
  299. // to the level object... they are for internal use only, and since they 
  300. // don't have sprite sequences defined for them ,the game will die horribly
  301. // if they are returned!  I warned you...
  302.     { INT_THROW_RIGHT, STAND_RIGHT, EOS },
  303.     { INT_THROW_LEFT, STAND_LEFT, EOS },
  304.     { INT_THROW_RIGHT_WALK, WALK_RIGHT, EOS },
  305.     { INT_THROW_LEFT_WALK, WALK_LEFT, EOS },
  306.     { INT_THROW_RIGHT_RUN, RUN_RIGHT, EOS },
  307.     { INT_THROW_LEFT_RUN, RUN_LEFT, EOS },
  308.  
  309.     { -1,-1,-1 }    // end of states.  don't change!
  310. };
  311.  
  312. typedef signed char SCHAR;
  313.  
  314. typedef struct 
  315. {
  316.     LONG    posx;
  317.     LONG    posy;
  318.     SCHAR   state;
  319.     SCHAR   velx;
  320.     SCHAR   vely;
  321.     SCHAR   curZ;
  322. } GENERIC_CHAR_INFO;
  323.  
  324. typedef struct
  325. {
  326.     int curState;
  327.     int LastMouseX;
  328.     int LastMouseY;
  329.     DWORD   timeLastUpdate;
  330.     int HitsLeft;
  331.     int pushedState;
  332.     CGameCharacter * myPie;
  333.     int type;           // 0 = main; 1=computer; 2= second;
  334.     int IGotKilled;
  335.     DWORD   Timeout;
  336.     DWORD   UpdateInterval;
  337. } KLOWN_DATA;
  338.  
  339.  
  340. #define KLOWN_MOVE  1
  341. #define KLOWN_PIE   2
  342.  
  343. HINSTANCE hInst = NULL;            // our library instance
  344. // This is returned by the 'Ident' function, but isn't used internally at all
  345. CGameVersionIdent version =
  346. {
  347.     RELEASE1_0,
  348.     GAMEID
  349. };
  350.  
  351. // prototypes so we can fill in the action arrays
  352. int PieCreate( CGameCharacter *, CGameLevel * );
  353. int PieAction( CGameCharacter *, CGameLevel * );
  354. int PieDestroy( CGameCharacter *, CGameLevel * );
  355. int PieCollide( CGameCharacter *, CGameCharacter *, CGameLevel * );
  356. int KlownCreate( CGameCharacter *, CGameLevel * );
  357. int KlownAction( CGameCharacter *, CGameLevel * );
  358. int KlownDestroy( CGameCharacter *, CGameLevel * );
  359. int KlownRemoteAction( CGameCharacter *, CGameLevel * );
  360. int KlownCollide( CGameCharacter *, CGameCharacter *, CGameLevel * );
  361.  
  362. CGameCharSequenceInfo char1seq[2] =
  363. {
  364.     // sequence 0: ThrownLeft
  365.     {"piefly.spr", "FlyLeft", 30, {"throw.wav", NULL, 100, 0}},
  366.     // sequence 1: ThrownRight
  367.     {"piefly.spr", "FlyRight", 30, {"throw.wav", NULL, 100, 0}}
  368. };
  369.  
  370. // NOTE: the klown sequences below are all the same.  They are included
  371. // separately to permit possible future changes in behaviour for different klowns.
  372. CGameCharSequenceInfo klown1seq[32] =
  373. {
  374.     {"c1stand.spr", "StandRight", 30, {NULL, NULL, 0, 0}},          // STAND_RIGHT
  375.     {"c1stand.spr", "StandLeft", 30, {NULL, NULL, 0, 0}},           // STAND_LEFT
  376.     {"c1walk.spr", "WalkRight", 30, {"walk.wav", NULL, 40, 1}},     // WALK_RIGHT
  377.     {"c1walk.spr", "WalkLeft", 30, {"walk.wav", NULL, 40, 1}},      // WALK_LEFT
  378.     {"c1run.spr", "RunRight", 30, {"run.wav", NULL, 60, 1}},        // RUN_RIGHT
  379.     {"c1run.spr", "RunLeft", 30, {"run.wav", NULL, 60, 1}},         // RUN_LEFT
  380.     {"c1turn.spr", "Right2Left", 30, {NULL, NULL, 80, 1}},          // R2L_TURN
  381.     {"c1turn.spr", "Left2Right", 30, {NULL, NULL, 80, 1}},          // L2R_TURN
  382.     {"c1throw.spr", "ThrowRight", 30, {NULL, NULL, 80, 1}},         // THROW_RIGHT
  383.     {"c1throw.spr", "ThrowLeft", 30, {NULL, NULL, 80, 1}},          // THROW_LEFT
  384.     {"c1stand.spr", "StandRight", 30, {NULL, NULL, 80, 1}},         // THROW_RIGHT_WALK
  385.     {"c1stand.spr", "StandLeft", 30, {NULL, NULL, 80, 1}},          // THROW_LEFT_WALK
  386.     {"c1stand.spr", "StandRight", 30, {NULL, NULL, 80, 1}},         // THROW_RIGHT_RUN
  387.     {"c1stand.spr", "StandLeft", 30, {NULL, NULL, 80, 1}},          // THROW_LEFT_RUN
  388.     {"c1walk45.spr", "InRight", 30, {"walk.wav", NULL, 40, 1}},     // IN_RIGHT
  389.     {"c1walk45.spr", "InLeft", 30, {"walk.wav", NULL, 40, 1}},      // IN_LEFT
  390.     {"c1walk45.spr", "OutRight", 30, {"walk.wav", NULL, 40, 1}},    // OUT_RIGHT
  391.     {"c1walk45.spr", "OutLeft", 30, {"walk.wav", NULL, 40, 1}},     // OUT_LEFT
  392.     {"c1duck.spr", "DuckRight", 30, {NULL, NULL, 40, 1}},           // DUCK_RIGHT
  393.     {"c1duck.spr", "DuckLeft", 30, {NULL, NULL, 40, 1}},            // DUCK_LEFT
  394.     {"c1block.spr", "BlockRight", 30, {NULL, NULL, 40, 1}},         // BLOCK_RIGHT
  395.     {"c1block.spr", "BlockLeft", 30, {NULL, NULL, 40, 1}},          // BLOCK_LEFT
  396.     {"c1poke.spr", "PokeRight", 30, {"nyuk.wav", NULL, 63, 0}},     // POKE_RIGHT
  397.     {"c1poke.spr", "PokeLeft", 30, {"nyuk.wav", NULL, 63, 0}},      // POKE_LEFT
  398.     {"c1piefac.spr", "PieFaceLeft", 30, {NULL, "piehit2.wav", 100, 0}},     // HIT_FACE_L
  399.     {"c1piefac.spr", "PieFaceRight", 30, {NULL, "piehit2.wav", 100, 0}},    // HIT_FACE_R
  400.     {"c1piehed.spr", "PieHeadLeft", 30, {NULL, "piehit2.wav", 100, 0}},     // HIT_BACK_L
  401.     {"c1piehed.spr", "PieHeadRight", 30, {NULL, "piehit2.wav", 100, 0}},    // HIT_BACK_R
  402.     {"c1stand.spr", "StandLeft", 30, {"woob.wav", NULL, 63, 0}},    // POKED_L
  403.     {"c1stand.spr", "StandRight", 30, {"woob.wav", NULL, 63, 0}},   // POKED_R
  404.     {"c1sad.spr", "C1SadLeft", 10, {"sad.wav", NULL, 100, 0}},      // IS_DEAD
  405.     {"c1sad.spr", "C1SadDone", 10, {NULL, NULL, 100, 0}}            // GAME_OVER
  406. };
  407.  
  408. CGameCharSequenceInfo klown2seq[32] =
  409. {
  410.     {"c2stand.spr", "C2StandRight", 30, {NULL, NULL, 0, 0}},            // STAND_RIGHT
  411.     {"c2stand.spr", "C2StandLeft", 30, {NULL, NULL, 0, 0}},         // STAND_LEFT
  412.     {"c2walk.spr", "C2WalkRight", 30, {"walk.wav", NULL, 40, 1}},       // WALK_RIGHT
  413.     {"c2walk.spr", "C2WalkLeft", 30, {"walk.wav", NULL, 40, 1}},        // WALK_LEFT
  414.     {"c2run.spr", "C2RunRight", 30, {"run.wav", NULL, 60, 1}},      // RUN_RIGHT
  415.     {"c2run.spr", "C2RunLeft", 30, {"run.wav", NULL, 60, 1}},           // RUN_LEFT
  416.     {"c2turn.spr", "C2Right2Left", 30, {NULL, NULL, 80, 1}},            // R2L_TURN
  417.     {"c2turn.spr", "C2Left2Right", 30, {NULL, NULL, 80, 1}},            // L2R_TURN
  418.     {"c2throw.spr", "C2ThrowRight", 30, {NULL, NULL, 80, 1}},           // THROW_RIGHT
  419.     {"c2throw.spr", "C2ThrowLeft", 30, {NULL, NULL, 80, 1}},            // THROW_LEFT
  420.     {"c2stand.spr", "C2StandRight", 30, {NULL, NULL, 80, 1}},           // THROW_RIGHT_WALK
  421.     {"c2stand.spr", "C2StandLeft", 30, {NULL, NULL, 80, 1}},            // THROW_LEFT_WALK
  422.     {"c2stand.spr", "C2StandRight", 30, {NULL, NULL, 80, 1}},           // THROW_RIGHT_RUN
  423.     {"c2stand.spr", "C2StandLeft", 30, {NULL, NULL, 80, 1}},            // THROW_LEFT_RUN
  424.     {"c2walk45.spr", "C2InRight", 30, {"walk.wav", NULL, 40, 1}},       // IN_RIGHT
  425.     {"c2walk45.spr", "C2InLeft", 30, {"walk.wav", NULL, 40, 1}},        // IN_LEFT
  426.     {"c2walk45.spr", "C2OutRight", 30, {"walk.wav", NULL, 40, 1}},  // OUT_RIGHT
  427.     {"c2walk45.spr", "C2OutLeft", 30, {"walk.wav", NULL, 40, 1}},       // OUT_LEFT
  428.     {"c2duck.spr", "C2DuckRight", 30, {NULL, NULL, 40, 1}},         // DUCK_RIGHT
  429.     {"c2duck.spr", "C2DuckLeft", 30, {NULL, NULL, 40, 1}},          // DUCK_LEFT
  430.     {"c2block.spr", "C2BlockRight", 30, {NULL, NULL, 40, 1}},           // BLOCK_RIGHT
  431.     {"c2block.spr", "C2BlockLeft", 30, {NULL, NULL, 40, 1}},            // BLOCK_LEFT
  432.     {"c2poke.spr", "C2PokeRight", 30, {"nyuk.wav", NULL, 63, 0}},       // POKE_RIGHT
  433.     {"c2poke.spr", "C2PokeLeft", 30, {"nyuk.wav", NULL, 63, 0}},        // POKE_LEFT
  434.     {"c2piefac.spr", "C2PieFaceLeft", 30, {NULL, "piehit2.wav", 100, 0}},       // HIT_FACE_L
  435.     {"c2piefac.spr", "C2PieFaceRight", 30, {NULL, "piehit2.wav", 100, 0}},  // HIT_FACE_R
  436.     {"c2piehed.spr", "C2PieHeadLeft", 30, {NULL, "piehit2.wav", 100, 0}},       // HIT_BACK_L
  437.     {"c2piehed.spr", "C2PieHeadRight", 30, {NULL, "piehit2.wav", 100, 0}},  // HIT_BACK_R
  438.     {"c2stand.spr", "C2StandLeft", 30, {"woob.wav", NULL, 63, 0}},  // POKED_L
  439.     {"c2stand.spr", "C2StandRight", 30, {"woob.wav", NULL, 63, 0}}, // POKED_R
  440.     {"c2sad.spr", "c2SadLeft", 10, {"sad.wav", NULL, 100, 0}},      // IS_DEAD
  441.     {"c2sad.spr", "c2SadDone", 10, {NULL, NULL, 100, 0}}            // GAME_OVER
  442. };
  443.  
  444. #if 0   // !!! don't have all the bitmaps yet
  445.  
  446. CGameCharSequenceInfo klown3seq[32] =
  447. {
  448.     {"C3stand.spr", "C3StandRight", 30, {NULL, NULL, 0, 0}},            // STAND_RIGHT
  449.     {"C3stand.spr", "C3StandLeft", 30, {NULL, NULL, 0, 0}},         // STAND_LEFT
  450.     {"C3walk.spr", "C3WalkRight", 30, {"walk.wav", NULL, 40, 1}},       // WALK_RIGHT
  451.     {"C3walk.spr", "C3WalkLeft", 30, {"walk.wav", NULL, 40, 1}},        // WALK_LEFT
  452.     {"C3run.spr", "C3RunRight", 30, {"run.wav", NULL, 60, 1}},      // RUN_RIGHT
  453.     {"C3run.spr", "C3RunLeft", 30, {"run.wav", NULL, 60, 1}},           // RUN_LEFT
  454.     {"C3turn.spr", "C3Right2Left", 30, {NULL, NULL, 80, 1}},            // R2L_TURN
  455.     {"C3turn.spr", "C3Left2Right", 30, {NULL, NULL, 80, 1}},            // L2R_TURN
  456.     {"C3throw.spr", "C3ThrowRight", 30, {NULL, NULL, 80, 1}},           // THROW_RIGHT
  457.     {"C3throw.spr", "C3ThrowLeft", 30, {NULL, NULL, 80, 1}},            // THROW_LEFT
  458.     {"C3stand.spr", "C3StandRight", 30, {NULL, NULL, 80, 1}},           // THROW_RIGHT_WALK
  459.     {"C3stand.spr", "C3StandLeft", 30, {NULL, NULL, 80, 1}},            // THROW_LEFT_WALK
  460.     {"C3stand.spr", "C3StandRight", 30, {NULL, NULL, 80, 1}},           // THROW_RIGHT_RUN
  461.     {"C3stand.spr", "C3StandLeft", 30, {NULL, NULL, 80, 1}},            // THROW_LEFT_RUN
  462.     {"C3walk45.spr", "C3InRight", 30, {"walk.wav", NULL, 40, 1}},       // IN_RIGHT
  463.     {"C3walk45.spr", "C3InLeft", 30, {"walk.wav", NULL, 40, 1}},        // IN_LEFT
  464.     {"C3walk45.spr", "C3OutRight", 30, {"walk.wav", NULL, 40, 1}},  // OUT_RIGHT
  465.     {"C3walk45.spr", "C3OutLeft", 30, {"walk.wav", NULL, 40, 1}},       // OUT_LEFT
  466.     {"C3duck.spr", "C3DuckRight", 30, {NULL, NULL, 40, 1}},         // DUCK_RIGHT
  467.     {"C3duck.spr", "C3DuckLeft", 30, {NULL, NULL, 40, 1}},          // DUCK_LEFT
  468.     {"C3block.spr", "C3BlockRight", 30, {NULL, NULL, 40, 1}},           // BLOCK_RIGHT
  469.     {"C3block.spr", "C3BlockLeft", 30, {NULL, NULL, 40, 1}},            // BLOCK_LEFT
  470.     {"C3poke.spr", "C3PokeRight", 30, {"nyuk.wav", NULL, 63, 0}},       // POKE_RIGHT
  471.     {"C3poke.spr", "C3PokeLeft", 30, {"nyuk.wav", NULL, 63, 0}},        // POKE_LEFT
  472.     {"C3piefac.spr", "C3PieFaceLeft", 30, {NULL, "piehit2.wav", 100, 0}},       // HIT_FACE_L
  473.     {"C3piefac.spr", "C3PieFaceRight", 30, {NULL, "piehit2.wav", 100, 0}},  // HIT_FACE_R
  474.     {"C3piehed.spr", "C3PieHeadLeft", 30, {NULL, "piehit2.wav", 100, 0}},       // HIT_BACK_L
  475.     {"C3piehed.spr", "C3PieHeadRight", 30, {NULL, "piehit2.wav", 100, 0}},  // HIT_BACK_R
  476.     {"C3stand.spr", "C3StandLeft", 30, {"woob.wav", NULL, 63, 0}},  // POKED_L
  477.     {"C3stand.spr", "C3StandRight", 30, {"woob.wav", NULL, 63, 0}}, // POKED_R
  478.     {"C3sad.spr", "C3SadLeft", 10, {"sad.wav", NULL, 100, 0}},      // IS_DEAD
  479.     {"C3sad.spr", "C3SadDone", 10, {NULL, NULL, 100, 0}}            // GAME_OVER
  480. };
  481. #endif
  482.  
  483. // number of klown sequence sets above -1 for main klown
  484. //#define NUM_AUTO_KLOWNS 2
  485. #define NUM_AUTO_KLOWNS 1
  486.  
  487. // table of sequence tables for allocating non-main klowns
  488. CGameCharSequenceInfo* klownSeqTable[NUM_AUTO_KLOWNS] =
  489. {
  490.     klown2seq //,
  491. //  klown3seq
  492. };
  493.  
  494. // returned by 'Info' function, and isn't used either (internally)
  495. CGameCharInfo character1 =
  496. {
  497.     "Pie",
  498.     2,
  499.     &char1seq[0],
  500.  
  501.     PieCreate,
  502.     PieAction,
  503.     PieDestroy,
  504.     NULL,
  505.     PieCollide
  506. };
  507.  
  508. // returned by 'Info' function, and isn't used either (internally)
  509. static CGameCharInfo character2 =
  510. {
  511.     "Klown",
  512.     32,
  513.     &klown1seq[0],
  514.  
  515.     KlownCreate,
  516.     KlownAction,
  517.     KlownDestroy,
  518.     KlownRemoteAction,
  519.     KlownCollide
  520. };
  521.  
  522. // returned by 'Info' function, and isn't used either (internally)
  523. // Klown2 uses the klown2 - klownN sequences above, allocated 1 at a time
  524. static CGameCharInfo character3 =
  525. {
  526.     "Klown2",
  527.     32,
  528.     &klown2seq[0],  // modified at create time
  529.  
  530.     KlownCreate,
  531.     KlownAction,
  532.     KlownDestroy,
  533.     KlownRemoteAction,
  534.     KlownCollide
  535. };
  536.  
  537. // This array allows the caller to get our information directly
  538. CGameCharInfo *characters[] =
  539. {
  540.     &character1,
  541.     &character2,
  542.     &character3
  543. };
  544.  
  545. CGameInfo dllinfo =
  546. {
  547.     3,                 // number of characters implemented in
  548.     // this DLL
  549.     characters             // array of CGameCharInfo pointers
  550. };
  551.  
  552. void InitStateIndex(STATE *states, int *index, int indexsize);
  553. // EXPORTED as ordinal #1:
  554. #if defined(__BORLANDC__) || defined(__WATCOMC__)
  555. extern "C" void CALLBACK Ident( CGameVersionIdent * id )
  556. #else
  557. void CALLBACK Ident( CGameVersionIdent * id )
  558. #endif
  559. {    
  560.     GetModuleFileName(NULL, inifile, 259);
  561.     char *p = strrchr(inifile, '.');
  562.     if (p)
  563.         lstrcpy(p+1, "GAM");
  564.  
  565.     gFastKlown = GetPrivateProfileInt("KRUSTY.DLL", "fastklown", 0, inifile);
  566.     gFastVel = GetPrivateProfileInt("KRUSTY.DLL", "fastvel", 20, inifile);
  567.     gDebugOut = GetPrivateProfileInt("KRUSTY.DLL", "debugout", 0, inifile);
  568.     gPieSpeed = GetPrivateProfileInt("KRUSTY.DLL", "piespeed", 5, inifile);
  569.     gPieRange = GetPrivateProfileInt("KRUSTY.DLL", "pierange", 500, inifile);
  570.     gKlownHits = GetPrivateProfileInt("KRUSTY.DLL", "hits", 10, inifile);
  571.     SENSITIVITY = GetPrivateProfileInt("KRUSTY.DLL", "JoystickSensitivity", 33, inifile);
  572.     RUN_THRESHOLD = GetPrivateProfileInt("KRUSTY.DLL", "RunThreshold", 66, inifile);
  573.     gAgression = GetPrivateProfileInt("KRUSTY.DLL", "aggression", 10, inifile);
  574.     gMobility = GetPrivateProfileInt("KRUSTY.DLL", "mobility", 3, inifile);
  575.     gTimeout = (DWORD)GetPrivateProfileInt("KRUSTY.DLL", "RemoteTimeout", 30, inifile)
  576.         * 1000;
  577.     gUpdateInterval = (DWORD)GetPrivateProfileInt("KRUSTY.DLL", "RemoteUpdateInterval", 100, inifile);
  578.     
  579.     memcpy( id, &version, sizeof( CGameVersionIdent ) );
  580.  
  581.     InitStateIndex(klown_states, &klown_states_index[0], INT_NUM_STATES);
  582. }
  583.  
  584. // EXPORTED as ordinal #2:
  585. #if defined(__BORLANDC__) || defined(__WATCOMC__)
  586. extern "C" void  CALLBACK Info( CGameInfo * info )
  587. #else
  588. void CALLBACK Info( CGameInfo * info )
  589. #endif
  590. {    
  591.     memcpy( info, &dllinfo, sizeof( dllinfo ) );
  592. }
  593.  
  594. void InitStateIndex(STATE *states, int *index, int indexsize)
  595. {
  596.     int ix;
  597.  
  598.     // set index to unused
  599.     memset(index, -1, indexsize * sizeof(int));
  600.  
  601.     // iterate through states, putting correct index into 'index'
  602.     ix = 0;
  603.     int laststate = -2;
  604.     while (states[ix].start != -1)
  605.     {
  606.         if (states[ix].start != laststate)
  607.         {
  608.             if (states[ix].start < indexsize)
  609.                 index[states[ix].start] = ix;
  610.  
  611.             laststate = states[ix].start;
  612.         }
  613.         ++ix;
  614.     }
  615. }
  616.  
  617. int ChangeState ( STATE * states, 
  618.                 int *index,
  619.                 int curstate, 
  620.                 int transition, 
  621.                 CGameCharacter * me, 
  622.                 int time)
  623. {
  624.     /*  
  625.         The STATEs are grouped by state; they are "clumped" together, so
  626.         that once we find the 'curstate' in the array, we can look at all
  627.         the possible transitions out of 'curstate'.
  628.  
  629.         The last state in the array of allowable states is "-1".  
  630.     */
  631.  
  632.  
  633.     // first off: does this state care about any transitions?
  634.     if (klown_state_flags[curstate] & MUST_FINISH)
  635.     {
  636.         // must finish this sequence; ignore transition!
  637.         if (me->NextSprite(time, FALSE) == 0)
  638.         {
  639.             // end of sequence;
  640.             transition = EOS;
  641.         }
  642.         else
  643.         {
  644.             // not end; just return
  645.             return(curstate);                       
  646.         }
  647.     }
  648.     else
  649.     {
  650.         // do the next sprite
  651.         me->NextSprite(time, TRUE);
  652.     }
  653.  
  654.     int ix = index[curstate];
  655.     while (states[ix].start == curstate)
  656.     {
  657.         if (states[ix].transition == transition)
  658.         {
  659.             return(states[ix].end);
  660.         }                   
  661.         ++ix;
  662.     }
  663.     // didn't find our transition, so don't change state
  664.     return(curstate);           
  665. }
  666.  
  667. int     PieCreate( CGameCharacter *me, CGameLevel *level )
  668. {
  669.     // use private data as plain old integer...
  670.     me->mpPrivateData = (void *) level->GetFrameTime();
  671.  
  672.     return ( ACTION_COMPLETED );
  673. }
  674.  
  675. int     PieAction( CGameCharacter *me, CGameLevel *level )
  676. {
  677.     int posx, posy, velx, vely;
  678.     int time = level->GetFrameTime();
  679.     int slices = (me->mLastTime == -1) ? 1 : time - me->mLastTime;
  680.     me->mLastTime = time;
  681.  
  682.     me->GetVelocity(&velx, &vely);
  683.  
  684.     // remember to use sub-pixels!
  685.     me->GetSubXY(&posx, &posy);
  686.     posx += SUBPIXEL_DELTA(velx, slices);
  687.     posy += SUBPIXEL_DELTA(vely, slices);
  688.  
  689.     if (time > ((int) me->mpPrivateData + gPieRange))
  690.     {
  691.         posy = -100000;
  692.         me->mpPrivateData = (void *)-1;
  693.         me->SetAndMove(posx, posy);
  694.         me->NextSprite(level->GetTimer()->Time, FALSE);
  695.         return(-2);     
  696.     }
  697.     else
  698.     {
  699.         me->SetAndMove(posx, posy);
  700.         me->NextSprite(level->GetTimer()->Time, FALSE);     
  701.  
  702.         if (velx < 0)
  703.             return(0);
  704.         else
  705.             return(1);
  706.     }
  707.  
  708. }
  709.  
  710. int     PieDestroy( CGameCharacter *me, CGameLevel *level )
  711. {
  712.     me->mpPrivateData = (void *)-1;
  713.     return ( ACTION_COMPLETED );
  714. }
  715.  
  716. int     PieCollide( CGameCharacter *me, CGameCharacter *other, CGameLevel *level )
  717. {   
  718.     int posx, posy;
  719.     me->GetSubXY(&posx, &posy);
  720.  
  721.     //move off the visible world, so we "disappear"
  722.     posy = -100000;
  723.     me->SetAndMove(posx, posy);
  724.     me->mpPrivateData = (void *)-1;
  725.     return(0);
  726. }
  727.  
  728. static int curKlown = 0;
  729.  
  730. static int     KlownCreate( CGameCharacter *me, CGameLevel *level )
  731. {
  732.     KLOWN_DATA  *pKlown = new KLOWN_DATA;
  733.     int x,y,buttons;
  734. //  srand(0);
  735.     memset(pKlown, 0, sizeof(KLOWN_DATA));
  736.     me->mpPrivateData = (void *) pKlown;
  737.     if (level->GetInput()->GetMouse(x, y, buttons))
  738.     {
  739.         pKlown->LastMouseX =  x;
  740.         pKlown->LastMouseY =  y;        
  741.     }
  742.  
  743.     pKlown->curState = STAND_RIGHT;
  744.     pKlown->pushedState = -1;
  745.     pKlown->HitsLeft = gKlownHits;
  746.     pKlown->timeLastUpdate = level->GetFrameTime();
  747.     pKlown->IGotKilled = 0;
  748.  
  749.     pKlown->Timeout = gTimeout;
  750.     pKlown->UpdateInterval = gUpdateInterval;
  751.  
  752.     BOOL isMain = (lstrcmpi(me->GetName(), "klown") == 0);
  753.  
  754.     if (isMain && gFastKlown)
  755.     {       
  756.         pKlown->curState = RUN_RIGHT;
  757.         me->SetVelocity(gFastVel,0);
  758.     }
  759.     else
  760.     {
  761.         pKlown->myPie = level->Add("Pie",me->GetCurrentZ(),0,-100000);      
  762.     }
  763.  
  764.     if (!isMain)
  765.     {
  766.         // set sequence set for non-main klowns using counter to allocate
  767.         // NOTE: this will change our global copy, so be careful!
  768.         me->mpCharInfo->Sequences = klownSeqTable[curKlown++ % NUM_AUTO_KLOWNS];
  769.     }
  770.  
  771.     return ( ACTION_COMPLETED );
  772. }
  773.  
  774. static void FirePie (
  775.     int posx,
  776.     int posy,
  777.     int velx,
  778.     int vely,
  779.     CGameCharacter *me, 
  780.     CGameLevel *level,
  781.     BOOL    fRemote
  782. )
  783. {
  784.     KLOWN_DATA *pKlown = (KLOWN_DATA *) me->mpPrivateData;
  785.         char chBuffer[128];
  786.  
  787.     if (pKlown->myPie == NULL)
  788.     {
  789.         pKlown->myPie = level->Add("Pie",me->GetCurrentZ(),0,0);                
  790.     }
  791.  
  792.     PieCreate(pKlown->myPie, level);
  793.  
  794.     pKlown->myPie->SetCurrentZ(me->GetCurrentZ());
  795.     if (velx > 0)   
  796.     {
  797.         pKlown->myPie->MoveTo(posx + me->GetCurWidth(), posy);
  798.     }
  799.     else    
  800.     {
  801.         pKlown->myPie->MoveTo(posx - 32, posy);
  802.     }
  803.  
  804.     pKlown->myPie->SetVelocity(velx, vely);
  805.     if (!fRemote)
  806.     {
  807.         GENERIC_CHAR_INFO   ci;
  808.  
  809.         ci.state = 0;
  810.         ci.posx = posx;
  811.         ci.posy = posy;
  812.         ci.velx = (velx > 0) ? 1 : -1;
  813.         ci.vely = (vely > 0) ? 1 : -1;
  814.                 wsprintf( chBuffer, "Pie %d %d %d %d\r\n",
  815.                     velx, vely, ci.velx, ci.vely);
  816.                 OutputDebugString(chBuffer);
  817.         ci.curZ = me->GetCurrentZ();
  818.         me->TransmitRemoteAction(KLOWN_PIE, &ci, sizeof(ci));
  819.     }
  820. }
  821.  
  822. int AddWithLimit(int base, int howmuch, int lowerlimit, int upperlimit)
  823. {
  824.     base += howmuch;
  825.     if (base > upperlimit)
  826.         base = upperlimit;
  827.     if (base < lowerlimit)
  828.         base = lowerlimit;
  829.     return(base);   
  830. }
  831.  
  832. int AdjustedY(int base, int curz, int newz, int minz, int maxz)
  833. {
  834.     int y_shift = 0;
  835.     int old_shift = 0;
  836.  
  837.     y_shift = (newz - (maxz - minz)) << 3;
  838.     old_shift = (curz - (maxz - minz)) << 3;
  839.     base += (old_shift << 8);
  840.     base -= (y_shift  << 8);
  841.     return(base);   
  842. }
  843.  
  844. // returns the new state ("action")
  845. static int     KlownAction( CGameCharacter *me, CGameLevel *level )
  846. {
  847.     int time = level->GetFrameTime();
  848.     int slices = (me->mLastTime == -1) ? 1 : time - me->mLastTime;
  849.     me->mLastTime = time;
  850.  
  851.     int velx, vely, zchange;
  852.     int posx, posy;
  853.     KLOWN_DATA *pKlown = (KLOWN_DATA *) me->mpPrivateData;
  854.  
  855.     int oldstate = pKlown->curState;
  856.     int newstate = oldstate;
  857.     int transition = NOTHING;
  858.  
  859.     JOYINFO joy;
  860.     int x, y, buttons;
  861.  
  862.     zchange = 0;
  863.  
  864.     me->GetVelocity(&velx, &vely);
  865.  
  866.     // remember to use sub-pixels!
  867.     me->GetSubXY(&posx, &posy);
  868.  
  869.     CGameInput * Input = level->GetInput();
  870.     if ((pKlown->type == 0) && (gFastKlown != (int) level->mFastKlown)) 
  871.     {
  872.         gFastKlown = (int) level->mFastKlown;
  873.         if (gFastKlown)
  874.         {
  875.             pKlown->curState = RUN_RIGHT;
  876.             velx = gFastVel;
  877.             vely = 0;
  878.             me->SetVelocity(velx,vely);
  879.             newstate = oldstate = RUN_RIGHT;        
  880.         }
  881.         else
  882.         {
  883.             pKlown->curState = STAND_RIGHT;
  884.             me->SetVelocity( 0,0 );
  885.             newstate = oldstate = STAND_RIGHT;      
  886.         }
  887.     }
  888.  
  889.     if (gFastKlown && (pKlown->type == 0))  
  890.     {
  891.         me->NextSprite(time);
  892.         newstate = oldstate;        
  893.  
  894.         if (SUB2WORLD(posx) <= (-level->GetMaxX()))
  895.         {
  896.             velx = -velx;
  897.             newstate = RUN_RIGHT;
  898.         }
  899.         else if (SUB2WORLD(posx) >= (level->GetMaxX() - me->GetCurWidth() ))
  900.         {
  901.             newstate = RUN_LEFT;
  902.             velx = -velx;
  903.         }
  904.     }
  905.     else
  906.     {
  907.     // step 1: Grab input and figure out what the command is:
  908.         velx=vely=zchange=0;
  909.  
  910.         int alt, ctrl, shift;
  911.         int right, left, up, down;
  912.  
  913.         alt = ctrl = shift = right = left = up = down = 0;
  914.  
  915.         switch (pKlown->type)
  916.         {
  917.             case 0:         // "normal"
  918.                 alt = Input->GetKeyboard(VK_MENU);
  919.                 ctrl = Input->GetKeyboard(VK_CONTROL);
  920.                 shift=Input->GetKeyboard(VK_SHIFT);
  921.                 right = (Input->GetKeyboard(VK_RIGHT) != 0) ||
  922.                        (Input->GetKeyboard(VK_NUMPAD6) != 0);
  923.                 left = (Input->GetKeyboard(VK_LEFT) != 0) ||
  924.                        (Input->GetKeyboard(VK_NUMPAD4) != 0);
  925.                 up = (Input->GetKeyboard(VK_UP) != 0) ||
  926.                        (Input->GetKeyboard(VK_NUMPAD8) != 0);
  927.                 down = (Input->GetKeyboard(VK_DOWN) != 0) ||
  928.                        (Input->GetKeyboard(VK_NUMPAD2) != 0);
  929.  
  930.                 if (! (up || down || left || right || shift))
  931.                 {
  932.  
  933.                     if (Input->GetMouse(x, y, buttons))
  934.                     {
  935.                         int deltaX = x - pKlown->LastMouseX;
  936.                         int deltaY = y - pKlown->LastMouseY;
  937.  
  938.                         right = (deltaX > MIN_MOUSE_MOVE);
  939.                         left = (deltaX < -MIN_MOUSE_MOVE);
  940.                         if ((deltaX > BIG_MOUSE_MOVE) ||  (deltaX < -BIG_MOUSE_MOVE))
  941.                         {
  942.                             ctrl = TRUE;
  943.                         }
  944.                         down = (deltaY > 5*MIN_MOUSE_MOVE);
  945.                         up = (deltaY < -5*MIN_MOUSE_MOVE);
  946.  
  947.                         shift = shift || (buttons & 1);
  948.                         alt = buttons & 2;
  949.  
  950.                         x = CenterX;
  951.                         y = CenterY;
  952.  
  953.                         pKlown->LastMouseX = x;
  954.                         pKlown->LastMouseY = y;
  955.                         SetCursorPos(x, y);
  956.                     }
  957.                 }
  958.  
  959.                 if (! (up || down || left || right || shift))
  960.                 {
  961.  
  962.                     // grab joystick input...
  963.                     if (Input->GetJoystick(1, &joy))
  964.                     {
  965.                         // motion left ,right, up or down; button 1=fire pie. button2=flip
  966.                         int vel;
  967.                         vel = joy.wXpos;
  968.                         if (vel >= SENSITIVITY)
  969.                         {
  970.                             // moved right:
  971.                             right = 1;
  972.                             if (vel >= RUN_THRESHOLD)
  973.                                 ctrl = 1;
  974.                         }
  975.                         else if (vel <= -SENSITIVITY)
  976.                         {
  977.                             // moved left:
  978.                             left = 1;
  979.                             if (vel <= -RUN_THRESHOLD)
  980.                                 ctrl = 1;
  981.                         }
  982.  
  983.                         vel = joy.wYpos;
  984.                         if (vel >= SENSITIVITY)
  985.                             down = 1;
  986.                         else if (vel <= -SENSITIVITY)
  987.                             up = 1;
  988.  
  989.                         if (joy.wButtons & JOY_BUTTON1)
  990.                             shift = 1;
  991.                         if (joy.wButtons & JOY_BUTTON2)
  992.                             alt = 1;
  993.                     }
  994.                 }
  995.                 break;
  996.  
  997.             case 1:         // "robo"
  998.                 // where is the main klown, relative to us?
  999.                 if (level->mMainKlown && (level->mMainKlown != me))
  1000.                 {
  1001.                     // get its rectangle
  1002.                     PRECT pMainRect = level->mMainKlown->GetRect();
  1003.                     PRECT pMyRect  = me->GetRect();
  1004.  
  1005.                     // first: if we were walking, we should keep on walking!
  1006.                     if (oldstate == WALK_LEFT || oldstate == WALK_RIGHT)
  1007.                     {
  1008.                         if (rand() % 10)
  1009.                         {
  1010.                             if (oldstate == WALK_LEFT)
  1011.                                 ++left;
  1012.                             else
  1013.                                 ++right;
  1014.                             goto no_change;
  1015.                             
  1016.                         }
  1017.  
  1018.                     }
  1019.  
  1020.                     if ((int)(rand() % 100) <= gMobility)
  1021.                     {
  1022.                         if (rand() % 5)
  1023.                         { 
  1024.                             if (pMainRect->left < pMyRect->left) 
  1025.                                ++left;
  1026.                             else
  1027.                                 ++right;
  1028.                         }
  1029.                         else
  1030.                         {
  1031.                             int z = level->mMainKlown->GetCurrentZ();
  1032.                             if ((z > me->GetCurrentZ()) || gFastKlown)
  1033.                             {
  1034.                                 // increase our z
  1035.                                 ++up;
  1036.                             }
  1037.                             else if (z < me->GetCurrentZ())
  1038.                             {
  1039.                                 // decrease our z
  1040.                                 ++down;
  1041.                             }
  1042.                         }
  1043.  
  1044. no_change:          
  1045.                     // nothing
  1046.                         ;
  1047.                     }
  1048.                     else if ((int)(rand() % 100) <= gAgression)
  1049.                         ++shift;
  1050.                 }
  1051.  
  1052.                 break;
  1053.  
  1054.             case 2:         // "second" always uses second joystick
  1055.                 if (Input->GetJoystick(2, &joy))
  1056.                 {
  1057.                     // motion left ,right, up or down; button 1=fire pie. button2=flip
  1058.                     int vel;
  1059.                     vel = joy.wXpos;
  1060.                     if (vel >= SENSITIVITY)
  1061.                     {
  1062.                         // moved right:
  1063.                         right = 1;
  1064.                         if (vel >= RUN_THRESHOLD)
  1065.                             ctrl = 1;
  1066.                     }
  1067.                     else if (vel <= -SENSITIVITY)
  1068.                     {
  1069.                         // moved left:
  1070.                         left = 1;
  1071.                         if (vel <= -RUN_THRESHOLD)
  1072.                             ctrl = 1;
  1073.                     }
  1074.  
  1075.                     vel = joy.wYpos;
  1076.                     if (vel >= SENSITIVITY)
  1077.                         down = 1;
  1078.                     else if (vel <= -SENSITIVITY)
  1079.                         up = 1;
  1080.  
  1081.                     if (joy.wButtons & JOY_BUTTON1)
  1082.                         shift = 1;
  1083.                     if (joy.wButtons & JOY_BUTTON2)
  1084.                         alt = 1;
  1085.                 }
  1086.                 break;
  1087.         }
  1088.  
  1089.         if (up)
  1090.             transition = GO_IN;
  1091.         if (down)
  1092.             transition = GO_OUT;
  1093.         if (left)
  1094.             transition = ctrl ? RUN_L : WALK_L;
  1095.         if (right)
  1096.             transition = ctrl ? RUN_R : WALK_R;
  1097.         if (shift)
  1098.             transition = THROW;
  1099.         if (alt && down)
  1100.             transition = DUCK;
  1101.         if (shift && down)
  1102.             transition = POKE;
  1103.         if (alt && shift)
  1104.             transition = BLOCK;
  1105.  
  1106.         // got a transition; figure out the new state
  1107.         if (pKlown->pushedState >= 0)
  1108.         {
  1109.             newstate = pKlown->pushedState;
  1110.             pKlown->pushedState = -1;
  1111.         }
  1112.         else
  1113.         {
  1114.             newstate = ChangeState( klown_states, 
  1115.                                     klown_states_index,
  1116.                                     oldstate, 
  1117.                                     transition, 
  1118.                                     me, 
  1119.                                     time);
  1120.         }
  1121.  
  1122.         switch (newstate)
  1123.         {
  1124.             case INT_COLLIDED_ON_RIGHT:
  1125.                 if (rand() % 2)
  1126.                 {
  1127.                     posx -= WORLD2SUB(me->GetCurWidth()/4);
  1128.                     ++zchange;                  
  1129.                 }
  1130.                 newstate = STAND_RIGHT;
  1131.                 break;
  1132.  
  1133.             case INT_COLLIDED_ON_LEFT:
  1134.                 if (rand() % 2)
  1135.                 {
  1136.                     posx += WORLD2SUB(me->GetCurWidth()/4);
  1137.                     ++zchange;
  1138.                 }
  1139.                 newstate = STAND_LEFT;
  1140.                 break;
  1141.                 
  1142.             case HIT_FACE_L:
  1143.             case HIT_FACE_R:
  1144.             case HIT_BACK_L:
  1145.             case HIT_BACK_R:
  1146.                 if (newstate != oldstate)
  1147.                 {
  1148.                     --pKlown->HitsLeft;
  1149.                     if (pKlown->HitsLeft <= 0)
  1150.                     {
  1151.                         newstate = IS_DEAD;
  1152.                     }
  1153.                 }
  1154.                 break;
  1155.  
  1156.             case IS_DEAD:
  1157.                 velx = 0;
  1158.                 vely = 0;
  1159.                 ++zchange;
  1160.                 break;
  1161.  
  1162.             case GAME_OVER:
  1163.                 level->GameOver();
  1164.                 pKlown->IGotKilled = 1;
  1165.  
  1166.                 // reset scores of all Klowns...
  1167.                 {
  1168.                     KLOWN_DATA * pK = (KLOWN_DATA *) level->mMainKlown->mpPrivateData;
  1169.                     if (pK)
  1170.                         pK->HitsLeft = gKlownHits;
  1171.                     if (level->mSecondKlown)
  1172.                     {
  1173.                         pK = (KLOWN_DATA *) level->mSecondKlown->mpPrivateData;
  1174.                         if (pK)
  1175.                             pK->HitsLeft = gKlownHits;
  1176.                     }
  1177.                         
  1178.                     // need to change this for more than one computer klown...
  1179.                     if (level->mComputerKlowns[0])
  1180.                     {
  1181.                         pK = (KLOWN_DATA *) level->mComputerKlowns[0]->mpPrivateData;
  1182.                         if (pK)
  1183.                             pK->HitsLeft = gKlownHits;
  1184.                     }
  1185.                 }
  1186.  
  1187.                 break;
  1188.  
  1189.             case WALK_RIGHT:
  1190.                 velx = WALK_VELOCITY;
  1191.                 break;
  1192.  
  1193.             case RUN_RIGHT:
  1194.                 velx = RUN_VELOCITY;
  1195.                 break;
  1196.  
  1197.             case WALK_LEFT:
  1198.                 velx = -WALK_VELOCITY;
  1199.                 break;
  1200.  
  1201.             case RUN_LEFT:
  1202.                 velx = -RUN_VELOCITY;
  1203.                 break;
  1204.  
  1205.             case THROW_LEFT:
  1206.             case THROW_RIGHT:
  1207.             case THROW_LEFT_WALK:
  1208.             case THROW_RIGHT_WALK:
  1209.             case THROW_LEFT_RUN:
  1210.             case THROW_RIGHT_RUN:
  1211.                 if (newstate != oldstate)
  1212.                     if (pKlown->myPie && (pKlown->myPie->mpPrivateData!=(void*)-1))
  1213.                         newstate = oldstate;
  1214.                 break;
  1215.  
  1216.             case INT_THROW_RIGHT:
  1217.                     newstate = STAND_RIGHT;
  1218.                     FirePie(SUB2WORLD(posx), SUB2WORLD(posy), gPieSpeed, 0, me, level, FALSE);
  1219.                     break;
  1220.  
  1221.             case INT_THROW_RIGHT_WALK:
  1222.                     newstate = WALK_RIGHT;
  1223.                     FirePie(SUB2WORLD(posx), SUB2WORLD(posy), gPieSpeed, 0, me, level, FALSE);
  1224.                     break;
  1225.  
  1226.             case INT_THROW_RIGHT_RUN:
  1227.                     newstate = RUN_RIGHT;
  1228.                     FirePie(SUB2WORLD(posx), SUB2WORLD(posy), gPieSpeed, 0, me, level, FALSE);
  1229.                     break;
  1230.  
  1231.             case INT_THROW_LEFT:
  1232.                     newstate = STAND_LEFT;
  1233.                     FirePie(SUB2WORLD(posx), SUB2WORLD(posy), -gPieSpeed, 0, me, level, FALSE);
  1234.                     break;
  1235.  
  1236.             case INT_THROW_LEFT_WALK:
  1237.                     newstate = WALK_LEFT;
  1238.                     FirePie(SUB2WORLD(posx), SUB2WORLD(posy), -gPieSpeed, 0, me, level, FALSE);
  1239.                     break;
  1240.  
  1241.             case INT_THROW_LEFT_RUN:
  1242.                     newstate = RUN_LEFT;
  1243.                     FirePie(SUB2WORLD(posx), SUB2WORLD(posy), -gPieSpeed, 0, me, level, FALSE);
  1244.                     break;
  1245.  
  1246.             case IN_LEFT:
  1247.                 {
  1248.                 int curz = me->GetCurrentZ();
  1249.                 velx = -32;
  1250.                 curz = AddWithLimit(curz, 1, me->GetMinZ(), me->GetMaxZ());
  1251.                 posy = AdjustedY(posy, me->GetCurrentZ(), curz, me->GetMinZ(), me->GetMaxZ());
  1252.                 me->SetCurrentZ(curz);
  1253.                 ++zchange;
  1254.                 }
  1255.                 break;
  1256.  
  1257.             case IN_RIGHT:
  1258.                 {
  1259.                 int curz = me->GetCurrentZ();
  1260.                 velx = 32;
  1261.                 curz = AddWithLimit(curz, 1, me->GetMinZ(), me->GetMaxZ());
  1262.                 posy = AdjustedY(posy, me->GetCurrentZ(), curz, me->GetMinZ(), me->GetMaxZ());
  1263.                 me->SetCurrentZ(curz);
  1264.                 ++zchange;
  1265.                 }
  1266.                 break;
  1267.  
  1268.             case OUT_LEFT:
  1269.                 {
  1270.                 int curz = me->GetCurrentZ();
  1271.                 velx=-32;
  1272.                 curz = AddWithLimit(curz, -1, me->GetMinZ(), me->GetMaxZ());
  1273.                 posy = AdjustedY(posy, me->GetCurrentZ(), curz, me->GetMinZ(), me->GetMaxZ());
  1274.                 me->SetCurrentZ(curz);
  1275.                 ++zchange;
  1276.                 }
  1277.                 break;
  1278.             case OUT_RIGHT:
  1279.                 {
  1280.                 int curz = me->GetCurrentZ();
  1281.                 velx=32;
  1282.                 curz = AddWithLimit(curz, -1, me->GetMinZ(), me->GetMaxZ());
  1283.                 posy = AdjustedY(posy, me->GetCurrentZ(), curz, me->GetMinZ(), me->GetMaxZ());
  1284.                 me->SetCurrentZ(curz);
  1285.                 ++zchange;
  1286.                 }
  1287.                 break;
  1288.         }
  1289.     }
  1290.  
  1291.     if (velx || vely || zchange)
  1292.     {
  1293.         posx += SUBPIXEL_DELTA(slices, velx);
  1294.         posy += SUBPIXEL_DELTA(slices, vely);
  1295.         int newX = SUB2WORLD(posx);
  1296.         int newY = SUB2WORLD(posy);
  1297.  
  1298.  
  1299.         if (pKlown->type == 0)
  1300.             level->ForceOnScreen(&newX, &newY, me->GetCurWidth(), me->GetCurHeight());
  1301.         else
  1302.             level->ForceOnScreen(&newX, &newY, me->GetCurWidth(), me->GetCurHeight(), FALSE);
  1303.         me->MoveTo(newX, newY);
  1304.     }
  1305.  
  1306.     me->SetVelocity(velx, vely);
  1307.     pKlown->curState = newstate;
  1308.  
  1309.  
  1310.     if (pKlown->type == 0)
  1311.     {
  1312.         if ((newstate != oldstate) || (velx || vely || zchange) 
  1313.         || (time - pKlown->timeLastUpdate > pKlown->UpdateInterval))
  1314.         {
  1315.             GENERIC_CHAR_INFO   ci;
  1316.                         int velx;
  1317.                         int vely;
  1318.  
  1319.  
  1320.             ci.state = newstate;
  1321.             me->GetSubXY((int *)&ci.posx, (int *)&ci.posy);
  1322.             me->GetVelocity(&velx, &vely);
  1323.                         ci.velx = velx;
  1324.                         ci.vely = vely;
  1325.             ci.curZ = me->GetCurrentZ();
  1326.  
  1327.             me->TransmitRemoteAction(KLOWN_MOVE, &ci, sizeof(ci));
  1328.             pKlown->timeLastUpdate = time;
  1329.         }       
  1330.     }
  1331.     return ( newstate );
  1332. }
  1333.  
  1334. static int     KlownDestroy( CGameCharacter *me, CGameLevel *level )
  1335. {
  1336.     delete (void *) me->mpPrivateData;
  1337.     return ( ACTION_COMPLETED );
  1338. }
  1339.  
  1340. static int     KlownRemoteAction( CGameCharacter *me, CGameLevel *level )
  1341. {
  1342.     KLOWN_DATA *pKlown = (KLOWN_DATA *) me->mpPrivateData;
  1343.     int oldstate = pKlown->curState;
  1344.  
  1345.     int time = level->GetFrameTime();
  1346.     int slices = (me->mLastTime == -1) ? 1 : time - me->mLastTime;
  1347.     me->mLastTime = time;
  1348.  
  1349.     void    *Data;
  1350.     int newstate = oldstate;
  1351.     int action;
  1352.     DWORD   DataSize;
  1353.  
  1354.     me->NextSprite(time, FALSE);
  1355.  
  1356.     int nActionsProcessed = 0;
  1357.     while ((action = me->GetRemoteAction(Data, DataSize)) != -1)
  1358.     {
  1359.  
  1360.         nActionsProcessed++;
  1361.  
  1362.         GENERIC_CHAR_INFO *ci = (GENERIC_CHAR_INFO *)Data;
  1363.  
  1364.         switch (action) {
  1365.         case KLOWN_MOVE:
  1366.             newstate = ci->state;
  1367.             pKlown->curState = newstate;
  1368.             me->SetCurrentZ(ci->curZ);
  1369.             me->SetVelocity(ci->velx, ci->vely);
  1370.             me->SetAndMove(ci->posx, ci->posy);
  1371.             break;
  1372.             
  1373.         case KLOWN_PIE:
  1374.             FirePie(ci->posx, ci->posy, ci->velx * gPieSpeed, 0, me , level, TRUE);
  1375.             break;
  1376.  
  1377.         }
  1378.         me->ReleaseRemoteAction(Data);
  1379.     }
  1380.  
  1381.     if (nActionsProcessed > 0)
  1382.     {
  1383.         pKlown->timeLastUpdate = time;
  1384.     } 
  1385.     else if (time - pKlown->timeLastUpdate > pKlown->Timeout)
  1386.     {
  1387.         // need to kill 'em off
  1388.         return(ACTION_KILLME);                  
  1389.     } 
  1390.     else 
  1391.     {
  1392.         int velx, vely;
  1393.         int posx, posy;
  1394.  
  1395.         // Haven't heard from him, but keep him moving!
  1396.         me->GetVelocity(&velx, &vely);
  1397.         me->GetSubXY(&posx, &posy);
  1398.         if (velx || vely)
  1399.         {
  1400.             posx += SUBPIXEL_DELTA(slices, velx);
  1401.             posy += SUBPIXEL_DELTA(slices, vely);
  1402.  
  1403.             me->SetAndMove(posx, posy);
  1404.             me->SetVelocity(velx, vely);
  1405.         }
  1406.     }
  1407.  
  1408.     return(newstate);
  1409. }
  1410.  
  1411. static int boogy = 0;
  1412. int     KlownCollide( CGameCharacter *me, CGameCharacter *other, CGameLevel *level )
  1413. {   
  1414.     KLOWN_DATA *pKlown = (KLOWN_DATA *) me->mpPrivateData;
  1415.     RECT myRect, otherRect;
  1416.     LPRECT pmyRect, potherRect;
  1417.  
  1418.     if ((pKlown->curState == GAME_OVER) ||
  1419.        (pKlown->curState == IS_DEAD))
  1420.         return(ACTION_COMPLETED);
  1421.         
  1422.  
  1423.     pmyRect = me->GetRect();
  1424.     potherRect = other->GetRect();
  1425.     memcpy(&myRect, pmyRect, sizeof(RECT));
  1426.     memcpy(&otherRect, potherRect, sizeof(RECT));
  1427.  
  1428.         if (lstrcmpi(other->GetName(), "Pie") == 0)
  1429.     {
  1430.         // got hit by a pie, so decrement HitsLeft
  1431.         int velx, vely;
  1432.         other->GetVelocity(&velx, &vely);
  1433.         switch (pKlown->curState)
  1434.         {
  1435.         case STAND_LEFT:
  1436.         case WALK_LEFT:
  1437.         case RUN_LEFT:
  1438.             pKlown->pushedState = (velx < 0) ? HIT_BACK_L : HIT_FACE_L;
  1439.             break;
  1440.         case STAND_RIGHT:
  1441.         case WALK_RIGHT:
  1442.         case RUN_RIGHT:
  1443.             pKlown->pushedState = (velx < 0) ? HIT_FACE_R : HIT_BACK_R;
  1444.             break;
  1445.         }
  1446.     }
  1447.     else
  1448.     {
  1449.         // hit another solid body... need to move out of the way:
  1450.         int posx, posy;
  1451.         int posx2, posy2;
  1452.  
  1453.         if ( (myRect.right < otherRect.left) ||
  1454.              (myRect.left > otherRect.right)
  1455.             )
  1456.             return(ACTION_COMPLETED);
  1457.  
  1458.         me->GetXY(&posx, &posy);
  1459.         other->GetXY(&posx2, &posy2);
  1460.  
  1461.         // back up...
  1462.         if (posx2 < posx)
  1463.             pKlown->pushedState = INT_COLLIDED_ON_LEFT;
  1464.         else if (posx2 > posx)
  1465.             pKlown->pushedState = INT_COLLIDED_ON_RIGHT;
  1466.         else 
  1467.         {
  1468.             // coincident... how to handle this?
  1469.             if (++boogy % 2)
  1470.                 pKlown->pushedState = IN_RIGHT;
  1471.             else
  1472.                 pKlown->pushedState = OUT_RIGHT;
  1473.         }
  1474.     }
  1475.     return(ACTION_COMPLETED);   
  1476. }
  1477.