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);
}