/*********************************** Sandstorm FIRE.C ************************************/ /**** INCLUDES ****/ #include #include "main.h" #include "graphics.h" #include "pad.h" #include "control.h" #include "debug.h" #include "sprite.h" #include "collide.h" #include "fire.h" #include "ai.h" #include "cdread.h" #include "sound.h" /**** GLOBALS ****/ int closest; //either 1 or 2 to indicate which CPU is closest int homing_status, fire_h_status; /**** DEFINES ****/ #define HOMING_TIME (200) #define FIRE_H_TIME (100) #define HOMING_H_SPEED (10) #define FIRE_H_SPEED (15) #define ROT (8) //how much the missile rotation vector is increased each frame /**** FIREBULLET ****/ void FireBullet( void ) { static int counter; static int current; if(padd&PADR2) { if( (p1items.upg>0) && (sel_item==0) ) { counter++; if(counter==1 || counter==BULL_GAP) { current++; if(current>20) current=0; p1items.upg--; if(p1items.upg==0) lock_sel9=1; //activate bull_stat[current]=1; } } } bull_dir[current]= rot; //assign rotation angle of car bullet_pos[current].vx=truck[0].coord.coord.t[0]; //set positions to car pos. bullet_pos[current].vz=truck[0].coord.coord.t[2]; bullet_pos[current].vy=-20; //clear counters if(counter==(BULL_GAP*2)) counter=0; //if(current==100) current=0; } //end FIREBULLET /**** MOVEBULLET ****/ void MoveBullet( void ) { int x; for(x=0;x<21;x++){ if(bull_stat[x]==1) { bullet_pos[x].vx +=((BULL_SPEED*SIN[bull_dir[x]>>12])>>12); bullet_pos[x].vz +=((BULL_SPEED*COS[bull_dir[x]>>12])>>12); } //reset particles if(bullet_pos[x].vx>3250 || bullet_pos[x].vx<-3250 || bullet_pos[x].vz>2935 || bullet_pos[x].vz<-3200) { bull_stat[x]=0; } if(bull_stat[x]==1) { //do collision test in the same loop to save CPU time //if bullets hit truck[1] HitRBM( &actcounter1, &truck[1].coord, greencar.radius, &bullet_pos[x], bulletsphere.radius, bull_stat[x], 2, &cpulife1, bull_dir[x], BULLET_DAMAGE, 0 ); //if bullets hit truck[2] HitRBM( &actcounter2, &truck[2].coord, greencar.radius, &bullet_pos[x], bulletsphere.radius, bull_stat[x], 2, &cpulife2, bull_dir[x], BULLET_DAMAGE, 0 ); } //make bullets dissappear when collision is found if( (CheckCollisionItem( &truck[1].coord, greencar.radius, &bullet_pos[x], bulletsphere.radius)==1) ) bull_stat[x]=0; if( (CheckCollisionItem( &truck[2].coord, greencar.radius, &bullet_pos[x], bulletsphere.radius)==1) ) bull_stat[x]=0; } } //end MOVEBULLET /**** CHANGEITEM ****/ /*********************** NOTE: sel_item values: 0=MG; 1=MINE; 2=F. MISSILE; 3=HOM. missile; 4=POW. MISS.; 5=RICO; 6=TIME; *************************/ void ChangeItem( void ) { static int counter; static int changecounter; static int change; if(padd&PADR1) { counter++; if(counter==1 || counter==10) sel_item++; } else counter=0; //skip to the next item if inventory count is 0 if(sel_item==0) { if(p1items.upg==0) sel_item++; } if(sel_item==1) { if(p1items.mine==0) sel_item++; } if(sel_item==2) { if(p1items.fire==0) sel_item++; } if(sel_item==3) { if(p1items.hom==0) sel_item++; } if(sel_item==4) { if(p1items.pow==0) sel_item++; } if(sel_item==5) { if(p1items.rico==0) sel_item++; } if(sel_item==6) { if(p1items.time==0) sel_item++; } //if(counter==20 || counter==-20) counter=0; //reset counter if(sel_item<0) sel_item=6; //keep sel_item in range if(sel_item>6 && (sel_item!=9) ) sel_item=0; //keep sel_item in range } /**** RICOCHET ****/ void Ricochet( void ) { static int counter; counter++; if(counter>40) counter=0; //create flashing effect if(counter>19 && counter<31) ricochet.r=255; else ricochet.r=0x80; if( (padd&PADL2)&&(p1items.rico>0) ) { if(sel_item==5) { rico_status=1; ricochet.attribute &=~(1<<31); ricochet.attribute |=(0<<31); rico_pos.vx=truck[0].coord.coord.t[0]; rico_pos.vz=truck[0].coord.coord.t[2]; p1items.rico=0; lock_sel9=1; } } if(rico_status==1){ rico_pos.vx+=x_speed; rico_pos.vz+=z_speed; if(rico_pos.vx>2935) x_speed=-20; if(rico_pos.vx<-2900) x_speed=20; if(rico_pos.vz<-2900) z_speed=20; if(rico_pos.vz>1162) z_speed=-20; } //determine direction of ricochet object for collision functions if(x_speed>0 && z_speed>0) rico_dir=(45<<12); if(x_speed>0 && z_speed<0) rico_dir=(135<<12); if(x_speed<0 && z_speed<0) rico_dir=(225<<12); if(x_speed<0 && z_speed>0) rico_dir=(315<<12); } //end RICOCHET /**** PLACEMINE ****/ void PlaceMine( void ) { static int counter; static int freezecount; static int det_counter; //smoothes the gap between placing a mine and detonation static int det_life; //destroys mine after detonation counter++; if(counter>60) counter=0; //increment and limit counter if( (padd&PADL2) && (p1items.mine>0) && (sel_item==1) && (mine_status==0) ) { mine_status=1; det_counter=1; mine_1.attribute &=~(1<<31); mine_2.attribute &=~(1<<31); mine_3.attribute &=~(1<<31); mine_1.attribute|=(0<<31); mine_2.attribute|=(0<<31); mine_3.attribute|=(0<<31); mine_1_pos.vx=mine_2_pos.vx=mine_3_pos.vx=truck[0].coord.coord.t[0]; mine_1_pos.vz=mine_2_pos.vz=mine_3_pos.vz=truck[0].coord.coord.t[2]; } if( (padd&PADL2) && (p1items.mine>0) && (sel_item==1) && (mine_status==1) && (det_counter>20) ) { detonate=1; det_life=1; det_counter=0; expl_status=1; } if(det_counter>0) det_counter++; if(det_counter>100) det_counter=21; //fire sprites coords are the same as mine coords except .vy value fire1_pos=fire2_pos=mine_1_pos; fire1_pos.vy=fire2_pos.vy=-38; /**** determine direction of mine impact ****/ if(detonate==1){ if(CheckCollisionItem( &truck[0].coord, greencar.radius, &mine_1_pos, mine_expl.radius) ) { if(truck[0].coord.coord.t[0]>mine_1_pos.vx && truck[0].coord.coord.t[2]>mine_1_pos.vz) mine_dir=(45<<12); if(truck[0].coord.coord.t[0]>mine_1_pos.vx &&truck[0].coord.coord.t[2]mine_1_pos.vz) mine_dir=(315<<12); } if(CheckCollisionItem( &truck[1].coord, greencar.radius, &mine_1_pos, mine_expl.radius) ) { if(truck[1].coord.coord.t[0]>mine_1_pos.vx && truck[1].coord.coord.t[2]>mine_1_pos.vz) mine_dir=(45<<12); if(truck[1].coord.coord.t[0]>mine_1_pos.vx &&truck[1].coord.coord.t[2]mine_1_pos.vz) mine_dir=(315<<12); } if(CheckCollisionItem( &truck[2].coord, greencar.radius, &mine_1_pos, mine_expl.radius) ) { if(truck[2].coord.coord.t[0]>mine_1_pos.vx && truck[2].coord.coord.t[2]>mine_1_pos.vz) mine_dir=(45<<12); if(truck[2].coord.coord.t[0]>mine_1_pos.vx &&truck[2].coord.coord.t[2]mine_1_pos.vz) mine_dir=(315<<12); } } mine_2_pos=mine_3_pos=mine_1_pos; if(detonate==1){ //test only if the mine is detonated //if detonated mine hits p1 HitRBM( &actcounter3, &truck[0].coord, greencar.radius, &mine_1_pos, mine_expl.radius, mine_status, 1, &life, mine_dir, MINE_DAMAGE, MINE_SLIDE ); //if detonated mine hits truck[1] HitRBM( &actcounter1, &truck[1].coord, greencar.radius, &mine_1_pos, mine_expl.radius, mine_status, 1, &cpulife1, mine_dir, MINE_DAMAGE, MINE_SLIDE ); //if detonated mine hits truck[2] HitRBM( &actcounter2, &truck[2].coord, greencar.radius, &mine_1_pos, mine_expl.radius, mine_status, 1, &cpulife2, mine_dir, MINE_DAMAGE, MINE_SLIDE ); } //picks which mine alert sprite to flash if(counter<11) { picksprite=1; firestatus=1; } if(counter>10 && counter<21) { picksprite=2; firestatus=2; } if(counter>20 && counter<31) { picksprite=3; firestatus=1; } if(det_life>0) det_life++; //destroy mine and fire after 60 frames if(det_life>41) { //max. det_life value be equal or close to collision sliding values det_life=0; mine_status=0; detonate=0; expl_status=0; p1items.mine=0; lock_sel9=1; } /*** combine time item here****/ if( (padd&PADL2) && (p1items.time>0) && (sel_item==6) ) { freeze=1; p1items.time--; if(p1items.time==0) lock_sel9=1; } if(freeze==1) { freezecount++; if(freezecount>FREEZETIME) { freeze=0; freezecount=0; } } } /**** FIREMISSILE ****/ void FireMissile( void ) { static int counter; static int closest; //calculating which CPU opponent is closest static int homing_c; //counter for homing missile as it follows opponent static int cpu1_d, cpu2_d; //distance from CPU enemies static int homing_count, fire_h_count; if( (padd&PADL2) && sel_item==2 && p1items.fire>0 && fire_m_status==0) { counter++; if(counter==1 || counter==15) { fire_m_status=1; fire_m_dir=rot; fire_h_status=1; //decide which enemy is closest to home missile to cpu1_d=( (abs(truck[0].coord.coord.t[0]-truck[1].coord.coord.t[0])) + (abs(truck[0].coord.coord.t[2]-truck[1].coord.coord.t[2])) ); cpu2_d=( (abs(truck[0].coord.coord.t[0]-truck[2].coord.coord.t[0])) + (abs(truck[0].coord.coord.t[2]-truck[2].coord.coord.t[2])) ); if(cpu1_d0 && homing_m_status==0) { counter++; if(counter==1 || counter==15) { homing_m_status=1; homing_m_dir=rot; homing_status=1; //decide which enemy is closest to home missile to cpu1_d=( (abs(truck[0].coord.coord.t[0]-truck[1].coord.coord.t[0])) + (abs(truck[0].coord.coord.t[2]-truck[1].coord.coord.t[2])) ); cpu2_d=( (abs(truck[0].coord.coord.t[0]-truck[2].coord.coord.t[0])) + (abs(truck[0].coord.coord.t[2]-truck[2].coord.coord.t[2])) ); if(cpu1_d0 && power_m_status==0) { counter++; if(counter==1) { power_m_status=1; power_m_dir=rot; power_m.vector.vy=truck[0].vector.vy; power_m.coord.coord.t[0]=truck[0].coord.coord.t[0]; //set positions to car pos. power_m.coord.coord.t[2]=truck[0].coord.coord.t[2]; p1items.pow--; if(p1items.pow==0) lock_sel9=1; power_m.obj.attribute &= ~(1<<31); } } //clear counters if(counter==(15)) counter=0; if(!(padd&PADL2)) counter=0; //move missiles when fired if(fire_m_status==1) { if(fire_h_status==1) fire_h_count++; if(fire_h_count>FIRE_H_TIME) { fire_h_count=0; fire_h_status=0; fire_m_status=0; } if(fire_h_status==1) { //limit how long fire missile homes if(closest==1) { if(fire_m.coord.coord.t[0]truck[1].coord.coord.t[0]) fire_m.coord.coord.t[0]-=FIRE_H_SPEED; if(fire_m.coord.coord.t[2]>truck[1].coord.coord.t[2]) fire_m.coord.coord.t[2]-=FIRE_H_SPEED; if(fire_m.coord.coord.t[2]truck[2].coord.coord.t[0]) fire_m.coord.coord.t[0]-=FIRE_H_SPEED; if(fire_m.coord.coord.t[2]>truck[2].coord.coord.t[2]) fire_m.coord.coord.t[2]-=FIRE_H_SPEED; if(fire_m.coord.coord.t[2]3250 || fire_m.coord.coord.t[0]<-3250 || fire_m.coord.coord.t[2]>2935 || fire_m.coord.coord.t[2]<-3200) { fire_m_status=0; } } if(homing_m_status==1) { if(homing_status==1) homing_count++; if(homing_count>HOMING_TIME) { homing_count=0; homing_status=0; homing_m_status=0; } if(homing_status==1) { //limit how long the missile homes if(closest==1) { if(homing_m.coord.coord.t[0]truck[1].coord.coord.t[0]) homing_m.coord.coord.t[0]-=HOMING_H_SPEED; if(homing_m.coord.coord.t[2]>truck[1].coord.coord.t[2]) homing_m.coord.coord.t[2]-=HOMING_H_SPEED; if(homing_m.coord.coord.t[2]truck[2].coord.coord.t[0]) homing_m.coord.coord.t[0]-=HOMING_H_SPEED; if(homing_m.coord.coord.t[2]>truck[2].coord.coord.t[2]) homing_m.coord.coord.t[2]-=HOMING_H_SPEED; if(homing_m.coord.coord.t[2]3250 || homing_m.coord.coord.t[0]<-3250 || homing_m.coord.coord.t[2]>2935 || homing_m.coord.coord.t[2]<-3200) { homing_m_status=0; } } if(power_m_status==1) { power_m.coord.coord.t[0] +=((MISSILE_SPEED*SIN[power_m_dir>>12])>>12); power_m.coord.coord.t[2] +=((MISSILE_SPEED*COS[power_m_dir>>12])>>12); if(power_m.coord.coord.t[0]>3250 || power_m.coord.coord.t[0]<-3250 || power_m.coord.coord.t[2]>2935 || power_m.coord.coord.t[2]<-3200) { power_m_status=0; } } if(fire_m_status==0) { fire_h_status=0; fire_h_count=0; } if(homing_m_status==0) { homing_count=0; homing_status=0; } } //end FIREMISSILE /**** ROTMISSILE ****/ void RotMissile( SVECTOR *vec, int *status ) { if(*status==1) { vec->vy+=ROT; if(vec->vy>4096) vec->vy=0; vec->vx+=ROT; if(vec->vx>4096) vec->vy=0; vec->vz+=ROT; if(vec->vz>4096) vec->vy=0; } } //end ROTMISSILE