← Back to contents
C source, ASCII text
— 16K bytes
— 1994-01-01
/*
------------------------------------------------------------------
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->velocity<max) obj->velocity++;
}
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(ez<pz)
return 90;
else
return 270;
}
o = px - ex;
if(ez>pz)
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(ez<pz)
return 90;
else
return 270;
}
o = px - ex;
if(ez>pz)
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<MAX_OBJECTS; i++)
{
register object *missile;
if(!obj_free[ENEMYMISSILE][i])
{
int difficult = player_score>>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; i<no_objects; i++)
{
obj = active_list[i];
if(obj->i_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; i<no_objects; i++)
{
target = active_list[i];
if(target->type==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; i<no_objects; i++)
{
target = active_list[i];
if(target->type<=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; i<no_objects; i++)
{
if(active_list[i]->type<=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(distance<sh_dist)
{
obj->target = active_list[i];
sh_dist = distance;
}
}
}
}
target = (object *) obj->target;
{
register char flag = 0;
for(i=0; i<no_objects; i++)
{
if(active_list[i]==target)
{
flag = 1;
break;
}
}
if(!flag)
{
obj->target = 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 && height<MAX_WORLD_Y-500)
obj->trans_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_y<MAX_WORLD_Y-100)
obj->trans_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 && height<MAX_WORLD_Y-500)
{
if(fdest>5)
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 */