/* This file is part of OpenBubbles.
 *
 * OpenBubbles is an SDL clone of Bubbles.
 * Copyright (C) 2004  Benny Sperisen
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * sprite.h contains the declarations for sprite and derived classes.
 *
 * Written by:
 *  Benny Sperisen
 *  lasindi@gmail.com
 *  www.freewebs.com/lasindi
 *****************************************************************************/

#ifndef SPRITE_H
#define SPRITE_H

#include "SDL.h"
#include "SDL_gfxPrimitives.h"
#include "SDL_rotozoom.h"
#include "SDL_image.h"
#include <list>
#include <cassert>
#include <cmath>
#include <iostream>
using namespace std;

#include "screen.h"
#include "bounce.h"
#include "miscellaneous.h"
#include "audioplayer.h"

#define KEYBOARD_SENSITIVITY 1.5
#define EXPLODE_FRICTION 0.1
#define SUCK_STRENGTH 0.25
#define EXPLODE 0
#define SUCK 1
#define IMMUNE_TIME 50
#define SHARKY_SPEED 0.4
// How fast the player's bubble expands as crumbs are sucked in.
#define EXPANSION_RATE 0.2
// How fast crumbs go out when they explode.
#define EXPLODE_SPEED 10
// An approximation of my favorite number.
#define PI 3.1415926535
// Length of crumb trail.
#define CRUMB_LENGTH 10
// Length of missle trail.
#define MISSLE_LENGTH 10

class sprite
{
public:
  sprite(int x,int y,Uint8 r,Uint8 g,Uint8 b,double x_velocity,
         double y_velocity,double radius=1);
  virtual void draw()=0;
  virtual void move();
  double x() const;
  double y() const;
  Uint8 r() const;
  Uint8 g() const;
  Uint8 b() const;
  double x_velocity() const;
  double y_velocity() const;
  double radius() const;
  virtual bool testCollision(sprite* otherSprite);
protected:
  double _x;
  double _y;
  Uint8 _r;
  Uint8 _g;
  Uint8 _b;
  double _x_velocity;
  double _y_velocity;
  double _radius;
};

class bubble: public sprite
{
  // Used to bounce two bubbles off of one another (STILL NEEDS LOTS OF
  // IMPROVEMENT).
  friend void bounceOff(bubble* bub1,bubble* bub2);
public:
  bubble(int x,int y,Uint8 r,Uint8 g,Uint8 b,double radius,double x_velocity,
         double y_velocity);
  virtual ~bubble();
  virtual void draw();
  virtual void setRadius(double radius);
  bool immune() const;
  void setImmune();
  // Used to identify the type of object (for derived classes).
  virtual char* identify() const;
  int number; // This is used to uniquely identify instances of bubble.
  virtual void freeSurfaces();
protected:
  virtual void loadPicture();
  // Used by bounceOff().
  void moveBack(bubble* other,double & realx,double & realy);
  char _immune; // indicates that playerBubble is immune to collisions
  SDL_Surface* _picture;
  SDL_Rect _dest;
  SDL_Rect _src;
};

extern list<bubble*> bubs;

class playerBubble: public bubble
{
public:
  playerBubble(int x,int y,Uint8 r,Uint8 g,Uint8 b,double radius,
               double x_velocity=0,double y_velocity=0);
  ~playerBubble();
  void move(); // assumes that SDL_PumpEvents() has been called
  void draw(); // We need to reimplement to flash while immune.
  void setRadius(double radius);
  char* identify() const;
  int state() const;
  void kill(); // increase _state by one
  void freeSurfaces();
protected:
  void loadPicture();
  void updatePicture();
  SDL_Surface* _initpic;
  int _state; // indicates whether the playerBubble is dead or not
};

class crumb: public sprite
{
public:
  crumb(int x,int y,Uint8 r,Uint8 g,Uint8 b,double x_velocity,
	double y_velocity,double value=0,bubble* sucker=NULL);
  virtual ~crumb();
  void draw();
  void move();
  void setSuck(bubble* sucker);
  double value() const;
  bool isExploding() const;
  bool hasSucker() const;
  bool testCollision(sprite* otherSprite);
private:
  bubble* _sucker;
  int _state;
  int _suck_counter;
  double _value; // how much it expands the player when it's eaten
  list<double> oldx;
  list<double> oldy;
};

extern list<crumb> crumbs;

void sprayCrumbs(int x,int y,double value,int number,Uint8 r,Uint8 g,Uint8 b,
                 playerBubble* sucker=NULL);

class bouncerBubble: public bubble
{
public:
  bouncerBubble(int x,int y,Uint8 r,Uint8 g,Uint8 b,double radius,
                double x_velocity,double y_velocity);
  char* identify() const;
protected:
  void loadPicture();
};

class sharkyBubble: public bubble
{
public:
  sharkyBubble(int x,int y,Uint8 r,Uint8 g,Uint8 b,double radius,
               playerBubble* player);
  void move();
  char* identify() const;
private:
  void loadPicture();
  playerBubble* _player;
};

class bonusBubble: public bubble
{
public:
  bonusBubble(int x,int y,Uint8 r,Uint8 g,Uint8 b,double radius,
              double x_velocity=0,double y_velocity=0);
  ~bonusBubble();
  void draw();
  void move();
  void setRadius(double radius);
  char* identify() const;
  void freeSurfaces();
private:
  void loadPicture();
  SDL_Surface* _originalbonus1;
  SDL_Surface* _originalbonus2;
  SDL_Surface* _bonus1;
  SDL_Surface* _bonus2;
  bool isblack;
  void updateBonus();
};

void getBonus(bubble* bonus,playerBubble* recipient);

class missleBubble: public bubble
{
public:
  missleBubble(int x,int y,Uint8 r,Uint8 g,Uint8 b,double radius,
               double x_velocity=0,double y_velocity=0);
  void move();
  char* identify() const;
private:
  void loadPicture();
};

extern list<missleBubble*> missles;

#endif
