www.pudn.com > nucsrc > DISP.C
/*============================================================================*/ /* PROJECT NUCLEUS. (c) RocSoft, 1995. */ /* v1.0 18 Jan 95. */ /*============================================================================*/ #include#include #include #include #include #include #include #include #include #include "\rocco\glib\games.h" #include #include #include #include #include "defines.h" #include "prototyp.h" #include "globals.h" /*==================[ External Variable Definitions ]=========================*/ extern char *Banner, Demo_Mode, Demo_Exited; extern int ParticleMass[]; extern int LogoIndex1[], LogoIndex2[], Logo_Control[14]; extern unsigned int Demo_Timer, Experiment_Timer; extern int *RootTable; extern BYTE Screen_Shot; extern HIGH_SCORE_TABLE High_Scores; /*=======================[ Local Variable Definitions ]=======================*/ int Last_Mins; unsigned char Neutron_Fired; unsigned char Update_Score; POWER_UP_TYPE Power_Up_Icon; int Power_Up_Delay; char *VictoryMsgs[]={ "Congratulations! You've successfully", "completed all of your tasks. I'm afraid", "you need to get another day job. Why", "don't be become your OWN boss and", "register! Upon registration you get", "your very own level editor to create", "loads and loads of different levels!", NULL }; char *DeathMsgs[NUMBER_OF_MELTDOWNS]={ "", "Time Meltdown!", "Mass Meltdown!", "Rogue Ray Meltdown!", "Rogue Particle Meltdown!" }; /*===================[ Functions For Display Control ]========================*/ void Add_Particle_To_Nucleus( int nuc, int mol, int d ) { int dx, dy, ac; PARTICLE *p=Cfg.particles+mol; NUCLEUS *n=Cfg.nuclei+nuc; n->mass += ParticleMass[p->type]; p->active = TRUE; p->r = (d<6) ? 3 : d>>1; p->nucleus = nuc; dx = p->x - n->cx; dy = p->y - n->cy; if ( d<2 ) ac=TRIG_TAB_FACTOR; else { ac = (dx*TRIG_TAB_FACTOR)/(d>>1); ac = ABS(ac); if ( ac > TRIG_TAB_FACTOR ) ac=TRIG_TAB_FACTOR; } if ( dx>=0 ) p->angle = (dy<0) ? 360-PseudoACos(ac) : PseudoACos(ac); else p->angle = (dy<0) ? 180+PseudoACos(ac) : 180-PseudoACos(ac); } int Calculate_Rogue_Interval( int mintime, int maxtime ) { return( (mintime || maxtime) ? ((random()%(maxtime-mintime+1))+mintime) : 0 ); } void Check_Beam_Collisions( void ) { BEAM *b; NUCLEUS *n; SHIELD *s; int i, j, dx, dy; for ( i=0, b=Cfg.beams; i active && object_active(BEAM_TOON_BASE_PRI+i) ) { for ( j=0, s=Cfg.shields; j active && object_active(SHIELD_TOON_BASE_PRI+j) ) { dx = s->x - b->x + ((s->x>b->x)?3:0); dx = ABS(dx); dy = s->y - b->y; dy = ABS(dy); if ( dx<36 && dy<36 && RootTable[dx*dx+dy*dy]<=((s->rx+s->ry)>>1) ) { Sfx( SFX_SHIELD_HIT ); delete_object( BEAM_TOON_BASE_PRI+i ); b->active = FALSE; break; } } } if ( b->active ) { for ( j=0, n=Cfg.nuclei; j mass ) { dx = n->cx - b->x + ((n->cx>b->x)?3:0); dx = ABS(dx); dy = n->cy - b->y; dy = ABS(dy); if ( dx<=NUCLEUS_HIT_TOLERANCE && dy<=NUCLEUS_HIT_TOLERANCE ) { Split_Nucleus( n,j,SFX_NUCLEUS_HIT ); delete_object( BEAM_TOON_BASE_PRI+i ); b->active = FALSE; Meltdown = ROGUE_RAY_MELTDOWN; break; } } } } } } } void Check_Bonus_Pickup( int x, int y ) { OBJECT *o=ObjectList[object_index(POWER_UP_TOON_BASE_PRI)]; if ( o->status==ACTIVE_OBJECT && o->x1<=x && x<=o->x2 && o->y1<=y && y<=o->y2 ) { delete_object( POWER_UP_TOON_BASE_PRI ); Sfx( SFX_BONUS_PICKUP ); Cfg.score += PTS_POWER_UP; Update_Score = TRUE; switch( Power_Up_Icon ) { case PUP_NEUTRON: if ( (Cfg.rays+=Lev->rays) > 99 ) Cfg.rays=99; Display_Neutron(); break; case PUP_SHIELD: if ( (Cfg.shield_cnt+=Lev->shields) > 99 ) Cfg.shield_cnt=99; Display_Shields(); break; } } } int Create_Protective_Shield( int x, int y ) { SHIELD *s; int i; for ( i=0, s=Cfg.shields; i active && !object_active(SHIELD_TOON_BASE_PRI+i) ) { s->active = TRUE; s->rx = Shield_Icons[0].w>>1; s->ry = Shield_Icons[0].h>>1; s->reps = s->frame = 0; s->time = Lev->shield_duration; add_object( SHIELD_TOON_BASE_PRI+i,Toon_Shield,0,s->x=x,s->y=y ); return( FALSE ); } } return( TRUE ); } int Create_Rogue_Beam( void ) { BEAM *b; int i; for ( i=0, b=Cfg.beams; i active && !object_active(BEAM_TOON_BASE_PRI+i) ) { b->active = TRUE; b->frame = (random()&0x01) ? 0 : (NUM_OF_BEAMS-1); b->x = (b->frame==0) ? VX_MIN : VX_MAX; b->y = (random()%(VY_MAX-VY_MIN-10)) + VY_MIN; b->vx = (b->frame==0) ? 3 : -3; add_object( BEAM_TOON_BASE_PRI+i,Toon_Beam,b->frame,b->x,b->y ); return( TRUE ); } } return( FALSE ); } int Create_Rogue_Particle( void ) { NUCLEUS *n; PARTICLE *p; int i, j, ok; for ( i=0, p=Cfg.rogues; i rogue && !object_active(ROGUE_TOON_BASE_PRI+i) ) { p->rogue = TRUE; p->delay = p->frame = 0; p->time = Lev->rogue_duration; do { p->x = (random()%(VX_MAX-VX_MIN+1)) + VX_MIN; p->y = (random()%(VY_MAX-VY_MIN+1)) + VY_MIN; for ( j=0, ok=TRUE, n=Cfg.nuclei; ok && j cx-p->x)<(NUCLEUS_HIT_TOLERANCE<<2) && ABS(n->cy-p->y)<(NUCLEUS_HIT_TOLERANCE<<2) ) ok=FALSE; } while ( !ok ); p->vx = Set_Particle_Velocity( SPEED_MASK_2,2 ); p->vy = Set_Particle_Velocity( SPEED_MASK_2,2 ); add_object( ROGUE_TOON_BASE_PRI+i,Toon_Rogue_Particle,0,p->x,p->y ); return( TRUE ); } } return( FALSE ); } void Cycle_Fractal_Colours( void ) { static char delay=0; unsigned char *buff=Pal.pal; if ( ++delay > 6 ) { delay = 0; _asm { pushf push ds push si push di lds si, buff add si, FRACTAL_CYCLE_COLOUR_1 mov ax, ds mov es, ax mov di, si cld /* Both es:[di] & ds:[si] point to palette start */ lodsw /* AX holds G:R colour components */ mov bx, ax /* Stash in bx */ lodsb /* AL hold B component */ mov dl, al /* Stash in dl */ mov cx, FRACTAL_CYCLE_COUNT shr cx, 1 rep movsw /* Move even number of words */ mov ax, bx /* es:[di] should point to last colour */ stosw mov al, dl stosb pop di pop si pop ds popf } } } void Detect_Particle_Collisions( void ) { int i, j, k, dx, dy, d, min; unsigned int adx, ady; PARTICLE *p, *pp; NUCLEUS *n; SPRITE *s1, *s2; for ( i=0, n=Cfg.nuclei; i cx-NUCLEUS_HIT_TOLERANCE<=MouseX && MouseX<=n->cx+NUCLEUS_HIT_TOLERANCE && n->cy-NUCLEUS_HIT_TOLERANCE<=MouseY && MouseY<=n->cy+NUCLEUS_HIT_TOLERANCE ) { Split_Nucleus( n,i,SFX_NUCLEUS_HIT ); Cfg.score += PTS_NUCLEUS_HIT; Update_Score = TRUE; } else { if ( n->mass >= Lev->critical_mass || n->cframe<=0 ) { if ( n->mass >= Lev->critical_mass && Lev->mass_meltdown ) Meltdown=MASS_MELTDOWN; Split_Nucleus( n,i,SFX_NUCLEUS_SPLIT ); } else { if ( Lev->rogue_particles ) { for ( j=0, p=Cfg.rogues; j rogue && object_active(ROGUE_TOON_BASE_PRI+j) ) { if ( ABS(n->cx-p->x) cy-p->y) count; i++, p++ ) { if ( !p->active && ABS(p->vx)<=MIN_SPEED && ABS(p->vy)<=MIN_SPEED ) { s1 = SParticles+p->type; for ( j=0, pp=Cfg.particles; j count && !p->active; j++, pp++ ) { if ( j!=i && ABS(pp->vx)<=MIN_SPEED && ABS(pp->vy)<=MIN_SPEED ) { s2 = SParticles+pp->type; if ( pp->active ) { min = (s1->w+s1->h)>>2; dx = Cfg.nuclei[pp->nucleus].cx; dy = Cfg.nuclei[pp->nucleus].cy; } else { min = (s2->w+s2->h+s1->w+s1->h)>>2; dx = pp->x; dy = pp->y; } dx -= p->x; dy -= p->y; if ( (adx=ABS(dx))<=min && (ady=ABS(dy))<=min ) { if ( (d=RootTable[adx*adx+ady*ady])<=min ) { if ( pp->active ) Add_Particle_To_Nucleus( pp->nucleus,i,d<<1 ); else { for ( k=0, n=Cfg.nuclei; (n->mass>0 || object_active(COUNTER_TOON_BASE_PRI+k)) && k cx = p->x + dx/2; n->cy = p->y + dy/2; n->speed= ANGLE_START; n->cframe = Lev->critical_time; n->n_fired= n->s_fired=FALSE; if ( add_object(COUNTER_TOON_BASE_PRI+k,Toon_Counter,n->cframe,n->cx-3,n->cy-2)==0 ) { Add_Particle_To_Nucleus( k,j,d ); Add_Particle_To_Nucleus( k,i,d ); } } } } } } } } } } void Display_Neutron( void ) { rect( PANEL_XBASE1+63,PANEL_YBASE+12,PANEL_XBASE1+78,PANEL_YBASE+19,CONTROL_PANEL_COLOUR,FILL,SPLIT_PAGE ); Spr_Printi( SFont,Cfg.rays,PANEL_XBASE1+63,PANEL_YBASE+12,2,8,HORIZ,SPLIT_PAGE ); } void Display_Panel( void ) { int i, j; Fade_Screen( MODE_320x200x256 ); splitscr( VS.my-SPLIT_SCREEN_HEIGHT+1 ); imgvwport( VX_MIN,VY_MIN,VX_MAX,VY_MAX ); mouselim( VX_MIN,VY_MIN,VX_MAX,VY_MAX ); /* Draw play area layout */ Draw_Fractal_Background( 0 ); putspr( Panel,0,0,OWRTE,0 ); putspr( Panel+2,VS.mx-7,0,OWRTE,0 ); putspr( Panel+4,0,VS.my-7,OWRTE,0 ); putspr( Panel+5,VS.mx-7,VS.my-7,OWRTE,0 ); rect( 0,0,VS.mx,SPLIT_SCREEN_HEIGHT-1,CONTROL_PANEL_COLOUR,FILL,SPLIT_PAGE ); putspr( Panel+6,0,0,OWRTE,SPLIT_PAGE ); putspr( Panel+8,VS.mx-7,0,OWRTE,SPLIT_PAGE ); putspr( Panel+11,0,SPLIT_SCREEN_HEIGHT-8,OWRTE,SPLIT_PAGE ); putspr( Panel+13,VS.mx-7,SPLIT_SCREEN_HEIGHT-8,OWRTE,SPLIT_PAGE ); for ( i=8; i =8 ) break; if ( ++i>6 ) { add_object( 0,Toon_Nucleus,0,((VS.mx-Nucleus_Logo.w)>>1)-6,(VS.my-Nucleus_Logo.h)>>1 ); Timers[5] = 72; } else { Logo_Control[i]=Logo_Control[i+7]=1; Timers[5] = (i<6)?LOGO_DELAY:LOGO_DELAY*3; } } if ( Demo_Exited ) break; } while ( uppercase((char)key)=='P' || !key ); CONSUME_KEYS; remove_objects(); } void Draw_Edged_Box( int x1, int y1, int x2, int y2, int sun, int shdw, int fill, int page ) { line( x1,y1,x2,y1,sun,page ); line( x1,y1,x1,y2,sun,page ); line( x1+1,y2,x2,y2,shdw,page ); line( x2,y2,x2,y1+1,shdw,page ); rect( x1+1,y1+1,x2-1,y2-1,fill,FILL,page ); line( x1+4,y1+3,x2-4,y1+3,shdw,page ); line( x1+4,y1+3,x1+4,y2-3,shdw,page ); line( x1+5,y2-3,x2-4,y2-3,sun,page ); line( x2-4,y2-3,x2-4,y1+4,sun,page ); } void Draw_Fractal_Background( int page ) { int x, y; for ( y=0; y<=VS.my; y+=Fractal.h ) for ( x=0; x<=VS.mx; x+=Fractal.w ) putspr( &Fractal,x,y,OWRTE,page ); } void End_Of_Level_Bonus( void ) { char *title="Bonus!", *equals="=", *msgs[2]={ "End Of Level!",NULL }; int ht=SFont[' '].h, wth=240, x1, y1, x2, y2, i, j, total, speedy=FALSE, cnt, pts; CONSUME_KEYS; Show_Error_Message( msgs,SFX_LEVEL_START,2,IPage ); x2 = (x1=(VS.mx+1-wth-6)>>1) + wth + 5; y2 = (y1=(VS.my+1-ht*11-6)>>1) + ht*11 + 5; Draw_Edged_Box( x1,y1,x2,y2,WHITE,GREY,L_GREY,IPage ); x2 = x1 + ((wth-Spr_Strlen(SFont,title))>>1); Spr_Print( SFont,title,x2,y1+5,PROPORTIONAL,HORIZ,IPage ); line( x2-1,y1+ht+5,x2+Spr_Strlen(SFont,title),y1+ht+5,WHITE,IPage ); line( x2-2,y1+ht+6,x2+Spr_Strlen(SFont,title)+1,y1+ht+6,GREY,IPage ); CONSUME_KEYS; Sfx( SFX_BONUS_PICKUP ); Spr_Print( SFont,"Level Completion",x1+11,y1+ht*3+5,PROPORTIONAL,HORIZ,IPage ); Spr_Print( SFont,equals,x1+22*8+3,y1+ht*3+5,PROPORTIONAL,HORIZ,IPage ); Spr_Printi( SFont,total=PTS_END_OF_LEVEL_BONUS,x1+24*8+3,y1+ht*3+5,5,8,HORIZ,IPage ); speedy = (inkey(0)!=0); for ( i=0; i<2; i++ ) { if ( !speedy ) { waitticks( 9 ); speedy = (inkey(0)!=0); } CONSUME_KEYS; if ( i==0 ) { y2 = y1+ht*5+5; cnt = Cfg.rays; pts = PTS_NEUTRON_LEFT; } else { y2 = y1+ht*7+5; cnt = Cfg.shield_cnt; pts = PTS_SHIELD_LEFT; } if ( !cnt ) pts=0; Spr_Print( SFont,(i==0)?"Remaining Neutrons":"Remaining Shields",x1+11,y2,PROPORTIONAL,HORIZ,IPage ); Spr_Printi( SFont,cnt,x1+19*8+3,y2,2,8,HORIZ,IPage ); Spr_Print( SFont,equals,x1+22*8+3,y2,PROPORTIONAL,HORIZ,IPage ); x2 = x1 + 24*8 + 3; for ( j=0; j<=cnt; j++ ) { if ( cnt==0 || j >2; ave_pr -= ave_pr>>3; for ( j=MAX_SHIELDS, s=Cfg.shields; j; j--, s++ ) { if ( s->active ) { ave_sr = (s->rx+s->ry)>>1; dx = (s->x >= p->x) ? s->x-p->x : p->x-s->x; dy = (s->y >= p->y) ? s->y-p->y : p->y-s->y; if ( dx<=(ave_sr+ave_pr) && dy<=(ave_sr+ave_pr) ) /* Prevents overflow for pseudoroot */ { d = RootTable[dx*dx+dy*dy]; m1 = p->x+p->vx-s->x; m1=ABS(m1); m2 = p->y+p->vy-s->y; m2=ABS(m2); m1 = RootTable[ m1*m1+m2*m2 ]; if ( (ave_sr<=d && d<=ave_sr+ave_pr && m1 =d && ave_sr-ave_pr<=d && m1>d) ) { /* Determine angle of incidence & therefore reflection */ if ( d>=ave_sr ) { Cfg.score += PTS_SHIELD_HIT; Update_Score = TRUE; } vx = p->vx*5; /* Velocity vector */ vy = p->vy*5; nx = (px=p->x)-s->x; /* Point of incidence & normal vector */ ny = (py=p->y)-s->y; m1 = RootTable[ nx*nx+ny*ny ]; m2 = RootTable[ vx*vx+vy*vy ]; factor = (m2*100)/m1; ac = (int) (((long)(nx*(-vx)+ny*(-vy))*(long)TRIG_TAB_FACTOR)/((long)(m1*m2))); if ( (theta=PseudoACos(ac)%360)<5 ) { rx = -vx; ry = -vy; } else { rx = (nx*PseudoCos(theta) - ny*PseudoSin(theta))/TRIG_TAB_FACTOR; ry = (nx*PseudoSin(theta) + ny*PseudoCos(theta))/TRIG_TAB_FACTOR; rx = (rx*factor)/100; ry = (ry*factor)/100; x1 = px-vx; y1 = py-vy; x2 = px+rx; y2 = py+ry; if ( ABS(x1-x2)<=3 && ABS(y1-y2)<=3 ) { theta = 180-theta; rx = ((-nx)*PseudoCos(theta) - (-ny)*PseudoSin(theta))/TRIG_TAB_FACTOR; ry = ((-nx)*PseudoSin(theta) + (-ny)*PseudoCos(theta))/TRIG_TAB_FACTOR; rx = (rx*factor)/100; ry = (ry*factor)/100; } } if ( (p->vx=rx/5)==0 ) p->vx=(rx>0)?1:-1; if ( (p->vy=ry/5)==0 ) p->vy=(ry>0)?1:-1; /* If at single speed, energize them to avoid being caught in rasp fashion */ if ( ABS(p->vx)==1 && ABS(p->vy)==1 ) { p->vx += (p->vx>0)?1:-1; p->vy += (p->vy>0)?1:-1; } Sfx( SFX_SHIELD_HIT ); return( TRUE ); } } } } return( FALSE ); } void Play_Demo( void ) { static int ftype; NUCLEUS *n; int i, dx, dy; if ( Target_Nuc==-1 || Cfg.nuclei[Target_Nuc].mass==0 ) { for ( Target_Nuc=-1, i=0, n=Cfg.nuclei; i mass ) { if ( (Lev->rogue_particles || Lev->rogue_beams) && !(n->n_fired || n->s_fired) ) { Target_Nuc = i; ftype = (n->s_fired) ? L_BUTTON:R_BUTTON; } else { if ( Lev->mass_meltdown && n->mass+4>=Lev->critical_mass && !n->s_fired ) { Target_Nuc = i; ftype = R_BUTTON; } else { if ( Lev->time_meltdown && !n->n_fired ) { Target_Nuc = i; ftype = L_BUTTON; } } } } } } if ( Target_Nuc != -1 ) { n = Cfg.nuclei+Target_Nuc; dx = n->cx - MouseX; dy = n->cy - MouseY; if ( ABS(dx) > 3 ) dx=(dx<0)?-3:3; if ( ABS(dy) > 3 ) dy=(dy<0)?-3:3; mousepos( MouseX+=dx,MouseY+=dy ); dx = MouseX - n->cx; dy = MouseY - n->cy; if ( ABS(dx)<4 && ABS(dy)<4 ) { if ( SyringeDir==0 ) { if ( ftype==L_BUTTON ) { if ( Cfg.rays ) { n->n_fired=TRUE; MouseB =ftype; } } else { if ( Cfg.shield_cnt ) { n->s_fired=TRUE; MouseB =ftype; } } Target_Nuc=-1; } } } } int Play_Level( void ) { int i, key=0; long score; unsigned int *t; PARTICLE *p; NUCLEUS *n; SHIELD *s; BEAM *b; char *msgs[2]={ "Get Ready!",NULL }; Meltdown = NO_MELTDOWN; do { Lev = Levels + Cfg.level - 1; if ( !Cfg.briefed ) { Show_Experiment_Guide(); Cfg.briefed=TRUE; if ( Demo_Mode && Demo_Exited ) break; } Fade_Screen( MODE_320x200x256 ); Draw_Fractal_Background( 0 ); fadein( &Pal,0 ); CONSUME_KEYS; Show_Error_Message( msgs,SFX_LEVEL_START,2,0 ); if ( Demo_Mode && Demo_Exited ) break; Last_Mins = Target_Nuc = -1; Display_Panel(); COPY_PAGE( 0,1 ); COPY_PAGE( 0,2 ); initialise_objects( MAX_OBJECTS,&Selective_Replace,&Colour_Cycle_Switcher ); mousepos( I_MouseX=MouseX=VS.mx>>1,I_MouseY=MouseY=VS.my>>1 ); SyringeOffset=SyringeDir=0; add_object( SYRINGE_TOON_BASE_PRI,Toon_Syringe,SyringeBase=5,MouseX,MouseY ); if ( Demo_Mode ) { add_object( DEMO_TOON_BASE_PRI,Toon_Demo,0,(VS.mx-Demo_Icons[0].w)>>1,(VS.my-Demo_Icons[0].h)>>1 ); Demo_Timer=360; } for ( i=0; i count; i++ ) add_object( PARTICLE_TOON_BASE_PRI+i,Toon_Particle[Cfg.particles[i].type],0,Cfg.particles[i].x,Cfg.particles[i].y ); for ( i=0, n=Cfg.nuclei; i mass ) add_object( COUNTER_TOON_BASE_PRI+i,Toon_Counter,n->cframe,n->cx-3,n->cy-2 ); for ( i=0, s=Cfg.shields; i active ) add_object( SHIELD_TOON_BASE_PRI+i,Toon_Shield,s->frame,s->x,s->y ); for ( i=0, b=Cfg.beams; i active ) add_object( BEAM_TOON_BASE_PRI+i,Toon_Beam,b->frame,b->x,b->y ); for ( i=0, p=Cfg.rogues; i rogue ) add_object( ROGUE_TOON_BASE_PRI+i,Toon_Rogue_Particle,p->frame,p->x,p->y ); Experiment_Timer = 18; Game_Paused = Neutron_Fired = Update_Score = FALSE; CONSUME_KEYS; do { if ( Demo_Mode ) Play_Demo(); else { _asm cli MouseB = I_MouseB; MouseX = I_MouseX; MouseY = I_MouseY; _asm sti } update_objects(0,0,2); if ( (key=inkey(0)) ) Process_Keystroke( key ); Cycle_Fractal_Colours(); if ( MouseB&L_BUTTON ) /* Left button to fire rays */ { if ( SyringeDir!=0 || !Lev->gun || Cfg.rays==0 ) { Sfx( SFX_NO_FIRE ); } else { Sfx( SFX_NEUTRON_FIRED ); SyringeDir=1; Cfg.rays--; Display_Neutron(); Neutron_Fired=TRUE; } MouseB ^= L_BUTTON; _asm cli I_MouseB = MouseB; _asm sti } if ( MouseB&R_BUTTON ) /* Right button to fire shields */ { if ( SyringeDir!=0 || !Lev->force_field || Cfg.shield_cnt==0 ) { Sfx( SFX_NO_FIRE ); } else { SyringeDir=1; if ( Create_Protective_Shield(MouseX,MouseY) ) Sfx( SFX_NO_FIRE ); else { Sfx( SFX_SHIELD_FIRED ); Cfg.shield_cnt--; Display_Shields(); } } MouseB ^= R_BUTTON; _asm cli I_MouseB = MouseB; _asm sti } Update_Particle_Positions(); Detect_Particle_Collisions(); if ( Lev->rogue_beams ) Check_Beam_Collisions(); if ( object_active(POWER_UP_TOON_BASE_PRI) ) Check_Bonus_Pickup(MouseX,MouseY); for ( i=0, t=Cfg.timers, n=Cfg.nuclei; i mass && !*t ) { if ( Lev->orbit_speed_up && n->speed<90 ) n->speed+=ANGLE_INC; n->cframe--; *t = SPEED_UP_TIME; } } if ( !Experiment_Timer ) { Cfg.time--; Display_Time(); Experiment_Timer = 18; for ( i=0, s=Cfg.shields; i time ) (s->time--); if ( (--Cfg.power_up_timer)==0 ) { Sfx( SFX_BONUS_PICKUP ); add_object( POWER_UP_TOON_BASE_PRI,Toon_PowerUp,((Power_Up_Icon=(Lev->powerup!=PUP_RANDOM)?Lev->powerup:(random()%PUP_RANDOM))==PUP_SHIELD)?0:8,VX_MIN-15,(random()%(VY_MAX-VY_MIN-15))+VY_MIN ); Power_Up_Delay = 0; Cfg.power_up_timer = Lev->power_up_delay; } if ( Lev->rogue_beams ) { if ( (--Cfg.beam_timer)==0 ) { if ( Create_Rogue_Beam() ) Sfx( SFX_ROGUE_BEAM ); Cfg.beam_timer = Calculate_Rogue_Interval( Lev->min_beam_sep,Lev->max_beam_sep ); } } if ( Lev->rogue_particles ) { for ( i=0, p=Cfg.rogues; i rogue && (--(p->time))==0 ) { p->rogue = FALSE; delete_object( ROGUE_TOON_BASE_PRI+i ); } if ( (--Cfg.rogue_timer)==0 ) { if ( Create_Rogue_Particle() ) Sfx( SFX_ROGUE_PARTICLE ); Cfg.rogue_timer = Calculate_Rogue_Interval( Lev->min_rogue_sep,Lev->max_rogue_sep ); } } } if ( Update_Score ) { Display_Score(); Update_Score=FALSE; } Neutron_Fired=FALSE; if ( Demo_Mode && (Demo_Exited || !Demo_Timer) ) break; } while ( key!=ESCAPEKEY && !Meltdown && Cfg.time ); Game_Paused = TRUE; remove_objects(); if ( Sound_Source==SOUND_BLASTER ) SB_abort(0x01); else flush_sounds(); score = Cfg.score; if ( Meltdown ) { Sfx( (random()&0x01)?SFX_SCREAM1:SFX_SCREAM2 ); rect( 0,0,VS.mx,VS.my,BLACK,FILL,2 ); Spr_Print( SFont,DeathMsgs[Meltdown],(VS.mx-Spr_Strlen(SFont,DeathMsgs[Meltdown]))>>1,30,PROPORTIONAL,HORIZ,2 ); melt_screen( IPage,2,6 ); CONSUME_KEYS; if ( Demo_Mode ) Meltdown=NO_MELTDOWN; else { Menu_New_Game( 0 ); Sfx( SFX_GAME_OVER ); sleep( 1 ); CONSUME_KEYS; } } if ( Demo_Mode && Demo_Exited ) break; if ( !Meltdown && (Cfg.time==0 || Demo_Mode) ) { if ( !Demo_Mode ) End_Of_Level_Bonus(); if ( (++Cfg.level) > Max_Levels ) { if ( !Demo_Mode ) Show_Error_Message( VictoryMsgs,SFX_FANFARE,20,IPage ); break; } Initialise_Level(); } } while ( key!=ESCAPEKEY && !Meltdown ); if ( !Demo_Mode && key!=ESCAPEKEY ) { CONSUME_KEYS; Hall_Of_Fame( &High_Scores,score,1 ); } return( 0 ); } void Print_Banner( int set_mode ) { char attr=ATTR(BLUE,WHITE); if ( set_mode ) setmode( 0x03 ); setpos( 0,0,0 ); _asm mov ax, 0920H _asm xor bh, bh _asm mov bl, attr _asm mov cx, 80 _asm int 10H setpos( (80-strlen(Banner))>>1,0,0 ); prints( Banner,attr,0 ); setpos( 0,5,0 ); } void Process_Keystroke( int key ) { SPRITE copy; int x, y; switch( key ) { case 'p': case 'P': Game_Paused=TRUE; if ( Sound_Source==SOUND_BLASTER ) { SB_pause(TRUE); SB_abort(0x02 ); } else hold_sound( ON ); if ( !Screen_Shot ) { getspr( ©,x=(VS.mx-Pause_Icon.w)>>1,y=(VS.my-Pause_Icon.h)>>1,Pause_Icon.w,Pause_Icon.h,IPage ); putspr( &Pause_Icon,x,y,OWRTE,IPage ); } Wait_For_Event( 32000 ); if ( !Screen_Shot ) { putspr( ©,x,y,OWRTE,IPage ); free( copy.buff ); } Game_Paused=FALSE; if ( Sound_Source==SOUND_BLASTER ) { SB_pause(FALSE); GOptions_Music(0); } else hold_sound( OFF ); break; case ESCAPEKEY: break; } } int Set_Particle_Velocity( int speed_mask, int min ) { register int v; do v=(random()%speed_mask)-(speed_mask>>1); while ( v==0 ); if ( v > 0 ) { if ( v < min ) v=min; } else if ( v > -min ) v=-min; return( v ); } int Show_Error_Message( char **msgs, SFX_TYPE sfx, int wait, int page ) { SPRITE save; int x1, y1, x2, y2, l, w, i, ht=SFont[' '].h; for ( l=w=0; msgs[l]; l++ ) if ( (i=Spr_Strlen(SFont,msgs[l]))>w ) w=i; w += 16; x1 = (VS.mx + 1 - w - 10)>>1; y1 = (VS.my + 1 - (l+2)*ht - 8)>>1; x2 = x1 + w + 9; y2 = y1 + (l+2)*ht + 7; if ( getspr(&save,x1,y1,(x2-x1+1),(y2-y1+1),page) ) Terminate( ERR_MALLOC ); Draw_Edged_Box( x1,y1,x2,y2,WHITE,GREY,L_GREY,page ); Sfx( sfx ); for ( i=0; i 0 && !Demo_Exited; w-- ) waitticks( 1 ); i=(Demo_Exited)?ESCAPEKEY:0; } else { if ( !wait ) i=getkey(0); else { Wait_For_Event( wait ); i=0; } } putspr( &save,x1,y1,OWRTE,page ); free( save.buff ); return( i ); } int Show_Experiment_Guide( void ) { #define MAX_MSGS 20 char buff[8], *msgs[MAX_MSGS]; int num=0, i, w, c; int x1, y1, x2, y2, ht; FONT f; rom_font( &f,ROM_8x8 ); ht = f.height; for ( i=0; i text[i]; i++ ) strcpy(msgs[num++],Lev->text[i]); *msgs[num++] = '\0'; strcpy( msgs[num++]," Summary" ); strsetx( msgs[num++],"Experiment Duration ",itoa(Lev->time,buff,10)," seconds.",NULL ); strsetx( msgs[num++],"Number Of Particles ",itoa(Lev->count,buff,10),".",NULL ); strsetx( msgs[num++],"Critical Mass ",itoa(Lev->critical_mass,buff,10)," units ",(Lev->mass_meltdown)?"(Meltdown!).":"(Split Only).",NULL ); strsetx( msgs[num++],"Critical Time ",itoa(Lev->critical_time,buff,10)," seconds ",(Lev->time_meltdown)?"(Meltdown!).":"(Split Only).",NULL ); strsetx( msgs[num++],"Atomic Injector ",(Lev->gun)?"ACTIVE (":"INACTIVE",(Lev->gun)?itoa(Lev->rays,buff,10):"",(Lev->gun)?" neutrons).":".",NULL ); strsetx( msgs[num++],"Nuclear Shields ",(Lev->force_field)?"ACTIVE (":"INACTIVE",(Lev->force_field)?itoa(Lev->shields,buff,10):"",(Lev->force_field)?").":".",NULL ); if ( Lev->rogue_beams ) strsetx( msgs[num++],"Rogue Beams ACTIVE (Meltdown!).",NULL ); if ( Lev->rogue_particles ) strsetx( msgs[num++],"Rogue Particles ACTIVE (Meltdown!).",NULL ); Fade_Screen( MODE_640x200x16 ); rect( 0,0,VS.mx,VS.my,BLUE,FILL,0 ); w = (sizeof(Levels[0].text[0])-1)*8 + 16; x1 = (VS.mx + 1 - w - 10)>>1; y1 = (VS.my + 1 - (num+2)*ht - 8)>>1; x2 = x1 + w + 9; y2 = y1 + (num+2)*ht + 7; Draw_Edged_Box( x1,y1,x2,y2,WHITE,GREY,L_GREY,0 ); Sfx( SFX_LEVEL_START ); for ( i=0; i mass = 0; n->s_fired = n->n_fired = FALSE; delete_object( COUNTER_TOON_BASE_PRI+nidx ); Sfx( sfx ); for ( i=Lev->count, p=Cfg.particles; i>0; i--, p++ ) { if ( p->active && p->nucleus==nidx ) { p->active = FALSE; p->vx = Set_Particle_Velocity( SPEED_MASK_2,2 ); p->vy = Set_Particle_Velocity( SPEED_MASK_2,2 ); } } } void Update_Particle_Positions( void ) { int i; PARTICLE *p; NUCLEUS *n; if ( Lev->rogue_particles ) { for ( i=0, p=Cfg.rogues; i rogue ) { Particle_Hit_Shield( p,RogueParticles[p->frame].w,RogueParticles[p->frame].h ); if ( p->x+p->vx < VX_MIN || p->x+p->vx > VX_MAX ) p->vx=-p->vx; if ( p->y+p->vy < VY_MIN || p->y+p->vy > VY_MAX ) p->vy=-p->vy; p->x += p->vx; p->y += p->vy; } } } for ( i=Lev->count, p=Cfg.particles; i>0; i--, p++ ) { if ( p->active ) { n = Cfg.nuclei + p->nucleus; if ( (p->angle+=n->speed) >= MAX_DEGREES ) p->angle-=MAX_DEGREES; p->x = n->cx + (p->r*PseudoCos(p->angle))/TRIG_TAB_FACTOR; p->y = n->cy + (p->r*PseudoSin(p->angle))/TRIG_TAB_FACTOR; } else { /* Look for particle hitting a shield */ Particle_Hit_Shield( p,SParticles[p->type].w,SParticles[p->type].h ); if ( p->x+p->vx < VX_MIN || p->x+p->vx > VX_MAX ) { if ( ABS(p->vx) > MIN_SPEED ) p->vx += (p->vx<0)?1:-1; p->vx=-p->vx; if ( p->x < VX_MIN ) p->x=VX_MIN; else if ( p->x > VX_MAX ) p->x=VX_MAX; } if ( p->y+p->vy < VY_MIN || p->y+p->vy > VY_MAX ) { if ( ABS(p->vy) > MIN_SPEED ) p->vy += (p->vy<0)?1:-1; p->vy=-p->vy; if ( p->y < VY_MIN ) p->y=VY_MIN; else if ( p->y > VY_MAX ) p->y=VY_MAX; } p->x += p->vx; p->y += p->vy; } } } /*==========================[ End Of Source File ]===========================*/