#include <cmath>
#include <Fblend.h>
#include "CMain.hpp"
#include "CDisplay.hpp"
#include "CBattle.hpp"
#include "Astar.hpp"
#include "Interaction.hpp"
#include "Quests.hpp"
#include "CMenu.hpp"

CBattle battle;

CBattle::CBattle()
{
//   destmap = "";
//   x = 0;
//   y = 0;
}

/*
volatile int speed_counter2  = 0;
void increment_speed_counter2()
{
    speed_counter2++;
}
END_OF_FUNCTION(increment_speed_counter2);

volatile int frame_count2, fps2  = 0;

void fps_proc2(void)
{
   fps2 = frame_count2;
   frame_count2 = 0;
}
END_OF_FUNCTION(fps_proc2);

void SetTimers2(void)
{
        LOCK_VARIABLE(speed_counter2);
        LOCK_FUNCTION(increment_speed_counter2);
        install_int_ex(increment_speed_counter2, BPS_TO_TIMER(5));

        LOCK_VARIABLE (frame_count2);
        LOCK_VARIABLE (fps2);        // Lock FPS
        LOCK_FUNCTION (fps_proc2);  // Lock FPScounter
        install_int(fps_proc2, 1000);
        frame_count2 = fps2 = 0;
}
(*/

CCoord::CCoord()
{
  hit = false;
}


void SWAP(int a, int b)
{
     int temp = a;
     a = b;
     b = temp;
}

// from wikipedia.org !! modified
void drawline2d(int x0, int y0, int x1, int y1)
{

    int i;
    int steep = 1;
    int sx, sy;
    int dx, dy;
    int e;

    dx = abs(x1 - x0);
    sx = ((x1 - x0) > 0) ? 1 : -1;
    dy = abs(y1 - y0);
    sy = ((y1 - y0) > 0) ? 1 : -1;
    if (dy > dx)
		{
            steep = 0;
            SWAP(x0, y0);
            SWAP(dx, dy);
            SWAP(sx, sy);
        }
        e = (dy << 1) - dx;

        for (i = 0; i < dx; i++)
         {



		if(x0>map.GetWidth()-1) return;
		if(x0<0) return;
		if(y0<0) return;
		if(y0>map.GetHeight()-1) return;





            if (steep)
				{
    /*             if(map.tile[0][y0][x0].seen == false)
                    {
                      map.tile[0][y0][x0].seen = true;
					  prtchar((char)map.tile[0][y0][x0].gfx, y0, x0);
                    }
			//if ((char)map.tile[0][y0][x0].gfx != '.') return;
			if ((char)map.tile[0][y0][x0].gfx == WALL || (char)map.tile[0][y0][x0].gfx == TREE ) return;
			*/
     			fblend_rect_add(Display.GetSurface(), x0*map.sizew, y0*map.sizeh, map.sizew, map.sizeh, makecol(255,0,0), 50 );
                }

            else
              {
				/*if(map.tile[0][x0][y0].seen == false)
                    {

                    map.tile[0][x0][y0].seen = true;
					prtchar((char)map.tile[0][x0][y0].gfx, x0, y0);

                    }
                 // if ((char)map.tile[0][x0][y0].gfx != '.') return;
				// if ((char)map.tile[0][x0][y0].gfx == WALL ) return;
				if(testme(x0, y0) ) return;
				*/
				fblend_rect_add(Display.GetSurface(), y0*map.sizew, x0*map.sizeh, map.sizew, map.sizeh, makecol(255,0,0), 50 );
                }

                while (e >= 0)
                {
                        y0 += sy;
                        e -= (dx << 1);
                }
                x0 += sx;
                e += (dy << 1);
        }
}


