#include "constants.h"
#include "plane.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>

#define PLANE_TURN_SPEED 5
#define SPEED 4

const int plane_power[16] = {RED_POWER,BLUE_POWER,GREEN_POWER,YELLOW_POWER,
		       RED_POWER,BLUE_POWER,GREEN_POWER,YELLOW_POWER,
		       RED_POWER,BLUE_POWER,GREEN_POWER,YELLOW_POWER,
		       GREY_POWER,GREY_POWER,GREY_POWER,BLACK_POWER};
const int plane_manover[16] = {RED_MANOVER*PLANE_TURN_SPEED,BLUE_MANOVER*PLANE_TURN_SPEED,GREEN_MANOVER*PLANE_TURN_SPEED,YELLOW_MANOVER*PLANE_TURN_SPEED,
			RED_MANOVER*PLANE_TURN_SPEED,BLUE_MANOVER*PLANE_TURN_SPEED,GREEN_MANOVER*PLANE_TURN_SPEED,YELLOW_MANOVER*PLANE_TURN_SPEED,
			RED_MANOVER*PLANE_TURN_SPEED,BLUE_MANOVER*PLANE_TURN_SPEED,GREEN_MANOVER*PLANE_TURN_SPEED,YELLOW_MANOVER*PLANE_TURN_SPEED,
			GREY_MANOVER*PLANE_TURN_SPEED,GREY_MANOVER*PLANE_TURN_SPEED,GREY_MANOVER*PLANE_TURN_SPEED,BLACK_MANOVER*PLANE_TURN_SPEED};
const int plane_mass[16] = {200,275,200,180,
		      200,275,200,180,
		      200,275,200,180,
		      200,200,200,180};
		      
const char plane_name[16][15] = { "Germany", "Finland", "England", "Japan",
			    "Germany", "Finland", "England", "Japan",
			    "Germany", "Finland", "England", "Japan",
			    "Neutral", "Neutral", "Neutral", "Black" };
const int plane_bombs[16] = { 4, 3, 5, 6,
			4, 3, 5, 6,
			4, 3, 5, 6,
			4, 4, 4, 6 };
			
const int plane_gas[16] = { 1600 ,1800 , 2047, 1400,
		      1600 ,1800 , 2047, 1400,
		      1600 ,1800 , 2047, 1400,
		      1800 ,1800 , 1800, 2047 };
		      
const int plane_ammo[16] = {96, 96, 127, 80,
		      96, 96, 127, 80,
		      96, 96, 127, 80,
		      96, 96, 96, 127};


const int t_plane_power[16] = {RED_POWER,BLUE_POWER,GREEN_POWER,YELLOW_POWER,
		       RED_POWER,BLUE_POWER,GREEN_POWER,YELLOW_POWER,
		       RED_POWER,BLUE_POWER,GREEN_POWER,YELLOW_POWER,
		       GREY_POWER,GREY_POWER,GREY_POWER,BLACK_POWER};

const int t_plane_manover[16] = {RED_MANOVER*PLANE_TURN_SPEED,BLUE_MANOVER*PLANE_TURN_SPEED,GREEN_MANOVER*PLANE_TURN_SPEED,YELLOW_MANOVER*PLANE_TURN_SPEED,
			RED_MANOVER*PLANE_TURN_SPEED,BLUE_MANOVER*PLANE_TURN_SPEED,GREEN_MANOVER*PLANE_TURN_SPEED,YELLOW_MANOVER*PLANE_TURN_SPEED,
			RED_MANOVER*PLANE_TURN_SPEED,BLUE_MANOVER*PLANE_TURN_SPEED,GREEN_MANOVER*PLANE_TURN_SPEED,YELLOW_MANOVER*PLANE_TURN_SPEED,
			GREY_MANOVER*PLANE_TURN_SPEED,GREY_MANOVER*PLANE_TURN_SPEED,GREY_MANOVER*PLANE_TURN_SPEED,BLACK_MANOVER*PLANE_TURN_SPEED};

const int t_plane_mass[16] = {200,275,200,180,
		      200,275,200,180,
		      200,275,200,180,
		      200,200,200,180};
		      

const int t_plane_bombs[16] = { 4, 3, 5, 6,
			4, 3, 5, 6,
			4, 3, 5, 6,
			4, 4, 4, 6 };
			
