/* Header: move.c,v 7.0.1.2 86/10/20 14:37:06 lwall Exp */

/* Log:	move.c,v
 * Revision 7.0.1.2  86/10/20  14:37:06  lwall
 * Picked some lint.
 *
 * Revision 7.0.1.1  86/10/16  10:52:09  lwall
 * Added Damage.  Fixed random bugs.
 *
 * Revision 7.0  86/10/08  15:12:40  lwall
 * Split into separate files.  Added amoebas and pirates.
 *
 */

#include "EXTERN.h"
#include "warp.h"
#include "bang.h"
#include "object.h"
#include "move.h"
#include "play.h"
#include "score.h"
#include "term.h"
#include "them.h"
#include "us.h"
#include "util.h"
#include "weapon.h"
#include "INTERN.h"
#include "move.h"

void
move_init(void)
{
    ;
}

void
bounce(OBJECT *obj)
{
    int x;
    int y;
    int count=0;

    y = (obj->posy - sgn(obj->vely) + YSIZE00) % YSIZE;
    x = (obj->posx - sgn(obj->velx) + XSIZE00) % XSIZE;
    while (occupant[y][x]) {
	y = (y + rand_mod(3) - 1 + YSIZE00) % YSIZE;
	x = (x + rand_mod(3) - 1 + XSIZE00) % XSIZE;
	if (++count > 10000) {     /* if universe full, get out of it fast */
	    unmake_object(obj);
	    if (ent) unmake_object(ent);
	    if (base) unmake_object(base);
	    finish = 1;
	    return;
	}
    }
    obj->posy = y;
    obj->posx = x;
    obj->vely = 0;
    obj->velx = 0;
    occupant[y][x] = obj;
    if (numamoebas && obj->image == ' ')
	mvaddc(y+1, x*2, amb[y][x]);
    else
	mvaddc(y+1, x*2, obj->image);
}

