These videos might hang your browser, sorry!
X-Caliber
$BG,0$$FD,15$$FG,4$//********************************** Glbls$FG$

class CtrlPanelState
{
 I8 bullet_radius,fuse_time;
} ctrl_panel;

#define SF_DESTROYED        0x100
#define SF_REMOVED        0x200

#define ENEMY_MASSES        3
#define ENEMY_SPRINGS        3
class Enemy1
{
 Enemy1 *next,*last;
 MassStruct p[ENEMY_MASSES];
 SpringStruct s[ENEMY_SPRINGS];
 double reload_done_time;
 double die_time,timeout;
 BoolI1 exploding;
};

class Bullet
{
 Bullet *next,*last;
 double radius;
 double fuse_time,timeout;
 MassStruct p;
};

#define MAX_THRUST        200.0
#define MAX_ANTISPIN        25.0
#define SPRING_CONSTANT        10000.0
#define MASS                1.0
#define MASS_RADIUS         7
#define DRAG_FACTOR        1.0
#define FIRE_RATE        25
#define ENEMY_FIRE_RATE        2.5

#define SHIP_MASSES        5
#define SHIP_SPRINGS        7
class Ship
{
 double t_left,t_right,antispin;
 MassStruct p[SHIP_MASSES];
 SpringStruct s[SHIP_SPRINGS];
 double reload_done_time;
 double die_time,timeout;
 BoolI1 exploding,dead;
};

#define CMD_NULL        0
#define CMD_SPIN_LEFT        1
#define CMD_SPIN_RIGHT        2
#define CMD_THRUST        3
#define CMD_FIRE        4
#define CMD_EXIT        5
BoolI1 game_over;

#define NUM_STARS        100
I8 stars_x[NUM_STARS],stars_y[NUM_STARS];

Enemy1 enemy_root;
Bullet bullet_root;
Ode *o=NULL;
Ship ship;
I8 level,score,remaining;


$FG,4$//********************************** Pictures$FG$


$PI,"<thruster>",1$






$FG,4$//********************************** Controls$FG$

#define CTRL_PANEL_SPACING 33
#define CTRL_PANEL_RANGE   30
#define CTRL_PANEL_BORDER  2

void DrawCtrlPanelCtrl(GrBitMap *base,Ctrl *c)
{
 CtrlPanelState *s=c->state;

 base->color=LTRED;
 GrBox(base, c->left,c->top,CTRL_PANEL_SPACING*3+2,CTRL_PANEL_SPACING*2+CTRL_PANEL_RANGE);
 base->color=DKGRAY;
 GrBox(base, c->left+CTRL_PANEL_BORDER,c->top+CTRL_PANEL_BORDER,
     
CTRL_PANEL_SPACING*3+2-2*CTRL_PANEL_BORDER,CTRL_PANEL_SPACING*2+CTRL_PANEL_RANGE-2*CTRL_PANEL_BORDER);
 base->color=BLACK;
 GrLine(base,c->left+CTRL_PANEL_SPACING,c->top+CTRL_PANEL_SPACING,
                         c->left+CTRL_PANEL_SPACING,c->top+CTRL_PANEL_SPACING+CTRL_PANEL_RANGE-1);
 GrLine(base,c->left+2*CTRL_PANEL_SPACING+1,c->top+CTRL_PANEL_SPACING,
                         c->left+2*CTRL_PANEL_SPACING+1,c->top+CTRL_PANEL_SPACING+CTRL_PANEL_RANGE-1);

 base->color=RED;
 GrPutS(base,c->left+CTRL_PANEL_SPACING-4*FONT_WIDTH/2,
                         c->top+CTRL_PANEL_SPACING-FONT_HEIGHT-2,"Size");
 GrPutS(base,c->left+2*CTRL_PANEL_SPACING+1-4*FONT_WIDTH/2,
                         c->top+CTRL_PANEL_SPACING-FONT_HEIGHT-2,"Fuse");
 base->color=LTRED;
 GrPrintF(base,c->left+CTRL_PANEL_SPACING-FONT_WIDTH/2,
                         c->top+CTRL_PANEL_SPACING+CTRL_PANEL_RANGE+3,
                         "%d",s->bullet_radius*10/CTRL_PANEL_RANGE);
 GrPrintF(base,c->left+2*CTRL_PANEL_SPACING+1-FONT_WIDTH/2,
                         c->top+CTRL_PANEL_SPACING+CTRL_PANEL_RANGE+3,
                         "%d",s->fuse_time*10/CTRL_PANEL_RANGE);
 GrBox(base,c->left+CTRL_PANEL_SPACING-3,         
c->top+CTRL_PANEL_SPACING+CTRL_PANEL_RANGE-1-s->bullet_radius-2 ,7,5);
 
GrBox(base,c->left+2*CTRL_PANEL_SPACING+1-3,c->top+CTRL_PANEL_SPACING+CTRL_PANEL_RANGE-1-s->fuse_time-2,7,5
);
 base->color=YELLOW;
 GrBox(base,c->left+CTRL_PANEL_SPACING-2,         
c->top+CTRL_PANEL_SPACING+CTRL_PANEL_RANGE-1-s->bullet_radius-1 ,5,3);
 
GrBox(base,c->left+2*CTRL_PANEL_SPACING+1-2,c->top+CTRL_PANEL_SPACING+CTRL_PANEL_RANGE-1-s->fuse_time-1,5,3
);
}

