#include "allegro.h"

#ifdef _WIN32
#include "winalleg.h"

#include <winsock.h>
#else
#define SOCKET_ERROR -1
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#endif
#include <png.h>

#include "defs.h"
#include "console.h"
#include "engine.h"
#include "gfx.h"
#include "init.h"
#include "items.h"
#include "level.h"
#include "loadpng.h"
#include "render.h"
#include "sound.h"
#include "weapons.h"

PALETTE backpal;

void initPanes()
{
   numViewports = 1 + splitScreen;
   viewport = new gameViewport[numViewports];
   int numRows = (numViewports+1) / 2;
   int numColumns = 1 + (numViewports > 1);
   for (int i=0; i<numViewports; i++)
   {
      viewport[i].paneSizeX = (320 - (numColumns-1)*2)/numColumns;
      viewport[i].paneSizeY = (157 + 10*(numViewports != 1) + 33*(numViewports > 2) - (numRows-1)*2)/numRows;
      viewport[i].paneX = 0+(i%numColumns)*(viewport[i].paneSizeX+2);
      viewport[i].paneY = 0+(i/numColumns)*(viewport[i].paneSizeY+2);
      viewport[i].player = i;
      viewport[i].hBarX = 0;
      viewport[i].hBarY = viewport[i].paneSizeY - 6;
      viewport[i].aBarX = viewport[i].paneSizeX - 79;
      viewport[i].aBarY = viewport[i].paneSizeY - 6;
      viewport[i].snipingEnabled = (numViewports == 1);
      viewport[i].snipingX = viewport[i].paneX + viewport[i].paneSizeX - 50;
      viewport[i].snipingY = 151;
      
      if ((stretch == RENDER_GL3) || (stretch == RENDER_STRETCH2))
      {
         viewport[i].paneSizeX *= 2;
         viewport[i].paneSizeY *= 2;
         viewport[i].paneX *= 2;
         viewport[i].paneY *= 2;
         viewport[i].snipingX *= 2;
         viewport[i].snipingY *= 2;
         viewport[i].hBarX = 0;
         viewport[i].hBarY = viewport[i].paneSizeY - 6;
         viewport[i].aBarX = viewport[i].paneSizeX - 79;
         viewport[i].aBarY = viewport[i].paneSizeY - 6;
      }

      viewport[i].leftpane = create_system_bitmap(viewport[i].paneSizeX, viewport[i].paneSizeY);
      viewport[i].sniping = create_bitmap(49, 49);
      viewport[i].paneSizeY -= 7;
   }
   Console.console = create_bitmap(320, 50);
   clear_bitmap(Console.console);
}

void freePanes()
{
   for (int i=0; i<numViewports; i++)
   {
      if (viewport[i].leftpane) destroy_bitmap(viewport[i].leftpane);
      if (viewport[i].sniping) destroy_bitmap(viewport[i].sniping);
   }
   delete [] viewport;
   Console.Close();
}

int initWorms(char *name)
{
   replace_filename(buf, name, "data/worm.bmp", sizeof(buf));
   imgWorm = load_bitmap(buf, backpal);
   if (!imgWorm)
   {
      return 1;
   }
   wormSkins = create_bitmap(432, 16*GP_MAX_PLAYERS);
   if (!wormSkins)
   {
      return 1;
   }
   return 0;
}

void freeWorms()
{
   if (imgWorm) destroy_bitmap(imgWorm);
   if (wormSkins) destroy_bitmap(wormSkins);
}

int initSniper(char *name)
{
   replace_filename(buf, name, "data/sniper.png", sizeof(buf));
   sniper = load_bitmap(buf, backpal);
   if (!sniper)
   {
      return 1;
   }
   return 0;
}

void freeSniper()
{
   if (sniper) destroy_bitmap(sniper);
}

int initLoading(char *name)
{
   replace_filename(buf, name, "data/loading.png", sizeof(buf));
   imgLoading = load_bitmap(buf, backpal);
   if (!imgLoading)
   {
      return 1;
   }
   return 0;
}

void freeLoading()
{
   if (imgLoading) destroy_bitmap(imgLoading);
}

int initSpecials(char *name)
{
   replace_filename(buf, name, "data/special.png", sizeof(buf));
   imgSpecial = load_png(buf, backpal);
   if (!imgSpecial)
   {
      return 1;
   }
   return 0;
}

void freeSpecials()
{
   if (imgSpecial) destroy_bitmap(imgSpecial);
}