const int t_plane_gas[16] = { 1600 ,1800 , 2047, 1400,
		      1600 ,1800 , 2047, 1400,
		      1600 ,1800 , 2047, 1400,
		      1800 ,1800 , 1800, 2047 };
		      
const int t_plane_ammo[16] = {96, 96, 127, 80,
		      96, 96, 127, 80,
		      96, 96, 127, 80,
		      96, 96, 96, 127};


const int cosinit[361] = {
    256,255,255,255,255,255,254,254,253,252,252,251,250,249,248,247,246,244,243,242,240,238,237,235,233,232,230,228,226,223,221,219,217,214,212,209,207,204,201,198,196,193,190,187,184,181,177,174,171,167,164,161,157,154,150,146,143,139,135,131,128,124,120,116,112,108,104,100,95,91,87,83,79,74,70,66,61,57,53,48,44,40,35,31,26,22,17,13,8,4,0,-4,-8,-13,-17,-22,-26,-31,-35,-40,-44,-48,-53,-57,-61,-66,-70,-74,-79,-83,-87,-91,-95,-100,-104,-108,-112,-116,-120,-124,-127,-131,-135,-139,-143,-146,-150,-154,-157,-161,-164,-167,-171,-174,-177,-181,-184,-187,-190,-193,-196,-198,-201,-204,-207,-209,-212,-214,-217,-219,-221,-223,-226,-228,-230,-232,-233,-235,-237,-238,-240,-242,-243,-244,-246,-247,-248,-249,-250,-251,-252,-252,-253,-254,-254,-255,-255,-255,-255,-255,-255,-255,-255,-255,-255,-255,-254,-254,-253,-252,-252,-251,-250,-249,-248,-247,-246,-244,-243,-242,-240,-238,-237,-235,-233,-232,-230,-228,-226,-223,-221,-219,-217,-214,-212,-209,-207,-204,-201,-198,-196,-193,-190,-187,-184,-181,-177,-174,-171,-167,-164,-161,-157,-154,-150,-146,-143,-139,-135,-131,-128,-124,-120,-116,-112,-108,-104,-100,-95,-91,-87,-83,-79,-74,-70,-66,-61,-57,-53,-48,-44,-40,-35,-31,-26,-22,-17,-13,-8,-4,0,4,8,13,17,22,26,31,35,40,44,48,53,57,61,66,70,74,79,83,87,91,95,100,104,108,112,116,120,124,127,131,135,139,143,146,150,154,157,161,164,167,171,174,177,181,184,187,190,193,196,198,201,204,207,209,212,214,217,219,221,223,226,228,230,232,233,235,237,238,240,242,243,244,246,247,248,249,250,251,252,252,253,254,254,255,255,255,255,255,255
};

const int sinit[361] = {
    0,4,8,13,17,22,26,31,35,40,44,48,53,57,61,66,70,74,79,83,87,91,95,100,104,108,112,116,120,124,127,131,135,139,143,146,150,154,157,161,164,167,171,174,177,181,184,187,190,193,196,198,201,204,207,209,212,214,217,219,221,223,226,228,230,232,233,235,237,238,240,242,243,244,246,247,248,249,250,251,252,252,253,254,254,255,255,255,255,255,255,255,255,255,255,255,254,254,253,252,252,251,250,249,248,247,246,244,243,242,240,238,237,235,233,232,230,228,226,223,221,219,217,214,212,209,207,204,201,198,196,193,190,187,184,181,177,174,171,167,164,161,157,154,150,146,143,139,135,131,128,124,120,116,112,108,104,100,95,91,87,83,79,74,70,66,61,57,53,48,44,40,35,31,26,22,17,13,8,4,0,-4,-8,-13,-17,-22,-26,-31,-35,-40,-44,-48,-53,-57,-61,-66,-70,-74,-79,-83,-87,-91,-95,-100,-104,-108,-112,-116,-120,-124,-127,-131,-135,-139,-143,-146,-150,-154,-157,-161,-164,-167,-171,-174,-177,-181,-184,-187,-190,-193,-196,-198,-201,-204,-207,-209,-212,-214,-217,-219,-221,-223,-226,-228,-230,-232,-233,-235,-237,-238,-240,-242,-243,-244,-246,-247,-248,-249,-250,-251,-252,-252,-253,-254,-254,-255,-255,-255,-255,-255,-255,-255,-255,-255,-255,-255,-254,-254,-253,-252,-252,-251,-250,-249,-248,-247,-246,-244,-243,-242,-240,-238,-237,-235,-233,-232,-230,-228,-226,-223,-221,-219,-217,-214,-212,-209,-207,-204,-201,-198,-196,-193,-190,-187,-184,-181,-177,-174,-171,-167,-164,-161,-157,-154,-150,-146,-143,-139,-135,-131,-128,-124,-120,-116,-112,-108,-104,-100,-95,-91,-87,-83,-79,-74,-70,-66,-61,-57,-53,-48,-44,-40,-35,-31,-26,-22,-17,-13,-8,-4,0
};