void UpdateDerivedCtrlPanelCtrl(Ctrl *c)
{
 CtrlPanelState *s=c->state;
 c->left=c->win_tss->win_pixel_width-(CTRL_PANEL_SPACING*3+2);
 c->right=c->left+CTRL_PANEL_SPACING*3+2;
 c->top=c->win_tss->win_pixel_height-(CTRL_PANEL_SPACING*2+CTRL_PANEL_RANGE);
 c->bottom=c->top+CTRL_PANEL_SPACING*2+CTRL_PANEL_RANGE;

 s->bullet_radius =LimitI8(s->bullet_radius,0,CTRL_PANEL_RANGE-1);
 s->fuse_time=LimitI8(s->fuse_time,0,CTRL_PANEL_RANGE-1);
}

BoolI8 LeftClickCtrlPanel(Ctrl *c,I8 x,I8 y,BoolI1 down)
{
 nounusedwarn down;
 TssStruct *tss=c->win_tss;
 CtrlPanelState *s=c->state;
 if (x<(c->right+c->left)/2)
     s->bullet_radius=CTRL_PANEL_RANGE-1-(y-(c->top+CTRL_PANEL_SPACING));
 else
     s->fuse_time=CTRL_PANEL_RANGE-1-(y-(c->top+CTRL_PANEL_SPACING));
 if (c->update_derived_values)
     c->update_derived_values(c);
 return TRUE; //true means no further button press processing
}

Ctrl *CtrlPanelNew()
{
 BoolI1 old_preempt;
 Ctrl *c=MAllocZ(sizeof(Ctrl));
 c->win_tss=Fs;
 c->flags=CTRLF_SHOW|CTRLF_CAPTURE_LEFT_IP;
 c->type=CTRLT_GENERIC;
 c->state=&ctrl_panel;
 c->draw_it=&DrawCtrlPanelCtrl;
 c->left_click=&LeftClickCtrlPanel;
 c->update_derived_values=&UpdateDerivedCtrlPanelCtrl;
 old_preempt=Preempt(OFF);
 InsQue(c,Fs->last_ctrl);
 UpdateDerivedTssValues;
 Preempt(old_preempt);
 return c;
}

void CtrlPanelDel(Ctrl *c)
{
 BoolI1 old_preempt=Preempt(OFF);
 RemQue(c);
 Preempt(old_preempt);
 Free(c);
}

$FG,4$//********************************** Enemy$FG$

Enemy1 *Enemy1New(I8 x,I8 y)
{
 I8 i;
 Enemy1 *ee=MAllocZ(sizeof(Enemy1));

 ee->p[0].x=x;
 ee->p[0].y=y;
 ee->p[1].x=x+15;
 ee->p[1].y=y;
 ee->p[2].x=x;
 ee->p[2].y=y+15;

 for (i=0;i<ENEMY_MASSES;i++) {
     ee->p[i].mass=MASS;
     ee->p[i].user_data=MASS_RADIUS;
     ee->p[i].drag_profile_factor=DRAG_FACTOR;
     InsQue(&ee->p[i],o->last_mass);
 }

 ee->s[0].end1=&ee->p[0];
 ee->s[0].end2=&ee->p[1];
 ee->s[1].end1=&ee->p[1];
 ee->s[1].end2=&ee->p[2];
 ee->s[2].end1=&ee->p[2];
 ee->s[2].end2=&ee->p[0];

 for (i=0;i<ENEMY_SPRINGS;i++) {
     ee->s[i].rest_length=DistD3(&ee->s[i].end1->x,&ee->s[i].end2->x);
     ee->s[i].constant=SPRING_CONSTANT;
     ee->s[i].user_data=LTPURPLE;
     InsQue(&ee->s[i],o->last_spring);
 }
 InsQue(ee,enemy_root.last);
 remaining++;
 return ee;
}

