/*
Copyright (c) 1998 Michael Haar, Ulrich Haar, Michael Thayer,
  Tobias Mueller, Tobias Lenz
All rights reserved.
Terroid Programming by Michael Haar, Michael Thayer, Ulrich Haar
Terroid Graphics by Ulrich Haar, Michael Haar
Terroid Music by Michael Thayer
Terroid Level design by Michael Haar, Ulrich Haar, Tobias Lenz
Terroid Beta testing by Tobias Mueller, Tobias Lenz

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice and credits, this unmodified list of conditions and the
   following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice and credits, this unmodified list of conditions and the
   following disclaimer in the documentation and/or other materials
   provided with the distribution.
3. Any credits displayed during programme execution must include the
   above or an equivalent credit list.
4. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.
5. The authors Michael Thayer and Michael Haar are to be informed,
   preferable by electronic mail, when this software is distributed
   commercially.  A single notification is required for any given
   distribution, and explicit copies of that distribution (e.g. for all
   resellers of a given Linux distribution).
6. If any modifications are made to the software, then a description of them
   must be included when the software is redistributed, or alternatively,
   the distributed binary or source code must be described as a product
   based on source code by Michael Haar, Michael Thayer and Ulrich Haar.

THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**********************************/
/* ballerspiel-Spielerfunktionen  */
/* (C) April 1996 by Michael Haar */
/**********************************/

/* Änderungen: */

#include <stdlib.h>
#include <string.h>
#include <dn.h>
#include "DEFS.H"
#include "FUNCS.H"
#include "VARS.H"

/* globale Variablen */
SPIELER spieler;
GFXBLK spielerpix[ANZ_SPIELERPICS];
GFXBLK schildpix[3];
GFXBLK infobalkenpix;
GFXBLK bombenpix, powerbeampix[4];
GFXBLK smartbombpix[4];
RGB redpal[4][256];
GFXBLK endgegnerenergiepix;
GFXBLK pausedpix;

extern EXTRA extra[MAX_EXTRAS];

/* Funktionsprototypen */
BOOLEAN init_spieler(unsigned char level);
void spieleraction();
void infobalken();
void set_playermines() ;

/* Funktionen */
BOOLEAN init_spieler(unsigned char level)
{
	int i;

	if(level == 0)
	{
		if(!load_pic("SCHIFF.PIX", screen_addr, alt_rgb))
			return(FALSE);

		// und getten
		get(0, 0, 53, 51, &spielerpix[2]);
		get(0, 52, 53, 52 + 51, &spielerpix[3]);
		get(54, 52, 54 + 53, 52 + 51, &spielerpix[1]);
		get(0, 2 * 52, 53, 2 * 52 + 51, &spielerpix[4]);
		get(54, 2 * 52, 54 + 53, 2 * 52 + 51, &spielerpix[0]);
		get(4, 195, 4 + 52 * 6 - 1, 199, &endgegnerenergiepix);

		//schild
		if(!load_pic("SCHILD.PIX", screen_addr, alt_rgb))
			return(FALSE);
		get(12, 7, 90, 56, &schildpix[0]);
		get(12, 61, 91, 112, &schildpix[1]);
		get(100, 9, 177, 58, &schildpix[2]);

		// Infoleiste, Energie, Leben
		if(!load_pic("LEISTE.PIX", screen_addr, alt_rgb))
			return(FALSE);
		get(0, 0, 319, 11, &infobalkenpix);
		get(0, 12, 7, 19, &bombenpix);
		get(0, 21, 7, 28, &powerbeampix[0]);
		get(8, 21, 15, 28, &powerbeampix[1]);
		get(16, 21, 23, 28, &powerbeampix[2]);
		get(24, 21, 31, 28, &powerbeampix[3]);
		// Paused
		get(0, 47, 151, 102, &pausedpix);

		// Smartbomb
		if(!load_pic("SMARTBOM.PIX", screen_addr, alt_rgb))
			return(FALSE);
		get(4, 1, 110, 77, &smartbombpix[3]);
		get(114, 2, 221, 78, &smartbombpix[2]);
		get(3, 79, 113, 157, &smartbombpix[1]);
		get(114, 79, 224, 157, &smartbombpix[0]);
	}

	// Neustart jedes Level
	spieler.anistufe = 2 * ANIFAC;
	spieler.x = screen_width / 12;
	spieler.y = screen_height / 2;
	spieler.xpl = 0;
	spieler.ypl = 0;
	spieler.energie = 100;
	for(i = 0; i < SPIELER_WAFFEN; i++)
		spieler.waffe_ok[i] = 0;
	spieler.absturz = 0;
	spieler.schild = 0;
	// eventuell bei Spiel-Neubeginn
	if(level == 0)
	{
		spieler.speed = 4;
		spieler.waffe[0] = 1;
		spieler.waffe[1] = 1;
		for(i = 2; i < SPIELER_WAFFEN; i++)
			spieler.waffe[i] = FALSE;
		spieler.smartbomb = 0;
		spieler.powerbeam = 0;
		if(game_difficulty == TRAINING)
			spieler.leben = 0;
		else if(game_mode == PLAY)
			spieler.leben = 3;
		else
			spieler.leben = 0;
		spieler.punkte = 0;
	}

	return(TRUE);
}