void update_state(state_t *s, input_t *in) {
    int mass;
    int initial_turn;
    int yyy,xxx;
    int temp;
    int player_x_speed, player_y_speed;
    int plane_tire_y;
    int up, down, power;

    s->in = *in;
    up = in->up;
    down = in->down;
    power = in->power;

    {
	s->was_on_airfield = 0;
	if (!s->upsidedown) {
	    yyy=5;
	    xxx=5;
	} else {
	    yyy=-5;
	    xxx=5; 
	}

	plane_tire_y = ((s->y) + (((-xxx*sinit[s->angle>>8]+yyy*cosinit[s->angle>>8]+128)>>8)<<8) +256)>>8;

	s->on_airfield = 0;

	if ((s->x >= (AIRFIELD_X1<<8)) && (s->x <= (AIRFIELD_X2<<8)) && (plane_tire_y >= AIRFIELD_Y - 1)) { 
	    if( ((s->angle>>8) <= TAIL_HIT_ANGLE) || ((s->angle>>8) >= (360-HIT_ANGLE)) ) {
		if (!s->upsidedown) {
		    if (plane_tire_y >= AIRFIELD_Y) {
			s->on_airfield = 1;
			s->was_on_airfield = 1;
		    } else {
			s->was_on_airfield = 1;
		    }
		    
		}  
	    }
	    
	    if( ((s->angle>>8) <=(180+6+HIT_ANGLE)) && ((s->angle>>8) >=(180+6-TAIL_HIT_ANGLE)) ) {
		if (s->upsidedown) {
		    if (plane_tire_y >= AIRFIELD_Y) {
			s->on_airfield = 1;
			s->was_on_airfield = 1;
		    } else {
			s->was_on_airfield = 1;
		    }
		    
		}  
	    }
	}
    }

    if (s->upsidedown) {
	int oldup;
	oldup =up;
	up = down;
	down = oldup;
    }  

    mass = plane_mass[s->plane];
    mass += s->ammo/10;
    if (plane_bombs[s->plane]!=6) {
	mass += s->bombs*12;
    } else {
	mass += s->bombs*10;
    }
    
    mass += s->gas/160;

    if (power) {
	if (s->speed < (1000+mass)) {
	    s->y += (1000-s->speed+mass)>>3;
	}
    } else {
	if (s->speed < (1500+mass)) {
	    s->y += (1350-s->speed+mass)>>3;
	}
    }
    
    initial_turn=(plane_manover[s->plane]<<8)/(mass+200);
    
    if (s->speed < 768) {
	if( (!s->on_airfield) && (!s->was_on_airfield) ) {
	    if(s->y < 0)
		s->y+=768;
	    
	    initial_turn = 0;
	    if (s->angle < (90<<8) && s->angle >=0)
		s->angle-=1024;
	    else
		if (s->angle > (90<<8) && s->angle<(270<<8))
		    s->angle += 1024;
		else
		    if(s->angle > (270<<8))
			s->angle -= 1024;
	    s->y+=256;
	} else {
	    s->on_airfield = s->was_on_airfield;
	    if (s->speed) {
		if (s->angle <= (TAIL_HIT_ANGLE<<8) || s->angle >= ((360-HIT_ANGLE)<<8)) {
		    s->angle += (768-s->speed)/2;		    	  		
		    if (s->angle > (TAIL_HIT_ANGLE<<8))
			s->angle = TAIL_HIT_ANGLE<<8;
		}
		
		if (s->angle <= ((180-TAIL_HIT_ANGLE)<<8) && s->angle >= ((180+HIT_ANGLE)<<8))
		{
		    s->angle -= (768-s->speed)/2;
		    if (s->angle < ((180+6-TAIL_HIT_ANGLE)<<8))
			s->angle = (180+6-TAIL_HIT_ANGLE)<<8;
		}		    	  	
	    }	
	    s->y+=512;
	}
    } else {
	initial_turn /= 1 + (((s->speed-768)/20)>>8);
    }
    
    if (s->angle >= (360<<8))
	s->angle -= 360<<8;
    if (s->angle < 0)
	s->angle += 360<<8;
    
    if(up || down) {
	if (s->speed > 0) {
	    s->speed -= initial_turn/100;
	}
	if (s->speed<0) {
	    s->speed += initial_turn/100;
	}
    }
		
    if (s->speed < 512) {
	up = 0;
	down = 0;
    }
	
    if (s->on_airfield && !(power && s->gas))
	if (s->speed < STOP_SPEED_LIMIT && s->speed > -STOP_SPEED_LIMIT)
	    s->speed = 0;

    if (!s->on_airfield)
	if(s->angle>(180<<8)) {
	    s->speed += ((90<<8)-abs(s->angle-(270<<8)))*mass/32000;
	}
    if (!s->on_airfield)
	if(s->angle < (180<<8) && s->angle>0)
	    s->speed -= ((90<<8)-abs(s->angle-(90<<8)))*mass/32000;

    if (power && s->gas) {
	s->speed += (plane_power[s->plane]<<8) / mass;
	s->gas--;
    }

    s->speed -= s->speed/50;

    if (s->speed) {
	if(up)
	    s->angle += initial_turn;
	if (down)
	    s->angle -= initial_turn;
    }

    if (s->angle >= (360<<8))
	s->angle -= 360<<8;
    if (s->angle < 0)
	s->angle += 360<<8;

    if (s->on_airfield && !s->speed) {
	if( ((s->angle>>8) <= TAIL_HIT_ANGLE) || ((s->angle>>8) >= (360-HIT_ANGLE)) )
	    s->angle = TAIL_HIT_ANGLE<<8;
	else
	    s->angle = (180+6-TAIL_HIT_ANGLE)<<8;
    }
		
    if (s->on_airfield && s->speed<512) {
	if( ((s->angle>>8) <= TAIL_HIT_ANGLE) || ((s->angle>>8) >= (360-HIT_ANGLE)) )
	    temp = (TAIL_HIT_ANGLE<<8)-(s->speed*10);
	else
	    temp = ((180+6-TAIL_HIT_ANGLE)<<8)+(s->speed*10);
	    
	if (temp > s->angle) {
	    if ((temp-s->angle)<256)
		s->angle=temp;
	    else
		s->angle+=256;
	}
			
	if (temp<s->angle) {
	    if ((s->angle-temp) < 256)
		s->angle = temp;
	    else
		s->angle -= 256;
	}
    }
	
    player_x_speed = (cosinit[s->angle>>8]*s->speed)/SPEED;
    player_y_speed = (sinit[s->angle>>8]*s->speed)/SPEED;
    s->x += player_x_speed >> 8;

    if (!(s->on_airfield && s->speed<768)) 
	s->y -= player_y_speed>>8;
	
    if(s->on_airfield) {
	int plane_tire_y;

	if (!s->upsidedown) {
	    yyy = 5;
	    xxx = 5;
	} else {
	    yyy = -5;
	    xxx = 5; 
	}
	plane_tire_y = (s->y) + (((-xxx*sinit[s->angle>>8]+yyy*cosinit[s->angle>>8]+128)>>8)<<8) + 256;
  
	if( (plane_tire_y) > (AIRFIELD_Y<<8))
	    s->y -= (plane_tire_y) - (AIRFIELD_Y<<8);
    }
    s->frame++;
}

void input_print(input_t *in) {
    printf("up %d down %d power %d\n",
	   in->up,
	   in->down,
	   in->power);
}

void state_print(state_t *s) {
    printf("%d %d %d %d %d %d %d %d %d %d %d %d %d ",
	   s->frame,
	   s->x>>8,
	   s->y>>8,
	   s->speed,
	   s->angle>>8,
	   s->upsidedown,
	   s->plane,
	   s->bombs,
	   s->ammo,
	   s->gas,
	   s->on_airfield,
	   s->was_on_airfield,
	   s->score);
    input_print(&s->in);
}