void Enemy1Del(Enemy1 *tempe)
{
 I8 i;
 for (i=0;i<ENEMY_MASSES;i++)
     RemQue(&tempe->p[i]);
 for (i=0;i<ENEMY_SPRINGS;i++)
     if (!(tempe->s[i].user_data&SF_REMOVED))
         RemQue(&tempe->s[i]);
 RemQue(tempe);
 Free(tempe);
 remaining--;
 score+=level;
}

$FG,4$//********************************** Ship$FG$

void InitShip(I8 x,I8 y)
{
 I8 i;

 MemSet(&ship,0,sizeof(Ship));

 ship.p[0].x=x;
 ship.p[0].y=y;
 ship.p[1].x=x+3;
 ship.p[1].y=y+10;
 ship.p[2].x=x-3;
 ship.p[2].y=y+10;
 ship.p[3].x=x+20;
 ship.p[3].y=y+20;
 ship.p[4].x=x-20;
 ship.p[4].y=y+20;

 for (i=0;i<SHIP_MASSES;i++) {
     ship.p[i].mass=MASS;
     ship.p[i].user_data=1;
     ship.p[i].drag_profile_factor=DRAG_FACTOR;
     InsQue(&ship.p[i],o->last_mass);
 }
 ship.p[3].mass/=10.0;
 ship.p[4].mass/=10.0;


 ship.s[0].end1=&ship.p[0];
 ship.s[0].end2=&ship.p[1];
 ship.s[1].end1=&ship.p[2];
 ship.s[1].end2=&ship.p[0];
 ship.s[2].end1=&ship.p[1];
 ship.s[2].end2=&ship.p[2];
 ship.s[3].end1=&ship.p[1];
 ship.s[3].end2=&ship.p[3];
 ship.s[4].end1=&ship.p[0];
 ship.s[4].end2=&ship.p[3];
 ship.s[5].end1=&ship.p[2];
 ship.s[5].end2=&ship.p[4];
 ship.s[6].end1=&ship.p[0];
 ship.s[6].end2=&ship.p[4];

 for (i=0;i<SHIP_SPRINGS;i++) {
     ship.s[i].rest_length=DistD3(&ship.s[i].end1->x,&ship.s[i].end2->x);
     ship.s[i].constant=SPRING_CONSTANT;
     ship.s[i].user_data=LTGRAY;
     InsQue(&ship.s[i],o->last_spring);
 }
}

void ShipDel()
{
 I8 i;
 for (i=0;i<SHIP_MASSES;i++)
     RemQue(&ship.p[i]);
 for (i=0;i<SHIP_SPRINGS;i++)
     if (!(ship.s[i].user_data&SF_REMOVED))
         RemQue(&ship.s[i]);
}

void AllDel(Ode *o)
{
 Enemy1 *tempe,*tempe1;
 Bullet *tempb=bullet_root.next,*tempb1;
 RemQue(o);
 tempe=enemy_root.next;
 while (tempe!=&enemy_root) {
     tempe1=tempe->next;
     Enemy1Del(tempe);
     tempe=tempe1;
 }
 while (tempb!=&bullet_root) {
     tempb1=tempb->next;
     RemQue(tempb);
     Free(tempb);
     tempb=tempb1;
 }
 OdeDel(o);
}