void spieler_neu()
{
	int i;

	reset_explosionen();

	if(spieler.leben > 0)
	{
		spieler.x = screen_width / 12;
		spieler.y = screen_height / 2;
		spieler.energie = 100;
	}
	spieler.xpl = 0;
	spieler.ypl = 0;
	spieler.absturz = 0;
	spieler.leben--;
	spieler.schild = 50;

	if(spieler.waffe[1] > 1)
		spieler.waffe[1]--;
	if(spieler.waffe[2] > 1)
		spieler.waffe[2]--;
	if(spieler.waffe[3] > 1)
		spieler.waffe[3]--;
	if(spieler.waffe[4] > 1)
		spieler.waffe[4]--;

	// Wenn kein Endgegner da
	if(endmonster.energie_max == 0)
	{
		// Levelposition zuruecksetzen
		game_scrollpos -= 2 * 320;
		if(game_scrollpos < 0)
			game_scrollpos = 0;
		// Alle Gegner löschen
		for(i = 0; i < MAX_OBJEKTE; i++)
			objekt[i].nr = 0;
		// Alle Extras löschen
		for(i = 0; i < MAX_EXTRAS; i++)
			extra[i].komm_zaehler = 99;
	}
}

void show_spieler(void)
{
	int i;

	if(spieler.absturz == 0)
	{
	    if (do_draw)
	      {
		if(spieler.waffe[1])
		{
			// LaserKanone
			objput(spieler.x - objpix[SCHUSSPICS + 5].w / 2 - spieler.waffe_ok[1] / 2 * SPEED_FAC + 10, spieler.y - 20 - objpix[SCHUSSPICS + 5].h / 2, &objpix[SCHUSSPICS + 5]);
			objput(spieler.x - objpix[SCHUSSPICS + 5].w / 2 - spieler.waffe_ok[1] / 2 * SPEED_FAC + 10, spieler.y + 20 - objpix[SCHUSSPICS + 5].h / 2, &objpix[SCHUSSPICS + 5]);
		}
		objput(spieler.x - 27, spieler.y - 26, &spielerpix[spieler.anistufe / ANIFAC]);
		// kreisende Minen
		for(i = 0; i < spieler.waffe[4]; i++)
			objput(spieler.mine[i].x - objpix[SCHUSSPICS + 27 + (main_counter % 30) / 10].w / 2, spieler.mine[i].y - objpix[SCHUSSPICS + 27 + (main_counter % 30) / 10].h / 2, &objpix[SCHUSSPICS + 27 + (main_counter % 30) / 10]);
		// Schild darüber
		if(spieler.schild > 0)
			objput(spieler.x - schildpix[0].w / 2, spieler.y - schildpix[0].h / 2, &schildpix[main_counter % 2]);
		else if(spieler.schild < 0)
			objput(spieler.x - schildpix[1].w / 2, spieler.y - schildpix[1].h / 2, &schildpix[2]);
		// eventuell Smartbombfeuern
		if((spieler.smartbomb > 0) && (spieler.smartbomb < 16))
			objput(spieler.x - smartbombpix[spieler.smartbomb / 4].w / 2, spieler.y - smartbombpix[spieler.smartbomb / 4].h / 2, &smartbombpix[spieler.smartbomb / 4]);
	      } /* if (do_draw) */
	}
	else
	{
		spieler.absturz--;
		if(spieler.absturz <= 0)
			spieler_neu();

		spieler.x += 3;
		spieler.y += 2;

// hat das hier Sinn, Ulrich???
/*		if(spieler.y > 340)
			for(i = 0; i < 20; i++)
				explode(spieler.x + (rand() % 60) - 40, spieler.y + (rand() % 60) - 50, 54, 52, 0); */

		if(spieler.y < screen_height + 50)
		{
			if (do_draw)
			  {
			    objput(spieler.x - 27, spieler.y - 26, &spielerpix[4]);
			  } /* if (do_draw) */

			if(spieler.absturz % 6 == 0)
				explode(spieler.x + (rand() % 50) - 25, spieler.y + (rand() % 40) - 20, 0, 0, 0);

			if((game_view == FULL) || (game_view == HIGH))
			{
				explode((spieler.x + (rand() % 50) - 45) , (spieler.y + (rand() % 50) - 35), 0, 0, 1);
				explode((spieler.x + (rand() % 50) - 45) , (spieler.y + (rand() % 50) - 35), rand() % 54, rand() % 52, 1);
				explode((spieler.x + (rand() % 50) - 45) , (spieler.y + (rand() % 50) - 35), rand() % 54, rand() % 52, 1);
				explode((spieler.x + (rand() % 50) - 45) , (spieler.y + (rand() % 50) - 35), 0, 0, 1);
			}

			if((rand() % 10 == 0) && (game_view == FULL))
				explode((spieler.x + (rand() % 50) - 45) , (spieler.y + (rand() % 50) - 35), 0, 0, 3);
	
			// und noch ab und zu rot ...
			if(rand() % 10 == 0)
				spieler.schild = -5;
		}
	}
}

