#include "allegro.h"

#ifdef _WIN32

#include "winalleg.h"
#include <winsock.h>

#else

#include <string.h>

#endif

#include "defs.h"
#include "console.h"
#include "ai.h"
#include "ai_waypt.h"
#include "engine.h"
#include "gfx.h"
#include "math.h"
#include "maths.h"
#include "network.h"
#include "player.h"
#include "rules.h"
#include "server.h"
#include "ai_lua.h"

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

void aiLuaOnDamage(worm *player, worm *enemy, int amount)
{

	int i;

   for (i = 0; i < GP_NUM_PLAYERS; i++)
      if (&worms[i] == enemy) break;

	lua_getglobal(player->aiScript, "onDamage");

	lua_pushnumber(player->aiScript, i);

	lua_pushnumber(player->aiScript, amount);

	lua_call(player->aiScript, 2, 0);

}

int getWormViewport(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int i;

	if (n != 1)
      lua_error(L);

   i = (int)lua_tonumber(L, 1);

	/* push the X */
	lua_pushnumber(L, worms[i].aiCurX);

	/* push the Y */
	lua_pushnumber(L, worms[i].aiCurY);

	/* return the number of results */
	return 2;
}

int getWormPos(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int i;

	if (n != 1)
      lua_error(L);

   i = (int)lua_tonumber(L, 1);

	/* push the X */
	lua_pushnumber(L, worms[i].coords.x);

	/* push the Y */
	lua_pushnumber(L, worms[i].coords.y);

	/* return the number of results */
	return 2;
}

int getWormVel(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int i;

	if (n != 1)
      lua_error(L);

   i = (int)lua_tonumber(L, 1);

	/* push the X */
	lua_pushnumber(L, (float)worms[i].vel.x / 1000.0);

	/* push the Y */
	lua_pushnumber(L, (float)worms[i].vel.y / 1000.0);

	/* return the number of results */
	return 2;
}

int getWormAim(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int i;

	if (n != 1)
      lua_error(L);

   i = (int)lua_tonumber(L, 1);

	/* push the Y */
	lua_pushnumber(L, worms[i].aim);

	/* return the number of results */
	return 1;
}

int getWormDir(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int i;

	if (n != 1)
      lua_error(L);

   i = (int)lua_tonumber(L, 1);

	lua_pushnumber(L, worms[i].dir);

	/* return the number of results */
	return 1;
}

int getWormTeam(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int i;

	if (n != 1)
      lua_error(L);

   i = (int)lua_tonumber(L, 1);

	lua_pushnumber(L, worms[i].team);

	/* return the number of results */
	return 1;
}

int getWormHealth(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int i;

	if (n != 1)
      lua_error(L);

   i = (int)lua_tonumber(L, 1);

	/* push the Y */
	if (worms[i].active)
		lua_pushnumber(L, worms[i].health);
	else
	   lua_pushnil(L);

	/* return the number of results */
	return 1;
}

int getWormFlag(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int i, j;

	if (n != 2)
      lua_error(L);

   i = (int)lua_tonumber(L, 1);
   j = (int)lua_tonumber(L, 2);

	/* push the Y */
	lua_pushnumber(L, worms[i].flags[j]);

	/* return the number of results */
	return 1;
}

int findWaypoint(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int x, y;

	if (n != 2)
      lua_error(L);

   x = (int)lua_tonumber(L, 1);
   y = (int)lua_tonumber(L, 2);

   int pt = findNearestPt(x,y);

	lua_pushnumber(L, pt);

	/* return the number of results */
	return 1;
}

int findPath(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int a, b;

	if (n != 2)
      lua_error(L);

   a = (int)lua_tonumber(L, 1);
   b = (int)lua_tonumber(L, 2);

   int pathPoint = -1;
   int pathFlags;
   
   findBotPath(a, b, &pathPoint, &pathFlags);

	lua_pushnumber(L, pathPoint);
	lua_pushnumber(L, pathFlags);

	/* return the number of results */
	return 2;
}

int getFlag(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int a, b;

	if (n != 2)
      lua_error(L);

   a = (int)lua_tonumber(L, 1);
   b = (int)lua_tonumber(L, 2);

	lua_pushnumber(L, (a & b) == b);

	/* return the number of results */
	return 1;
}

int getWaypointPos(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int x;

	if (n != 1)
      lua_error(L);

   x = (int)lua_tonumber(L, 1);

	lua_pushnumber(L, waypts[x].x);
	lua_pushnumber(L, waypts[x].y);

	/* return the number of results */
	return 2;
}