$FG,4$//**********************************$FG$
void UpdateWin(TssStruct *tss)
{
 I8 i,j;
 GrBitMap *base=GrAlias(grbase,tss);
 double mag,arg;
 Enemy1 *tempe;
 Bullet *tempb;
 BoolI1 sound_on=FALSE;
 D3 p,p1,p2;
 double t_left,t_right,spin,d;
 SpringStruct *temps;

 LtfUpdateAuxLtf(tss);

 if (o!=tss->last_ode) goto done_draw;


 base->color=WHITE;
 GrPrintF(base,0,FONT_HEIGHT,"Level:%d Score:%d",level,score);
 if (game_over)
     GrPutS(base,(tss->win_pixel_width-9*FONT_WIDTH)/2,
                             (tss->win_pixel_height-FONT_HEIGHT)/2,"Game Over");

 for (i=0;i<NUM_STARS;i++)
     GrPlot(base,stars_x[i],stars_y[i]);

 temps=o->next_spring;
 while (temps!=&o->next_spring) {
     base->color=temps->user_data.u1[0];
     GrLine(base,temps->end1->x,temps->end1->y,
                             temps->end2->x,temps->end2->y);
     temps=temps->next;
 }

 tempe=enemy_root.next;
 while (tempe!=&enemy_root) {
     for (i=0;i<ENEMY_MASSES;i++) {
         if (i==0)
             base->color=LTRED;
         else
             base->color=RED;
         GrCircle(base,tempe->p[i].x,tempe->p[i].y,MASS_RADIUS);
         GrFloodFill(base,tempe->p[i].x,tempe->p[i].y,TRUE);
         base->color=WHITE;
         GrCircle(base,tempe->p[i].x,tempe->p[i].y,MASS_RADIUS);
     }
     if (tempe->exploding && tempe->die_time<=t<=tempe->timeout)
         for (j=0;j<ENEMY_MASSES;j++) {
             d=(t-tempe->die_time)/(tempe->timeout-tempe->die_time);
             d=7*Sin(pi*d)*(6+j)+1;
             for (i=1;i<d;i++) {
                 if (i&1)
                     base->color=YELLOW;
                 else
                     base->color=LTRED;
                 GrCircle(base,tempe->p[j].x,tempe->p[j].y,i);
             }
         }
     tempe=tempe->next;
 }

 tempb=bullet_root.next;
 while (tempb!=&bullet_root) {
     if (t>tempb->fuse_time) {
         d=(t-tempb->fuse_time)/(tempb->timeout-tempb->fuse_time);
         d=7*Sin(pi*d)*tempb->radius+1;
         for (i=1;i<d;i++) {
             if (i&1)
                 base->color=YELLOW;
             else
                 base->color=LTRED;
             GrCircle(base,tempb->p.x,tempb->p.y,i);
         }
     } else {
         if (tempb->radius<=0.5) {
             base->color=LTGREEN;
             GrPlot(base,tempb->p.x,tempb->p.y);
         } else {
             base->color=YELLOW;
             GrCircle(base,tempb->p.x,tempb->p.y,tempb->radius);
             if (tempb->radius>1)
                 GrFloodFill(base,tempb->p.x,tempb->p.y,TRUE);
             base->color=LTGREEN;
             GrCircle(base,tempb->p.x,tempb->p.y,tempb->radius);
         }
     }
     tempb=tempb->next;
 }

 if (!ship.exploding) {
     if (d=NormD3(SubD3(&ship.p[0].x,&ship.p[1].x,&p1))) {
         SubD3(&ship.p[0].DxDt,&ship.p[1].DxDt,&p2);
         CrossD3(&p1,&p2,&p);
         spin=p.z/d;
     } else
         spin=0;
     t_left =Limit(ship.t_left+spin*ship.antispin,0,MAX_THRUST);

     if (d=NormD3(SubD3(&ship.p[0].x,&ship.p[2].x,&p1))) {
         SubD3(&ship.p[0].DxDt,&ship.p[2].DxDt,&p2);
         CrossD3(&p1,&p2,&p);
         spin=p.z/d;
     } else
         spin=0;
     t_right=Limit(ship.t_right-spin*ship.antispin,0,MAX_THRUST);


     SubD3(&ship.p[1].x,&ship.p[0].x,&p1);
     SubD3(&ship.p[2].x,&ship.p[0].x,&p2);
     UnitD3(AddD3(&p1,&p2,&p));

     if (!(ship.s[3].user_data&SF_DESTROYED)) {
         base->color=YELLOW;
         AddEquD3(MulD3(t_left/25,&p,&p1),&ship.p[3].x);
         GrLine(base,ship.p[1].x,ship.p[1].y,p1.x,p1.y);
         R2P(&mag,&arg,p.x,p.y);
         GrElemsPlotRotZ(base,ship.p[3].x,ship.p[3].y,0,$IB,"<thruster>",1$,arg);
     }

     if (!(ship.s[5].user_data&SF_DESTROYED)) {
         base->color=YELLOW;
         AddEquD3(MulD3(t_right/25,&p,&p2),&ship.p[4].x);
         GrLine(base,ship.p[2].x,ship.p[2].y,p2.x,p2.y);
         R2P(&mag,&arg,p.x,p.y);
         GrElemsPlotRotZ(base,ship.p[4].x,ship.p[4].y,0,$IB,"<thruster>",1$,arg);
     }
 }

 if (ship.exploding && !ship.dead)
     for (j=0;j<SHIP_MASSES;j++) {
         d=(t-ship.die_time)/(ship.timeout-ship.die_time);
         d=7*Sin(pi*d)*(6+j)+1;
         for (i=1;i<d;i++) {
             if (i&1)
                 base->color=YELLOW;
             else
                 base->color=LTRED;
             GrCircle(base,ship.p[j].x,ship.p[j].y,i);
         }
     }

 if (sound_on) {
     music_mute=TRUE;
     Sound(1000);
 } else
     music_mute=FALSE;
done_draw:
 GrDel(base);
}