void infobalken()
{
	int w;

	if (!do_draw) return ;

	put(0, 0, &infobalkenpix);
	if(spieler.energie >= 0)
		box(43 + spieler.energie * (84 - 43) / 100, 0, 84, 11, 0, TRUE, FALSE);
	else
		box(43, 0, 84, 11, 0, TRUE, FALSE);
	if(spieler.smartbomb == 0)
		put(185, 2, &bombenpix);
	put(101, 1, &powerbeampix[spieler.powerbeam / (16 * SPEED_FAC)]);
	if(spieler.leben > -1)
		itoa(spieler.leben, txt, 10);
	else
		itoa(0, txt, 10);
	put_text(&digitalfnt, 152, 1, txt);

	if(spieler.punkte < 10)
		sprintf(txt, "00000%d", spieler.punkte);
	else if(spieler.punkte < 100)
		sprintf(txt, "0000%d", spieler.punkte);
	else if(spieler.punkte < 1000)
		sprintf(txt, "000%d", spieler.punkte);
	else if(spieler.punkte < 10000)
		sprintf(txt, "00%d", spieler.punkte);
	else if(spieler.punkte < 100000)
		sprintf(txt, "0%d", spieler.punkte);
	else
		sprintf(txt, "%d", spieler.punkte);

	put_text(&digitalfnt, 224, 1, txt);

	if(endmonster.energie_max)
	{
		w = 4 + (52 * endmonster.energie_aktuell / endmonster.energie_max) * 6 - 1;
		clip_x2 = w;
		objput(4, 194, &endgegnerenergiepix);
		clip_x2 = screen_width - 1;
	}
}