void CBattle::Battle(bool isportal)
{
MIDI *space_mid = load_midi("./data/music/space.mid");
MIDI *spacewalk_mid = load_midi("./data/music/spacewalkbiatch.mid");
MIDI *dark = load_midi("./data/music/dark.mid");
MIDI *dark2 = load_midi("./data/music/dark2.mid");
MIDI *knightsrevenge = load_midi("./data/music/knightsrevenge.mid");
MIDI *inprog = load_midi("./data/music/inprog.mid");
MIDI *stringscool = load_midi("./data/music/stringscool.mid");
MIDI *tribalbeat = load_midi("./data/music/tribalbeat.mid");

     // LoadMap();
     // Place Character!
     // Npc's should already be set according to the map.

     // Start Loop
        // Randomly determine who goes first  ENEMIES THEN FRIENDLY or F then E
        // Enemies have ASTAR on and (at this moment) only can attack melee!
        // Basically all AI will involve trying to get the to the player the quickest!
        // Continue until player or ALL enemies are DEAD! <= 0 HP
     // End Loop

     SetTimers(60);
     
     choice_bmp = load_bitmap("./data/choice.bmp", NULL);
     selector = load_bitmap("./data/selector.bmp", NULL);
     
//     map.LoadMap("./data/battle.map");
     map.SetPositions();

     for(int i = 0; i<map.max_npc; ++i)
     {
        map.npc[i].UpdateTargets();
        map.npc[i].LoadStats();
     }
     
    accumulated_gold = 0;
    accumulated_exp = 0;

    posx = player[0].x;
    posy = player[0].y;
    turn = 0;
    
    // Holds where the player/npc can move
    coord.resize(map.GetHeight());
    for(int i = 0; i!= map.GetHeight(); ++i)
    coord[i].resize(map.GetWidth());

    AStarSearch<MapSearchNode> astarsearch[25];
//vector<int>
//	std::vector< AStarSearch<MapSearchNode> > astarsearch;
//	astarsearch.resize(map.max_npc+5);

 	MapSearchNode nodeStart;
    MapSearchNode nodeEnd;
    

	unsigned int SearchState;
	unsigned int SearchSteps = 0;
    
    for(int i = 0; i<map.max_npc; ++i)
    {
   	  nodeStart.x = map.npc[i].x/16;
   	  nodeStart.y = map.npc[i].y/16;

	  // Define the goal state
      nodeEnd.x = player[map.npc[i].target].x/16;
      nodeEnd.y = player[map.npc[i].target].y/16;
  	  astarsearch[i].SetStartAndGoalStates( nodeStart, nodeEnd );
  	  
  	do
	{
		SearchState = astarsearch[i].SearchStep();

		SearchSteps++;
     }while( SearchState == AStarSearch<MapSearchNode>::SEARCH_STATE_SEARCHING );

	if( SearchState == AStarSearch<MapSearchNode>::SEARCH_STATE_SUCCEEDED )
	{
//        allegro_message("steps %d, SearchSteps", SearchSteps);
        //allegro_message("OK");
    }
  	  
    }
	
    int npccounter = 0;

//	quest.quest_bit = 1;




   MapSearchNode *node;
   node = astarsearch[npccounter].GetSolutionStart();

//     int steps = 0;


     bool done = false;
     bool didattack = false;
     
     
//     player[0].hp+=4;
//     player[0].dam++;

     int timer = 0;
     
     
     player[0].UpdateMovement(); // Update the camera
     while(!done)
     {
      while (speed_counter > 0)
      {
        	if( midi_pos < 0 )
        	{
        	    int randmusic = rand()%9;
        		switch(randmusic)
                {
        		case 1:
        			play_midi(space_mid, NULL);
        		    break;
        		case 2:
        	    	play_midi(spacewalk_mid, NULL);
        		    break;
        		case 3:
        			play_midi(dark, NULL);
        			break;
        		case 4:
        			play_midi(dark2, NULL);
        			break;
        		case 5:
        			play_midi(knightsrevenge, NULL);
        			break;
        		case 6:
        			play_midi(inprog, NULL);
        			break;
        		case 7:
        			play_midi(stringscool, NULL);
        			break;
        		case 8:
        			play_midi(tribalbeat, NULL);
        			break;
        		}
           }

            if(speed_counter == 1 && timer > 30)
            {
                if(player[0].frame%2 == 0) player[0].frame++;
                else if(player[0].frame%2 != 0) player[0].frame--;

                if(player[1].frame%2 == 0) player[1].frame++;
                else if(player[1].frame%2 != 0) player[1].frame--;
            }

            for(int i = 0; i<map.max_npc; ++i)
            {
                if(speed_counter == 1)
                {
                    timer ++;
                    if(timer > 30)
                    {
                          if(map.npc[i].frame == 1)
                          map.npc[i].frame = 0;
                          else map.npc[i].frame = 1;
                          timer = 0;
                    }
                }
            }


      //  if(key[KEY_ESC] || key[KEY_F1]) done = true;
      // TODO: Only for debug USE!

        if(turn == 2) // NPCs' turn
        {

          //for(int i = 0; i<map.max_npc; ++i)
          //{
            if(!map.npc[npccounter].moving) map.npc[npccounter].steps++;
            
            if(map.npc[npccounter].steps >= 15)
             {
           //     if(didattack == false)
           //        NpcAttack(npccounter, map.npc[npccounter].x,  map.npc[npccounter].y, map.npc[npccounter].target);
                map.npc[npccounter].done = true;
//              allegro_message("npccounter %d max(-1) %d", npccounter, map.max_npc-1);
                if(npccounter >= map.max_npc-1)
                {
                     turn = 0; // reset back to the PC's turn
                     npccounter = 0;
                }
                else
                {
                    npccounter++;
                    map.npc[npccounter].UpdateMovement();
//                    node = astarsearch[npccounter].GetSolutionStart();
                }
                    


                map.npc[npccounter].steps = 0;

             }

            else if(map.npc[npccounter].moving == 0 && !(map.npc[npccounter].steps >=15))
            {
//                  node = astarsearch[npccounter].GetSolutionStart();
                  node = astarsearch[npccounter].GetSolutionNext();

                  if( !node )
				  {
				  	break;
			      }
			      
// GO for the target but if you can't find him go for the next best thing

MapSearchNode testz;
testz.x = player[map.npc[npccounter].target].x/16;
testz.y = player[map.npc[npccounter].target].y/16;
//  allegro_message("%d %d", testz.x, testz.y);

             if(node->GoalDistanceEstimate( testz ) < map.npc[npccounter].range) // was < 1
             {

                if( NpcAttack(npccounter, map.npc[npccounter].x,  map.npc[npccounter].y, map.npc[npccounter].target) )
                {
                    map.npc[npccounter].steps=15;
                    didattack = true;
                    speed_counter = -1;
                    break;
                }
             }

       
        else {
//             else if( player[
//             map.CheckPlayer();
	            if( map.npc[npccounter].x < node->x*16) map.npc[npccounter].Move(map,EAST);
 				else if( map.npc[npccounter].x > node->x*16) map.npc[npccounter].Move(map,WEST);
				else if( map.npc[npccounter].y > node->y*16) map.npc[npccounter].Move(map,NORTH);
                else if( map.npc[npccounter].y < node->y*16) map.npc[npccounter].Move(map,SOUTH);

              //  steps++;
           }
           
            }
            
           if(map.npc[npccounter].moving == 1)  map.npc[npccounter].UpdateMovement();

         // }
        }

        if(turn == 1 && CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE)) // Extra Character
        {
          HandlePlayerMovement(turn);
        }
        else if(turn == 1) turn = 2;

        if(turn == 0) // Main PC
        {
          HandlePlayerMovement(turn);
        }

          //   map.npc[1].UpdateMovement();

          update_key(KEY_SPACE, &key_space);
          if(key_space == 1 && !player[0].moving && turn == 0 || (key[KEY_ALT] &&  !player[0].moving && turn == 0 ))
          {
             FinalizeBattle(turn, player[turn].x, player[turn].y);

             for(int i = 0; i<map.max_npc; ++i)
             {
               astarsearch[i].CancelSearch();
               nodeStart.x = map.npc[i].x/16;
               nodeStart.y = map.npc[i].y/16;
               nodeEnd.x = player[map.npc[i].target].x/16;
               nodeEnd.y = player[map.npc[i].target].y/16;
         	   astarsearch[i].SetStartAndGoalStates( nodeStart, nodeEnd );
               SearchSteps = 0;

               do{
                  SearchState = astarsearch[i].SearchStep();
        		  SearchSteps++;
               }while( SearchState == AStarSearch<MapSearchNode>::SEARCH_STATE_SEARCHING );

               node = astarsearch[i].GetSolutionStart();
             
             }
         //    steps = 0;

             speed_counter = -1; // to prevent skipping!
             if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE)) player[1].UpdateMovement();
             else if(map.max_npc!=0) map.npc[0].UpdateMovement();
          }

          else if(key_space == 1 && !player[1].moving && turn == 1 && CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE))
          {
             FinalizeBattle(turn, player[turn].x, player[turn].y);



             for(int i = 0; i<map.max_npc; ++i)
             {
               astarsearch[i].CancelSearch();
               nodeStart.x = map.npc[i].x/16;
               nodeStart.y = map.npc[i].y/16;
               nodeEnd.x = player[map.npc[i].target].x/16;
               nodeEnd.y = player[map.npc[i].target].y/16;
         	   astarsearch[i].SetStartAndGoalStates( nodeStart, nodeEnd );
               SearchSteps = 0;


               do{
                  SearchState = astarsearch[i].SearchStep();
        		  SearchSteps++;
               }while( SearchState == AStarSearch<MapSearchNode>::SEARCH_STATE_SEARCHING );

               node = astarsearch[i].GetSolutionStart();

             }

          //   steps = 0;
             
             speed_counter = -1; // to prevent skipping!
             if(map.max_npc!=0) map.npc[0].UpdateMovement();
             else player[0].UpdateMovement();
          }


          for(int i = 0; i<map.max_npc; ++i)
          {
                  if(map.npc[i].hp <= 0)
                  {
                       accumulated_gold += map.npc[i].gold;
                       accumulated_exp += map.npc[i].exp;
                       // TODO: INSERT COOL ANIMATION HERE!
                       std::vector<CNpc>::iterator pos;
                       pos = map.npc.begin() + i;
                       map.npc.erase(pos);
                       map.max_npc--;
                  }
          }
          
          if(map.max_npc <= 0)
          {
             Talkf("", "You WON! You accumulated %d gold! You accumulated %d exp!", accumulated_gold, accumulated_exp);
             player[0].gold+=accumulated_gold; // share gold!
             
             player[0].exp += accumulated_exp;
             player[1].exp += accumulated_exp;
             done = true;
             speed_counter = -1;
          }
          if(player[0].hp <= 0)
          {
            DeathSequence();
            done = true;
          }
          if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) && player[1].hp <= 0)
          {
            DeathSequence();
            done = true;
          }

        speed_counter--;
      }


        ClearGrid();
        
        
        if(turn == 0)
        {
            map.DrawMap(0, player[turn].cam.x, player[turn].cam.y);
            map.DrawMapTrans(1, player[turn].cam.x, player[turn].cam.y);
            map.DrawObjects( NULL, player[turn].cam.x, player[turn].cam.y);
            masked_blit( player[0].gfx, Display.GetSurface(), player[0].frame*16, player[0].facing*16, player[0].x-player[turn].cam.x, player[0].y-player[turn].cam.y, 16, 16);
            if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) )
            {
                masked_blit( player[1].gfx, Display.GetSurface(), player[1].frame*16, player[1].facing*16, player[1].x-player[turn].cam.x, player[1].y-player[turn].cam.y, 16, 16);
            }
            DrawGrid(turn, player[turn].movement_range);

        }
        
        else if(turn == 1 && CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE))
        {
            map.DrawMap(0, player[turn].cam.x, player[turn].cam.y);
            map.DrawMapTrans(1, player[turn].cam.x, player[turn].cam.y);
            map.DrawObjects( NULL, player[turn].cam.x, player[turn].cam.y);
            masked_blit( player[0].gfx, Display.GetSurface(), player[0].frame*16, player[0].facing*16, player[0].x-player[turn].cam.x, player[0].y-player[turn].cam.y, 16, 16);
            if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) )
            {
                masked_blit( player[1].gfx, Display.GetSurface(), player[1].frame*16, player[1].facing*16, player[1].x-player[turn].cam.x, player[1].y-player[turn].cam.y, 16, 16);
            }
            DrawGrid(turn, player[turn].movement_range);
        }
        
        
        else if(turn == 2)
        {
   	        map.DrawMap(0, map.npccam.x, map.npccam.y);
		    map.DrawMapTrans(1, map.npccam.x, map.npccam.y);
            map.DrawObjects( NULL, map.npccam.x, map.npccam.y);
            masked_blit( player[0].gfx, Display.GetSurface(), player[0].frame*16, player[0].facing*16, player[0].x-map.npccam.x, player[0].y-map.npccam.y, 16, 16);
            if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) )
            {
                masked_blit( player[1].gfx, Display.GetSurface(), player[1].frame*16, player[1].facing*16, player[1].x-map.npccam.x, player[1].y-map.npccam.y, 16, 16);
            }
        }
        /*
        if(turn == false)
        {

          	map.DrawMap(0, map.npccam.x, map.npccam.y);
		    map.DrawMapTrans(1, map.npccam.x, map.npccam.y);
            map.DrawObjects( NULL, map.npccam.x, map.npccam.y);
            masked_blit( player[0].gfx, Display.GetSurface(), player[0].frame*16, player[0].facing*16, player[0].x-map.npccam.x, player[0].y-map.npccam.y, 16, 16);
            if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) )
            {
                masked_blit( player[1].gfx, Display.GetSurface(), player[1].frame*16, player[1].facing*16, player[1].x-map.npccam.x, player[1].y-map.npccam.y, 16, 16);
            }
        }
        */
        
        // Draw everything to the screen
        textprintf_ex(Display.GetSurface(), font, 0, 0, makecol(255,255,255), -1,
                  "Move 1 %d 2 %d at (%d)steps%d TURN %d map. %d %d NPC target %d", map.npc[0].moving, map.npc[1].moving, npccounter, map.npc[npccounter].steps, turn, npccounter, map.max_npc, map.npc[0].target);
        blit(Display.GetSurface(), screen, 0, 0, 0, 0, screen->w, screen->h);
        clear_bitmap(Display.GetSurface());
     }
     
     
     
     // The PC survived now load the map and place the PC
     if(!isportal)
     {
        player[0].x = map.battle_x;
        player[0].y = map.battle_y;
        
        map.LoadMap(map.battle_destmap);
        map.LoadNpcs();
        player[0].UpdateMovement(); // refresh camera!
     }
}