int initHoles(char *name)
{
   BITMAP *temp;
   int i;

   replace_filename(buf, name, "data/holes.bmp", sizeof(buf));
   temp = load_bitmap(buf, backpal);
   if (!temp)
   {
      return 1;
   }
   for (i=0; i<255; i++)
   if (i*16 < temp->w)
   {
      holes[i] = create_bitmap(16, 16);
      blit(temp, holes[i], i*16, 0, 0, 0, 16, 16);
   } else break;
   destroy_bitmap(temp);
   return 0;
}

void freeHoles()
{
   int i;
   for (i=0; i<255; i++)
   {
      if (holes[i]) destroy_bitmap(holes[i]);
   }
}

int initFire(char *name)
{
   BITMAP *temp;
   int i;

   replace_filename(buf, name, "data/fire.bmp", sizeof(buf));
   temp = load_bitmap(buf, backpal);
   if (!temp)
   {
      return 1;
   }
   for (i=0; i<9; i++)
   {
      fire[i] = create_bitmap(16, 16);
      blit(temp, fire[i], i*16, 0, 0, 0, 16, 16);
   }
   destroy_bitmap(temp);
   return 0;
}

void freeFire()
{
   int i;
   for (i=0; i<9; i++)
   {
      if (fire[i]) destroy_bitmap(fire[i]);
   }
}

int initWeaps(char *name)
{
   replace_filename(buf, name, "data/weapons.bmp", sizeof(buf));
   imgWeap = load_bitmap(buf, backpal);
   if (!imgWeap)
   {
      return 1;
   }
   return 0;
}

void freeWeaps()
{
   if (imgWeap) destroy_bitmap(imgWeap);

   for (int i=0; i<weapCount; i++)
   {
      if (weapons[i].wormSkin)
      {
         destroy_bitmap(weapons[i].wormSkin);
      }
   }
}

int initCrosshair(char *name)
{
   replace_filename(buf, name, "data/crosshair.bmp", sizeof(buf));
   crosshair = load_bitmap(buf, backpal);
   if (!crosshair)
   {
      return 1;
   }
   return 0;
}

void freeCrosshair()
{
   if (crosshair) destroy_bitmap(crosshair);
}

int initFont(char *name)
{
   replace_filename(buf, name, "data/font.bmp", sizeof(buf));
   gameFont = load_bitmap(buf, backpal);
   if (!gameFont)
   {
      return 1;
   }
   return 0;
}

void freeFont()
{
   if (gameFont) destroy_bitmap(gameFont);
}

void freeItems()
{
   interact *tmpItem;
   while (itemList)
   {
      tmpItem = itemList->next;
      free(itemList);
      itemList = tmpItem;
   }
}

void initStuff()
{
   initPanes();
}

void freeStuff()
{
   freePanes();
}

