ref: dfb4b522830edab8f3856289d326d6cf5e930644
dir: /sys/src/games/swar/swar.c/
/* * swar -- jerq space war * td&rob 84.01.01 * * ported to 9front on 31jul2021 */ #include <u.h> #include <libc.h> #include <draw.h> #include <event.h> int xc, yc; #define NOBJ (1+2+6*2) #define MSPEED (V/32) /* speed of missile relative to ship */ #define SZ 512 /* maximum scaled coordinate */ #define V 256 /* velocity scale factor */ #define G (V*11585) /* 11585 is SZ**(3./2.) */ #define ALIVE 1 #define DEAD 2 #define SUN 3 #define BOOM 4 #define HYPER 5 #define SLEEP 40 /* ms per iteration */ #define TUBA (2000/SLEEP) /* iterations until born again */ #define HYTIME ((600+rand()%600)/SLEEP) /* iterations in hyperspace */ char *starbits[]={ #include "deathstar.icon" }; Image *stardwg; Rectangle starrect={0, 0, 16, 16}; char *p0bits[]={ #include "player0.icon" }; Image *p0dwg; Rectangle p0rect={0, 0, 44, 44}; char *p1bits[]={ #include "player1.icon" }; Image *p1dwg; Rectangle p1rect={0, 0, 44, 44}; char *misbits[]={ #include "missile.icon" }; Image *misdwg; Rectangle misrect={0, 0, 32, 32}; char *boombits[]={ #include "boom.icon" }; Image *boomdwg; Rectangle boomrect={0, 0, 64, 64}; struct obj{ int x, y; int vx, vy; /* scaled by V */ int orientation; int state; int diameter; Image *bp; int curdwg; #define wrapped timer int timer; }obj[NOBJ], iobj[]={ {0, 0, 0, 0, 0, SUN, 16}, { 300, 0, 0, 5*V, 8, ALIVE, 11, 0, 0, TUBA}, {-300, 0, 0, -5*V, 0, ALIVE, 11, 0, 0, TUBA}, {0, 0, 0, 0, 0, ALIVE, 8}, }; #define ATT (&obj[0]) #define P0 (&obj[1]) #define P1 (&obj[2]) int score[3]; #define NORIENTATION 16 struct dv{ int x, y; }dv[NORIENTATION]={ #include "accel.h" }; int xc, yc, size; void kbdplayer(int c); void hyper(struct obj *o); void right(struct obj *o); void left(struct obj *o); void jerk(struct obj *o); int isqrt(int x); void fire(struct obj *o); void initobj(struct obj *o); void deathto(struct obj *o, int doboom); void boom(struct obj *o); void shards(struct obj *o); void move(struct obj *o); void blot(struct obj *o, int dwg); void collide(struct obj *o, struct obj *p); void newscore(struct obj *o, struct obj *p); void drawscore(char *str, int sc, int where); void doscore(void); Image *initbitmap(char *bits[], Rectangle r); #define sq(x) ((x)*(x)) #define muldiv(a, b, c) ((a)*(b)/(c)) int min(int a, int b) { return a<b? a: b; } int abs(int a) { return a<0? -a: a; } void redraw(void) { draw(screen, screen->r, display->black, nil, ZP); blot(ATT, ATT->orientation); doscore(); } void eresized(int) { if(getwindow(display, Refnone) < 0) sysfatal("resized"); xc=(screen->r.min.x+screen->r.max.x)/2; yc=(screen->r.min.y+screen->r.max.y)/2; size=min(screen->r.max.x-screen->r.min.x, screen->r.max.y-screen->r.min.y)/2; redraw(); } void main(void) { struct obj *o, *p; initdraw(nil,nil,nil); einit(Ekeyboard|Emouse); iobj[0].bp = stardwg = initbitmap(starbits, starrect); iobj[1].bp = p0dwg = initbitmap(p0bits, p0rect); iobj[2].bp = p1dwg = initbitmap(p1bits, p1rect); iobj[3].bp = misdwg = initbitmap(misbits, misrect); boomdwg = initbitmap(boombits, boomrect); xc=(screen->r.min.x+screen->r.max.x)/2; yc=(screen->r.min.y+screen->r.max.y)/2; size=min(screen->r.max.x-screen->r.min.x, screen->r.max.y-screen->r.min.y)/2; for(o=obj;o<=P1;o++) initobj(o); for(;o!=&obj[NOBJ];o++) o->state=DEAD; for(;;){ redraw(); for(o=obj;o!=&obj[NOBJ];o++){ switch(o->state){ case ALIVE: case SUN: for(p=o+1;p!=&obj[NOBJ];p++) if(p->state!=DEAD) collide(o, p); if(o>P1) left(o); move(o); break; case HYPER: if(--o->timer==0){ blot(o, o->curdwg); o->state=ALIVE; if(rand()%4==0){ deathto(o, 1); newscore(ATT, o); } }else move(o); break; case DEAD: if((o==P0 || o==P1) && --o->timer==0) initobj(o); break; case BOOM: shards(o); move(o); break; } } flushimage(display, 1); while(ecanmouse()) emouse(); if(ecankbd()) kbdplayer(ekbd()); sleep(SLEEP); } } void kbdplayer(int c){ switch(c){ case 'k': left(P0); break; case 'o': jerk(P0); break; case ';': right(P0); break; case 'l': fire(P0); break; case '.': case ',': hyper(P0); break; case 'a': left(P1); break; case 'w': jerk(P1); break; case 'd': right(P1); break; case 's': fire(P1); break; case 'z': case 'x': hyper(P1); break; case 'Q': exits(""); break; } } void hyper(struct obj *o){ if(o->state!=ALIVE) return; o->state=HYPER; o->timer=HYTIME; blot(o, o->curdwg); } void right(struct obj *o){ if(++o->orientation==NORIENTATION) o->orientation=0; } void left(struct obj *o){ if(--o->orientation<0) o->orientation=NORIENTATION-1; } void jerk(struct obj *o){ o->vx+=dv[o->orientation].x/2; o->vy+=dv[o->orientation].y/2; } int isqrt(int x){ int s, u; if(x<=0) return(0); if(x>=32768L*(32768L/4)) return(2*isqrt(x/4)); /* avoid overflow */ for(s=2, u=4;u<x;s+=s, u*=4); while((u=((x+s*s)/s)>>1)<s) s=u; return(s); } void fire(struct obj *o){ struct obj *m; int vx, vy, vl; if(o->state!=ALIVE) return; for(m=o+2;m<&obj[NOBJ];m+=2) if(m->state==DEAD){ initobj(m); m->state=ALIVE; vl=isqrt(sq(o->vx)+sq(o->vy)); if(vl==0) vl=V; vx=muldiv(vl, dv[o->orientation].x, V); vy=muldiv(vl, dv[o->orientation].y, V); m->x=o->x+muldiv(vx, (o->diameter+m->diameter), vl); m->y=o->y+muldiv(vy, (o->diameter+m->diameter), vl); m->vx=o->vx+MSPEED*dv[o->orientation].x; m->vy=o->vy+MSPEED*dv[o->orientation].y; blot(m, m->orientation); return; } } void initobj(struct obj *o){ *o=(o>P1)?iobj[P1-obj+1]:iobj[o-obj]; if(o<=P1) blot(o, o->orientation); } void deathto(struct obj *o, int doboom){ o->state=DEAD; blot(o, o->curdwg); if(doboom) boom(o); } void boom(struct obj *o){ o->state=BOOM; o->bp=boomdwg; o->diameter=boomdwg->r.max.x/4; blot(o, o->orientation=0); } void shards(struct obj *o){ if(++o->orientation==16){ blot(o, o->curdwg); o->state=DEAD; o->timer=TUBA; } } void move(struct obj *o){ int r32; int x, y; if(o->state==DEAD || o->state==SUN) return; r32=o->x*o->x+o->y*o->y; if(r32!=0){ r32*=isqrt(r32); /* pow(r, 3./2.) */ if(r32!=0){ o->vx-=G*o->x/r32; o->vy-=G*o->y/r32; } } x=o->x+o->vx/V; y=o->y+o->vy/V; if(x<-SZ || SZ<x){ if(o>P1 && o->wrapped){ Death: deathto(o, 0); return; } if(x<-SZ) x+=2*SZ; else x-=2*SZ; o->wrapped++; } if(y<-SZ || SZ<y){ if(o>P1 && o->wrapped) goto Death; if(y<-SZ) y+=2*SZ; else y-=2*SZ; o->wrapped++; } if(o->state!=HYPER) blot(o, o->curdwg); o->x=x, o->y=y; if(o->state!=HYPER) blot(o, o->orientation); } #define BLOTSIZE 5 #define rescale(x) muldiv(x, size, SZ) void blot(struct obj *o, int dwg) { Point p; int dx = dwg % 4*o->diameter, dy = dwg / 4*o->diameter; p = Pt(rescale(o->x)+xc-o->diameter/2, rescale(o->y)+yc-o->diameter/2); draw(screen, rectaddpt(Rect(dx,dy,dx+o->diameter,dy+o->diameter),p), o->bp, nil, Pt(dx, dy)); o->curdwg = dwg; } void collide(struct obj *o, struct obj *p) { int doneboom; /* o<p always */ if(o->state!=HYPER && p->state!=HYPER && sq(rescale(o->x-p->x))+sq(rescale(o->y-p->y))< sq(o->diameter+p->diameter)/4){ newscore(o, p); if(doneboom=o->state==ALIVE) deathto(o, 1); if(p->state==ALIVE) deathto(p, !doneboom || (o==P0 && p==P1)); } } void newscore(struct obj *o, struct obj *p) { doscore(); /* o<p always */ score[2]++; if(o==P0 || p==P0) score[1]++; if(o==P1 || p==P1) score[0]++; doscore(); } void drawscore(char *str, int sc, int where) { static char buf[16]; char *p = buf+6; int s; while(*p++=*str++) ; p = buf+6; s = abs(sc); do{ *--p = s%10 + '0'; s /= 10; }while(s); if(sc < 0) *--p = '-'; if(where == 2) s = screen->r.min.x + 20; else if(where == 1) s = (screen->r.min.x + screen->r.max.x - stringwidth(font, p))/2; else s = screen->r.max.x - stringwidth(font, p) - 20; 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); string(screen, Pt(s, screen->r.min.y+5), display->white, ZP, font, p); } void doscore(void) { drawscore(" MCI", score[0], 0); drawscore(" AT&T", score[2], 1); drawscore(" SPRINT", score[1], 2); } Image * initbitmap(char *bits[], Rectangle r) { Point p; char *bit; Image *b=allocimage(display, r, screen->chan, 0, DTransparent); if(b==0) sysfatal("allocimage: %r"); for(p.y = r.min.y; p.y != r.max.y; p.y++){ bit = bits[p.y-r.min.y]; for(p.x = r.min.x; p.x != r.max.x; p.x++){ while(*bit==' ') bit++; if(*bit++=='x') draw(b, Rpt(p,addpt(p,Pt(1,1))), display->white, nil, ZP); } } return b; }