void Explosion(MassStruct *tempm1,double r)
{
 MassStruct *tempm;
 D3 p1;
 double d;

 tempm=o->next_mass;
 while (tempm!=&o->next_mass) {
     if (tempm!=tempm1) {
         SubD3(&tempm->state->x,&tempm1->state->x,&p1);
         d=(NormD3(&p1)-tempm->user_data);
         if (d<1) d=1;
         d=2e8*r`7/d`6;
         if (d>1e5) d=1e5;
         MulEquD3(&p1,d);
         AddEquD3(&tempm->DstateDt->DxDt,&p1);
     }
     tempm=tempm->next;
 }
}

void MyDerivative(Ode *ode,double t,Order2D3 *state,Order2D3 *DstateDt)
{
 I8 i;
 double d,dd,dd2,spin,t_left,t_right;
 TssStruct *tss=ode->win_tss;
 D3 p,p1,p2;
 Bullet *tempb;
 Enemy1 *tempe;

 tempb=bullet_root.next;
 while (tempb!=&bullet_root) {
     tempe=enemy_root.next;
     while (tempe!=&enemy_root) {
         for (i=0;i<ENEMY_MASSES;i++) {
             SubD3(&tempe->p[i].state->x,&tempb->p.state->x,&p);
             dd=SqrNormD3(&p);
             dd2=Sqr(tempb->radius+MASS_RADIUS);
             if (dd<=dd2) {
                 d=Sqrt(dd)+0.0001;
                 MulEquD3(&p,Sqr(Sqr(dd2-dd))/d);
                 AddEquD3(&tempe->p[i].DstateDt->DxDt,&p);
                 SubEquD3(&tempb->p.DstateDt->DxDt,&p);
             }
         }
         tempe=tempe->next;
     }
     tempb=tempb->next;
 }

 if (!ship.exploding) {
     for (i=0;i<SHIP_MASSES;i++) {
         d=ship.p[i].state->x;
         if (d-MASS_RADIUS<0)
             ship.p[i].DstateDt->DxDt+=Sqr(Sqr(Sqr(d-MASS_RADIUS)));
         if (d+MASS_RADIUS>tss->win_pixel_width)
             ship.p[i].DstateDt->DxDt-=Sqr(Sqr(Sqr((d+MASS_RADIUS)-tss->win_pixel_width)));

         d=ship.p[i].state->y;
         if (d-MASS_RADIUS<0)
             ship.p[i].DstateDt->DyDt+=Sqr(Sqr(Sqr(d-MASS_RADIUS)));
         if (d+MASS_RADIUS>tss->win_pixel_height)
             ship.p[i].DstateDt->DyDt-=Sqr(Sqr(Sqr((d+MASS_RADIUS)-tss->win_pixel_height)));
     }
 } else if (!ship.dead)
     for (i=0;i<SHIP_MASSES;i++)
         Explosion(&ship.p[i],3.0);

 tempe=enemy_root.next;
 while (tempe!=&enemy_root) {
     for (i=0;i<ENEMY_MASSES;i++) {
         d=tempe->p[i].state->x;
         if (d-MASS_RADIUS<0)
             tempe->p[i].DstateDt->DxDt+=Sqr(Sqr(Sqr(d-MASS_RADIUS)));
         if (d+MASS_RADIUS>tss->win_pixel_width)
             tempe->p[i].DstateDt->DxDt-=Sqr(Sqr(Sqr((d+MASS_RADIUS)-tss->win_pixel_width)));

         d=tempe->p[i].state->y;
         if (d-MASS_RADIUS<0)
             tempe->p[i].DstateDt->DyDt+=Sqr(Sqr(Sqr(d-MASS_RADIUS)));
         if (d+MASS_RADIUS>tss->win_pixel_height)
             tempe->p[i].DstateDt->DyDt-=Sqr(Sqr(Sqr((d+MASS_RADIUS)-tss->win_pixel_height)));
     }
     if (tempe->exploding && tempe->die_time<=t<=tempe->timeout)
         for (i=0;i<ENEMY_MASSES;i++)
             Explosion(&tempe->p[i],3.0);
     tempe=tempe->next;
 }

 tempb=bullet_root.next;
 while (tempb!=&bullet_root) {
     if (tempb->fuse_time<=t<=tempb->timeout)
         Explosion(&tempb->p,tempb->radius);
     tempb=tempb->next;
 }

 if (!ship.exploding) {
     if (d=NormD3(SubD3(&ship.p[0].state->x,&ship.p[1].state->x,&p1))) {
         SubD3(&ship.p[0].state->DxDt,&ship.p[1].state->DxDt,&p2);
         CrossD3(&p1,&p2,&p);
         spin=p.z/d;
     } else
         spin=0;
     t_left =Limit(ship.t_left+spin*ship.antispin,0,MAX_THRUST);

     if (d=NormD3(SubD3(&ship.p[0].state->x,&ship.p[2].state->x,&p1))) {
         SubD3(&ship.p[0].state->DxDt,&ship.p[2].state->DxDt,&p2);
         CrossD3(&p1,&p2,&p);
         spin=p.z/d;
     } else
         spin=0;
     t_right=Limit(ship.t_right-spin*ship.antispin,0,MAX_THRUST);

     SubD3(&ship.p[0].state->x,&ship.p[1].state->x,&p1);
     SubD3(&ship.p[0].state->x,&ship.p[2].state->x,&p2);
     UnitD3(AddD3(&p1,&p2,&p));
     if (!(ship.s[3].user_data&SF_DESTROYED)) {
         MulD3(t_left,&p,&p1);
         AddEquD3(&ship.p[3].DstateDt->DxDt,&p1);
     }
     if (!(ship.s[5].user_data&SF_DESTROYED)) {
         MulD3(t_right,&p,&p2);
         AddEquD3(&ship.p[4].DstateDt->DxDt,&p2);
     }
 }
}