void
move_universe(void)
{
    OBJECT *curobj;
    int x;
    int y;
    OBJECT *temp;
    OBJECT *thenext;

    for (curobj = movers; curobj != &root; curobj = curobj->next) {
	x = curobj->posx;
	y = curobj->posy;
	if (curobj == occupant[y][x]) {
	    occupant[y][x] = 0;
	}
	else if (curobj->type != Torp && curobj->type != Web) {
	    resetty();
	    abort();
	}
    }
    for (curobj = movers; curobj != &root; curobj = thenext) {
	thenext = curobj->next;
	if (curobj->vely || curobj->velx) {
	    y = curobj->posy;
	    x = curobj->posx;
	    if (curobj->image != ' ' &&
	      (!(temp=occupant[y][x]) || temp->image==' ') ) {
		move(y+1, x*2, numamoebas ? amb[y][x] : ' ');
	    }
	    y = (y + curobj->vely + YSIZE00) % YSIZE;
	    x = (x + curobj->velx + XSIZE00) % XSIZE;
	    if (!(temp=occupant[y][x]) || temp->type != Star ||
	      curobj->type != Torp || curobj->image == '+' ||
	      curobj->image == 'x') {
		curobj->posy = y;
		curobj->posx = x;
	    }
	    else {
		if (curobj->image == '0') {
		    curobj->vely = rand_mod(3)-1;
		    curobj->velx = rand_mod(3)-1;
		}
		else
		    curobj->vely = curobj->velx = 0;
		y = curobj->posy;
		x = curobj->posx;
	    }
	}
	else {			/* not moving */
	    y = curobj->posy;
	    x = curobj->posx;
	    if (curobj->type == Torp ||
		curobj->type == Star ||
		curobj->type == Web) {
		curobj->flags |= STATIC;
		curobj->next->prev = curobj->prev;
		curobj->prev->next = curobj->next;
		curobj->prev = movers->prev;
		curobj->next = movers;
		movers->prev->next = curobj;
		movers->prev = curobj;
	    }
	}
	if ((temp = occupant[y][x]) != NULL) {		/* already occupied? */
	    if (!temp->contend) {
		if (temp->type == Torp) {
		    if (temp->image == '+')
			blast[y][x] += 1250;
		    else if (temp->image == 'o' && (base||ent))
			blast[y][x] += 500+super*20;
		    else if (temp->image == 'O' && (base||ent))
			blast[y][x] += 5000+super*100;
		}
	    }
	    yblasted[y] |= 1;
	    xblasted[x] |= 1;
	    blasted = true;
	    curobj->contend = temp;
	    occupant[y][x] = curobj;
	    switch (curobj->type) {
	    case Enemy:
		if (numamoebas && curobj == nuke && temp->image == '+')
		    blast[y][x] += 80000;
		else if (temp->type == Enemy)
		    blast[y][x] += 10;
		else
		    goto defblast;
		break;
	    case Crusher:
		if (curobj->velx)
		    blast[y][x] += 100000;
		else
		    goto defblast;
		break;
	    case Torp:
		if (curobj->image == '+')
		    blast[y][x] += (temp==nuke ? 80000 : 1250);
		else if (curobj->image == 'o')
		    blast[y][x] += 500+super*20;
		else if (curobj->image == 'O')
		    blast[y][x] += 5000+super*100;
		goto defblast;
	    case Star:
		if (temp == ent)
		    goto damshield;
		goto defblast;
	    case Enterprise:
		if (temp->type == Star) {
	      damshield:
		    if (!rand_mod(10)) {
			if (!damflag[NOSHIELDS])
			    damage++;
			if (damflag[NOSHIELDS] < 100)
			    damflag[NOSHIELDS] += rand_mod(smarts)/5+2;
		    }
		}
		goto defblast;
	    default:
	      defblast:
		blast[y][x] += rand_mod(751)+1;
		break;
	    }
	}
	else {
	    occupant[y][x] = curobj;
	    if (curobj->image != ' ' &&
	        (curobj->velx || curobj->vely ||
		 curobj->type == Torp || curobj->type == Web) ) {
		mvaddc(y+1, x*2, curobj->image);
	    }
	    if (curobj->type == Crusher && curobj->velx) {
		blast[y][x] += 100000;
		yblasted[y] |= 1;
		xblasted[x] |= 1;
		blasted = true;
	    }
	}
    }
    if (blasted) {
	int minxblast = -1;
	int maxxblast = -2;
	long tmpblast;

	blasted = numamoebas;
	for (x=0; x<XSIZE; x++) {
	    if (xblasted[x]) {
		xblasted[x] = 0;
		maxxblast = x;
		if (minxblast < 0)
		    minxblast = x;
	    }
	}
	for (y=0; y<YSIZE; y++) {
	    if (yblasted[y]) {
		yblasted[y] = 0;
		for (x=minxblast; x<=maxxblast; x++) {
		    tmpblast = blast[y][x];
		    if (numamoebas && amb[y][x] == '~') {
			if ((temp = occupant[y][x]) != NULL) {
			    if (temp->image == '&')
				tmpblast >>= 1;
			    else if (temp->type == Web)
				tmpblast = 100000;
			    else
				tmpblast += 50 + temp->energy/100;
			    if (tmpblast > 250 && !rand_mod(5+(inumstars>>4)))
				modify_amoeba(y,x,1,'~',5);
			}
			xblasted[x] = 2;
			yblasted[y] = 2;
		    }
		    if (tmpblast) {
			OBJECT *biggie = 0;

			blast[y][x] = 0;
			temp = occupant[y][x];
			if (tmpblast < 0) {
			    if (numamoebas && tmpblast < -1000000 &&
				amb[y][x] == '~' && temp != nuke) {
				amb[y][x] = ' ';
				if (!temp)
				    make_plink(y,x);
				ambsize--;
			    }
			    tmpblast = 0;
			}
			if (temp) {
			    if ((!numamoebas || amb[y][x]==' ') &&
			      tmpblast < 100000)
				make_plink(y,x);
			    for ( ;temp;
			      temp = curobj->contend,curobj->contend = 0){
				curobj = temp;
				switch (curobj->type) {
				case Enterprise: {
				    long tmp = curobj->energy;

				    if (ent->energy>500 || apolloflag & 1)
					curobj->energy -= tmpblast /
					   ((apolloflag & 1)
					    ? 20
					    : (5+abs(ent->velx)+abs(ent->vely))
					       / ((damflag[NOSHIELDS]>>3)+1)+1);
				    else
					curobj->energy -= tmpblast;
				    if (rand_mod(1 + tmp - curobj->energy) > 100
					|| ent->energy < (entmax>>1)) {
					if (debug & 128 ||
					  (damage <= smarts/10 &&
					   !rand_mod(6-smarts/20-massacre) )) {
					    tmp = rand_mod(MAXDAMAGE);
					    if (damflag[tmp]) {
						if (damflag[tmp] < 60)
						  damflag[tmp] += rand_mod(60);
					    }
					    else {
						damflag[tmp] =
						  rand_mod(smarts+10)+2;
						damage++;
					    }
					}
				    }
				    break;
				}
				case Base:
				    if (base->energy > 1000 || apolloflag & 2)
					curobj->energy -= tmpblast /
					   ((apolloflag & 2)?20:5);
				    else
					curobj->energy -= tmpblast;
				    break;
				case Crusher:
				    if (tmpblast > 132767)
					curobj->energy -= (tmpblast - 100000);
				    else if (tmpblast >= 100000) {
					curobj->energy += (tmpblast - 100000);
					if (curobj->energy > 32767)
					    curobj->energy = 32767;
				    }
				    else	/* vulnerable while feeding */
					curobj->energy -= tmpblast;
				    break;
				case Enemy:
				    curobj->energy -= tmpblast*10/enemshields;
				    break;
				default:
				    curobj->energy -= tmpblast;
				    break;
				}
				if (curobj->energy < 0) {	/* killed it? */
				    switch (curobj->image) {
				    case 'A':
					tmpblast = 100000;
					make_blast(y,x,8192L,1);
					numapollos = apolloflag = 0;
					numstars--;
					numenemies--;
					curscore += 5000;
					deados = 0;
					break;
				    case 'E': case 'e': case 'C': case 'c':
					ent = 0;
					numents--;
					if (base)
					    status = 2;
					else
					    status = 3;
					deados = 0;
					break;
				    case 'B': case 'b':
					base = 0;
					numbases--;
					if (ent)
					    status = entmode;
					else
					    status = 3;
					deados = 0;
					break;
				    case '&': {
					int i, xxx, yyy;

					for (i = 0; i < YSIZE; i++)
					    yblasted[i] &= 1;
					for (i = 0; i < XSIZE; i++)
					    xblasted[i] &= 1;
					numamoebas = 0;	/* ignore amb[][] now */
					for (yyy = 0; yyy < YSIZE; yyy++) {
					    for (xxx = 0; xxx < XSIZE; xxx++) {
						if (amb[yyy][xxx] == '~' &&
						    !occupant[yyy][xxx]) {
						    mvaddch(yyy+1,xxx*2,' ');
						}
					    }
					}
					numenemies--;
					curscore += 10000;
					if (curobj == enemies)
					    enemies = curobj->next;
					deados = 0;
					break;
				    }
				    case '<': case '>': {
					int i;

					numenemies--;
					numcrushes = 0;
					curscore += 10000;
					if (curobj == movers)
					    movers = curobj->next;
					if (curobj == enemies)
					    enemies = curobj->next;
					deados = 0;

					tmpblast = 100000;
					make_blast(y,(x+XSIZE00)%XSIZE,10000L,0);
					if (curobj->image == '<') {
					    for (i=XSIZE00; i<=XSIZE01; i++)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					    for (i=XSIZE00; i<=XSIZE02; i++)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					    make_blast(y,(x+XSIZE03)%XSIZE,
						10000L,1);
					    for (i=XSIZE00; i<=XSIZE08; i++)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					}
					else {
					    for (i=XSIZE00; i>=XSIZE99; i--)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					    for (i=XSIZE00; i>=XSIZE98; i--)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					    make_blast(y,(x+XSIZE97)%XSIZE,
						10000L,1);
					    for (i=XSIZE00; i>=XSIZE92; i--)
						make_blast(y,(x+i)%XSIZE,
						    10000L,0);
					}
				    }
				    break;
				    case 'K':
					numenemies--;
					curscore += curobj->mass;
					if (curobj == enemies)
					    enemies = curobj->next;
					deados = 0;
					break;
				    case 'T':
					numenemies--;
					curscore += curobj->mass*3/2;
					if (curobj == enemies)
					    enemies = curobj->next;
					deados = 0;
					break;
				    case 'R': case ' ': case 'P':
					numenemies--;
					if (curobj->flags & PIRATE)
					    curscore += curobj->mass;
					else
					    curscore += curobj->mass*3;
					if (curobj == enemies)
					    enemies = curobj->next;
					deados = 0;
					break;
				    case 'G':
					numenemies--;
					numgorns--;
					tmpblast = 100000;
					if (madgorns)
					    curscore += curobj->mass/2;
					else
					    curscore += curobj->mass*2;
					if (curobj == enemies)
					    enemies = curobj->next;
					{
					    int xxx,yyy;

					    for (xxx = -1; xxx<=1; xxx++)
						for (yyy = -1; yyy<=1; yyy++)
						    if (rand_mod(2+massacre))
							fire_torp(curobj,
							    yyy,xxx);
					}
					deados = 0;
					break;
				    case '@':
					numinhab--;
					/* FALL THROUGH */
				    case '*':
					banging = true;
					numstars--;
					break;
				    case '|': case '-': case '/': case '\\':
					tmpblast = 100000;
					make_blast(y,x,curobj->mass,1);
					banging = true;
					deados = 0;
					break;
				    case 'x':
					curscore += 10;
					deados = 0;
					break;
				    case 'X':
					curscore += 100;
					numxes--;
					deados = 0;
					break;
				    case '0':
					curscore += 35;
					numos--;
					deados += 3;
					break;
				    case 'o':
					curscore += 100;
					numos--;
					deados++;
					break;
				    case 'O':
					curscore += 200;
					numos--;
					deados += 2;
					break;
				    case 'M':
					deadmudds++;
					inumfriends--;
					numfriends--;
					if (curobj == enemies)
					    enemies = curobj->next;
					break;
				    case 'Q': case 'W': case 'Y': case 'U':
				    case 'I': case 'S': case 'D': case 'H':
				    case 'J': case 'L': case 'Z': case 'V':
				    case 'F':
					numfriends--;
					if (curobj == enemies)
					    enemies = curobj->next;
					if (inumfriends < 10)
					    madfriends += 500;
					else
					    madfriends += 10000/inumfriends;
					break;
				    }
				    if (tmpblast < 100000)
					make_blast(y,x,curobj->mass,1);
				    unmake_object(curobj);
				}
				else {		/* didn't kill anything */
				    if (!biggie)
					biggie = curobj;
				    else {
					if (biggie->mass > curobj->mass)
					    bounce(curobj);
					else {
					    bounce(biggie);
					    biggie = curobj;
					}
				    }
				}
			    }
			    if (biggie) {
				occupant[y][x] = biggie;
				if (numamoebas && biggie->image == ' ')
				    mvaddch(y+1,x*2, amb[y][x]);
				else
				    mvaddch(y+1,x*2, biggie->image);
			    }
			    else {
				occupant[y][x] = 0;
				mvaddch(y+1, x*2, numamoebas ? amb[y][x] : ' ');
			    }
			}
		    }
		}
	    }
	}
    }
    do_bangs();
    if (numcrushes && movers->type == Crusher)
	movers->vely = 0;
    if ((curobj = base) != NULL) {
	char ch;

	curobj->velx = 0;
	curobj->vely = 0;
	curobj->energy += 25*lookaround(curobj->posy,curobj->posx,Star);
	if (curobj->energy > basemax)
	    curobj->energy = basemax;
	if (curobj->energy >= 1000)
	    ch = 'B';
	else
	    ch = 'b';
	if (ch != curobj->image) {
	    setimage(curobj, ch);
	}
    }
    if ((curobj = ent) != NULL) {
	char ch;

	if (entmode == 0) {
	    curobj->velx = 0;
	    curobj->vely = 0;
	}
	if (base && !cloaking && !curobj->velx && !curobj->vely &&
	  lookfor(curobj->posy,curobj->posx,Base)) {
	    int tmp;

#ifdef lint
	    tmp = 0;
#else
	    tmp = (int) (base->energy - 1000 < entmax - curobj->energy ?
		         base->energy - 1000 : entmax - curobj->energy);
#endif
	    if (tmp < 0)
		tmp = 0;
	    curobj->energy += tmp;
	    base->energy -= tmp;
	    tmp = (btorp < 50 - etorp ?
		   btorp : 50 - etorp);
	    etorp += tmp;
	    btorp -= tmp;
	    if (damage) {
		tmp = rand_mod(MAXDAMAGE);
		if (damflag[tmp] > 5) {
		    damflag[tmp] = rand_mod(5)+1;
		}
	    }
	}
	if (curobj->energy >= 500 && (!damage || !damflag[NOSHIELDS]))
	    ch = cloaked?'C':'E';
	else
	    ch = cloaked?'c':'e';
	if (ch != curobj->image) {
	    setimage(curobj, ch);
	}
    }
}