void demosteuern()
{
	int i, xr, yr, min_x, min_y, o;
	BOOLEAN ausweichen;

	ausweichen = FALSE;
	o = -1;
	min_x = 1000000;
	for(i = 0; i < MAX_OBJEKTE; i++)
		if(objekt[i].nr && (objekt[i].art > 1))
		{
			xr = objekt[i].bahn.x / KURVENFAC - spieler.x;
			yr = abs(objekt[i].bahn.y / KURVENFAC - spieler.y);
			if((xr < 50) && (xr < min_x) && (yr < 30))
			{
				o = i;
				min_x = xr;
				ausweichen = TRUE;
			}
		}

	if(!ausweichen)
	{
		o = -1;
		min_x = 1000000;
		min_y = 1000000;
		for(i = 0; i < MAX_OBJEKTE; i++)
			if(objekt[i].nr && (objekt[i].art > 1) && (objekt[i].art < 100) && (objekt[i].energie < 100000))
			{
				xr = objekt[i].bahn.x / KURVENFAC - spieler.x;
				yr = abs(objekt[i].bahn.y / KURVENFAC - spieler.y);
				if((xr > 50) && (xr < min_x) && (yr < min_y))
				{
					o = i;
					min_x = xr;
					min_y = yr;
				}
			}
		// einer da!
		if(o >= 0)
		{
			yr = objekt[o].bahn.y / KURVENFAC - spieler.y;
			// Hinsteuern
			if((yr < 0) && (spieler.y > clip_y1))
			{
				if(spieler.y - spieler.speed >= objekt[o].bahn.y / KURVENFAC)
					spieler.ypl -= spieler.speed;
			}
			else if((yr > 0) && (spieler.y < clip_y2))
			{
				if(spieler.y + spieler.speed <= objekt[o].bahn.y / KURVENFAC)
					spieler.ypl += spieler.speed;
			}
		}
	}
	else
	{
		yr = objekt[o].bahn.y / KURVENFAC - spieler.y;
		// Ausweichen
		if((yr < 0) && (spieler.y < clip_y2))
			spieler.ypl += spieler.speed;
		else if((yr > 0) && (spieler.y > clip_y1))
			spieler.ypl -= spieler.speed;
	}
}

