#ifdef MSVC
#include "stdio.h"
#endif

#include "allegro.h"
#include "viewports.h"

extern "C" {
	#include "lua.h"
	#include "lualib.h"
	#include "lauxlib.h"
}

// enable demos
#define DEMOS

#define OLD_BOUNCE

#define SPLITSCREEN

#define VIEW_X 320
#define VIEW_Y 150

//liero style weapon affected code
#define OLD_AIM

extern int numViewports;
extern gameViewport *viewport;

extern char VERSION[16];

class coordsint
{
public:
   int x, y;
};

class coordslong
{
public:
   long x, y;
};

class special
{
public:
   int num;
   int damage;
   char frame, numFrames;
   int animDelay;
   int hole;
   long blowOnHit;
   int detectDist;
   int flashTime, shakeTime;
   int soundNum, numSounds;
   char pushObjects;
   char pushWorms;
   long freezeTime;
};

class special_obj
{
public:
   char active;
   char owner;
   special *spec;
   int x, y;
   long int localTime;
   char *visible;
};

class wobj
{
public:
   char sndLoop;
   int sndToLoop;
   int num;
   long blowOnHit;
   long initSpeed, speedVariation;
   long spread;
   long bounce;
   int fireDelay;
   int frame, numFrames;
   int animDelay;
   long gravity;
   int timeToExplode;
   int explosion;
   char shrapnel;
   int shrapCount;
   long shrapAffected;
   char expOnGround, expOnWorm, remOnWorm;
   int spawnSpecial;
   char specialDelay;
   int spawnWobj;
   char wobjDelay;
   long wobjAffect;
   int bulletColor;
   int randomExpTime;
   int detectDist;
   int physicsLoop;
   int damage;
   char drawOnGround;
   char animOnGround;
   long drunk;
   long multiply;
   int bounceExp;
   long bounceLimit;
   long freezeTime;
   char expOnExp;
};

class weapon
{
public:
   char sndLoop;
   int sndToLoop;
   int num;
   char name[20];
   int affectedByWorm;
   int laserSight;
   long blowAway, blowOnHit;
   int showCone;
   int maxAmmo;
   int loadTime;
   int numObjects;
   int blood;
   long initSpeed, speedVariation;
   long spread;
   long bounce;
   int fireDelay;
   int frame, numFrames;
   int animDelay;
   long gravity;
   int timeToExplode;
   int explosion;
   char shrapnel;
   int shrapCount;
   long shrapAffected;
   char expOnGround, expOnWorm, remOnWorm;
   int spawnSpecial;
   char specialDelay;
   int spawnWobj;
   char wobjDelay;
   long wobjAffect;
   int bulletColor;
   int randomExpTime;
   char weapType;
   int detectDist;
   int physicsLoop;
   int damage;
   char animOnGround;
   int soundNum, reloadSnd;
   long drunk;
   long botRange;
   int ejectShells;
   long accel;
   long multiply;
   int bounceExp;
   long bounceLimit;
   char expOnObject;
   char remOnObject;
   long freezeTime;
   char expOnExp;
   BITMAP *wormSkin;
   long homingDist, homingSpeed, homingAccel;
};

class waypoint {
public:
   char active;
   int x, y;
   char used;
   struct {
      int link;
      float dist;
      int flags;
   } links[4];
   int flags;
};

#define NUM_FLAGS 14

class worm
{
public:
 char name[21];
 int num;

 int health, kills, lives;
 char dir, aim, frame, active, team, skin;
 coordsint coords, ropecoords;
 coordslong pos, vel, oldpos, rope, ropevel;
 long ropeLen;                     
 char sentKeys;
 worm *lineCatch, *enemy;
 waypoint *dest;
 long chaseTime, enemyTime;
 long localTime;
 char isAi;
 char flags[NUM_FLAGS];
 char buttons[7];
 long next_aim, next_frame, show_fire, next_dig, next_spawn, next_rope;

 char weaps[5];
 int reload[5];
 int ammo[5];
 long next_fire[5];
 char curWeap;
 long flashEnd, shakeEnd;
 long freezeEnd;

 int aiPath;
 int aiFlags;
 int aiState;
 long aiDist;
 int aiCurX, aiCurY;
 long aimStarted;
 
 void engineGravity(worm *tmpWorm);
 void engineTestBorders(worm *tmpWorm);
 void engineWorldCollision(worm *tmpWorm);
 void engineRopeCollision(worm *tmpWorm);
 void engineRopePull(worm *tmpWorm);

 lua_State *aiScript;
// worm *last, *next;
};

class interact
{
public:
   void start();
   void draw(gameViewport *where);
   void blow(worm *player);
   void collision(worm *player);
   void ownerDead(worm *killer);
   void think();
   void physics();
   long localTime;
   long x, y, VelX, VelY, OldX, OldY, spawnX, spawnY;
   long detectDist, gravity, bounce, respawn, amount;
   int CurX, CurY, type;
   worm *owner;
   char name[30];
   interact *next, *prev;

   void engineGravity();
   void engineTestBorders();
   void engineWorldCollision();
   void engineWormCollision();
};

class wobj_obj
{
public:
   int sndChan;
   char active;
   worm *owner;
   weapon *weap;
   wobj *obj;
   int frame;
   long x, y, VelX, VelY, OldX, OldY;
   int CurX, CurY;
   long int localTime;
   char visible;

   void engineGravity(wobj_obj *tmpObj);
   void engineTestBorders(wobj_obj *tmpObj);
   void engineWorldCollision(wobj_obj *tmpObj);
   void engineWormCollision(wobj_obj *tmpObj);
};

