
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;

public abstract class Soldier extends Creature {


	int offensivePower;	// 攻撃力
	int defensivePower;	// 防御力

	int attackSpeed;	// 攻撃スピード。マシンガン兵なら、この数値は高いだろうし、火縄銃兵なら低いだろう。
	int attackSpeedPower;	// 攻撃スピードが、いまどれくらいたまったか。一定値(現在は20)にいたると、攻撃を開始する。
	static final int ATTACK_TIMING = 20;	// 上記の「一定値」は、この定数が決定する。

	int maxSpeed;		// 最高速度
	int acceleration;	// 加速度

	int presentSpeed;	// 現在速度
	int movementPower;	// 移動力。(各ユニットは1ターンごとに、現在速度に応じた移動力がたまっていく。現在そのユニットがいる地形におうじた移動力がたまれば、つぎのマスにすすむことができる。)

	public int getPresentSpeed() { return presentSpeed; }

	public Soldier(int x, int y, Board tacticsField, Direction direction, int nationality) {
		super(x, y, tacticsField,  direction, nationality);

		this.x = x;
		this.y = y;
		board = tacticsField;

		this.direction = direction;
		this.nationality = nationality;

		walking = true;

		this.target = null;
		this.auto = false;

		init();
	}
	public Soldier(int x, int y, Board tacticsField, Direction direction, int nationality, Unit target, boolean auto) {
		super(x, y, tacticsField,  direction, nationality, target, auto);

		this.x = x;
		this.y = y;
		board = tacticsField;

		this.direction = direction;
		this.nationality = nationality;

		walking = true;

		this.target = target;
		this.auto = auto;

		init();
	}

	public void init() {
		hp = 100;	//兵士数を100に設定。
		maxHP = 100;	//そのクラスの最大兵士数を100に。

		offensivePower = 2;
		defensivePower = 2;

		presentSpeed = 0;
		maxSpeed = 2;
		acceleration = 1;

		attackSpeed = 5;

		movementPower = 0;
		attackSpeedPower = 0;
	}

	public void run() {

		// まず自分が生きているかどうか。死んでいた場合には即刻終了する。
		if (!checkExistence()) {
			remove();
			return;
		}

		// もし自動操縦状態ならば、なにをすればよいか自己判断させる。
		if (auto)
			selfJudge();

		// 停止していろという命令が出されていなければ、歩こうとしてみる。
		if (walking)
			move();

		// 攻撃スピードが十分にたまっていれば、敵をさがして攻撃を開始。
		if (ATTACK_TIMING <= (attackSpeedPower += attackSpeed) ) {
			Soldier enemy = searchEnemy();

			// 攻撃範囲内に敵がいるか？
			if (enemy != null) {
				attack(enemy);		// いれば攻撃し、
				attackSpeedPower = 0;	// 蓄積された攻撃スピードを0に。

			// 現在速度を修正。
			if (--presentSpeed < 0)
				presentSpeed = 0;

			}
			else
				attackSpeedPower = ATTACK_TIMING;
		}
	}

	public void show(Graphics g, int x, int y, Component view) {
		uge.show(g, x,y, this, view);
	}

	protected void move() {


		// 速度に応じてユニットの移動力を増やす。(一歩すすむためには、その地形に応じた移動力が必要。)
		if (0 >= presentSpeed)
			movementPower += acceleration;
		else
			movementPower += presentSpeed;

		// もし移動力が十分にたまっているのなら、いまいるスクウェアから抜け出す。
		if (board.getGround(x,y).getRestraint() < movementPower ) {

			int destX = direction.getNextX() + x;
			int destY = direction.getNextY() + y;

			if ( board.moveCreature( x, y, destX, destY ) ) {
			 // 移動に成功。
				x = destX;
				y = destY;

				// 現在速度を修正。
				if ( (presentSpeed += acceleration) > maxSpeed)
					presentSpeed = maxSpeed;

			}
			else {
			// 移動に失敗。

				// 前方に敵がいるかいないか
				Soldier frontSoldier = (Soldier)board.getCreature(destX,destY);

				if (frontSoldier != null) {
					if ( direction.getDirection() == frontSoldier.getDirection().getDirection() ) {
						if ( presentSpeed > frontSoldier.getPresentSpeed() )
							presentSpeed = frontSoldier.getPresentSpeed();
					}
					else {
						presentSpeed = 0;
					}
				}
				else {
					presentSpeed = 0;
				}
			}

		}
	}

