/***************************************************************************
                          breakout.h  -  description
                             -------------------
    begin                : Thu Apr 20 2000
    copyright            : (C) 2000 by Michael Speck
    email                : kulkanie@gmx.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef BREAKOUT_H
#define BREAKOUT_H

/**
  *@author Michael Speck
  */

#include "sdl.h"
#include "sndsrv.h"
#include "hiscore.h"
#include "dynlist.h"

// how many small rects before update full screen //
#define UPDATERECTS 200

#define MAX_MAP_W   20
#define MAX_MAP_H   30
struct InitData{
    // game //
    char name[12];
    int diff;
    int startlevel;
    int lvls_frm_file;
    char lvl_path[32];
    char lvl_file[20];
    // controls //
    int k_left;
    int k_right;
    int k_fire;
    int control;
    int warp;
    int motion_mod;
    // sound //
    int snd_on;
    int snd_vol;
    // move with key_speed pix per sec when keys are used //
    float key_speed;
    // graphics //
    int trp;
    int anim;
    int bkgnd;
    int fullscreen;
    int convex;
    // new //
    int invert;
    int rnd_start;
    int no_exdisp;
};

// mouse buttons //
#define MB_LEFT    1
#define MB_MIDDLE  2
#define MB_RIGHT   3

struct Vector {
    float   x, y;
};

// shrapnell //
struct Shrapnell {
    SDL_Surface *ss_pic;
    Vector      v;
    float       x, y;
    float       alpha;
};

// extra //
enum ExtraType {
    EX_NONE = 0,
    EX_SCORE200,
    EX_SCORE500,
    EX_SCORE1000,
    EX_SCORE2000,
    EX_SCORE5000,
    EX_SCORE10000,
    EX_SHORTEN,
    EX_LENGTHEN,
    EX_LIFE,
    EX_SLIME,
    EX_METAL,
    EX_BALL,
    EX_WALL,
    EX_FROZEN,
    EX_WEAPON,
    EX_RANDOM,
    EX_FAST,
    EX_SLOW,
    EX_NUMBER
};
struct Extra {
    float       x, y;
    float       alpha;
    int         extra;
};

// brick //
#define MAP_EMPTY   0
#define MAP_WALL    1
#define MAP_BRICK   2
struct MapBrick {
    int type;
    int id;
    int dur; // durability //
    ExtraType extra; // extra released when destroyed //
    int score;
};

// corner //
#define NONE        0
#define UPPERLEFT   4
#define UPPERRIGHT  5
#define LOWERLEFT   6
#define LOWERRIGHT  7
struct Corner {
    int x, y;
    int type;
};

// target //
#define TOP     0
#define RIGHT   1
#define BOTTOM  2
#define LEFT    3
struct Target {
    int     exists; // is there a target //
    int     mx, my; // position in map //
    float   x, y; // reset position of ball //
    int     time; // time till contact //
    int     cur_tm; // current time //
    int     side; // contact with which side? //
    Vector  a; // reflection vector //
};

// ball //
struct Ball {
    float   cur_x, cur_y;
    int     x, y;
    float   v_x, v_y; // vector components //
    int     attached; // attached to club ? //
    int     club_con; // contact with club //
    int     ign_club; // ignore club //
    Target  t; // target in map //
    Target  t2; // possible second brick //
};

// club //
struct Club {
    float   cur_x;
    int     x, y;
    float   v_x;
    int     w, h;
    int     len; // how many middle components ? //
    int     max_len; // limit
    float   friction; // how much relative speed is given to balls ?
    int     time;
};

// plasma shot //
struct Shot {
    float   x, y;
    float   cur_fr;
    Target  t;
    int     next_too;
};

// difficulty //
struct Difficulty {
    int     lives, max_lives;
    int     con_cost;
    int     club_size;
    int     club_max_size;
    float   score_mod;
};

struct Level;

