module vs.action.bullet;



public import gedo.math.direction;
public import gedo.audio.sound;
public import vs.action.effect;
public import vs.action.visualtask;



public enum BulletType
{
	HIT,
	SHOT,
	HOLD,
	SPELL,
}



alias bool delegate(Vector p) GetHoldPosition;
alias void delegate(VisualTask t, Vector p) OnCollide;



public interface BulletSystem
{
	bool isRunning(VisualTask t);

	void pause(VisualTask t);
	void resume();
}



public class Bullet : VisualTask
{
public:
	GetHoldPosition getHoldPosition;
	OnCollide       onCollideOwner;


	void start(Vector pos, Direction d, Position* t)
	{
		direction.copyFrom(d);

		position.previous[] = pos[];
		position.current[]  = pos[];

		_target = t;
		_dones  = 0;
		_time   = -1;
		_pauseCount = 0;

		onStart();

		update();
	}


	override void update()
	{
		if((cast(BulletSystem)parent.parent.parent).isRunning(cast(VisualTask)parent))
		{
			super.update();

			if(_pauseCount <= 0)
			{
				++_time;

				onUpdate();
			}
			else
			{
				--_pauseCount;
			}
		}
	}


	void updateRelativePosition()
	{
	}


	float radius()
	{
		return 2.0;
	}


	Vector[] points()
	{
		return (cast(Vector*)&position)[0..2];
	}


	void onCollide(Vector center)
	{
	}


	BulletType type()
	{
		return BulletType.HIT;
	}


	abstract Power power()
	{
		return null;
	}


	int time()
	{
		return _time;
	}


	abstract Sound hitSE()
	{
		return null;
	}


	abstract EffectProgram hitEffect()
	{
		return null;
	}


	void onStart()
	{
	}


	void getKnockBackDirection(Vector v)
	{
		direction.toVector(power.direction[0], power.direction[1], power.direction[2], v);

		.gedo.math.vector.normalize(v);
	}


	void homing(float level)
	{
		if(_target)
		{
			Vector d;

			.gedo.math.vector.subtract(d, _target.current, position.current);

			Vector f;

			direction.getFront(f);

			if(level >= .std.math.PI/256.0 || .gedo.math.vector.dot(f, d) >= 0.0)
			{
				.gedo.math.vector.normalize(d);

				direction.homing(d, level, true);
			}
		}
		else
		{
			assert(0);
		}
	}


	void target(Position* t)
	{
		_target = t;
	}


	bool isCollided(uint index)
	{
		return ((1<<index) & _dones) != 0;
	}


	bool isCollided()
	{
		return (_dones != 0);
	}


	void collide(uint index)
	{
		_dones |= (1<<index);
	}


	void pause(int count)
	{
		_pauseCount = count;
	}


protected:
	Position* _target;
	uint      _dones;
	int       _time;
	int       _pauseCount;


	void clearDones()
	{
		_dones = 0;
	}


	void fillDones()
	{
		_dones |= ~0;
	}


	abstract void onUpdate()
	{
	}
}



public class Power
{
public:
	Vector direction;


	this(uint d, float v, Vector dr = cast(Vector)[0.0, 1.0, 0.0])
	{
		_damage   = d;
		_velocity = v;

		direction[] = dr[];
	}


	uint damage()
	{
		return _damage;
	}


	float velocity()
	{
		return _velocity;
	}


private:
	float _velocity;
	uint  _damage;
}