class weapon_obj
{
public:
   int sndChan;
   char active;
   worm *owner;
   weapon *weap;
   long frame;
   long x, y, VelX, VelY, OldX, OldY;
   int CurX, CurY, OX, OY;
   long int localTime;
   char visible;
   char dir, aim;
   long countTrail, countSTrail;

   void engineGravity(weapon_obj *tmpObj);
   void engineTestBorders(weapon_obj *tmpObj);
   void engineWorldCollision(weapon_obj *tmpObj);
   void engineWormCollision(weapon_obj *tmpObj);
   void engineObjectCollision(weapon_obj *tmpWeap);
};

extern interact *itemList;

#define GP_MAX_PLAYERS 8

#define GP_MAX_OBJECTS 512
#define GP_MAX_SPECIALS 1024
#define GP_MAX_WOBJECTS 2048

#define IMG_NUM_WEAPS 130
#define IMG_NUM_SPECIAL 70

extern char localAddr[256];

extern char auto_screenshot, instantReload;
extern long next_screenshot, deathcam_delay;

extern char stretch, outlineFonts;
extern int stretchX, stretchY;
extern BITMAP *tmpb, *tmpd;

extern int GP_DIG_DELAY, IMG_DIG_HOLE, GP_WORM_HEALTH, GP_WORM_RESPAWN, GP_DIG_DIST;
extern long GP_JUMPER_FORCE, GP_KICKER_FORCE, GP_FLASH_DIM, GP_ITEM_GRAVITY;

extern int fleshObject, fleshCount, dirtObject, dirtChance, shellObject;

extern int respawnObject;
extern int respawnPoint;
extern int respawnNumPoints;
extern int respawnPoints[32];

extern int isServer, asyncServer, isDedicated, serverRestart, lanGame, drawMap;

extern int weapCount, wobjCount, specCount;

extern int GP_NUM_PLAYERS;

extern char buf[256];

extern char mapName[21];

extern char serverAddr[256];

extern worm worms[GP_MAX_PLAYERS];
extern weapon weapons[256];
extern special specials[256];
extern wobj wobjs[256];

extern weapon_obj weapon_objs[GP_MAX_OBJECTS];
extern special_obj special_objs[GP_MAX_SPECIALS];
extern wobj_obj wobj_objs[GP_MAX_WOBJECTS];

extern volatile char allowFrame;

extern long gameTime;

extern char gameStart, gotKeys, gameOver, pScroll;

extern BITMAP *background, *level, *material, *lights, *parallax, *sniper, *imgLoading;
extern BITMAP *imgWorm, *holes[255], *fire[9], *crosshair, *imgWeap, *imgSpecial;
extern BITMAP *buffer, *gameFont, *wormSkins;

extern long mapSizeX, mapSizeY;

extern long cosinus[33], sinus[33];

extern long wormColors[10];

extern int lineColor, lineNumColors, lineColors[16], lineHook, bloodObject, ropeSound, deathSndFirst,
           deathSndCount, hurtSndFirst, hurtSndCount, reloadSnd, talkSnd;

extern unsigned char bufor[2*GP_MAX_PLAYERS];

/*
  Functions
*/

extern char splitScreen, numPlayers;
extern unsigned char hudAlpha;

class playerData
{
public:
   char playerName[21];
   char localTeam, localSkin;
   char localWeaps[5];
   char keys[15];
   char joybtns[3];
   int useJoy;
};

extern playerData players[GP_MAX_PLAYERS];

inline int getFrame(int i)
{
   if (i<3) return 0;
   if (i<7) return 1;
   if (i<10) return 2;
   if (i<13) return 3;
   if (i<19) return 4;
   if (i<23) return 5;
   if (i<27) return 6;
   if (i<30) return 7;
   return 8;
}

void networkProcess();
void networkServerProcess();

//define GP_WALK_ACC 100
//define GP_WALK_LIMIT 1500

#define GP_NO_REBOUNCE 20

extern long GP_LINE_DIST, GP_LINE_DIST2, GP_LINE_FORCE, GP_LINE_FORCE2; //5 10 40 140

#define GP_AIM_DELAY 1
#define GP_FRAME_DELAY 8

#define GC_LINE_COLOR 80*256*256 + 80*256 + 80
#define GC_PINK (255*256*256 + 255)
#define GC_WHITE 255*256*256 + 255*256 + 255
//define GC_HUD 255*256*256 + 255*256 + 255
//define GC_AMMO 255*256
#define GC_RELOAD makecol(255, 0, 0)
#define GC_HEALTH makecol(128, 255, 0)
#define GC_BLUE 255

#define FL_APPLY_GRAV 0
#define FL_JUMP_RELEASED 1
#define FL_ROPE_OUT 2
#define FL_ROPE_HIT 3
#define FL_ROPE_PULL 4
#define FL_CAN_JUMP 5
#define FL_GOT_ENEMY 6
#define FL_ANIM_FORWARD 7
#define FL_CAN_CHANGE 8
#define FL_JUMP_OK 9
#define FL_ROPE_OK 10
#define FL_SHOW_CAM 11
#define FL_PREDATOR 12
#define FL_CROSSHAIR 13

#define GK_JUMP 0
#define GK_FIRE 1
#define GK_CHANGE 2
#define GK_LEFT 3
#define GK_RIGHT 4
#define GK_UP 5
#define GK_DOWN 6
#define GK_CHAT 7
//            QUICKTEXT       //
#define GK_QUICK 10
extern char quicktexts[10][51];
extern int quicktextActive;
/////////////////////////////////

#define DIR_RIGHT 0
#define DIR_LEFT 1

#define KP_JUMP 1
#define KP_FIRE 2
#define KP_CHANGE 4
#define KP_LEFT 8
#define KP_RIGHT 16
#define KP_UP 32
#define KP_DOWN 64


