1/* Header: move.c,v 7.0.1.2 86/10/20 14:37:06 lwall Exp */
2
3/* Log:	move.c,v
4 * Revision 7.0.1.2  86/10/20  14:37:06  lwall
5 * Picked some lint.
6 *
7 * Revision 7.0.1.1  86/10/16  10:52:09  lwall
8 * Added Damage.  Fixed random bugs.
9 *
10 * Revision 7.0  86/10/08  15:12:40  lwall
11 * Split into separate files.  Added amoebas and pirates.
12 *
13 */
14
15#include "EXTERN.h"
16#include "warp.h"
17#include "bang.h"
18#include "object.h"
19#include "move.h"
20#include "play.h"
21#include "score.h"
22#include "term.h"
23#include "them.h"
24#include "us.h"
25#include "util.h"
26#include "weapon.h"
27#include "INTERN.h"
28#include "move.h"
29
30void
31move_init(void)
32{
33    ;
34}
35
36void
37bounce(OBJECT *obj)
38{
39    int x;
40    int y;
41    int count=0;
42
43    y = (obj->posy - sgn(obj->vely) + YSIZE00) % YSIZE;
44    x = (obj->posx - sgn(obj->velx) + XSIZE00) % XSIZE;
45    while (occupant[y][x]) {
46	y = (y + rand_mod(3) - 1 + YSIZE00) % YSIZE;
47	x = (x + rand_mod(3) - 1 + XSIZE00) % XSIZE;
48	if (++count > 10000) {     /* if universe full, get out of it fast */
49	    unmake_object(obj);
50	    if (ent) unmake_object(ent);
51	    if (base) unmake_object(base);
52	    finish = 1;
53	    return;
54	}
55    }
56    obj->posy = y;
57    obj->posx = x;
58    obj->vely = 0;
59    obj->velx = 0;
60    occupant[y][x] = obj;
61    if (numamoebas && obj->image == ' ')
62	mvaddc(y+1, x*2, amb[y][x]);
63    else
64	mvaddc(y+1, x*2, obj->image);
65}
66
67void
68move_universe(void)
69{
70    OBJECT *curobj;
71    int x;
72    int y;
73    OBJECT *temp;
74    OBJECT *thenext;
75
76    for (curobj = movers; curobj != &root; curobj = curobj->next) {
77	x = curobj->posx;
78	y = curobj->posy;
79	if (curobj == occupant[y][x]) {
80	    occupant[y][x] = 0;
81	}
82	else if (curobj->type != Torp && curobj->type != Web) {
83	    resetty();
84	    abort();
85	}
86    }
87    for (curobj = movers; curobj != &root; curobj = thenext) {
88	thenext = curobj->next;
89	if (curobj->vely || curobj->velx) {
90	    y = curobj->posy;
91	    x = curobj->posx;
92	    if (curobj->image != ' ' &&
93	      (!(temp=occupant[y][x]) || temp->image==' ') ) {
94		move(y+1, x*2, numamoebas ? amb[y][x] : ' ');
95	    }
96	    y = (y + curobj->vely + YSIZE00) % YSIZE;
97	    x = (x + curobj->velx + XSIZE00) % XSIZE;
98	    if (!(temp=occupant[y][x]) || temp->type != Star ||
99	      curobj->type != Torp || curobj->image == '+' ||
100	      curobj->image == 'x') {
101		curobj->posy = y;
102		curobj->posx = x;
103	    }
104	    else {
105		if (curobj->image == '0') {
106		    curobj->vely = rand_mod(3)-1;
107		    curobj->velx = rand_mod(3)-1;
108		}
109		else
110		    curobj->vely = curobj->velx = 0;
111		y = curobj->posy;
112		x = curobj->posx;
113	    }
114	}
115	else {			/* not moving */
116	    y = curobj->posy;
117	    x = curobj->posx;
118	    if (curobj->type == Torp ||
119		curobj->type == Star ||
120		curobj->type == Web) {
121		curobj->flags |= STATIC;
122		curobj->next->prev = curobj->prev;
123		curobj->prev->next = curobj->next;
124		curobj->prev = movers->prev;
125		curobj->next = movers;
126		movers->prev->next = curobj;
127		movers->prev = curobj;
128	    }
129	}
130	if ((temp = occupant[y][x]) != NULL) {		/* already occupied? */
131	    if (!temp->contend) {
132		if (temp->type == Torp) {
133		    if (temp->image == '+')
134			blast[y][x] += 1250;
135		    else if (temp->image == 'o' && (base||ent))
136			blast[y][x] += 500+super*20;
137		    else if (temp->image == 'O' && (base||ent))
138			blast[y][x] += 5000+super*100;
139		}
140	    }
141	    yblasted[y] |= 1;
142	    xblasted[x] |= 1;
143	    blasted = true;
144	    curobj->contend = temp;
145	    occupant[y][x] = curobj;
146	    switch (curobj->type) {
147	    case Enemy:
148		if (numamoebas && curobj == nuke && temp->image == '+')
149		    blast[y][x] += 80000;
150		else if (temp->type == Enemy)
151		    blast[y][x] += 10;
152		else
153		    goto defblast;
154		break;
155	    case Crusher:
156		if (curobj->velx)
157		    blast[y][x] += 100000;
158		else
159		    goto defblast;
160		break;
161	    case Torp:
162		if (curobj->image == '+')
163		    blast[y][x] += (temp==nuke ? 80000 : 1250);
164		else if (curobj->image == 'o')
165		    blast[y][x] += 500+super*20;
166		else if (curobj->image == 'O')
167		    blast[y][x] += 5000+super*100;
168		goto defblast;
169	    case Star:
170		if (temp == ent)
171		    goto damshield;
172		goto defblast;
173	    case Enterprise:
174		if (temp->type == Star) {
175	      damshield:
176		    if (!rand_mod(10)) {
177			if (!damflag[NOSHIELDS])
178			    damage++;
179			if (damflag[NOSHIELDS] < 100)
180			    damflag[NOSHIELDS] += rand_mod(smarts)/5+2;
181		    }
182		}
183		goto defblast;
184	    default:
185	      defblast:
186		blast[y][x] += rand_mod(751)+1;
187		break;
188	    }
189	}
190	else {
191	    occupant[y][x] = curobj;
192	    if (curobj->image != ' ' &&
193	        (curobj->velx || curobj->vely ||
194		 curobj->type == Torp || curobj->type == Web) ) {
195		mvaddc(y+1, x*2, curobj->image);
196	    }
197	    if (curobj->type == Crusher && curobj->velx) {
198		blast[y][x] += 100000;
199		yblasted[y] |= 1;
200		xblasted[x] |= 1;
201		blasted = true;
202	    }
203	}
204    }
205    if (blasted) {
206	int minxblast = -1;
207	int maxxblast = -2;
208	long tmpblast;
209
210	blasted = numamoebas;
211	for (x=0; x<XSIZE; x++) {
212	    if (xblasted[x]) {
213		xblasted[x] = 0;
214		maxxblast = x;
215		if (minxblast < 0)
216		    minxblast = x;
217	    }
218	}
219	for (y=0; y<YSIZE; y++) {
220	    if (yblasted[y]) {
221		yblasted[y] = 0;
222		for (x=minxblast; x<=maxxblast; x++) {
223		    tmpblast = blast[y][x];
224		    if (numamoebas && amb[y][x] == '~') {
225			if ((temp = occupant[y][x]) != NULL) {
226			    if (temp->image == '&')
227				tmpblast >>= 1;
228			    else if (temp->type == Web)
229				tmpblast = 100000;
230			    else
231				tmpblast += 50 + temp->energy/100;
232			    if (tmpblast > 250 && !rand_mod(5+(inumstars>>4)))
233				modify_amoeba(y,x,1,'~',5);
234			}
235			xblasted[x] = 2;
236			yblasted[y] = 2;
237		    }
238		    if (tmpblast) {
239			OBJECT *biggie = 0;
240
241			blast[y][x] = 0;
242			temp = occupant[y][x];
243			if (tmpblast < 0) {
244			    if (numamoebas && tmpblast < -1000000 &&
245				amb[y][x] == '~' && temp != nuke) {
246				amb[y][x] = ' ';
247				if (!temp)
248				    make_plink(y,x);
249				ambsize--;
250			    }
251			    tmpblast = 0;
252			}
253			if (temp) {
254			    if ((!numamoebas || amb[y][x]==' ') &&
255			      tmpblast < 100000)
256				make_plink(y,x);
257			    for ( ;temp;
258			      temp = curobj->contend,curobj->contend = 0){
259				curobj = temp;
260				switch (curobj->type) {
261				case Enterprise: {
262				    long tmp = curobj->energy;
263
264				    if (ent->energy>500 || apolloflag & 1)
265					curobj->energy -= tmpblast /
266					   ((apolloflag & 1)
267					    ? 20
268					    : (5+abs(ent->velx)+abs(ent->vely))
269					       / ((damflag[NOSHIELDS]>>3)+1)+1);
270				    else
271					curobj->energy -= tmpblast;
272				    if (rand_mod(1 + tmp - curobj->energy) > 100
273					|| ent->energy < (entmax>>1)) {
274					if (debug & 128 ||
275					  (damage <= smarts/10 &&
276					   !rand_mod(6-smarts/20-massacre) )) {
277					    tmp = rand_mod(MAXDAMAGE);
278					    if (damflag[tmp]) {
279						if (damflag[tmp] < 60)
280						  damflag[tmp] += rand_mod(60);
281					    }
282					    else {
283						damflag[tmp] =
284						  rand_mod(smarts+10)+2;
285						damage++;
286					    }
287					}
288				    }
289				    break;
290				}
291				case Base:
292				    if (base->energy > 1000 || apolloflag & 2)
293					curobj->energy -= tmpblast /
294					   ((apolloflag & 2)?20:5);
295				    else
296					curobj->energy -= tmpblast;
297				    break;
298				case Crusher:
299				    if (tmpblast > 132767)
300					curobj->energy -= (tmpblast - 100000);
301				    else if (tmpblast >= 100000) {
302					curobj->energy += (tmpblast - 100000);
303					if (curobj->energy > 32767)
304					    curobj->energy = 32767;
305				    }
306				    else	/* vulnerable while feeding */
307					curobj->energy -= tmpblast;
308				    break;
309				case Enemy:
310				    curobj->energy -= tmpblast*10/enemshields;
311				    break;
312				default:
313				    curobj->energy -= tmpblast;
314				    break;
315				}
316				if (curobj->energy < 0) {	/* killed it? */
317				    switch (curobj->image) {
318				    case 'A':
319					tmpblast = 100000;
320					make_blast(y,x,8192L,1);
321					numapollos = apolloflag = 0;
322					numstars--;
323					numenemies--;
324					curscore += 5000;
325					deados = 0;
326					break;
327				    case 'E': case 'e': case 'C': case 'c':
328					ent = 0;
329					numents--;
330					if (base)
331					    status = 2;
332					else
333					    status = 3;
334					deados = 0;
335					break;
336				    case 'B': case 'b':
337					base = 0;
338					numbases--;
339					if (ent)
340					    status = entmode;
341					else
342					    status = 3;
343					deados = 0;
344					break;
345				    case '&': {
346					int i, xxx, yyy;
347
348					for (i = 0; i < YSIZE; i++)
349					    yblasted[i] &= 1;
350					for (i = 0; i < XSIZE; i++)
351					    xblasted[i] &= 1;
352					numamoebas = 0;	/* ignore amb[][] now */
353					for (yyy = 0; yyy < YSIZE; yyy++) {
354					    for (xxx = 0; xxx < XSIZE; xxx++) {
355						if (amb[yyy][xxx] == '~' &&
356						    !occupant[yyy][xxx]) {
357						    mvaddch(yyy+1,xxx*2,' ');
358						}
359					    }
360					}
361					numenemies--;
362					curscore += 10000;
363					if (curobj == enemies)
364					    enemies = curobj->next;
365					deados = 0;
366					break;
367				    }
368				    case '<': case '>': {
369					int i;
370
371					numenemies--;
372					numcrushes = 0;
373					curscore += 10000;
374					if (curobj == movers)
375					    movers = curobj->next;
376					if (curobj == enemies)
377					    enemies = curobj->next;
378					deados = 0;
379
380					tmpblast = 100000;
381					make_blast(y,(x+XSIZE00)%XSIZE,10000L,0);
382					if (curobj->image == '<') {
383					    for (i=XSIZE00; i<=XSIZE01; i++)
384						make_blast(y,(x+i)%XSIZE,
385						    10000L,0);
386					    for (i=XSIZE00; i<=XSIZE02; i++)
387						make_blast(y,(x+i)%XSIZE,
388						    10000L,0);
389					    make_blast(y,(x+XSIZE03)%XSIZE,
390						10000L,1);
391					    for (i=XSIZE00; i<=XSIZE08; i++)
392						make_blast(y,(x+i)%XSIZE,
393						    10000L,0);
394					}
395					else {
396					    for (i=XSIZE00; i>=XSIZE99; i--)
397						make_blast(y,(x+i)%XSIZE,
398						    10000L,0);
399					    for (i=XSIZE00; i>=XSIZE98; i--)
400						make_blast(y,(x+i)%XSIZE,
401						    10000L,0);
402					    make_blast(y,(x+XSIZE97)%XSIZE,
403						10000L,1);
404					    for (i=XSIZE00; i>=XSIZE92; i--)
405						make_blast(y,(x+i)%XSIZE,
406						    10000L,0);
407					}
408				    }
409				    break;
410				    case 'K':
411					numenemies--;
412					curscore += curobj->mass;
413					if (curobj == enemies)
414					    enemies = curobj->next;
415					deados = 0;
416					break;
417				    case 'T':
418					numenemies--;
419					curscore += curobj->mass*3/2;
420					if (curobj == enemies)
421					    enemies = curobj->next;
422					deados = 0;
423					break;
424				    case 'R': case ' ': case 'P':
425					numenemies--;
426					if (curobj->flags & PIRATE)
427					    curscore += curobj->mass;
428					else
429					    curscore += curobj->mass*3;
430					if (curobj == enemies)
431					    enemies = curobj->next;
432					deados = 0;
433					break;
434				    case 'G':
435					numenemies--;
436					numgorns--;
437					tmpblast = 100000;
438					if (madgorns)
439					    curscore += curobj->mass/2;
440					else
441					    curscore += curobj->mass*2;
442					if (curobj == enemies)
443					    enemies = curobj->next;
444					{
445					    int xxx,yyy;
446
447					    for (xxx = -1; xxx<=1; xxx++)
448						for (yyy = -1; yyy<=1; yyy++)
449						    if (rand_mod(2+massacre))
450							fire_torp(curobj,
451							    yyy,xxx);
452					}
453					deados = 0;
454					break;
455				    case '@':
456					numinhab--;
457					/* FALL THROUGH */
458				    case '*':
459					banging = true;
460					numstars--;
461					break;
462				    case '|': case '-': case '/': case '\\':
463					tmpblast = 100000;
464					make_blast(y,x,curobj->mass,1);
465					banging = true;
466					deados = 0;
467					break;
468				    case 'x':
469					curscore += 10;
470					deados = 0;
471					break;
472				    case 'X':
473					curscore += 100;
474					numxes--;
475					deados = 0;
476					break;
477				    case '0':
478					curscore += 35;
479					numos--;
480					deados += 3;
481					break;
482				    case 'o':
483					curscore += 100;
484					numos--;
485					deados++;
486					break;
487				    case 'O':
488					curscore += 200;
489					numos--;
490					deados += 2;
491					break;
492				    case 'M':
493					deadmudds++;
494					inumfriends--;
495					numfriends--;
496					if (curobj == enemies)
497					    enemies = curobj->next;
498					break;
499				    case 'Q': case 'W': case 'Y': case 'U':
500				    case 'I': case 'S': case 'D': case 'H':
501				    case 'J': case 'L': case 'Z': case 'V':
502				    case 'F':
503					numfriends--;
504					if (curobj == enemies)
505					    enemies = curobj->next;
506					if (inumfriends < 10)
507					    madfriends += 500;
508					else
509					    madfriends += 10000/inumfriends;
510					break;
511				    }
512				    if (tmpblast < 100000)
513					make_blast(y,x,curobj->mass,1);
514				    unmake_object(curobj);
515				}
516				else {		/* didn't kill anything */
517				    if (!biggie)
518					biggie = curobj;
519				    else {
520					if (biggie->mass > curobj->mass)
521					    bounce(curobj);
522					else {
523					    bounce(biggie);
524					    biggie = curobj;
525					}
526				    }
527				}
528			    }
529			    if (biggie) {
530				occupant[y][x] = biggie;
531				if (numamoebas && biggie->image == ' ')
532				    mvaddch(y+1,x*2, amb[y][x]);
533				else
534				    mvaddch(y+1,x*2, biggie->image);
535			    }
536			    else {
537				occupant[y][x] = 0;
538				mvaddch(y+1, x*2, numamoebas ? amb[y][x] : ' ');
539			    }
540			}
541		    }
542		}
543	    }
544	}
545    }
546    do_bangs();
547    if (numcrushes && movers->type == Crusher)
548	movers->vely = 0;
549    if ((curobj = base) != NULL) {
550	char ch;
551
552	curobj->velx = 0;
553	curobj->vely = 0;
554	curobj->energy += 25*lookaround(curobj->posy,curobj->posx,Star);
555	if (curobj->energy > basemax)
556	    curobj->energy = basemax;
557	if (curobj->energy >= 1000)
558	    ch = 'B';
559	else
560	    ch = 'b';
561	if (ch != curobj->image) {
562	    setimage(curobj, ch);
563	}
564    }
565    if ((curobj = ent) != NULL) {
566	char ch;
567
568	if (entmode == 0) {
569	    curobj->velx = 0;
570	    curobj->vely = 0;
571	}
572	if (base && !cloaking && !curobj->velx && !curobj->vely &&
573	  lookfor(curobj->posy,curobj->posx,Base)) {
574	    int tmp;
575
576#ifdef lint
577	    tmp = 0;
578#else
579	    tmp = (int) (base->energy - 1000 < entmax - curobj->energy ?
580		         base->energy - 1000 : entmax - curobj->energy);
581#endif
582	    if (tmp < 0)
583		tmp = 0;
584	    curobj->energy += tmp;
585	    base->energy -= tmp;
586	    tmp = (btorp < 50 - etorp ?
587		   btorp : 50 - etorp);
588	    etorp += tmp;
589	    btorp -= tmp;
590	    if (damage) {
591		tmp = rand_mod(MAXDAMAGE);
592		if (damflag[tmp] > 5) {
593		    damflag[tmp] = rand_mod(5)+1;
594		}
595	    }
596	}
597	if (curobj->energy >= 500 && (!damage || !damflag[NOSHIELDS]))
598	    ch = cloaked?'C':'E';
599	else
600	    ch = cloaked?'c':'e';
601	if (ch != curobj->image) {
602	    setimage(curobj, ch);
603	}
604    }
605}
606
607int
608lookaround(int y, int x, char what)
609{
610    OBJECT *obj;
611    int count=0;
612    int xp;
613    int xm;
614
615    if ((obj=occupant[y][xp=(x+XSIZE01)%XSIZE])&&obj->type == what) /* 0, 1 */
616	count++;
617    if ((obj=occupant[y][xm=(x+XSIZE99)%XSIZE])&&obj->type == what) /* 0, -1 */
618	count++;
619    if ((obj=occupant[y=(y+YSIZE99)%YSIZE][xp])&&obj->type == what) /* -1, 1 */
620	count++;
621    if ((obj=occupant[y][x])&&obj->type == what)                    /* -1, 0 */
622	count++;
623    if ((obj=occupant[y][xm])&&obj->type == what)                   /* -1, -1 */
624	count++;
625    if ((obj=occupant[y=(y+2)%YSIZE][xp])&&obj->type == what)       /* 1, 1 */
626	count++;
627    if ((obj=occupant[y][x])&&obj->type == what)                    /* 1, 0 */
628	count++;
629    if ((obj=occupant[y][xm])&&obj->type == what)                   /* 1, -1 */
630	count++;
631    return (count);
632}
633
634int
635lookfor(int y, int x, char what)
636{
637    OBJECT *obj;
638    int xp;
639    int xm;
640
641    if (((obj=occupant[y][xp=(x+XSIZE01)%XSIZE])&&obj->type == what)||/* 0, 1 */
642        ((obj=occupant[y][xm=(x+XSIZE99)%XSIZE])&&obj->type == what)||/* 0, -1 */
643        ((obj=occupant[y=(y+YSIZE99)%YSIZE][xp])&&obj->type == what)||/* -1, 1 */
644        ((obj=occupant[y][x])&&obj->type == what)                   ||/* -1, 0 */
645        ((obj=occupant[y][xm])&&obj->type == what)                  ||/* -1,-1 */
646        ((obj=occupant[y=(y+2)%YSIZE][xp])&&obj->type == what)      ||/* 1, 1 */
647        ((obj=occupant[y][x])&&obj->type == what)                   ||/* 1, 0 */
648        ((obj=occupant[y][xm])&&obj->type == what))                   /* 1, -1 */
649	return(1);
650    return (0);
651}
652
653OBJECT*
654lookimg(int y, int x, char what)
655{
656    OBJECT *obj;
657    int xp;
658    int xm;
659
660    if (((obj=occupant[y][xp=(x+XSIZE01)%XSIZE])&&obj->image==what)||/* 0, 1 */
661        ((obj=occupant[y][xm=(x+XSIZE99)%XSIZE])&&obj->image==what)||/* 0, -1 */
662        ((obj=occupant[y=(y+YSIZE99)%YSIZE][xp])&&obj->image==what)||/* -1, 1 */
663        ((obj=occupant[y][x])&&obj->image==what)                   ||/* -1, 0 */
664        ((obj=occupant[y][xm])&&obj->image==what)                  ||/* -1,-1 */
665        ((obj=occupant[y=(y+2)%YSIZE][xp])&&obj->image==what)      ||/* 1, 1 */
666        ((obj=occupant[y][x])&&obj->image==what)                   ||/* 1, 0 */
667        ((obj=occupant[y][xm])&&obj->image==what))                   /* 1, -1 */
668	return obj;
669    return NULL;
670}
671