void CBattle::HandlePlayerMovement(int which)
{
    if(key[KEY_RIGHT] && coord[player[which].y/map.sizeh][player[which].x/map.sizew+1].hit == true )
	{
		player[which].MoveBlock(map, EAST);
	}

	if(key[KEY_LEFT] && coord[player[which].y/map.sizeh][player[which].x/map.sizew-1].hit == true)
	{
		player[which].MoveBlock(map, WEST);
	}

	if(key[KEY_UP] && coord[player[which].y/map.sizeh-1][player[which].x/map.sizew].hit == true)
	{
		player[which].MoveBlock(map, NORTH);
	}


	if(key[KEY_DOWN] && coord[player[which].y/map.sizeh+1][player[which].x/map.sizew].hit == true)
	{
		player[which].MoveBlock(map, SOUTH);
	}

	player[which].UpdateMovement();
	
}

void CBattle::DrawGrid(int which, int radius)
{
  for(int i =1; i<360; ++i)
  {
     for(int j = 0; j<radius; ++j)
     {
        int x = 0;
        int y = 0;

        x = j*cos(i/180.0f*3.14f);
        y = j*sin(i/180.0f*3.14f);
       if( posx/map.sizew+x>0 && posy/map.sizeh+y>0 && posx/map.sizew+x< map.GetWidth()*16 && posy/map.sizeh+y< map.GetHeight())
       {
        if(!coord[posy/map.sizeh+y][posx/map.sizew+x].hit)
        {
//          map.TransTile(coord[posy/map.sizeh+y][posx/map.sizew+x].hit, posx+x*16, posy+y*16);
       	   fblend_rect_trans(Display.GetSurface(), posx+x*16-player[which].cam.x, posy+y*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
        }
        coord[posy/map.sizeh+y][posx/map.sizew+x].hit = true;
       }
     }
  }
}

void CBattle::ClearGrid()
{
   for(int i = 0; i<map.GetHeight(); ++i)
    for(int j = 0; j<map.GetWidth(); ++j)
    {
      coord[i][j].hit = false;
    }
}

void CBattle::FinalizeBattle(int which, int x, int y)
{
    bool selected = false;
    int choice = 0;
    
    int key_up = 1;
    int key_down = 1;
    while(!selected)
    {
       update_key(KEY_UP, &key_up);
       update_key(KEY_DOWN, &key_down);
       update_key(KEY_SPACE, &key_space);
       if(key_up == 1 && choice > 0 ) choice --;
       if(key_down == 1 && choice < 6 ) choice ++;

       // Move
       if(key_space==1 && choice == 0)
       {
          selected = true;
       }

       // Attack
       if(key_space==1 && choice == 1)
       {
          if(AttackSelect(which))
          {
            if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) )
            {
               posx = player[which^1].x;//+player[0].cam.x;
               posy = player[which^1].y;//map.npc[0].y;//+player[0].cam.y;
            }
            else
            {
                posx = player[0].x;
                posy = player[0].y;
            }
           selected = true;
           turn++;
          }
       }

       // Magic
       if(key_space==1 && choice == 2)
       {

       }

       // Use items
       if(key_space==1 && choice == 3)
       {
         int healed = 0;
         for(int i = 0; i < MAX_INV; ++i)
         {
                 // TODO: I changed it to 'potion' because it was fucking up and I didn't want to figure out why I used a RING OF PROTECTION to heal myself
            if( player[which].inv[i].id == 4 /* A potion*/ )
            {
                Talkf("", "You have used a potion, your wounds magically heal!", player[which].inv[i].name.c_str());
                
                if(player[which].hp + 15 <= player[which].max_hp) player[which].hp = player[which].max_hp;
                else player[which].hp = player[which].max_hp;
                //player[which].hp = player[which].max_hp;
                player[which].inv[i].id = 0;
                healed = 1;
                choice = 0;
                break;
            }
            
            if(healed == 0)
            {
               if( player[which^1].inv[i].id == 4 /* A potion*/ )
               {
                Talkf("", "You have used a potion, your wounds magically heal!", player[which^1].inv[i].name.c_str());
                
                if(player[which].hp + 15 <= player[which].max_hp) player[which].hp = player[which].max_hp;
                else player[which].hp = player[which].max_hp;
                //player[which].hp = player[which].max_hp;
                player[which^1].inv[i].id = 0;
                healed = 1;
                choice = 0;
                break;
               }
            }
         }
         
        
         
       }

       // Flee
       if(key_space==1 && choice == 4)
       {

       }

       // View
       if(key_space==1 && choice == 5)
       {
          ViewBattlefield(which);
       }
       
       // End Turn
       if(key_space==1 && choice == 6)
       {
        if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) )
        {
           posx = player[which^1].x;//+player[0].cam.x;
           posy = player[which^1].y;//map.npc[0].y;//+player[0].cam.y;
        }
        else
        {
            posx = player[0].x;
            posy = player[0].y;
        }
           selected = true;
           turn++;
       }


       map.DrawMap(0, player[which].cam.x, player[which].cam.y);
       map.DrawMapTrans(1, player[which].cam.x, player[which].cam.y);
       map.DrawObjects( NULL, player[which].cam.x, player[which].cam.y);
       masked_blit( player[0].gfx, Display.GetSurface(), player[0].frame*16, player[0].facing*16, player[0].x-player[which].cam.x, player[0].y-player[which].cam.y, 16, 16);
       if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) )
       {
           masked_blit( player[1].gfx, Display.GetSurface(), player[1].frame*16, player[1].facing*16, player[1].x-player[which].cam.x, player[1].y-player[which].cam.y, 16, 16);
       }