void spieleraction(void)
{
	int i;

	// Anzeige
	show_spieler();

	if(spieler.anistufe > 2 * ANIFAC)
		spieler.anistufe--;
	else if(spieler.anistufe < 2 * ANIFAC)
		spieler.anistufe++;

	if(spieler.absturz == 0)
	{
		// Steuerung
		if((keyTest(KEY_UP) || joy1_up()) && (spieler.y > clip_y1) && (game_mode == PLAY))
		{
			spieler.ypl -= spieler.speed;
			if(spieler.anistufe > 1)
				spieler.anistufe -= 2;
		}
		if((keyTest(KEY_DOWN) || joy1_down()) && (spieler.y < clip_y2) && (game_mode == PLAY))
		{
			spieler.ypl += spieler.speed;
			if(spieler.anistufe < 5 * ANIFAC - 2)
				spieler.anistufe += 2;
		}
		if((keyTest(KEY_LEFT) || joy1_left()) && (spieler.x > clip_x1) && (game_mode == PLAY))
			spieler.xpl -= spieler.speed;
		if((keyTest(KEY_RIGHT) || joy1_right()) && (spieler.x < clip_x2) && (game_mode == PLAY))
			spieler.xpl += spieler.speed;

		/* Bewegung */
		spieler.x += spieler.xpl;
		spieler.y += spieler.ypl;
		spieler.xpl = 0;
		spieler.ypl = 0;

		if(game_mode == DEMO)
			demosteuern();

		// Waffen aufladen
		for(i = 0; i < SPIELER_WAFFEN; i++)
			if(spieler.waffe_ok[i])
				spieler.waffe_ok[i]--;
		// Beam hochzaehlen
		if(spieler.powerbeam < 4 * 16 * SPEED_FAC - 1)
			spieler.powerbeam++;
		// Schild abbauen
		if(spieler.schild > 0)
			spieler.schild--;
		else if(spieler.energie <= 0)
		{
			if (sounddevice != 4) start_sample(warningsnd, md_numchn - 1);

			// Spieler nach Treffer tot!
			spieler.absturz = (200 - spieler.y) / 2 + 60;
			spieler.schild = 0;
			SetPalette(gamepal);
			spieler.energie = 0;
		}
		// Smartbombschiessen
		if((spieler.smartbomb < 16) && (spieler.smartbomb > 0))
			spieler.smartbomb--;
		// kreisende Minen - erstmal so:
		set_playermines();

		// Feuern
		if(((game_mode != DEMO) && (keyTest(KEY_RCTRL) ||
		  keyTest(KEY_LCTRL) || keyTest(KEY_SPACE) || keyTest(KEY_V)
		  || joy1_b1())) || ((game_mode == DEMO) && (rand() % 10 == 0)))
		{
			// normaler Schuss
			if(spieler.waffe_ok[0] == 0)
			{
				neuer_schuss(spieler.x, spieler.y, 2, spieler.powerbeam / (16 * SPEED_FAC));
				spieler.waffe_ok[0] = 16 / SPEED_FAC;
			}
			// Laserkanonen
			if(spieler.waffe[1] && (spieler.waffe_ok[1] == 0))
			{
				neuer_schuss(spieler.x + 20, spieler.y - 20, spieler.waffe[1] - 1, 5);
				neuer_schuss(spieler.x + 20, spieler.y + 20, spieler.waffe[1] - 1, 5);
				spieler.waffe_ok[1] = 24 / SPEED_FAC;

				if (sounddevice != 4) start_sample(lasersnd, md_numchn - 1);
			}
			// Rakete
			if(spieler.waffe[2] && (spieler.waffe_ok[2] == 0))
			{
				if(spieler.waffe[2] == 1)
				{
					neuer_schuss(spieler.x + 8, spieler.y, 50, 8);
					spieler.waffe_ok[2] = 48;
				}
				else if(spieler.waffe[2] == 2)
				{
					neuer_schuss(spieler.x - 8, spieler.y - 16, 35, 8);
					neuer_schuss(spieler.x - 8, spieler.y + 16, 35, 8);
					spieler.waffe_ok[2] = 52;
				}
				else
				{
					neuer_schuss(spieler.x + 8, spieler.y, 30, 8);
					neuer_schuss(spieler.x - 8, spieler.y - 16, 30, 8);
					neuer_schuss(spieler.x - 8, spieler.y + 16, 30, 8);
					spieler.waffe_ok[2] = 56;
				}
			}
			// Rotschuss
			if(spieler.waffe_ok[3] == 0)
			{
				if(spieler.waffe[3] == 1)
				{
					neuer_schuss(spieler.x + 10, spieler.y - 10, 1, 12);
					neuer_schuss(spieler.x + 10, spieler.y + 10, 3, 12);
				}
				else if(spieler.waffe[3] == 2)
				{
					neuer_schuss(spieler.x + 10, spieler.y - 10, 1, 12);
					neuer_schuss(spieler.x + 10, spieler.y + 10, 3, 12);
					neuer_schuss(spieler.x - 10, spieler.y, 6, 12);
				}
				else if(spieler.waffe[3] == 3)
				{
					neuer_schuss(spieler.x + 10, spieler.y - 10, 1, 12);
					neuer_schuss(spieler.x + 10, spieler.y + 10, 3, 12);
					neuer_schuss(spieler.x + 10, spieler.y - 10, 7, 12);
					neuer_schuss(spieler.x + 10, spieler.y + 10, 5, 12);
				}
				spieler.waffe_ok[3] = 16 / SPEED_FAC;
			}
			// Mine
/*			if(spieler.waffe[4] && (spieler.waffe_ok[4] == 0))
			{
				neuer_schuss(spieler.x, spieler.y, 6, 13);
				spieler.waffe_ok[4] = 48 / SPEED_FAC;
			} */
			// andere Waffen
			spieler.powerbeam = 0;
		}
		// Bombe benutzen
		if(keyTest(KEY_RALT) || keyTest(KEY_LALT) || keyTest(KEY_B) || joy1_b2() || (game_mode == DEMO))
			if(spieler.smartbomb == 16)
			{
				// Alle Gegner töten
				kill_all_objects();
	
				spieler.smartbomb--;
			}
	}
}

void set_playermines()
{
	int i;
	int sinus, cosinus;

	for(i = 0; i < spieler.waffe[4]; i++)
	{
		// Noch nicht gut:
		spieler.mine[i].energie = 5;
		// Und Bewegte Koordinaten
		sinus = sintab[(main_counter * 10 + i * 360 / spieler.waffe[4]) % 360];
		cosinus = sintab[((main_counter * 10 + i * 360 / spieler.waffe[4])) % 360 + 90];
		spieler.mine[i].x = -((cosinus * 50) >> SINFAC) + spieler.x + 5;
		spieler.mine[i].y = ((sinus * 50 * 3 / 4) >> SINFAC) + spieler.y;
	}
}