void CheckDamage()
{
 I8 i;
 Enemy1 *tempe,*tempe1;
 if (!ship.dead) {
     if (ship.exploding && t>ship.die_time) {
         ShipDel;
         ship.dead=TRUE;
     } else
         for (i=0;i<SHIP_SPRINGS;i++) {
             if (Abs(ship.s[i].f)>2.0*ship.s[i].constant)
                 ship.s[i].user_data|=SF_DESTROYED;
             if (ship.s[i].user_data&SF_DESTROYED) {
                 if (!(ship.s[i].user_data&SF_REMOVED)) {
                     RemQue(&ship.s[i]);
                     ship.s[i].user_data|=SF_REMOVED;
                 }
                 if (i<3) {
                     if (!ship.exploding) {
                         ship.exploding=TRUE;
                         ship.die_time=t;
                         ship.timeout=t+0.75;
                         game_over=TRUE;
                         break;
                     }
                 }
             }
         }
 }

 tempe=enemy_root.next;
 while (tempe!=&enemy_root) {
     tempe1=tempe->next;
     if (tempe->exploding) {
         if (t>tempe->timeout)
             Enemy1Del(tempe);
     } else
         for (i=0;i<ENEMY_SPRINGS;i++) {
             if (Abs(tempe->s[i].f)>4.0*tempe->s[i].constant) {
                 tempe->exploding=TRUE;
                 tempe->die_time=t;
                 tempe->timeout=t+0.75;
                 break;
             }
         }
     tempe=tempe1;
 }
}

$FG,4$//********************************** Bullets$FG$

