#ifndef _ACTOR_H_
#define _ACTOR_H_
// no, I will NOT use #pragma once. It's not standard. don't ask.


// sprite defines
#define SPRANIMS			12 // number of different animations per sprite
// stills
#define SPR_STILLDOWN		0
#define SPR_STILLUP			1
#define SPR_STILLLEFT		2
#define SPR_STILLRIGHT		3
// walkers
#define SPR_MOVEDOWN		4
#define SPR_MOVEUP			5
#define SPR_MOVELEFT		6
#define SPR_MOVERIGHT		7
// states
#define SPR_ATTACK			8
#define SPR_DEAD			9
#define SPR_USE				10
#define SPR_TAKEDAMAGE		11


// state defines 
#define NUMSTATES						20

#define ACTOR_MOVELEFT					2
#define ACTOR_MOVERIGHT					4
#define ACTOR_MOVEUP					8
#define ACTOR_MOVEDOWN					16
#define ACTOR_IDLE						32
#define ACTOR_ATTACK					64
#define ACTOR_HIDE						128
#define ACTOR_SEEK						256
#define ACTOR_DEAD						512
#define ACTOR_USE						1024
// end the AI+Sprite states, start type states
#define ACTOR_TYPE_PLAYER				2048
#define ACTOR_TYPE_BADDIE				4096
#define ACTOR_TYPE_ITEM					8192
#define ACTOR_TYPE_EFFECT				16384
// these aren't really states, they're commands
#define ACTOR_TAKEDAMAGE				32768
#define ACTOR_SET_TYPE					65536

typedef struct
{
	unsigned int sx, sy, w, h;
} BoundingBox;

struct ActorCmd {
	unsigned int cmd;
	unsigned int cmdFlags;
	void *target;
	ActorCmd();
	ActorCmd(unsigned int c, unsigned int cf, void *target);
};

class Sprite2D
{
protected:
    SDL_Surface *bitmap;
	unsigned int fw, fh;
	unsigned long frameticks;
	unsigned int numframes;
public:	
	Sprite2D();
	Sprite2D(char *gfxname, long ticks, int frames, int fw, int fh);
	void init(char *gfxname, long ticks, int frames, int fw, int fh);
	void drawFrame(SDL_Surface *canvas, int frame, int px, int py, int flip);
	int getfw();
	int getfh();
	int getticks();
	int getframes();
	~Sprite2D();
};

class Actor2D
{
protected:
    int px, py;
	int vx, vy;
	int animCurrFrame;
	int animCurrTicks;
	unsigned long lastTicks;
	float animSpeedOverride;
	long state;
    Sprite2D *sprite; // the default sprite
	Sprite2D *stateSprites[NUMSTATES]; // the per-state sprites
	std::queue<ActorCmd> cmdList; // FIFO command queue for the actor

	void setState(long state);
	void addState(long state);
	void delState(long state);
	void procQueue();
public:
	BoundingBox bbox;
	Actor2D();
	Actor2D(Sprite2D *spr, float speedOverride);
	void init(Sprite2D *spr, float speedOverride);
	int getpx();
	int getpy();
	int getvx();
	int getvy();
	// state manipulation
	long getState();
    int hasState(long state);
	// position and velocity manipulation
	void move(int x, int y);
	void moveAbs(int x, int y);
	void setVelocity(int x, int y);
    void update();
	bool collidesWith(Actor2D *actor);
    // rendering and sprite manipulation
	void setSprite(Sprite2D *spr);
	void render(SDL_Surface *canvas);
	void setStateSprite(Sprite2D *spr, long state);
	// other stuff
	void command(int cmd, int flags, void *target);
	void command(ActorCmd cmd);
};

class AIActor : public Actor2D
{
protected:
	unsigned int primTarget; // type of actor it targets
	unsigned int range; // the range it will pursue the target at	
	Actor2D *target; // the target it's currently moving to
public:
	AIActor(Sprite2D *spr, float speedOverride, 
				 unsigned int target, unsigned int maxrange);	
	void updateAI(std::vector<Actor2D *> actorList);
};

#endif // _ACTOR_H_
