/******************************************************************************
*									      *
*	(C) 1993 by K. Ballueder					      *
*									      *
*	See README and COPYING for details.				      *
*									      *
*	Please feel free to contact me:					      *
*		kballued@charon.physik.uni-osnabrueck.de		      *
*		kballued@jupiter.rz.uni-osnabrueck.de			      *
*									      *
******************************************************************************/


/*
 * React: andere Objekte reagieren lassen
 *
 */

#include <stdlib.h>

#include "bdash.h"
#include "systems.h"
#include "graphic.h"
#include "game.h"
#include "movers.h"
#include "sound.h"
#include "scores.h"

#ifdef OS_DOS
#	include <alloc.h>
#endif

extern void fatal_error(char *err);

/* Stack zur Verwaltung der moeglicherweise zu behandelnden Felder */

typedef int stacktype[][2];

#define REACT_INITIAL_STACKSIZE 1

#define IS_VIECH(a) (a>=FELD_KAEFER_1 && a<=FELD_KAEFER_5a)

void bearbeite_feld(int x, int y);

void kill_beetle(int x, int y)
{
	int x1, y1;

	increment_score(1);
	kill_object(x,y);
	for(y1 = y-1; y1 <= y+1; y1++)
		for(x1 = x-1; x1 <= x+1; x1++)
			if(x1 >0 && y1 > 0 && x1 < level_x_size
				&& y1 < level_y_size)
			{	kill_object(x1,y1); /* maybe a stone? */
				if(level_table[y1][x1] == FELD_ERDE ||
				   level_table[y1][x1] == FELD_LEER)
				   {	level_table[y1][x1] = FELD_DIAMANT_1;
				   	bearbeite_feld(x1,y1);
				   	draw_image(x1,y1,FELD_DIAMANT_1);
				   }
			}
	update_graphics();
}

void explode(int x, int y)
{
	int dx, dy;
	unsigned char object;

	for(dy = 1;dy >-2;dy--)
		for(dx = -1;dx < 2; dx++)
		 if(x+dx >= 0 && x+dx < level_x_size && y+dy >= 0 && y+dy<level_y_size &&\
				level_table[y+dy][x+dx] != FELD_MAUER&&\
				(dy<1 ||(dy==1 && level_table[y][x+dx]!=FELD_MAUER)))
					draw_image(x+dx,y+dy,FELD_EXPLODE);
	soundeffect(SND_EXPLODE);
	if(level_table[y][x] == FELD_SPIELER_1)
		tod();
	level_table[y][x] = FELD_LEER;	/* to avoid endless recursion */
	update_graphics();

	for(dy = 1;dy >-2;dy--)
		for(dx = -1;dx < 2; dx++)
			if(x+dx >= 0 && x+dx < level_x_size && y+dy >= 0 && y+dy<level_y_size)
			{ if((object = level_table[y+dy][x+dx]) == FELD_SPIELER_1)
					tod();
				else
				if(IS_VIECH(object))
			kill_beetle(x+dx,y+dy);
				if(object == FELD_BOMBE || object == FELD_BOMBE_2)
					explode(x+dx,y+dy);
			}
	for(dy = 1;dy >-2;dy--)
		for(dx = -1;dx < 2; dx++)
		{ if(x+dx >= 0 && x+dx < level_x_size && y+dy >= 0 && y+dy<level_y_size\
				 && level_table[y+dy][x+dx] != FELD_MAUER&&\
				 (dy<1 ||(dy==1 && level_table[y][x+dx]!=FELD_MAUER)))
			{ level_table[y+dy][x+dx] = FELD_LEER;
				draw_leer(x+dx,y+dy);
			}
		}
	update_graphics();
	for(dx=-1;dx<2;dx++)
		bearbeite_feld(x+dx,y-2);
	for(dy=-1;dy<2;dy++)
	{ if(x > 1)
			bearbeite_feld(x-2,y+dy);
		if(x < level_x_size-2)
			bearbeite_feld(x+2,y+dy);
	}
}





static stacktype *react_stack;
static unsigned top_of_stack = 0;
static unsigned react_stacksize;

void init_react_stack(void)
{
  if((react_stack = malloc(sizeof(int)*REACT_INITIAL_STACKSIZE*2))==NULL)
    fatal_error("init_react_stack");
  react_stacksize = REACT_INITIAL_STACKSIZE;

}

void free_react_stack(void)
{
	react_stacksize = 0;
	free(react_stack);
}


