1 /*
2  *  Play a game of Tag..  this is kind of like the Anti-Swarm
3  *  instead of heading towards 'IT' .. everyone runs away from it
4  *	Written by Jer (mpython@gnu.ai.mit.edu , jer@gulik.gweep.net)
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <X11/X.h>
10 #include <X11/Xlib.h>
11 #include "lmath.h"
12 #include "trippy.h"
13 
14 #ifdef WINDOWS
15 extern foo options;
16 extern HPALETTE hPal;
17 #endif
18 
19 #define sgn(x)  ((x)==0?0:((x)>0?1:-1))
20 
21 struct kid
22 {
23   long x,y;
24   long oldx,oldy;
25   signed int vx,vy;
26   signed int maxvx, maxvy;
27   unsigned int color;
28 };
29 
30 int cur_kid;
31 
32 struct kid  **playground_p;
33 struct kid  **it;
34 struct kid  **it_target;
35 struct kid  **last_it;
36 
37 static struct kid* findClosestKid(int);
38 
39 void
init_it(int winno)40 init_it(int winno)
41 {
42 
43   it[winno] = &playground_p[winno][rndm(options.number)];
44   last_it[winno]=0;
45 #ifdef WINDOWS
46   it[winno]->color = GetNearestPaletteIndex(hPal,RGB(0,255,255));
47 #else
48   it[winno]->color = 3*numcolors/6; /* CYAN */
49 #endif
50   it_target[winno] = findClosestKid(winno);
51 }
52 
53 void
init_kid(int winno,struct kid * pt)54 init_kid (int winno, struct kid *pt)
55 {
56   pt->x = (long)rndm(CX[winno])*64;
57   pt->y = (long)rndm(CY[winno])*64;
58   pt->oldx = pt->x;
59   pt->oldy = pt->y;
60   pt->vx= pt->vy=0;
61   pt->maxvx = rndm(8*64)+64;
62   pt->maxvy = rndm(8*64)+64;
63 
64   if(options.multi)
65     pt->color = rndm(numcolors);
66   else
67 #ifdef WINDOWS
68     pt->color=GetNearestPaletteIndex(hPal,RGB(255,255,0));
69 #else
70     pt->color=numcolors/6; /* YELLOW */
71 #endif
72 }
73 
74 void
draw_kid(int winno,struct kid * b)75 draw_kid (int winno, struct kid  *b)
76 {
77   XDrawLine (display, window[winno], color_gcs[b->color], b->x/64,b->y/64,
78 	     b->oldx/64, b->oldy/64);
79 }
80 
81 void
clear_kid(int winno,struct kid * b)82 clear_kid (int winno, struct kid  *b)
83 {
84   XDrawLine (display, window[winno], color_gcs[0], b->x/64, b->y/64,
85 	     b->oldx/64, b->oldy/64);
86 }
87 
88 void
moveIt(int winno,long x,long y)89 moveIt(int winno, long x, long y)
90 {
91   clear_kid(winno,it[winno]);
92   it[winno]->x = x*64;
93   it[winno]->y = y*64;
94   it[winno]->vx = it[winno]->vy = 0;
95 }
96 
97 int
update_kid(int winno,struct kid * b)98 update_kid (int winno, struct kid * b)
99 {
100   long x, y;
101   unsigned long usecx = (long)CX[winno]*64;
102   unsigned long usecy = (long)CY[winno]*64;
103 
104   clear_kid (winno, b);
105 
106   x = b->x; y = b->y;
107   if(b==it[winno])
108   {
109     b->vx += sgn(it_target[winno]->x - x)*16;
110     b->vy += sgn(it_target[winno]->y - y)*16;
111   }
112   else
113   {
114     if(math_dist(b->x,b->y,it_target[winno]->x,it_target[winno]->y)<(32*64))
115     {  /* too close, run away!!! */
116       b->vx += -sgn(it[winno]->x-x)*16;
117       b->vy += -sgn(it[winno]->y-y)*16;
118     }
119     else
120     {
121       b->vx >>=1;  /* slow down by half */
122       b->vy >>=1;
123     }
124 
125 #if 0
126     else /* head back into the middle */
127     {
128       b->vx += sgn(usecx>>1-x)*16;
129       b->vy += sgn(usecy>>1-y)*16;
130     }
131 #endif
132   }
133 
134   if(abs(b->vx)>b->maxvx) b->vx=b->maxvx*sgn(b->vx);
135   if(abs(b->vy)>b->maxvy) b->vy=b->maxvy*sgn(b->vy);
136 
137   b->x += b->vx + (rndm(3)-1);
138   b->y += b->vy + (rndm(3)-1);
139 
140 /* keep everyone in the playyard */
141   if(b->x<0)
142   {
143     b->x= 0;
144     b->vx = 0;
145   }
146   else if (b->x>=usecx)
147   {
148     b->x= usecx-64;
149     b->vx = 0;
150   }
151   if(b->y<0)
152   {
153     b->y= 0;
154     b->vy =0;
155   }
156   else if(b->y>=usecy)
157   {
158     b->y= usecy-64;
159     b->vy = 0;
160   }
161 
162   b->oldx = x; b->oldy = y;
163 
164   draw_kid (winno, b);
165   if(options.multi)
166     b->color = (b->color+1)%numcolors;
167   return 0;
168 }
169 
170 int
update_it(int winno)171 update_it(int winno)
172 {
173   /*
174   if(!rndm(100) || (it[winno].x == it_target_x) &&
175 		   (it[winno].y == it_target_y))
176   {
177     it_target_x = (long)rndm(CX[winno])*64;
178     it_target_y = (long)rndm(CY[winno])*64;
179   }
180   */
181   it_target[winno] = findClosestKid(winno);
182 
183 /*  update_kid(winno,&it[winno],it_target_x,it_target_y); */
184   return 0;
185 }
186 
187 struct kid*
findClosestKid(int winno)188 findClosestKid(int winno)
189 {
190   int d = 999999,temp_d;
191   int i, itnum;
192   struct kid* temp=0;
193 
194   itnum=-1;
195   for (i=0;i<options.number;i++)
196   {
197     if(&playground_p[winno][i]==it[winno])
198       continue;
199     if(&playground_p[winno][i]==last_it[winno])
200       continue;
201 
202     if((temp_d=math_dist(it[winno]->x,it[winno]->y,
203 			 playground_p[winno][i].x,playground_p[winno][i].y))<d)
204     {
205       d=temp_d;
206       temp=&playground_p[winno][i];
207       itnum=i;
208       if(d<=64)  /* gotcha */
209         break;
210     }
211   }
212 
213   if(d<=64) /* TAG! no tagbacks */
214   {
215     it[winno]->color = numcolors/6; /* YELLOW */
216     last_it[winno] = it[winno];
217     it[winno] = temp;
218     it[winno]->color = 3*numcolors/6; /* CYAN */
219     it_target[winno] = &playground_p[winno][rndm(options.number)];
220     fprintf(stderr,"TAG! #%d is it\n",itnum);
221     return it_target[winno];
222 
223   }
224   else
225     return temp;
226 }
227 
228 static int inited=0;
229 
230 void
init_playground(int winno)231 init_playground(int winno)
232 {
233   if(!inited)
234   {
235     playground_p=(struct kid  * *) malloc((sizeof(struct kid *) *
236 					   options.windows));
237     it = (struct kid  **) malloc((sizeof(struct kid )*options.windows));
238     it_target =(struct kid  **) malloc((sizeof(struct kid )*options.windows));
239     last_it =  (struct kid  **) malloc((sizeof(struct kid )*options.windows));
240     inited=1;
241   }
242 
243   if(options.number < 3)
244   {
245     options.number=3;  /* you need at least 3 to play tag */
246   }
247 
248 
249   playground_p[winno] = (struct kid  *) malloc(sizeof (struct kid ) *
250 					       options.number);
251 
252   for (cur_kid=0; cur_kid<options.number; cur_kid++)
253   {
254     init_kid (winno,&(playground_p[winno][cur_kid]));
255     draw_kid (winno,&(playground_p[winno][cur_kid]));
256   }
257   init_it(winno);
258 }
259 
260 void
exit_playground(int winno)261 exit_playground(int winno)
262 {
263   if(inited)
264   {
265     free(playground_p[winno]);
266     free(playground_p);
267     free(it);
268     free(it_target);
269     free(last_it);
270     inited=0;
271   }
272 }
273 
274 void
exit_tag()275 exit_tag()
276 {
277   exit_playground(0);
278 }
279 
280 void
draw_playground(int winno)281 draw_playground(int winno)
282 {
283   for(cur_kid=0;cur_kid<options.number;cur_kid++)
284   {
285     update_kid(winno,&(playground_p[winno][cur_kid]));
286   }
287   update_it(winno);
288 }
289