void EnemyFire(Enemy1 *tempe)
{
 D3 p,p1,p2;
 double r,fuse_time;
 Bullet *tempb;
 if (t>tempe->reload_done_time) {
     r=1.5+0.5;
     fuse_time=0.4;
     tempb=MAllocZ(sizeof(Bullet));
     CopyD3(&tempb->p.x,&tempe->p[0].x);
     tempb->radius=r;
     tempb->fuse_time=t+1.5*fuse_time;
     tempb->timeout=tempb->fuse_time+0.125;
     tempb->p.mass=0.3*r*r*r*MASS;
     SubD3(&tempe->p[0].x,&tempe->p[1].x,&p1);
     SubD3(&tempe->p[0].x,&tempe->p[2].x,&p2);
     AddD3(&p1,&p2,&p);
     AddEquD3(&tempb->p.x,MulEquD3(CopyD3(&p1,UnitD3(&p)),r+MASS_RADIUS+5));
     AddEquD3(MulEquD3(&p,1000/(r+1)),&tempe->p[0].DxDt);
     CopyD3(&tempb->p.DxDt,&p);
     MulEquD3(&p,tempb->p.mass/tempe->p[0].mass/100.0);
     SubEquD3(&tempe->p[0].DxDt,&p);
     InsQue(&tempb->p,o->last_mass);
     InsQue(tempb,bullet_root.last);
     tempe->reload_done_time=t+r/ENEMY_FIRE_RATE;
 }
}

void Fire()
{
 D3 p,p1,p2;
 double r,fuse_time;
 Bullet *tempb;
 if (!ship.exploding && t>ship.reload_done_time) {
     r=3.0*ctrl_panel.bullet_radius/CTRL_PANEL_RANGE+0.5;
     fuse_time=ToDouble(ctrl_panel.fuse_time+1)/CTRL_PANEL_RANGE;
     tempb=MAllocZ(sizeof(Bullet));
     CopyD3(&tempb->p.x,&ship.p[0].x);
     tempb->radius=r;
     tempb->fuse_time=t+1.5*fuse_time;
     tempb->timeout=tempb->fuse_time+0.125;
     tempb->p.mass=0.3*r*r*r*MASS;
     SubD3(&ship.p[0].x,&ship.p[1].x,&p1);
     SubD3(&ship.p[0].x,&ship.p[2].x,&p2);
     AddD3(&p1,&p2,&p);
     AddEquD3(&tempb->p.x,MulEquD3(CopyD3(&p1,UnitD3(&p)),r+MASS_RADIUS+5));
     AddEquD3(MulEquD3(&p,1000/(r+1)),&ship.p[0].DxDt);
     CopyD3(&tempb->p.DxDt,&p);
     MulEquD3(&p,tempb->p.mass/ship.p[0].mass/100.0);
     SubEquD3(&ship.p[0].DxDt,&p);
     InsQue(&tempb->p,o->last_mass);
     InsQue(tempb,bullet_root.last);
     ship.reload_done_time=t+r/FIRE_RATE;
 }
}

void ExpireShots()
{
 Bullet *tempb=bullet_root.next,*tempb1;
 while (tempb!=&bullet_root) {
     tempb1=tempb->next;
     if (t>tempb->timeout) {
         RemQue(tempb);
         RemQue(&tempb->p);
         Free(tempb);
     }
     tempb=tempb1;
 }
}

$FG,4$//********************************** AI$FG$

void AI()
{
 D3 p,p1,p2;
 Enemy1 *tempe=enemy_root.next;
 if (!ship.exploding) {
     while (tempe!=&enemy_root) {
         SubD3(&tempe->p[0].x,&tempe->p[1].x,&p1);
         SubD3(&tempe->p[0].x,&tempe->p[2].x,&p2);
         AddD3(&p1,&p2,&p);
         SubD3(&ship.p[0].x,&tempe->p[0].x,&p1);
         if (DotD3(UnitD3(&p),UnitD3(&p1))>0.995)
             EnemyFire(tempe);
         tempe=tempe->next;
     }
 }
}

$FG,4$//********************************** Init$FG$


void InitObjs()
{
 I8 i;
 enemy_root.next=enemy_root.last=&enemy_root;
 bullet_root.next=bullet_root.last=&bullet_root;

 for (i=0;i<NUM_STARS;i++) {
     stars_x[i]=RandU2%GR_WIDTH;
     stars_y[i]=RandU2%GR_HEIGHT;
 }

 InitShip(Fs->win_pixel_width/2,Fs->win_pixel_height/2);
 for (i=0;i<level+3;i++)
     Enemy1New(RandU2%(Fs->win_pixel_width-20)+10,RandU2%(Fs->win_pixel_height-20)+10);
}


$FG,4$//********************************** Main$FG$