void initPhysics()
{
   int i, c;
   
   override_config_file("data/wurmz!.cfg");

   medKitRespawn = get_config_int("Items", "MediKitRespawn", 0);
   medKitPickup = get_config_int("Items", "MediKitPickup", 0);
   flagRespawn = get_config_int("Items", "FlagRespawn", 0);
   flagPickup = get_config_int("Items", "FlagPickup", 0);
   GP_ITEM_GRAVITY = get_config_int("Items", "Gravity", 50);
   itemExplosion = get_config_int("Items", "Explosion", 0);
   padHit = get_config_int("Items", "KickerPadSound", 0);

   bloodObject = get_config_int("wurmz!", "BloodObject", 0);
   fleshObject = get_config_int("wurmz!", "FleshObject", 0);
   fleshCount = get_config_int("wurmz!", "FleshCount", 1);
   dirtObject = get_config_int("wurmz!", "DirtObject", 0);
   dirtChance = get_config_int("wurmz!", "DirtChance", 100);
   shellObject = get_config_int("wurmz!", "ShellObject", 0);

   hurtSndFirst = get_config_int("wurmz!", "HurtFirstSound", 0);
   hurtSndCount = get_config_int("wurmz!", "HurtNumSounds", 1);
   deathSndFirst = get_config_int("wurmz!", "DeathFirstSound", 0);
   deathSndCount = get_config_int("wurmz!", "DeathNumSounds", 1);
   reloadSnd = get_config_int("wurmz!", "ReloadSound", 0);

   auto_screenshot = get_config_int("wurmz!", "AutoScreenshot", 0);
   deathcam_delay = get_config_int("wurmz!", "DeathCamDelay", 1);

   GP_WORM_HEALTH = get_config_int("wurmz!", "MaxHealth", 100);
   GP_WORM_RESPAWN = get_config_int("wurmz!", "ForcedRespawn", 200);

   Engine.wormSizeX = get_config_int("Worms", "SizeX", 1);
   Engine.wormSizeYMin = get_config_int("Worms", "SizeYMin", 2);
   Engine.wormSizeYMax = get_config_int("Worms", "SizeYMax", 8);
   Engine.wormFireOffs = get_config_int("Worms", "FireOffset", 4);

   Engine.wormMinAngle = get_config_int("Worms", "MinAngle", 0);
   Engine.wormMaxAngle = get_config_int("Worms", "MaxAngle", 32);

   Engine.crosshairDist = get_config_int("Worms", "CrosshairDist", 15);
   Engine.laserDist = get_config_int("Worms", "LaserDist", 2000);
   Engine.wormWalkAccel = get_config_int("Worms", "WalkAccel", 100);
   Engine.wormWalkLimit = get_config_int("Worms", "WalkLimit", 1500);
   Engine.crateDrops = get_config_int("Items", "CrateDrops", 0);
   Engine.crateHealthMin = get_config_int("Items", "CrateHealthMin", 10);
   Engine.crateHealthVar = get_config_int("Items", "CrateHealthVar", 10);
   Engine.crateHealthCount = get_config_int("Items", "CrateHealthCount", 10);
   Engine.crateWeapCount = get_config_int("Items", "CrateWeapCount", 10);
   Engine.crateDropRate = get_config_int("Items", "CrateDropRate", 600);
   Engine.items.flagSprite = get_config_int("Items", "FlagSprite", 0);
   Engine.items.medikitSprite = get_config_int("Items", "CrateHealthSprite", 0);
   Engine.items.weappackSprite = get_config_int("Items", "CrateWeapSprite", 0);
   Engine.items.drawNamesOnBonuses = get_config_int("Items", "DrawNamesOnBonuses", 1);
   Engine.items.fireProbability = get_config_int("Items", "FireProbability", 0);
   Engine.weapSpawnDist = get_config_int("Weapons", "SpawnDistance", 7);

   Weather.snowParticle = get_config_int("Weather", "SnowFlake", 0);
   Weather.rainColor = get_config_int("Weather", "RainColor", 0);
   Weather.lightningColor = get_config_int("Weather", "LightningColor", 0);
   Weather.lightningTime = get_config_int("Weather", "LightningTime", 1000);

   for (i=0; i<9; i++)
   {
      sprintf(buf, "FirePos%dX", i);
      Engine.firePos[i].x = get_config_int("Worms", buf, 0);
      sprintf(buf, "FirePos%dY", i);
      Engine.firePos[i].y = get_config_int("Worms", buf, 0);
   }

   GP_FLASH_DIM = get_config_int("Weapons", "FlashDimTime", 15);

   Engine.wormJumpForce = get_config_int("Physics", "JumpForce", 1000);
   Engine.wormGravity = get_config_int("Physics", "Gravity", 40);
   Engine.wormAirControl = get_config_int("Physics", "AirControl", 1000);
   Engine.wormFriction = get_config_int("Physics", "Friction", 890);
   Engine.wormTermVelocity = get_config_int("Physics", "TerminalVelocity", 5000);

   Engine.wormBounceDown = get_config_int("Physics", "BounceOffFloor", 330);
   Engine.wormBounceLeft = get_config_int("Physics", "BounceOffLeft", 200);
   Engine.wormBounceRight = get_config_int("Physics", "BounceOffRight", 200);
   Engine.wormBounceUp = get_config_int("Physics", "BounceOffCeil", 330);

   Engine.rope.gravity = get_config_int("Rope", "Gravity", 10);

   Engine.wormSafeTime = get_config_int("wurmz!", "WurmUpTime", 0);
   Engine.wormSafeSprite = get_config_int("Physics", "WurmUpSprite", 0);

   Engine.wormRandomSpawn = get_config_int("Worms", "RandomSpawn", 0);
   Engine.wormJumpOnGroungCheck = get_config_int("Worms", "JumpOnGroundCheck", 1);
   Engine.wormJumpReleasedCheck = get_config_int("Worms", "JumpReleasedCheck", 1);
   Engine.wormAimAccelDelay = get_config_int("Worms", "AimAccelDelay", 0);

   lineHook = get_config_int("Rope", "HookImage", 0);
   lineNumColors = get_config_int("Rope", "NumColors", 1);
   ropeSound = get_config_int("Rope", "Sound", 0);
   talkSnd = get_config_int("Wurmz!", "TalkSound", 0);

   Engine.rope.affectedByWorm = get_config_int("Rope", "AffectedByWorm", 300);
   Engine.rope.physicsLoop = get_config_int("Rope", "PhysicsLoop", 1);
   Engine.rope.initSpeed = get_config_int("Rope", "InitSpeed", 5000);
   Engine.rope.enabled = get_config_int("Rope", "EnableRope", 1);
   Engine.rope.defaultLen = get_config_int("Rope", "DefaultLength", 4);
   Engine.rope.maxLen = get_config_int("Rope", "MaxLength", 1000);
   GP_LINE_DIST = get_config_int("Rope", "Dist1", 5);
   GP_LINE_DIST2 = get_config_int("Rope", "Dist2", 10);
   GP_LINE_FORCE = get_config_int("Rope", "Force1", 40);
   GP_LINE_FORCE2 = get_config_int("Rope", "Force2", 140);
   
   for (i=0; i<lineNumColors; i++)
   {
      sprintf(buf, "RopeColor%d", i);
      c = get_config_int("Rope", buf, 0);
      lineColors[i] = makecol((c >> 16)&0xFF, (c >> 8)&0xFF, (c)&0xFF);
   }

   respawnObject = get_config_int("wurmz!", "RespawnObject", 0);

   GP_DIG_DELAY = get_config_int("wurmz!", "DigDelay", 1);
   GP_DIG_DIST = get_config_int("wurmz!", "DigDist", 5);
   IMG_DIG_HOLE = get_config_int("wurmz!", "DigHole", 0);

   for (i=0; i<10; i++)
   {
      sprintf(buf, "TeamColor%d", i);
      c = get_config_int("Teams", buf, 0);
      wormColors[i] = makecol((c >> 16)&0xFF, (c >> 8)&0xFF, (c)&0xFF);
   }
}