int
lookaround(int y, int x, char what)
{
    OBJECT *obj;
    int count=0;
    int xp;
    int xm;

    if ((obj=occupant[y][xp=(x+XSIZE01)%XSIZE])&&obj->type == what) /* 0, 1 */
	count++;
    if ((obj=occupant[y][xm=(x+XSIZE99)%XSIZE])&&obj->type == what) /* 0, -1 */
	count++;
    if ((obj=occupant[y=(y+YSIZE99)%YSIZE][xp])&&obj->type == what) /* -1, 1 */
	count++;
    if ((obj=occupant[y][x])&&obj->type == what)                    /* -1, 0 */
	count++;
    if ((obj=occupant[y][xm])&&obj->type == what)                   /* -1, -1 */
	count++;
    if ((obj=occupant[y=(y+2)%YSIZE][xp])&&obj->type == what)       /* 1, 1 */
	count++;
    if ((obj=occupant[y][x])&&obj->type == what)                    /* 1, 0 */
	count++;
    if ((obj=occupant[y][xm])&&obj->type == what)                   /* 1, -1 */
	count++;
    return (count);
}

int
lookfor(int y, int x, char what)
{
    OBJECT *obj;
    int xp;
    int xm;

    if (((obj=occupant[y][xp=(x+XSIZE01)%XSIZE])&&obj->type == what)||/* 0, 1 */
        ((obj=occupant[y][xm=(x+XSIZE99)%XSIZE])&&obj->type == what)||/* 0, -1 */
        ((obj=occupant[y=(y+YSIZE99)%YSIZE][xp])&&obj->type == what)||/* -1, 1 */
        ((obj=occupant[y][x])&&obj->type == what)                   ||/* -1, 0 */
        ((obj=occupant[y][xm])&&obj->type == what)                  ||/* -1,-1 */
        ((obj=occupant[y=(y+2)%YSIZE][xp])&&obj->type == what)      ||/* 1, 1 */
        ((obj=occupant[y][x])&&obj->type == what)                   ||/* 1, 0 */
        ((obj=occupant[y][xm])&&obj->type == what))                   /* 1, -1 */
	return(1);
    return (0);
}

OBJECT*
lookimg(int y, int x, char what)
{
    OBJECT *obj;
    int xp;
    int xm;

    if (((obj=occupant[y][xp=(x+XSIZE01)%XSIZE])&&obj->image==what)||/* 0, 1 */
        ((obj=occupant[y][xm=(x+XSIZE99)%XSIZE])&&obj->image==what)||/* 0, -1 */
        ((obj=occupant[y=(y+YSIZE99)%YSIZE][xp])&&obj->image==what)||/* -1, 1 */
        ((obj=occupant[y][x])&&obj->image==what)                   ||/* -1, 0 */
        ((obj=occupant[y][xm])&&obj->image==what)                  ||/* -1,-1 */
        ((obj=occupant[y=(y+2)%YSIZE][xp])&&obj->image==what)      ||/* 1, 1 */
        ((obj=occupant[y][x])&&obj->image==what)                   ||/* 1, 0 */
        ((obj=occupant[y][xm])&&obj->image==what))                   /* 1, -1 */
	return obj;
    return NULL;
}
