/* ------------------------------------------------------------------ Black Nebula File : enemy.c Programmer: Colin Adams Date: 6/5/91 Last Modified : 10/6/91 Description: Updates the enemy objects in space (movement and rotations) Will be fixed a lot for the next version. ------------------------------------------------------------------ */ #include "3d.h" extern short U_rot; #define DecreaseVelocity(obj) { if(obj->velocity>4)obj->velocity--; } #define IncreaseMissileVelocity(obj) {if(obj->velocity<30)obj->velocity++;} #define DecreaseMissileVelocity(obj) {if(obj->velocity>20)obj->velocity--;} extern void AddNewObject(short, short, short, short); extern int player_missiles; int player_scale, player_score; short num_active[NO_OBJ_TYPES]; /* ------------------------------------------------------------------ Coding ------------------------------------------------------------------ */ void IncreaseVelocity(object *obj) /* some ships move much faster than others.... */ { register int max; switch(obj->type) { case SHUTTLE: max = 5; break; case KRAIT: max = 11; break; case GECKO: max = 8; break; case THARGOID: max = 11; break; case MAMBA: max = 8; break; } if(obj->velocityvelocity++; } int GetTargetAngle(object *obj, short px, short pz) { register int o, angle, tempint; register char quad; int temp, ex = obj->trans_x+obj->centre_x, ez = obj->trans_z+obj->centre_z; float depth, temp2; int d; tempint = px-ex; depth = tempint * tempint; tempint = pz-ez; depth += tempint * tempint; if(ex>px) { o = ex - px; if(ez>pz) quad = 4; else { if(pz==ez) return 0; quad = 1; } } else { if(px==ex) { if(ezpz) quad = 3; else { if(pz==ez) return 180; quad = 2; } } temp = o * 4096; temp2 = fsqrt(depth); d = temp/temp2; if(d>4096) d = 4096; /* to fix small errors */ angle = anti_sin[d]; switch(quad) { case 1: angle = 90 - angle; break; case 2: angle = 90 + angle; break; case 3: angle = 180 + (90-angle); break; case 4: angle += 270; break; } return angle; } int GetPointAngle(int *de, short px, short pz) { register int o, angle, tempint; register char quad; int temp; float depth, temp2; int d; tempint = px-ex; depth = tempint * tempint; tempint = pz-ez; *de = (depth += tempint * tempint); if(ex>px) { o = ex - px; if(ez>pz) quad = 4; else { if(pz==ez) return 0; quad = 1; } } else { if(px==ex) { if(ezpz) quad = 3; else { if(pz==ez) return 180; quad = 2; } } temp = o * 4096; temp2 = fsqrt(depth); d = temp/temp2; if(d>4096) d = 4096; /* to fix small errors */ angle = anti_sin[d]; switch(quad) { case 1: angle = 90 - angle; break; case 2: angle = 90 + angle; break; case 3: angle = 180 + (90-angle); break; case 4: angle += 270; break; } return angle; } void LaunchMissile(object *obj) /* this object would like to launch a missile at the player... */ { register int i; int tx = obj->centre_x + obj->trans_x + FastCos(200, obj->heading); int tz = obj->centre_z + obj->trans_z - FastSin(200, obj->heading); for(i=0; i>12; register int rand = getrandom(0, 30-difficult) - (30-difficult)/2; int heading = obj->heading + rand; if(heading<0) heading += 360; else if(heading>359) heading -= 360; missile = &obj_types[ENEMYMISSILE][i]; Translate_Obj_Abs(missile, tx, obj->trans_y+obj->centre_y, tz); missile->i_am_dying = missile->lastdrawme = missile->lastdraw2 = 0; missile->velocity = 25 + difficult; missile->timeinflight = 0; missile->heading = heading; Rotate_Obj_Abs(missile, 0, heading, 0); missile->explode = 0; obj_free[ENEMYMISSILE][i] = 1; active_list[no_objects] = missile; no_objects++; num_active[ENEMYMISSILE]++; StartSound(0); return; } } } void MoveObjects(void) /* horrible sprawling routine... should be broken up */ { register int i; register object *obj; for(i=0; ii_am_dying) continue; else obj->drawme = 1; switch(obj->type) { case FIXED: Rotate_Obj_Rel(obj, 2, 2, 2); break; case PLAYER: break; case ENEMYMISSILE: { register int i; register object *target; if(obj->timeinflight++>40) { obj->i_am_dying = 1; obj->explode = 1; break; } obj->trans_x += FastCos(obj->velocity, obj->heading); obj->trans_z -= FastSin(obj->velocity, obj->heading); if(obj->trans_x<0) obj->trans_x = MAX_WORLD_X; else if(obj->trans_x > MAX_WORLD_X) obj->trans_x = 0; if(obj->trans_z<0) obj->trans_z = MAX_WORLD_Z; else if(obj->trans_z>MAX_WORLD_Z) obj->trans_z = 0; /* check if missile hit something */ for(i=0; itype==MYMISSILE) { register int temp, distance; temp = (target->trans_x + target->centre_x) - (obj->trans_x + obj->centre_x); distance = temp * temp; temp = (target->trans_y + target->centre_y) - (obj->trans_y + obj->centre_y); distance += temp * temp; temp = (target->trans_z + target->centre_z) - (obj->trans_z + obj->centre_z); distance += temp * temp; if(distance<(obj->radius + 2000)) { obj->i_am_dying = target->i_am_dying = 1; obj->explode = target->explode = 1; StartSound(2); break; } } } Rotate_Obj_Rel(obj, 5, 0, 0); break; } case MYMISSILE: { register int i; register object *target; if(obj->timeinflight++>50) { obj->i_am_dying = 1; obj->explode = 1; break; } obj->trans_x += FastCos(obj->velocity, obj->heading); obj->trans_z -= FastSin(obj->velocity, obj->heading); if(obj->trans_x<0) obj->trans_x = MAX_WORLD_X; else if(obj->trans_x > MAX_WORLD_X) obj->trans_x = 0; if(obj->trans_z<0) obj->trans_z = MAX_WORLD_Z; else if(obj->trans_z>MAX_WORLD_Z) obj->trans_z = 0; /* check if missile hit something */ for(i=0; itype<=MAMBA) { register int temp, distance; temp = (target->trans_x + target->centre_x) - (obj->trans_x + obj->centre_x); distance = temp * temp; temp = (target->trans_y + target->centre_y) - (obj->trans_y + obj->centre_y); distance += temp * temp; temp = (target->trans_z + target->centre_z) - (obj->trans_z + obj->centre_z); distance += temp * temp; if(distance<(obj->radius + 2000)) { obj->i_am_dying = target->i_am_dying = 1; obj->explode = target->explode = 1; switch(target->type) { case FIXED: player_score += 1000; break; case THARGOID: player_score += 1500; break; case ENEMYMISSILE: player_score += 10; break; case KRAIT: player_score += 600; break; case MAMBA: player_score+= 1000; default: player_score += 300; } { register int temp = player_score>>12; if(temp>player_scale) { player_scale = temp; player_missiles++; } } StartSound(2); break; } } } Rotate_Obj_Rel(obj, 5, 0, 0); break; } case GUIDEDMISSILE: { register short dest, fdest, theight, height, s1, s2, i; register object *target; Rotate_Obj_Rel(obj, 5, 0, 0); if(obj->timeinflight++>100) { obj->i_am_dying = 1; obj->explode = 1; break; } if(obj->target==NULL) /* no target yet */ { register int sh_dist = 0x7fffffff; /* a really big number */ for(i=0; itype<=MAMBA && active_list[i]->type>ENEMYMISSILE) { register int temp, distance; register object *target = active_list[i]; temp = (target->trans_x + target->centre_x) - (obj->trans_x + obj->centre_x); distance = temp * temp; temp = (target->trans_y + target->centre_y) - (obj->trans_y + obj->centre_y); distance += temp * temp; temp = (target->trans_z + target->centre_z) - (obj->trans_z + obj->centre_z); distance += temp * temp; if(distancetarget = active_list[i]; sh_dist = distance; } } } } target = (object *) obj->target; { register char flag = 0; for(i=0; itarget = NULL; /* get a new target next frame */ break; } } /* move missile */ height = obj->trans_y + obj->centre_y; theight = target->trans_y + target->centre_y; if(theight>height && heighttrans_y += 5; else if(height>5) obj->trans_y -= 5; dest = GetTargetAngle(target, obj->trans_x+obj->centre_x, obj->trans_z+obj->centre_z); if(dest<0) break; s1 = dest - obj->heading; /* get +ve diff. heading */ s2 = obj->heading + 360 - dest; fdest = abs(s1)>abs(s2) ? -s2 : s1; if(fdest>180) { DecreaseMissileVelocity(obj); } else { IncreaseMissileVelocity(obj); } if(fdest>0) { if(fdest>5) fdest = 5; Rotate_Obj_Rel(obj, 0, fdest, 0); obj->heading += fdest; } else { if(fdest<-5) { obj->heading -= 5; Rotate_Obj_Rel(obj, 0, -5, 0); } else { Rotate_Obj_Rel(obj, 0, fdest, 0); obj->heading += fdest; } } if(obj->heading>359) obj->heading -= 360; else if(obj->heading<0) obj->heading += 360; obj->trans_x += FastCos(obj->velocity, obj->heading); obj->trans_z -= FastSin(obj->velocity, obj->heading); if(obj->trans_x<0) obj->trans_x = MAX_WORLD_X; else if(obj->trans_x > MAX_WORLD_X) obj->trans_x = 0; if(obj->trans_z<0) obj->trans_z = MAX_WORLD_Z; else if(obj->trans_z>MAX_WORLD_Z) obj->trans_z = 0; /* now check if the target was hit! */ { register int temp, distance; temp = (target->trans_x + target->centre_x) - (obj->trans_x + obj->centre_x); distance = temp * temp; temp = (target->trans_y + target->centre_y) - (obj->trans_y + obj->centre_y); distance += temp * temp; temp = (target->trans_z + target->centre_z) - (obj->trans_z + obj->centre_z); distance += temp * temp; if(distance<(obj->radius + 2500)) { obj->i_am_dying = target->i_am_dying = 1; obj->explode = target->explode = 1; switch(target->type) { case FIXED: player_score += 1000; break; case THARGOID: player_score += 1500; break; case ENEMYMISSILE: player_score += 10; break; case KRAIT: player_score += 600; break; case MAMBA: player_score+= 1000; default: player_score += 300; } { register int temp = player_score>>12; if(temp>player_scale) { player_scale = temp; player_missiles++; } } StartSound(2); } } break; } case EXPLOSION: /* floats away */ { int rad; if((--(obj->timeinflight))==0) { obj->i_am_dying = 1; obj->explode = 0; break; } rad = getrandom(0,10); if(obj->up_or_down) { if(obj->trans_ytrans_y += rad; } else { if(obj->trans_y>100) obj->trans_y -= rad; } if(rad>5) rad = getrandom(1, 6); else rad = -getrandom(1, 6); Rotate_Obj_Rel(obj, rad+2, rad-1, rad+1); obj->trans_x += FastCos(obj->velocity, obj->heading); obj->trans_z -= FastSin(obj->velocity, obj->heading); if(obj->trans_x<0) obj->trans_x = MAX_WORLD_X; else if(obj->trans_x > MAX_WORLD_X) obj->trans_x = 0; if(obj->trans_z<0) obj->trans_z = MAX_WORLD_Z; else if(obj->trans_z>MAX_WORLD_Z) obj->trans_z = 0; break; } default: /* enemy ship combat algorithm... */ { register short dest, fdest, height, s1, s2; int distance; if(obj->type==THARGOID) Rotate_Obj_Rel(obj, 0, 5, 0); else if(obj->type==KRAIT) Rotate_Obj_Rel(obj, 5, 0, 0); height = obj->trans_y + obj->centre_y; fdest = ey - height; fdest = abs(fdest); if(ey>height && height5) obj->trans_y += 5; else obj->trans_y += fdest; } else if(height>5) { if(fdest>5) obj->trans_y -= 5; else obj->trans_y -= fdest; } dest = GetPointAngle(&distance,obj->trans_x, obj->trans_z); if(dest<0) break; s1 = dest - obj->heading; /* get +ve diff. heading */ s2 = obj->heading + 360 - dest; fdest = abs(s1)>abs(s2) ? -s2 : s1; if(fdest>180) { DecreaseVelocity(obj); } else { IncreaseVelocity(obj); } if(fdest>0) { if(fdest>5) fdest = 5; Rotate_Obj_Rel(obj, 0, fdest, 0); obj->heading += fdest; } else { if(fdest<-5) { obj->heading -= 5; Rotate_Obj_Rel(obj, 0, -5, 0); } else { Rotate_Obj_Rel(obj, 0, fdest, 0); obj->heading += fdest; } } if(abs(fdest)<10 && distance<(2500*2500)) { if(obj->type==THARGOID) { if(getrandom(0, 20)==0) LaunchMissile(obj); } else if(obj->type==MAMBA) { if(getrandom(0,25)==0) LaunchMissile(obj); } else if(obj->type==KRAIT) { if(getrandom(0,35)==0) LaunchMissile(obj); } else { if(getrandom(0,45)==0) LaunchMissile(obj); } } if(obj->heading>359) obj->heading -= 360; else if(obj->heading<0) obj->heading += 360; obj->trans_x += FastCos(obj->velocity, obj->heading); obj->trans_z -= FastSin(obj->velocity, obj->heading); if(obj->trans_x<0) obj->trans_x = MAX_WORLD_X; else if(obj->trans_x > MAX_WORLD_X) obj->trans_x = 0; if(obj->trans_z<0) obj->trans_z = MAX_WORLD_Z; else if(obj->trans_z>MAX_WORLD_Z) obj->trans_z = 0; break; } } } } void UpdateObjects(void) /* Creates new objects, adding them to the game dynamically */ { if(!num_active[FIXED]) /* space stations */ { /* there are none left, so I'll create 4 new ones ... */ AddNewObject(FIXED, 500, 1000, 500); AddNewObject(FIXED, MAX_WORLD_Z-500, 1000, 500); AddNewObject(FIXED, 500, 1000, MAX_WORLD_Z-500); AddNewObject(FIXED, MAX_WORLD_Z-500, 1000, MAX_WORLD_Z-500); } if(num_active[3]+num_active[4]+num_active[5]+num_active[6]+ num_active[2]!=3) { switch(getrandom(0,3)) { case 0: AddNewObject(getrandom(SHUTTLE,MAMBA), getrandom(600,7000), 1000, MAX_WORLD_Z-100); break; case 1: AddNewObject(getrandom(SHUTTLE,MAMBA), getrandom(600,7000), 1000, 100); break; case 2: AddNewObject(getrandom(SHUTTLE,MAMBA), MAX_WORLD_X-200, 1000, getrandom(600,7000)); break; case 3: AddNewObject(getrandom(SHUTTLE,MAMBA), 100, 1000, getrandom(600,7000)); break; } } } /* end of module enemy.c */