void bearbeite_feld(int x, int y) /* zu bearbeitendes Feld merken! */
{
	if(top_of_stack == react_stacksize-1)
	{ if((react_stack =\
		realloc(react_stack,sizeof(int)*2*(react_stacksize+=1)))==NULL)
			fatal_error("bearbeite_feld");
	}
	(*react_stack)[++top_of_stack][0] = x;
	(*react_stack)[top_of_stack][1] = y;
}

void react(void)  /* Stack abarbeiten */
{
	unsigned x,y, object, object2;

	if(! top_of_stack) /* nix zu tun */
		return;

	do
	{ 	object = level_table[y = (*react_stack)[top_of_stack][1]]\
				[x = (*react_stack)[top_of_stack--][0]];
		if(CAN_FALL(object)&&y != level_y_size-1)
		{ 	/** Feld darunter leer? **/
			switch(level_table[y+1][x])
			{
			case FELD_LEER:  /* fallen */
				move_object(x,y,x,y+1,object);
				update_graphics();
				if(y > 0)
					bearbeite_feld(x,y-1); /* war noch was darber? */
				if(y < level_y_size-3)
				{ 	if(level_table[y+2][x]==FELD_SPIELER_1
						&& object != FELD_BOMBE\
						&& object != FELD_BOMBE_2)
						tod();
					if((object2 = level_table[y+2][x])==FELD_BOMBE_2
						|| object2 == FELD_BOMBE
						|| IS_VIECH(object2))
						explode(x,y+1);
					else
					{	if((object == FELD_BOMBE||object==FELD_BOMBE_2)\
						&& level_table[y+2][x] != FELD_LEER)
							explode(x,y+1);
						else
						if(level_table[y+2][x] != FELD_LEER)
						{	if(object == FELD_STEIN_2
								|| object == FELD_STEIN)
								soundeffect(SND_BUMP);
						}
					}
				}
				bearbeite_feld(x,y+1);
				continue;
			break;
			case  FELD_WATER:
				move_object(x,y,x,y+1,object);
				soundeffect(SND_WATER);
				draw_image(x,y+1,FELD_WATER);
				level_table[y+1][x]=FELD_WATER;
				update_graphics();
			break;
			default:
				if(object == FELD_CHEESE_2)
				{	level_table[y][x] = FELD_CHEESE_1;
					add_object(x,y,CHEESE1,FELD_CHEESE_1,0);
					update_graphics();
					continue;
				}
			break;
			}
				
			if(x > 0 && level_table[y][x-1]==FELD_LEER)
			{ 	object2 = level_table[y+1][x]; /* das darunter */
				if(CAN_FALL(object2)&&(level_table[y+1][x-1] == FELD_LEER))
				{ 	move_object(x,y,x-1,y+1,object);
					update_graphics();
					if(y < level_y_size-3)
					{ 	if(level_table[y+2][x-1] == FELD_SPIELER_1)
							tod();
						if((object2=level_table[y+2][x-1])==FELD_BOMBE||\
							object2 == FELD_BOMBE_2||IS_VIECH(object2))
							explode(x-1,y+2);
						else
						if((object==FELD_BOMBE_2
						||object == FELD_BOMBE)
						&& level_table[y+2][x-1]!=FELD_LEER)
							explode(x-1,y+2);
					}
					bearbeite_feld(x-1,y+1);
					if(y > 0)
						bearbeite_feld(x,y-1);
					continue;
				}
			}
			if(x < level_x_size-1 && level_table[y][x+1]==FELD_LEER)
			/** rechts daneben ist frei **/
			{ 	object2 = level_table[y+1][x]; /* das darunter */
				/** rechts darunter frei? **/
				if(CAN_FALL(object2)&&(level_table[y+1][x+1] == FELD_LEER))
				{ 	move_object(x,y,x+1,y+1,object);
					if(y < level_y_size-3)
					{ 	if(level_table[y+2][x+1] == FELD_SPIELER_1)
							tod();
						if((object2=level_table[y+2][x+1])==FELD_BOMBE||\
						object2 == FELD_BOMBE_2||IS_VIECH(object2))
							explode(x+1,y+2);
						else
						if((object == FELD_BOMBE
						|| object == FELD_BOMBE_2)
						&& level_table[y+2][x+1] != FELD_LEER)
							explode(x+1,y+2);
					}
					bearbeite_feld(x+1,y+1);
					if(y > 0)
						bearbeite_feld(x,y-1);
					continue;
				}
			}
		}
		else
		if(object == FELD_LEER)
		{  	if(x < level_x_size-1 && level_table[y][x+1] != FELD_LEER)
				bearbeite_feld(x+1,y);
			if(x > 0 && level_table[y][x-1] != FELD_LEER)
				bearbeite_feld(x-1,y);
		}
	}while(top_of_stack); /* alle abarbeiten! */
}