//       rect(Display.GetSurface(), player[0].x-player[0].cam.x, player[0].y-player[0].cam.y, player[0].x+16-player[0].cam.x-1, player[0].y+16-player[0].cam.y-1, makecol(255,0,0));
  //     DrawGrid(which, 5);

       masked_blit(choice_bmp, Display.GetSurface(), 0, 0, screen->w/2-choice_bmp->w/2, screen->h/2+screen->h/4, choice_bmp->w, choice_bmp->h);
   	   masked_stretch_blit( selector, Display.GetSurface(), 0, 0, selector->w, selector->h,  screen->w/2-choice_bmp->w/2+15,  screen->h/2+screen->h/4+choice*10+10, 9,9);
       textprintf_ex(Display.GetSurface(), font, screen->w/2-choice_bmp->w/2+25,  screen->h/2+screen->h/4+10, makecol(0,0,0), -1,    "Move");
       textprintf_ex(Display.GetSurface(), font, screen->w/2-choice_bmp->w/2+25,  screen->h/2+screen->h/4+10+10, makecol(0,0,0), -1, "Attack");
       textprintf_ex(Display.GetSurface(), font, screen->w/2-choice_bmp->w/2+25,  screen->h/2+screen->h/4+20+10, makecol(0,0,0), -1, "Magic");
       textprintf_ex(Display.GetSurface(), font, screen->w/2-choice_bmp->w/2+25,  screen->h/2+screen->h/4+30+10, makecol(0,0,0), -1, "Use Item");
       textprintf_ex(Display.GetSurface(), font, screen->w/2-choice_bmp->w/2+25,  screen->h/2+screen->h/4+40+10, makecol(0,0,0), -1, "Flee");
       textprintf_ex(Display.GetSurface(), font, screen->w/2-choice_bmp->w/2+25,  screen->h/2+screen->h/4+50+10, makecol(0,0,0), -1, "View");
       textprintf_ex(Display.GetSurface(), font, screen->w/2-choice_bmp->w/2+25,  screen->h/2+screen->h/4+60+10, makecol(0,0,0), -1, "End Turn");


       
       if(choice == 1)
       {
            ClearGrid();

      if(player[which].fighting_range != 1)
      {
       for(int i = -player[which].fighting_range; i<player[which].fighting_range; ++i)
        for(int j = -player[which].fighting_range; j<player[which].fighting_range; ++j)
        {
                if(i*i+j*j < player[which].fighting_range*player[which].fighting_range)
                {
                   fblend_rect_trans(Display.GetSurface(), player[which].x+j*16-player[which].cam.x, player[which].y+i*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
                   coord[player[which].y/map.sizeh+i][player[which].x/map.sizew+j].hit = true;
                }
        }
      }

      else
      {

       fblend_rect_trans(Display.GetSurface(), player[which].x+0*16-player[which].cam.x, player[which].y+0*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
          coord[player[which].y/map.sizeh][player[which].x/map.sizew].hit = true;

       fblend_rect_trans(Display.GetSurface(), player[which].x+1*16-player[which].cam.x, player[which].y+0*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
          coord[(player[which].y)/map.sizeh][(player[which].x)/map.sizew+1].hit = true;

       fblend_rect_trans(Display.GetSurface(), player[which].x+-1*16-player[which].cam.x, player[which].y+0*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
          coord[(player[which].y)/map.sizeh][(player[which].x)/map.sizew-1].hit = true;

       fblend_rect_trans(Display.GetSurface(), player[which].x+0*16-player[which].cam.x, player[which].y+1*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
          coord[(player[which].y)/map.sizeh+1][(player[which].x)/map.sizew].hit = true;

       fblend_rect_trans(Display.GetSurface(), player[which].x+0*16-player[which].cam.x, player[which].y+-1*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
          coord[(player[which].y)/map.sizeh-1][(player[which].x)/map.sizew].hit = true;
       }
             


             
//            fblend_rect_trans(Display.GetSurface(), player[which].x+1*16-player[which].cam.x, player[which].y+1*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
/*            fblend_rect_trans(Display.GetSurface(), player[which].x+1*16-player[which].cam.x, player[which].y+1*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
            fblend_rect_trans(Display.GetSurface(), player[which].x+-1*16-player[which].cam.x, player[which].y+1*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );

            fblend_rect_trans(Display.GetSurface(), player[which].x+2*16-player[which].cam.x, player[which].y+0*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
            fblend_rect_trans(Display.GetSurface(), player[which].x+-2*16-player[which].cam.x, player[which].y+0*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
*/
       }
       
       blit(Display.GetSurface(), screen, 0, 0, 0, 0, screen->w, screen->h);
       clear_bitmap(Display.GetSurface());
       

       
    }
    

}

/* TODO: Cleanup *cough* hacky */
void CBattle::ViewBattlefield(int which)
{
     bool done = false;
     int key_right = 1;
     int key_up = 1;
     int key_down = 1;
     int key_left = 1;
     int key_enter = 1;
     int key_alt = 0;
     
     int selection_x = player[which].x;
     int selection_y = player[which].y;
     
     while(!done)
     {

       update_key(KEY_UP, &key_up);
       update_key(KEY_DOWN, &key_down);
       update_key(KEY_RIGHT, &key_right);
       update_key(KEY_LEFT, &key_left);
       update_key(KEY_ENTER, &key_enter);
       update_key(KEY_ALT, &key_alt);
       
       if(key_right == 1)
       {
	    	player[which].ViewBlock(map, EAST);
       }

       if(key_left == 1)
       {
    		player[which].ViewBlock(map, WEST);
       }

 	   if(key_up == 1)
       {
 	    	player[which].ViewBlock(map, NORTH);
	   }


	   if(key_down == 1)
       {
    		player[which].ViewBlock(map, SOUTH);
       }
       
       if(key_enter == 1 && map.CheckNpcs(player[which].x, player[which].y))
       {
           menu.ShowBattleStatus(false, map.GetNpcid(player[which].x, player[which].y));
           clear_keybuf();
           readkey();
       }
       
       else if(key_enter == 1 && map.CheckPlayer(player[which].x, player[which].y))
       {
         //if(player[which^1].x == selection_x && player[which^1].y == selection_y)
         //   menu.ShowBattleStatus(true, which^1);
         if(player[which].x == selection_x && player[which].y == selection_y)
            menu.ShowBattleStatus(true, which);
            
         if(player[which].x == player[which^1].x && player[which].y == player[which^1].y)
            menu.ShowBattleStatus(true, which^1);
           clear_keybuf();
           readkey();
       }

       if(key_alt == 1)
       {
         done = true;
         player[which].x = selection_x;
         player[which].y = selection_y;
       }
       
       player[which].UpdateMovement();
       
       
       map.DrawMap(0, player[which].cam.x, player[which].cam.y);
       map.DrawMapTrans(1, player[which].cam.x, player[which].cam.y);
       map.DrawObjects( NULL, player[which].cam.x, player[which].cam.y);

   if(which == 0)
   {
       masked_blit( player[0].gfx, Display.GetSurface(), player[0].frame*16, player[0].facing*16, selection_x-player[which].cam.x, selection_y-player[which].cam.y, 16, 16);
       if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) )
          masked_blit( player[1].gfx, Display.GetSurface(), player[1].frame*16, player[1].facing*16, player[1].x-player[which].cam.x, player[1].y-player[which].cam.y, 16, 16);
       rect(Display.GetSurface(), player[0].x-player[which].cam.x, player[0].y-player[which].cam.y, player[0].x-player[which].cam.x+15, player[0].y-player[which].cam.y+15, makecol(255,0,0));
       
   }
       
   if(which == 1)
   {
       masked_blit( player[0].gfx, Display.GetSurface(), player[0].frame*16, player[0].facing*16, player[0].x-player[which].cam.x, player[0].y-player[which].cam.y, 16, 16);
       if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) )
       {
           masked_blit( player[1].gfx, Display.GetSurface(), player[1].frame*16, player[1].facing*16, selection_x-player[which].cam.x, selection_y-player[which].cam.y, 16, 16);
           rect(Display.GetSurface(), player[1].x-player[which].cam.x, player[1].y-player[which].cam.y, player[1].x-player[which].cam.x+15,  player[1].y-player[which].cam.y+15, makecol(255,0,0));
       }
   }
       
       blit(Display.GetSurface(), screen, 0, 0, 0, 0, screen->w, screen->h);
       clear_bitmap(Display.GetSurface());
       
     }
}