void initPlayer()
{
   int i;
   
   for (int num = 0; num < numPlayers; num++)
   {
      char tempName[255];

      sprintf(tempName, "Player.%d", num);
      sprintf(tempName, "%s", get_config_string("profiles", tempName, "Player.cfg"));
      override_config_file(tempName);
      sprintf(players[num].playerName, "%s", get_config_string("wurmz!", "PlayerName", "Player"));
   
      players[num].useJoy = get_config_int("wurmz!", "UseJoy", 0);

      players[num].joybtns[GK_JUMP] = get_config_int("wurmz!", "JoyJump", 0);
      players[num].joybtns[GK_FIRE] = get_config_int("wurmz!", "JoyFire", 1);
      players[num].joybtns[GK_CHANGE] = get_config_int("wurmz!", "JoyChange", 2);
   
      players[num].keys[GK_JUMP] = get_config_int("wurmz!", "KeyJump", KEY_K);
      players[num].keys[GK_FIRE] = get_config_int("wurmz!", "KeyFire", KEY_L);
      players[num].keys[GK_CHANGE] = get_config_int("wurmz!", "KeyChange", KEY_J);
      players[num].keys[GK_LEFT] = get_config_int("wurmz!", "KeyLeft", KEY_LEFT);
      players[num].keys[GK_RIGHT] = get_config_int("wurmz!", "KeyRight", KEY_RIGHT);
      players[num].keys[GK_UP] = get_config_int("wurmz!", "KeyUp", KEY_UP);
      players[num].keys[GK_DOWN] = get_config_int("wurmz!", "KeyDown", KEY_DOWN);
      players[num].keys[GK_CHAT] = get_config_int("wurmz!", "KeyChat", KEY_T);
   //         QUICKTEXT         //   
      players[num].keys[GK_QUICK] = get_config_int("wurmz!", "KeyQuick", KEY_Q);
      char chTemp[50];
      for(i=0; i<10; i++) {
         sprintf(chTemp, "Text%i", i);
         sprintf(quicktexts[i],"%s",get_config_string("QuickText", chTemp, ""));
      }
   ///////////////////////////////
   
      players[num].localTeam = get_config_int("wurmz!", "Team", 0);
      players[num].localSkin = get_config_int("wurmz!", "Skin", 0);
      for (i=0; i<5; i++)
      {
         sprintf(buf, "Weapon.%d", i);
         players[num].localWeaps[i] = get_config_int("wurmz!", buf, 0);
      }
   }
}

void freeAllStuff()
{
   freeLevel();
   freeItems();
   freeSniper();
   freeLoading();
   freeFont();
   freeStuff();
   freeHoles();
   freeFire();
   freeSpecials();
   freeWeaps();
   freeCrosshair();
   freeWorms();
   freeRenderer();
}