	/** 引数として与えられた兵士にたいし攻撃する */
	void attack(Soldier enemy) {

		Direction attackedDirection = new Direction( direction );

		// 敵を攻撃する。
		attackedDirection.calculateDirectionStoD(x, y,  enemy.getX(), enemy.getY());		
		enemy.attacked( getOffensivePower(attackedDirection), attackedDirection );

		// 敵から反撃される。
		attackedDirection.calculateDirectionStoD( enemy.getX(), enemy.getY(), x, y );		
		this.attacked( enemy.getOffensivePower(attackedDirection), attackedDirection );

	}

	/** 攻撃力を算出するルーチン。兵士のもつ「攻撃力」「現在速力」「体力」「方角」によって求める */
	public int getOffensivePower(Direction attackedDirection) {

///		int retOffensivePower = offensivePower + board.getGround(x,y).getOffensivePower(attackedDirection) + (hp>>2);
		int retOffensivePower = 10;

/*		if (direction.getDirection() == attackDirection.getDirection())
			retOffensivePower += (3+presentSpeed);
		else if ( direction.getDirection() == ((attackDirection.getDirection()+1)&3) )
			retOffensivePower += (2+presentSpeed);
		else if ( direction == ((attackDirection-1)&3) )
			retOffensivePower += (1+presentSpeed);
*/
		return retOffensivePower;
	}

	/** 防御力を算出するルーチン。兵士のもつ「防御力」「現在速力」「方角」によって求める */
	public int getDefensivePower(Direction attackedDirection) {

///		int retDefensivePower = defensivePower + board.getGround(x,y).getDefensivePower(attackedDirection) + (hp>>3);
		int retDefensivePower = 5;

/*		switch () {
			case Direction.UP:
				retDefensivePower += presentSpeed;
				break;

			case Direction.LEFT:
				retDefensivePower += (presentSpeed + 1);
				break;

			case Direction.RIGHT:
				retDefensivePower += (presentSpeed + 2);
				break;

			case Direction.DOWN:
				retDefensivePower += (presentSpeed + 3);
				break;
		}
*/
		return retDefensivePower;
	}


	/** 自身の攻撃範囲に敵がいるかどうかを判断するルーチン */
	public Soldier searchEnemy() {

		Soldier enemy = null;
		Direction tempDirection = new Direction( direction );
		int destX = x;
		int destY = y;

		destX += tempDirection.getNextX();
		destY += tempDirection.getNextY();

		enemy = (Soldier)board.getCreature(destX, destY);
		if ( !checkEnemy(enemy) ) {

			tempDirection.leftTurn();
			destX += tempDirection.getNextX();
			destY += tempDirection.getNextY();

			enemy = (Soldier)board.getCreature(destX, destY);
			if ( !checkEnemy(enemy) ) {

				tempDirection.contraryTurn();
				destX += ( tempDirection.getNextX() * 2 );
				destY += ( tempDirection.getNextY() * 2 );

				enemy = (Soldier)board.getCreature(destX, destY);
				if ( !checkEnemy(enemy) )
					enemy = null;
			}
		}

		return enemy;
	}


	/** 敵から攻撃されたときに呼び出されるルーチン。 */
	public void attacked(int damage, Direction attackedDirection) {
				
		// どれくらいのダメージを受けたか。
		damage -= getDefensivePower(attackedDirection);
		// そのダメージがマイナスになったら、0に補整。
		if (0 < damage)
			hp -= damage;

	}



}