class BreakOut {
public: 
    BreakOut();
    ~BreakOut();
    InitData* Setup();
    int  Run();
    void InitGame();
    void InitLevel(int l);
    void LoadLevel(int l);
    HiScore* GetHiScore();
    int BuyContinue();
    int ConfirmQuit();
    void GameOver();
    char* NextLine(char *buf, char *cp, char *l);
    char* ParseEntry(char *buf, char *cp, char *l);
    void UseOrigLevels();
    // club //
    void Club_Reset();
    void Club_Hide();
    void Club_Update(int ms);
    void Club_Show();
    void Club_AlphaShow(int a);
    int  Club_Resize(int c);
    void Club_CheckBallReflection(int old_x);
    void Club_HandleContact(Ball *b, Vector a);
    // ball //
    Ball* Ball_Create(int x, int y, float a, float v);
    void Ball_ComputeVec(Ball *b, float a, float v);
    void Ball_CheckBrickReflection(Ball *b);
    void Ball_NewTargets(int mx, int my);
    void Ball_CheckConvexReflection(Ball *b, float old_x, float old_y);
    void Ball_CheckClubReflection(Ball *b, float old_x, float old_y);
    void Ball_AdjustSpeed(Ball *b, float v);
    void Ball_GetTarget(Ball *b);
    void Ball_ClearTarget(Target *t);
    void Ball_MaskV(Ball *b, float old_vx);
    void Balls_Reset();
    void Balls_Hide();
    int  Balls_Update(int ms);
    void Balls_Show();
    void Balls_AlphaShow(int a);
    // brick //
    void Brick_Remove(int mx, int my, int shot);
    void Brick_CreateShrapnells(int x, int y, int shot);
    // update //
    void AddRefreshRect(int x, int y, int w, int h);
    void Refresh();
    // life //
    void Life_Hide();
    void Life_Show();
    // score //
    void Score_Hide();
    void Score_Update(int ms);
    void Score_Show();
    // extra //
    void Extra_Create(ExtraType extra, int x, int y);
    void Extra_Use(int extra);
    void Extras_Hide();
    void Extras_Update(int ms);
    void Extras_Show();
    // shrapnells //
    void Shr_Create(int x, int y, int w, int h, float vx, float vy);
    void Shr_Hide();
    void Shr_Update(int ms);
    void Shr_Show();
    // wall //
    void Wall_Hide();
    void Wall_Update(int ms);
    void Wall_Show();
    // plasma weapon //
    void Wpn_Update(int ms);
    // plasma shot //
    void Shots_Hide();
    void Shots_Update(int ms);
    void Shots_Show();
    void Shots_NewTargets(int mx, int my);
    Shot* Shot_Create();
    void Shot_GetTarget(Shot *s);
    // pause //
    void Pause();
    // snap shot //
    void SnapShot();
    // corner //
    void Corner_Check(Corner *c, float v_x, float v_y);
    // levels //
    FILE* Levels_OpenFile(char *str);
    void Levels_LoadFromFile();
    int  Levels_ParseFile(FILE *f);
    void Levels_Delete();
    // shine //
    void Sh_Hide();
    void Sh_Update(int ms);
    void Sh_Show();
    void Sh_New();
    // credit //
    void Credit_Hide();
    void Credit_Update(int ms);
    void Credit_Show();
    void Credit_Init();
    // extra display //
    void ExDisp_Hide();
    void ExDisp_Show();
private:	
    // misc //
    int         fullscreen;
    SDL_Surface *ss_bkgnd;
    SDL_Surface *ss_picture;
    SDL_Surface *ss_fr_luc;
    SDL_Surface *ss_fr_left;
    SDL_Surface *ss_fr_top;
    SDL_Surface *ss_fr_right;
    SDL_Surface *ss_fr_ruc;
    SDL_Surface *ss_fr_rlc;
    InitData    init_data;
    char        *cfg_path;
    SFnt        *font;
    Level       *levels;
    Level       *file_levels;
    float       motion_mod;
    // level //
    int         lev_num;
    char        lev_author[32], lev_name[32];
    int         level;
    int         lev_w, lev_h;
    MapBrick    lev_map[MAX_MAP_W][MAX_MAP_H];
    int         lev_bricks;
    int         new_level;
    // brick //
    SDL_Surface *ss_bricks;
    int         brick_score;
    int         brick_w, brick_h;
    // club //
    SDL_Surface *ss_club;
    int         club_cw, club_ch; // size of component //
    Club        club;
    // ball //
    SDL_Surface *ss_ball;
    int         ball_rad; // radius //
    int         ball_dia; // diameter //
    int         ball_w, ball_h; // size of a sprite //
    DList       ball_list;
    float       ball_vm; // v max //
    float       ball_v; // ball's speed //
    float       ball_old_v; // old speed (before extra used) //
    float       ball_vhmask, ball_vvmask; // velocity masks //
    float       ball_v_add;
    int         ball_pnts[4][7][2]; // points from the ball's surface //
    // hiscore //
    HiScoreEntry player;
    HiScore     *hiscore;
    // events //
    int         keystate[SDLK_LAST];
    int         buttonstate[4];
    int         mouse_moved;
    int         mx;
    // draw rects //
    SDL_Rect    rects[UPDATERECTS];
    int         rect_num;
    // life //
    SDL_Surface *ss_life;
    int         life_y;
    int         max_lives; // maximum that can be dsiplayed //
    // score //
    SDL_Surface *ss_numbers;
    float       cur_score;
    int         score_x, score_y, score_w, score_h;
    int         score_xoff, score_lw;
    // extras //
    SDL_Surface *ss_extras;
    DList       extra_list;
    int         cur_extras[EX_NUMBER];
    // shrapnells //
    DList       shrapnell_list;
    // wall //
    float       wall_alpha;
    int         wall_time;
    // plasma weapon //
    SDL_Surface *ss_weapon;
    int         wpn_time;
    int         wpn_y_off;
    int         wpn_x, wpn_y, wpn_w, wpn_h, wpn_fr_num;
    int         wpn_sx_off, wpn_sy_off; // shot position offset when created //
    float       wpn_cur, wpn_fpms;
    // plasma shot //
    DList       shot_list;
    SDL_Surface *ss_shot;
    float       shot_fpms, shot_v_y;
    int         shot_w, shot_h, shot_fr_num, shot_alpha;
    int         fire_shot;
    int         max_shots;
    int         shot_time, shot_delay;
    // snapshot //
    int         snapshot;
    // extra times //
    int         metal_time;
    int         frozen_time;
    int         slime_time;
    int         fast_time;
    int         slow_time;
    // extra display //
    int         ed_x, ed_y; // offset releative to 0,0
    int         ed_offsets[EX_NUMBER];
    // cursor //
    SDL_Cursor  *original_cur;
    SDL_Cursor  *empty_cur;
    // difficulty //
    Difficulty  diff[3];
    // shine //
    SDL_Surface *ss_sh;
    float       sh_pms;
    int         sh_fr;
    float       sh_cur;
    int         sh_x, sh_y;
    // credit //
    float       cr_alpha;
    float       cr_pms;
    int         cr_cur;
    int         cr_time;
    int         cr_x, cr_y, cr_w, cr_h;
    char        cr_str[32];
    int         cr_status;
#ifdef SOUND
    Wave        *snd_ref, *snd_boom, *snd_lup, *snd_ldown, *snd_exp, *snd_shr;
    Wave        *snd_sco, *snd_fre, *snd_shot, *snd_sli, *snd_wea, *snd_met, *snd_wal;
    Wave        *snd_damn1, *snd_damn2;
    Wave        *snd_good, *snd_exc;
    Wave        *snd_wontgiveup;
    Wave        *snd_click;
    Wave        *snd_speedup, *snd_speeddown;
#endif
};

void Shr_Free(void *p);

#endif