int getRopePos(lua_State *L)
{

	/* get number of arguments */
	int n = lua_gettop(L);
	int i;

	if (n != 1)
      lua_error(L);

   i = (int)lua_tonumber(L, 1);

	lua_pushnumber(L, worms[i].rope.x / 1000);
	lua_pushnumber(L, worms[i].rope.y / 1000);

	/* return the number of results */
	return 2;
}

int aiLuaPrint(lua_State *L)
{
	int n = lua_gettop(L);

	if (n != 1)
      lua_error(L);

   Console.WriteF(lua_tostring(L, 1));

   return 0;
}

int aiLuaAim(lua_State *L)
{
	int n = lua_gettop(L);
	int x1, x2, y1, y2;

	if (n != 4)
      lua_error(L);

   x1 = (int)lua_tonumber(L, 1);
   y1 = (int)lua_tonumber(L, 2);
   x2 = (int)lua_tonumber(L, 3);
   y2 = (int)lua_tonumber(L, 4);

   float px = fabs(x2 - x1);
   float py = y2 - y1;

   int angle = 16-(INT((atan2(py, px)*32.0)/(3.1415)));

	lua_pushnumber(L, angle);

	/* return the number of results */
	return 1;

}

int aiLuaAimToVec(lua_State *L)
{
	int n = lua_gettop(L);
	int x;

	if (n != 1)
      lua_error(L);

   x = (int)lua_tonumber(L, 1);

	lua_pushnumber(L, (float)sinus[x] / 1000.0);
	lua_pushnumber(L, (float)cosinus[x] / 1000.0);

	/* return the number of results */
	return 2;

}

int aiLuaTrace(lua_State *L)
{
	int n = lua_gettop(L);
	int x1, x2, y1, y2, weap;

	if (n != 5)
      lua_error(L);

   x1 = (int)lua_tonumber(L, 1);
   y1 = (int)lua_tonumber(L, 2);
   x2 = (int)lua_tonumber(L, 3);
   y2 = (int)lua_tonumber(L, 4);
   weap = (int)lua_tonumber(L, 5);

   if (weap >= 2)
      traceWalk(x1,y1,x2,y2,weap-2);
   else
      traceLine(x1,y1,x2,y2,weap);
   
	lua_pushnumber(L, traceX);
	lua_pushnumber(L, traceY);

	/* return the number of results */
	return 2;

}

void aiLuaSetConsts()
{
   int i;
   
   FILE *aiFile = fopen("bots/includes.inc", "w");

   sprintf(buf, "-- automatically generated by Wurmz!\n-- all changes will be lost\n\n", gameType);
   fwrite(buf, strlen(buf), 1, aiFile);

   sprintf(buf, "gameType = %d;\n", gameType);
   fwrite(buf, strlen(buf), 1, aiFile);
   sprintf(buf, "teamPlay = %d;\n", teamplay);
   fwrite(buf, strlen(buf), 1, aiFile);
   sprintf(buf, "tactics = %d;\n", tactics);
   fwrite(buf, strlen(buf), 1, aiFile);

   sprintf(buf, "weaponData = {};\n");
   fwrite(buf, strlen(buf), 1, aiFile);

	for (i = 0; i < weapCount; i++)
   {
      sprintf(buf, "weaponData[%d] = {};\n", i+1);
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"affectedByWormMotion\"] = %f;\n", i+1, (float)weapons[i].affectedByWorm / 1000.0);
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"avgDamage\"] = %f;\n", i+1, weapDmg(i));
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"avgExplosionTime\"] = %d;\n", i+1, weapons[i].timeToExplode + weapons[i].randomExpTime / 2);
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"explodeOnWorm\"] = %s;\n", i+1, (weapons[i].remOnWorm) ? "true" : "false");
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"explosionDist\"] = %d;\n", i+1, weapons[i].explosion != -1 ? specials[weapons[i].explosion].detectDist : 0);
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"fireDelay\"] = %d;\n", i+1, weapons[i].fireDelay);
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"gravity\"] = %f;\n", i+1, (float)weapons[i].gravity * (float)weapons[i].physicsLoop / 1000.0);
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"initSpeed\"] = %f;\n", i+1, (float)(weapons[i].initSpeed + weapons[i].speedVariation/2) * (float)weapons[i].physicsLoop / 1000.0);
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"loadTime\"] = %d;\n", i+1, weapons[i].loadTime);
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"maxRange\"] = %f;\n", i+1, (float)weapons[i].botRange / 1000.0);
      fwrite(buf, strlen(buf), 1, aiFile);
      sprintf(buf, "weaponData[%d][\"name\"] = \"%s\";\n", i+1, weapons[i].name);
      fwrite(buf, strlen(buf), 1, aiFile);
   }

   fclose(aiFile);
}

