Codebase list icebreaker / HEAD line.c
HEAD

Tree @HEAD (Download .tar.gz)

line.c @HEADraw · history · blame

/*
* IceBreaker
* Copyright (c) 2000-2020 Matthew Miller <mattdm@mattdm.org>
*   http://www.mattdm.org/
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/


#include <SDL.h>
#include "icebreaker.h"
#include "globals.h"
#include "line.h"
#include "laundry.h"
#include "grid.h"
#include "themes.h"

Line createline(int linenum)
{
	Line l;

	switch (linenum)
	{
		case 1: 
			l.id='1';
			l.colorpointer=&(color.line1);
		break;
		case 2:
			l.id='2'; 
			l.colorpointer=&(color.line2);
		break;
		default: 
			l.id='L';
			l.colorpointer=&(color.background);
		break;
	}
		
	l.on=false;
	l.dir=UP;
	l.geom.x=0;
	l.geom.y=0;
	l.geom.w=BLOCKWIDTH;
	l.geom.h=BLOCKHEIGHT;
	l.mark=l.geom;
	l.dead=false;
	l.speedslower=false;
	l.stuckcount=0;
	return(l);
}

void startline(Line * l, LineDir d, int x, int y)
{
	l->on=true;
	l->dir=d;
	l->stuckcount=0;

	switch (d)
	{
		case UP: 
			l->geom.w=BLOCKWIDTH;
			l->geom.h=1;
			l->geom.x=x;
			l->geom.y=y-1; 
		break;
		case DOWN:
			l->geom.w=BLOCKWIDTH;
			l->geom.h=1;
			l->geom.x=x;
			l->geom.y=y; 
		break;
		case LEFT: 
			l->geom.w=1;
			l->geom.h=BLOCKHEIGHT;
			l->geom.x=x-1;
			l->geom.y=y;			
		break;
		case RIGHT:
			l->geom.w=1;
			l->geom.h=BLOCKHEIGHT;
			l->geom.x=x;
			l->geom.y=y;
		break;
	}
	l->mark=l->geom;
}


int moveline(Line * l)
{
	int finish=false;
	char check1;
	char check2;

	markgrid(l->mark.x,l->mark.y,l->mark.w,l->mark.h,l->id);
	SDL_FillRect(screen,&(l->mark),*(l->colorpointer));
	soil(l->mark);

	switch (l->dir)
	{
		case UP:
			check1=grid[l->geom.x][l->geom.y-1];
			check2=grid[l->geom.x+BLOCKWIDTH-1][l->geom.y-1];
		break;
		case DOWN:
			check1=grid[l->geom.x][l->geom.y+l->geom.h];
			check2=grid[l->geom.x+BLOCKWIDTH-1][l->geom.y+l->geom.h];
		break;
		case LEFT:
			check1=grid[l->geom.x-1][l->geom.y];
			check2=grid[l->geom.x-1][l->geom.y+BLOCKHEIGHT-1];
		break;
		case RIGHT:
			check1=grid[l->geom.x+l->geom.w][l->geom.y];
			check2=grid[l->geom.x+l->geom.w][l->geom.y+BLOCKHEIGHT-1];
		break;
		default: // this will never happen. really.
			fprintf(stderr,"Line has no direction. That shouldn't have happened.\n");
			check1='!';
			check2='!';
		break;
	}
	

	if (check1 == ' ' && check2 == ' ')
	{ // next space is empty
		switch (l->dir)
		{
			case UP:
				l->geom.y--;
				l->geom.h++;
				l->mark.y--;
				l->mark.h=1;
			break;
			case DOWN:
				l->geom.h++; // increase length of line -- top stays same 
				l->mark.y+=l->mark.h;
				l->mark.h=1;
			break;
			case LEFT:
				l->geom.x--;
				l->geom.w++;
				l->mark.x--;
				l->mark.w=1;
			break;
			case RIGHT:
				l->geom.w++; // increase width of line -- left side stays same 
				l->mark.x+=l->mark.w;
				l->mark.w=1;
			break;
		}
	}
	else if (check1 == '*' || check2 == '*')
	{ // hit a penguin. kills line.
		l->dead=true;
	}
	else if (check1 == '1' || check2 == '1' || check1 == '2' || check2 == '2')
	{
		if (l->stuckcount>LINEMAXSTUCK)
		{
			// FIX -- should play sound when this happens, to
			// let users know that this isn't a mistake.
			finish=true;
		}
		else
		{
			l->stuckcount++;
			
			// FIX: kludge-o-rama!!
			// this could work around the irritating thing where
			// a line gets started 'on top' of another line. but it
			// is totally repairing the symptom, not the bug. *sigh*
			//if (l->geom.w==1 || l->geom.h==1) finish=true;
		}
	}
	else
	{ // hit something else
		finish=true;
	}
	
	if (finish)
	{
		markgrid(l->mark.x,l->mark.y,l->mark.w,l->mark.h,l->id);
		SDL_FillRect(screen,&(l->mark),*(l->colorpointer));
		soil(l->mark);
		finishline(l);
		return(1);
	}
	
	return(0);
}

void finishline(Line * l)
{
	int i;
	int quick1=false;
	int quick2=false;
	
	l->on=false;	
	
	//printwholegrid();
	
	switch (l->dir)
  	{
  		case DOWN:
  		// falls through.
  		case UP:
  			markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,'|');
  			SDL_FillRect(screen,&l->geom,color.background);
  			soil(l->geom);		
  				
  			// scan along edges to quickly determine if this
  			// is going to be complicated.
  			quick1=true; quick2=true;
  			for (i=l->geom.y+BLOCKHEIGHT/2;i<l->geom.y+l->geom.h;i++)
  			{
  				if (grid[l->geom.x-1][i] != ' ' && grid[l->geom.x-1][i] != '*') quick1=false;
  				if (grid[l->geom.x+BLOCKWIDTH][i] != ' ' && grid[l->geom.x+BLOCKWIDTH][i] != '*') quick2=false;
  			}
  				
  			//printf("Quick %d %d\n",quick1,quick2);
  				
  			checkempty(l->geom.x-BLOCKWIDTH/2,l->geom.y+BLOCKHEIGHT/2);
  			checkempty(l->geom.x+BLOCKWIDTH+BLOCKWIDTH/2/2,l->geom.y+BLOCKHEIGHT/2);
  		
  			if (!quick1)
  				for (i=l->geom.y+BLOCKHEIGHT/2+BLOCKHEIGHT;i<l->geom.y+l->geom.h;i+=BLOCKHEIGHT)
  					checkempty(l->geom.x-BLOCKWIDTH/2,i);
  			if (!quick2)
  				for (i=l->geom.y+BLOCKHEIGHT/2+BLOCKHEIGHT;i<l->geom.y+l->geom.h;i+=BLOCKHEIGHT)
  					checkempty(l->geom.x+BLOCKWIDTH+BLOCKWIDTH/2,i);
  		break;
  		case RIGHT:
  		// falls through
  		case LEFT:
  			markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,'-');
  			SDL_FillRect(screen,&l->geom,color.background);
  			soil(l->geom);		
	
  			// scan along edges to quickly determine if this
  			// is going to be complicated.
  			quick1=true; quick2=true;
  			for (i=l->geom.x+BLOCKWIDTH/2;i<l->geom.x+l->geom.w;i++)
  			{
  				if (grid[i][l->geom.y-1] != ' ' && grid[i][l->geom.y-1] != '*') quick1=false;
  				if (grid[i][l->geom.y+BLOCKHEIGHT] != ' ' && grid[i][l->geom.y+BLOCKHEIGHT] != '*') quick2=false;
  			}
  				
  			//printf("Quick %d %d\n",quick1,quick2);
	  			
	  		checkempty(l->geom.x+BLOCKWIDTH/2,l->geom.y-BLOCKHEIGHT/2);
	  		checkempty(l->geom.x+BLOCKWIDTH/2,l->geom.y+BLOCKHEIGHT+BLOCKHEIGHT/2);
	  			
	  		if (!quick1)
	  			for (i=l->geom.x+BLOCKWIDTH/2+BLOCKWIDTH;i<l->geom.x+l->geom.w;i+=BLOCKWIDTH)
		  			checkempty(i,l->geom.y-BLOCKHEIGHT/2);
	  			
	  		if (!quick2)
	  			for (i=l->geom.x+BLOCKWIDTH/2+BLOCKWIDTH;i<l->geom.x+l->geom.w;i+=BLOCKWIDTH)
		  			checkempty(i,l->geom.y+BLOCKHEIGHT+BLOCKHEIGHT/2);
	  		
		break;
	}
	
}


void killline(Line * l)
{
	l->on=false;
	l->dead=false;
	
	switch (l->dir)
  	{
  		case DOWN:
		// falls through.
  		case UP:
  			markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,' ');
  			// FIXORAMA
  			SDL_BlitSurface(gridsave,&l->geom, screen, &l->geom);
  			soil(l->geom);		
  		break;
  		case RIGHT:
  		// falls through
  		case LEFT:
  			markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,' ');
  			// FIXORAMA
  			SDL_BlitSurface(gridsave,&l->geom, screen, &l->geom);
  			soil(l->geom);		
	  	break;
	}
}