void XCaliber()
{
 I8 ch,cmd,p1,p2,sc,i;
 void *old_update=Fs->update_win;
 Ltf *l,*old_cur_ltf=Fs->cur_ltf,*old_aux_ltf=Fs->aux_ltf;
 BoolI1 old_preempt=Preempt(OFF),
         old_border=WinBorder(OFF);
 Ctrl *cp=CtrlPanelNew;
 I8 old_attr=Fs->text_attr;

 Fs->text_attr=BLACK<<4+WHITE;
 WinMax;

 Fs->cur_ltf=NULL;

 Fs->aux_ltf=l=InitSysAuxLtf(TRUE);
 LtfPutSExt(l,"$$MA+A+TML+IV,\"Restart | \",\"\r\"$$");
 LtfPutSExt(l,"$$MA+A+TML+IV,\"Exit\",\"\\033\"$$");

 Fs->update_win=&UpdateWin;
 do {
     game_over=FALSE;
     score=0;
     level=1;
     o=OdeNew(0,0.01,ODEF_HAS_MASSES);
     o->derivative=&MyDerivative;
     o->min_tolerance=1e-32;
     o->drag_v3=0.00001;
     InitObjs;
     InsQue(o,Fs->last_ode);
     ch=0;
     do {
         while (!game_over &&
                 (cmd=ScanMsg(&p1,&p2,1<<MSG_KEY_DOWN|1<<MSG_KEY_UP|1<<MSGF_ALLOW_KEY_DESC))) {
             ch=p1; sc=p2;
             if (cmd==MSG_KEY_DOWN) {
                 if (ch==CH_SPACE) {
                     if (!l->best_d && l->cur_entry!=l) {
                         LtfRunEntry(l,l->cur_entry,TRUE);
                         LtfUnlock(l);
                         ch=0;
                         l->best_d=MAX_I8;
                     } else
                         Fire;
                 } else if (sc.u1[0]==SC_CURSOR_RIGHT) {
                     if (sc&SCF_SHIFT)
                         ctrl_panel.fuse_time+=2;
                     else
                         ship.t_right=MAX_THRUST;
                 } else if (sc.u1[0]==SC_CURSOR_LEFT) {
                     if (sc&SCF_SHIFT)
                         ctrl_panel.fuse_time-=2;
                     else
                         ship.t_left =MAX_THRUST;
                 } else if (sc.u1[0]==SC_CURSOR_UP) {
                     if (sc&SCF_SHIFT)
                         ctrl_panel.bullet_radius+=2;
                     else {
                         ship.t_right=MAX_THRUST;
                         ship.t_left =MAX_THRUST;
                     }
                 } else if (sc.u1[0]==SC_CURSOR_DOWN) {
                     if (sc&SCF_SHIFT)
                         ctrl_panel.bullet_radius-=2;
                     else
                         ship.antispin=MAX_ANTISPIN;
                 }
             } else {
                 if (sc.u1[0]==SC_CURSOR_RIGHT)
                     ship.t_right=0;
                 else if (sc.u1[0]==SC_CURSOR_LEFT)
                     ship.t_left =0;
                 else if (sc.u1[0]==SC_CURSOR_UP) {
                     ship.t_right=0;
                     ship.t_left =0;
                 } else if (sc.u1[0]==SC_CURSOR_DOWN)
                     ship.antispin=0;
             }
         }
         AI;
         ExpireShots;
         CheckDamage;
         WinSync; //msgs are only queued by winmngr
         if (game_over)
             ch=ScanChar;
         else {
             if (!remaining) {
                 level++;
                 for (i=0;i<level+3;i++)
                     Enemy1New(RandU2%(Fs->win_pixel_width-20)+10,RandU2%(Fs->win_pixel_height-20)+10);
                 }
         }
     } while (ch!=CH_ESC && ch!=CH_CR && ch!=CH_CTRLQ);
     AllDel(o);
 } while (ch!=CH_ESC && ch!=CH_CTRLQ);
 music_mute=FALSE;
 CtrlPanelDel(cp);
 LtfDel(l);
 Fs->aux_ltf=old_aux_ltf;
 if (Fs->cur_ltf=old_cur_ltf)
     LtfBottom(Fs->cur_ltf);
 Fs->text_attr=old_attr;
 Fs->update_win=old_update;

 WinBorder(old_border);
 Preempt(old_preempt);
}
Home

Flight Simulator
FirstPersonShootr
BigGuns
BirdLand
MultiCore
Tanks
TimeOut
X-Caliber