]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/swar/swar.c
bring games/swar from 1ed sources.
[plan9front.git] / sys / src / games / swar / swar.c
1 /*
2  * swar -- jerq space war
3  * td&rob 84.01.01
4  *
5  * ported to 9front on 31jul2021
6  */
7 #include <u.h>
8 #include <libc.h>
9 #include <draw.h>
10 #include <event.h>
11 int xc, yc;
12 #define NOBJ    (1+2+6*2)
13 #define MSPEED  (V/32)                          /* speed of missile relative to ship */
14 #define SZ      512                             /* maximum scaled coordinate */
15 #define V       256                             /* velocity scale factor */
16 #define G       (V*11585)                       /* 11585 is SZ**(3./2.) */
17 #define ALIVE   1
18 #define DEAD    2
19 #define SUN     3
20 #define BOOM    4
21 #define HYPER   5
22 #define SLEEP   40                              /* ms per iteration */
23 #define TUBA    (2000/SLEEP)                    /* iterations until born again */
24 #define HYTIME  ((600+rand()%600)/SLEEP)        /* iterations in hyperspace */
25 char *starbits[]={
26 #include "deathstar.icon"
27 };
28 Image *stardwg;
29 Rectangle starrect={0, 0, 16, 16};
30 char *p0bits[]={
31 #include "player0.icon"
32 };
33 Image *p0dwg;
34 Rectangle p0rect={0, 0, 44, 44};
35 char *p1bits[]={
36 #include "player1.icon"
37 };
38 Image *p1dwg;
39 Rectangle p1rect={0, 0, 44, 44};
40 char *misbits[]={
41 #include "missile.icon"
42 };
43 Image *misdwg;
44 Rectangle misrect={0, 0, 32, 32};
45 char *boombits[]={
46 #include "boom.icon"
47 };
48 Image *boomdwg;
49 Rectangle boomrect={0, 0, 64, 64};
50 struct obj{
51         int x, y;
52         int vx, vy;             /* scaled by V */
53         int orientation;
54         int state;
55         int diameter;
56         Image *bp;
57         int curdwg;
58 #define wrapped timer
59         int timer;
60 }obj[NOBJ], iobj[]={
61         {0, 0, 0, 0, 0, SUN, 16},
62         { 300, 0, 0,  5*V, 8, ALIVE, 11, 0, 0, TUBA},
63         {-300, 0, 0, -5*V, 0, ALIVE, 11, 0, 0, TUBA},
64         {0, 0, 0, 0, 0, ALIVE, 8},
65 };
66 #define ATT     (&obj[0])
67 #define P0      (&obj[1])
68 #define P1      (&obj[2])
69 int score[3];
70 #define NORIENTATION    16
71 struct dv{
72         int x, y;
73 }dv[NORIENTATION]={
74 #include "accel.h"
75 };
76
77 int xc, yc, size;
78 void kbdplayer(int c);
79 void hyper(struct obj *o);
80 void right(struct obj *o);
81 void left(struct obj *o);
82 void jerk(struct obj *o);
83 int isqrt(int x);
84 void fire(struct obj *o);
85 void initobj(struct obj *o);
86 void deathto(struct obj *o, int doboom);
87 void boom(struct obj *o);
88 void shards(struct obj *o);
89 void move(struct obj *o);
90 void blot(struct obj *o, int dwg);
91 void collide(struct obj *o, struct obj *p);
92 void newscore(struct obj *o, struct obj *p);
93 void drawscore(char *str, int sc, int where);
94 void doscore(void);
95 Image *initbitmap(char *bits[], Rectangle r);
96
97 #define sq(x)   ((x)*(x))
98 #define muldiv(a, b, c) ((a)*(b)/(c))
99
100 int
101 min(int a, int b)
102 {
103         return a<b? a: b;
104 }
105
106 int
107 abs(int a)
108 {
109         return a<0? -a: a;
110 }
111
112 void
113 redraw(void)
114 {
115         draw(screen, screen->r, display->black, nil, ZP);
116         blot(ATT, ATT->orientation);
117         doscore();
118 }
119
120 void
121 eresized(int)
122 {
123         if(getwindow(display, Refnone) < 0)
124                 sysfatal("resized");
125         xc=(screen->r.min.x+screen->r.max.x)/2;
126         yc=(screen->r.min.y+screen->r.max.y)/2;
127         size=min(screen->r.max.x-screen->r.min.x,
128                 screen->r.max.y-screen->r.min.y)/2;
129         redraw();
130 }
131
132 void
133 main(void)
134 {
135         struct obj *o, *p;
136
137         initdraw(nil,nil,nil);
138         einit(Ekeyboard|Emouse);
139
140         iobj[0].bp = stardwg = initbitmap(starbits, starrect);
141         iobj[1].bp = p0dwg = initbitmap(p0bits, p0rect);
142         iobj[2].bp = p1dwg = initbitmap(p1bits, p1rect);
143         iobj[3].bp = misdwg = initbitmap(misbits, misrect);
144         boomdwg = initbitmap(boombits, boomrect);
145
146         xc=(screen->r.min.x+screen->r.max.x)/2;
147         yc=(screen->r.min.y+screen->r.max.y)/2;
148         size=min(screen->r.max.x-screen->r.min.x,
149                 screen->r.max.y-screen->r.min.y)/2;
150
151         for(o=obj;o<=P1;o++)
152                 initobj(o);
153
154         for(;o!=&obj[NOBJ];o++)
155                 o->state=DEAD;
156
157         for(;;){
158                 redraw();
159                 for(o=obj;o!=&obj[NOBJ];o++){
160                         switch(o->state){
161                         case ALIVE:
162                         case SUN:
163                                 for(p=o+1;p!=&obj[NOBJ];p++)
164                                         if(p->state!=DEAD)
165                                                 collide(o, p);
166                                 if(o>P1)
167                                         left(o);
168                                 move(o);
169                                 break;
170                         case HYPER:
171                                 if(--o->timer==0){
172                                         blot(o, o->curdwg);
173                                         o->state=ALIVE;
174                                         if(rand()%4==0){
175                                                 deathto(o, 1);
176                                                 newscore(ATT, o);
177                                         }
178                                 }else
179                                         move(o);
180                                 break;
181                         case DEAD:
182                                 if((o==P0 || o==P1) && --o->timer==0)
183                                         initobj(o);
184                                 break;
185                         case BOOM:
186                                 shards(o);
187                                 move(o);
188                                 break;
189                         }
190                 }
191                 flushimage(display, 1);
192                 while(ecanmouse()) emouse();
193                 if(ecankbd()) kbdplayer(ekbd());
194                 sleep(SLEEP);
195         }
196 }
197 void kbdplayer(int c){
198         switch(c){
199         case 'k': left(P0);     break;
200         case 'o': jerk(P0);     break;
201         case ';': right(P0);    break;
202         case 'l': fire(P0);     break;
203         case '.':
204         case ',': hyper(P0);    break;
205         case 'a': left(P1);     break;
206         case 'w': jerk(P1);     break;
207         case 'd': right(P1);    break;
208         case 's': fire(P1);     break;
209         case 'z':
210         case 'x': hyper(P1);    break;
211         case 'Q': exits("");    break;
212         }
213 }
214 void hyper(struct obj *o){
215         if(o->state!=ALIVE)
216                 return;
217         o->state=HYPER;
218         o->timer=HYTIME;
219         blot(o, o->curdwg);
220 }
221 void right(struct obj *o){
222         if(++o->orientation==NORIENTATION)
223                 o->orientation=0;
224 }
225 void left(struct obj *o){
226         if(--o->orientation<0)
227                 o->orientation=NORIENTATION-1;
228 }
229 void jerk(struct obj *o){
230         o->vx+=dv[o->orientation].x/2;
231         o->vy+=dv[o->orientation].y/2;
232 }
233 int isqrt(int x){
234         int s, u;
235         if(x<=0)
236                 return(0);
237         if(x>=32768L*(32768L/4))
238                 return(2*isqrt(x/4));   /* avoid overflow */
239         for(s=2, u=4;u<x;s+=s, u*=4);
240         while((u=((x+s*s)/s)>>1)<s)
241                 s=u;
242         return(s);
243 }
244 void fire(struct obj *o){
245         struct obj *m;
246         int vx, vy, vl;
247         if(o->state!=ALIVE)
248                 return;
249         for(m=o+2;m<&obj[NOBJ];m+=2)
250                 if(m->state==DEAD){
251                         initobj(m);
252                         m->state=ALIVE;
253                         vl=isqrt(sq(o->vx)+sq(o->vy));
254                         if(vl==0)
255                                 vl=V;
256                         vx=muldiv(vl, dv[o->orientation].x, V);
257                         vy=muldiv(vl, dv[o->orientation].y, V);
258                         m->x=o->x+muldiv(vx, (o->diameter+m->diameter), vl);
259                         m->y=o->y+muldiv(vy, (o->diameter+m->diameter), vl);
260                         m->vx=o->vx+MSPEED*dv[o->orientation].x;
261                         m->vy=o->vy+MSPEED*dv[o->orientation].y;
262                         blot(m, m->orientation);
263                         return;
264                 }
265 }
266 void initobj(struct obj *o){
267         *o=(o>P1)?iobj[P1-obj+1]:iobj[o-obj];
268         if(o<=P1)
269                 blot(o, o->orientation);
270 }
271 void deathto(struct obj *o, int doboom){
272         o->state=DEAD;
273         blot(o, o->curdwg);
274         if(doboom)
275                 boom(o);
276 }
277 void boom(struct obj *o){
278         o->state=BOOM;
279         o->bp=boomdwg;
280         o->diameter=boomdwg->r.max.x/4;
281         blot(o, o->orientation=0);
282 }
283 void shards(struct obj *o){
284         if(++o->orientation==16){
285                 blot(o, o->curdwg);
286                 o->state=DEAD;
287                 o->timer=TUBA;
288         }
289 }
290 void move(struct obj *o){
291         int r32;
292         int x, y;
293         if(o->state==DEAD || o->state==SUN)
294                 return;
295         r32=o->x*o->x+o->y*o->y;
296         if(r32!=0){
297                 r32*=isqrt(r32);        /* pow(r, 3./2.) */
298                 if(r32!=0){
299                         o->vx-=G*o->x/r32;
300                         o->vy-=G*o->y/r32;
301                 }
302         }
303         x=o->x+o->vx/V;
304         y=o->y+o->vy/V;
305         if(x<-SZ || SZ<x){
306                 if(o>P1 && o->wrapped){
307     Death:
308                         deathto(o, 0);
309                         return;
310                 }
311                 if(x<-SZ) x+=2*SZ; else x-=2*SZ;
312                 o->wrapped++;
313         }
314         if(y<-SZ || SZ<y){
315                 if(o>P1 && o->wrapped)
316                         goto Death;
317                 if(y<-SZ) y+=2*SZ; else y-=2*SZ;
318                 o->wrapped++;
319         }
320         if(o->state!=HYPER)
321                 blot(o, o->curdwg);
322         o->x=x, o->y=y;
323         if(o->state!=HYPER)
324                 blot(o, o->orientation);
325 }
326
327 #define BLOTSIZE        5
328 #define rescale(x)      muldiv(x, size, SZ)
329
330 void
331 blot(struct obj *o, int dwg)
332 {
333         Point p;
334         int dx = dwg % 4*o->diameter, dy = dwg / 4*o->diameter;
335
336         p = Pt(rescale(o->x)+xc-o->diameter/2, rescale(o->y)+yc-o->diameter/2);
337
338         draw(screen, rectaddpt(Rect(dx,dy,dx+o->diameter,dy+o->diameter),p), o->bp, nil, Pt(dx, dy));
339         o->curdwg = dwg;
340 }
341
342 void
343 collide(struct obj *o, struct obj *p)
344 {
345         int doneboom;
346         /* o<p always */
347         if(o->state!=HYPER && p->state!=HYPER
348         && sq(rescale(o->x-p->x))+sq(rescale(o->y-p->y))<
349                 sq(o->diameter+p->diameter)/4){
350                 newscore(o, p);
351                 if(doneboom=o->state==ALIVE)
352                         deathto(o, 1);
353                 if(p->state==ALIVE)
354                         deathto(p, !doneboom || (o==P0 && p==P1));
355         }
356 }
357
358 void
359 newscore(struct obj *o, struct obj *p)
360 {
361         doscore();
362         /* o<p always */
363         score[2]++;
364         if(o==P0 || p==P0)
365                 score[1]++;
366         if(o==P1 || p==P1)
367                 score[0]++;
368         doscore();
369 }
370
371 void
372 drawscore(char *str, int sc, int where)
373 {
374         static char buf[16];
375         char *p = buf+6;
376         int s;
377
378         while(*p++=*str++)
379                 ;
380
381         p = buf+6;
382         s = abs(sc);
383         do{
384                 *--p = s%10 + '0';
385                 s /= 10;
386         }while(s);
387
388         if(sc < 0)
389                 *--p = '-';
390
391         if(where == 2)
392                 s = screen->r.min.x + 20;
393         else if(where == 1)
394                 s = (screen->r.min.x + screen->r.max.x - stringwidth(font, p))/2;
395         else
396                 s = screen->r.max.x - stringwidth(font, p) - 20;
397
398         draw(screen, Rpt(Pt(s, screen->r.min.y+5),Pt(s+stringwidth(font, p), screen->r.min.y+5+font->height)), display->black, nil, ZP);
399         string(screen, Pt(s, screen->r.min.y+5), display->white, ZP, font, p);
400 }
401
402 void
403 doscore(void)
404 {
405         drawscore(" MCI", score[0], 0);
406         drawscore(" AT&T", score[2], 1);
407         drawscore(" SPRINT", score[1], 2);
408 }
409
410 Image *
411 initbitmap(char *bits[], Rectangle r)
412 {
413         Point p;
414         char *bit;
415         Image *b=allocimage(display, r, screen->chan, 0, DTransparent);
416
417         if(b==0)
418                 sysfatal("allocimage: %r");
419
420         for(p.y = r.min.y; p.y != r.max.y; p.y++){
421                 bit = bits[p.y-r.min.y];
422                 for(p.x = r.min.x; p.x != r.max.x; p.x++){
423                         while(*bit==' ')
424                                 bit++;
425                         if(*bit++=='x')
426                                 draw(b, Rpt(p,addpt(p,Pt(1,1))), display->white, nil, ZP);
427                 }
428         }
429         return b;
430 }