bool CBattle::AttackSelect(int which)
{
     int key_right = 1;
     int key_up = 1;
     int key_down = 1;
     int key_left = 1;
     key_space = 1;

     int selection_x = player[which].x;
     int selection_y = player[which].y;

     bool done = false;
     
     do{
       update_key(KEY_UP, &key_up);
       update_key(KEY_DOWN, &key_down);
       update_key(KEY_RIGHT, &key_right);
       update_key(KEY_LEFT, &key_left);
       update_key(KEY_SPACE, &key_space);

       map.DrawMap(0, player[which].cam.x, player[which].cam.y);
       map.DrawMapTrans(1, player[which].cam.x, player[which].cam.y);
       map.DrawObjects( NULL, player[which].cam.x, player[which].cam.y);
       masked_blit( player[0].gfx, Display.GetSurface(), player[0].frame*16, player[0].facing*16, player[0].x-player[which].cam.x, player[0].y-player[which].cam.y, 16, 16);
       if(CHECK_BIT(quest.quest_bit, QUEST_RECRUIT_FEMALE) )
       {
           masked_blit( player[1].gfx, Display.GetSurface(), player[1].frame*16, player[1].facing*16, player[1].x-player[which].cam.x, player[1].y-player[which].cam.y, 16, 16);
       }
       
       ClearGrid();
       
      if(player[which].fighting_range != 1)
      {
       for(int i = -player[which].fighting_range; i<player[which].fighting_range; ++i)
        for(int j = -player[which].fighting_range; j<player[which].fighting_range; ++j)
        {
                if(i*i+j*j < player[which].fighting_range*player[which].fighting_range)
                {
                   fblend_rect_trans(Display.GetSurface(), player[which].x+j*16-player[which].cam.x, player[which].y+i*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
                   coord[player[which].y/map.sizeh+i][player[which].x/map.sizew+j].hit = true;
                }
        }
      }
      
      else
      {

       fblend_rect_trans(Display.GetSurface(), player[which].x+0*16-player[which].cam.x, player[which].y+0*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
          coord[player[which].y/map.sizeh][player[which].x/map.sizew].hit = true;

       fblend_rect_trans(Display.GetSurface(), player[which].x+1*16-player[which].cam.x, player[which].y+0*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
          coord[(player[which].y)/map.sizeh][(player[which].x)/map.sizew+1].hit = true;

       fblend_rect_trans(Display.GetSurface(), player[which].x+-1*16-player[which].cam.x, player[which].y+0*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
          coord[(player[which].y)/map.sizeh][(player[which].x)/map.sizew-1].hit = true;

       fblend_rect_trans(Display.GetSurface(), player[which].x+0*16-player[which].cam.x, player[which].y+1*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
          coord[(player[which].y)/map.sizeh+1][(player[which].x)/map.sizew].hit = true;

       fblend_rect_trans(Display.GetSurface(), player[which].x+0*16-player[which].cam.x, player[which].y+-1*16-player[which].cam.y, map.sizew, map.sizeh, makecol(255,0,0), 150 );
          coord[(player[which].y)/map.sizeh-1][(player[which].x)/map.sizew].hit = true;
       }
       rect(Display.GetSurface(), selection_x-player[which].cam.x, selection_y-player[which].cam.y, selection_x+15-player[which].cam.x, selection_y+15-player[which].cam.y, makecol(255,0,0));
       rect(Display.GetSurface(), selection_x+1-player[which].cam.x, selection_y+1-player[which].cam.y, selection_x+14-player[which].cam.x, selection_y+14-player[which].cam.y, makecol(255,255,0));

       blit(Display.GetSurface(), screen, 0, 0, 0, 0, screen->w, screen->h);
       clear_bitmap(Display.GetSurface());
       

       if(key_right == 1 && coord[selection_y/map.sizeh][selection_x/map.sizew+1].hit == true)
           selection_x+=16;
       if(key_left == 1 && coord[selection_y/map.sizeh][selection_x/map.sizew-1].hit == true)
           selection_x-=16;
       if(key_down == 1 && coord[selection_y/map.sizeh+1][selection_x/map.sizew].hit == true)
           selection_y+=16;
       if(key_up == 1 && coord[selection_y/map.sizeh-1][selection_x/map.sizew].hit == true)
           selection_y-=16;

       if(key_space == 1)
       {
           if(map.CheckNpcs(selection_x, selection_y))
           {
              //allegro_message("hit %d for xxxx dam ", map.GetNpcid(selection_x, selection_y));
              PlayerAttack(which, map.GetNpcid(selection_x, selection_y));
              return true;
           }
       }

       if(key[KEY_ALT] || key[KEY_ESC] || key[KEY_LCONTROL] || key[KEY_RCONTROL])
       {
                  done = true;
       }
       
     }while(!done);

     return false;
}


void CBattle::PlayerAttack(int which, int npcnum)
{
  // TODO: need a better to-hit algo
  if( rand()%(10-1+1)+1 >= 3) // 70% chance of hitting
  {
     int damage = rand()%(player[which].dam-1+1+1)+0; // notice the extra +1
     Talkf("Attacking: "+map.npc[npcnum].name, "Your attack does %d damage! Leaving your enemy with %d HP left.", damage, map.npc[npcnum].hp-damage);
     map.npc[npcnum].hp-=damage;
  }
  else
  {
      Talk("","Your attack missed!");
      
  }
}

// TODO: Bug, if the range is not melee (1) then the NPC will have to be on one of the cardinal poles to be able to attack!
bool CBattle::NpcAttack(int num, int x, int y, int target)
{
  int dir = 0;
  int attacking = -1;
  
  ClearGrid();
  
  // Ranged combat!
  if(map.npc[num].range != 1)
  {
     for(int i = -map.npc[num].range; i<map.npc[num].range; ++i)
      for(int j = -map.npc[num].range; j<map.npc[num].range; ++j)
      {
          if(i*i+j*j < map.npc[num].range*map.npc[num].range)
          {
              coord[map.npc[num].y/16+i][map.npc[num].x/map.sizew+j].hit = true;
          }
      }

      
    for(int i = 0 ; i<map.GetHeight(); ++i)
     for(int j = 0; j<map.GetWidth(); ++j)
      {
          if(coord[i][j].hit == true && attacking != target)
          {
             if(map.CheckPlayer(j*16, i*16))
             {
              dir = EAST; // doesn't matter it's not used in here anyway
              attacking = map.WhichPlayer(j*16, i*16);
             }
          }
      }
   }

 // Melee
 else
 {
      if(map.CheckPlayer(x+1, y) && attacking != target)
      {
        dir = EAST;
        attacking = map.WhichPlayer(x+1, y);
      }

      else if(map.CheckPlayer(x-1, y) && attacking != target)
      {
        dir = WEST;
        attacking = map.WhichPlayer(x-1, y);
      }

      else if(map.CheckPlayer(x, y+1) && attacking != target)
      {
        dir = SOUTH;
        attacking = map.WhichPlayer(x, y+1);
      }

      else if(map.CheckPlayer(x, y-1) && attacking != target)
      {
        dir = NORTH;
        attacking = map.WhichPlayer(x, y-1);
      }
 }


if(dir != 0)
{
    if( rand()%(10-1+1)+1 >= 3) // 70% chance of hitting
    {
        int damage = rand()%(map.npc[num].dam-1+1+1)+0; // notice the extra +1
        if( damage - player[attacking].ac >= 0 )
        {
         Talkf(map.npc[num].name,"Attacks %s and does %d damage!!! HP is now %d(%d)", player[attacking].name.c_str(), damage, player[attacking].hp-damage, player[attacking].max_hp);
         player[attacking].hp-= damage; //- player[attacking].ac;
        }
        else
        {
           Talkf("","Your armour protects you from harm!");
        }
    }

    else
    {
        Talkf(map.npc[num].name + ":","Attacks %s and misses!", player[attacking].name.c_str());

    }
 return true;
}

// did nothing
return false;
}

void CBattle::DeathSequence()
{
 if( map.name != "blackhawk_battle.map")//!CHECK_BIT(quest.quest_bit, QUEST_FOUGHT_ROBERT) )
 {
      BITMAP *death_bmp = load_bitmap("./data/deathscene.tga", NULL);
      clear(screen);
      blit(death_bmp, screen, 0, 0, screen->w/2-death_bmp->w/2, screen->h/2-death_bmp->h/2, death_bmp->w, death_bmp->h);
      textprintf_ex(screen, font, screen->w/2-200, screen->h/2, makecol(255,0,0), -1,
                      "You (or your companion) died...");
      readkey();
      exit(1);
 }
 else if( map.name == "blackhawk_battle.map")
 {
  player[0].hp = player[0].max_hp;
//  REMOVE_BIT(quest.quest_bit, QUEST_FOUGHT_ROBERT);
 }
}
