home *** CD-ROM | disk | FTP | other *** search
- /*
-
- ------------------------------------------------------------------
-
- Black Nebula
-
- File : main3d.c
- Programmer: Colin Adams
- Date: 29/3/91
- Last Modified : 10/6/91
-
- Description:
-
- Controls the main loop of the player's ship.
-
- ------------------------------------------------------------------
-
- */
-
- #define AMIGA_INCLUDES
- #include "3d.h"
-
- #define FIRE 1
- #define RIGHT 2
- #define LEFT 4
- #define DOWN 8
- #define UP 16
-
- #define DELAY_TIME 2
-
-
- /* ------------------------------------------------------------------
- External Variables
- ------------------------------------------------------------------
- */
-
- extern short swapflag;
- extern object myship;
- extern int player_score, player_scale;
- extern struct RastPort my_rast_port, back_rast_port;
- extern struct View my_view, back_view;
- extern struct ViewPort my_view_port, back_view_port;
- extern struct BitMap my_bit_map;
- extern struct BitMap back_bit_map;
- extern void AddNewObject(short, short, short, short);
- extern void SpinObjCentres(void);
- extern int GetPointAngle(int *, short, short);
-
- /* ------------------------------------------------------------------
- Variables
- ------------------------------------------------------------------
- */
-
- static int last_draw = 0;
- int player_missiles;
- short U_rot = 270, W_rot = 180;
- short View2_Angle;
- int cos_angle[360], sin_angle[360];
- char rotate[4];
-
- /* pointers to bitmaps for console update */
-
- PLANEPTR front_alt[4], back_alt[4];
- PLANEPTR front_sp[4], back_sp[4];
-
- PLANEPTR front_radar[66][4];
- PLANEPTR back_radar[66][4];
-
- char colour_mask[16][4];
- UBYTE on_pat[8], off_pat[8];
-
- /* ------------------------------------------------------------------
- Routines
- ------------------------------------------------------------------
- */
-
- void SetUpConsole(void)
- /* precalculation of bitmap pointers for fast drawing */
- {
- unsigned char i, j;
-
- for(i=0; i<16; i++)
- {
- colour_mask[i][0] = i & 1;
- colour_mask[i][1] = i & 2;
- colour_mask[i][2] = i & 4;
- colour_mask[i][3] = i & 8;
- }
-
- for(i=0; i<DEPTH; i++)
- {
- front_alt[i] = my_bit_map.Planes[i] + (G/8) * 225;
- front_sp[i] = my_bit_map.Planes[i] + (G/8) * 245;
-
- back_alt[i] = back_bit_map.Planes[i] + (G/8) * 225;
- back_sp[i] = back_bit_map.Planes[i] + (G/8) * 245;
-
- for(j=0; j<66; j++)
- {
- front_radar[j][i] = my_bit_map.Planes[i] + (G/8) * (182+j) + 16;
- back_radar[j][i] = back_bit_map.Planes[i] + (G/8) * (182+j) + 16;
- }
- }
-
- on_pat[0] = 1;
- off_pat[0] = ~1;
-
- on_pat[1] = 2;
- off_pat[1] = ~2;
-
- on_pat[2] = 4;
- off_pat[2] = ~4;
-
- on_pat[3] = 8;
- off_pat[3] = ~8;
-
- on_pat[4] = 16;
- off_pat[4] = ~16;
-
- on_pat[5] = 32;
- off_pat[5] = ~32;
-
- on_pat[6] = 64;
- off_pat[6] = ~64;
-
- on_pat[7] = 128;
- off_pat[7] = ~128;
-
- }
-
- void UpdateAlt(void)
- /* updates the altmeter on the user display */
- {
- int byte = ey / (MAX_WORLD_Y/9);
- unsigned int i;
-
- for(i=0; i<DEPTH; i++)
- {
- register PLANEPTR temp, temp2;
- register unsigned int j;
-
- temp = front_alt[i] + byte;
- temp2 = back_alt[i] + byte;
-
- for(j=1; j<=9; j++)
- {
- register unsigned int colour;
-
- if(byte)
- {
- if(j>5)
- colour = j + 4;
- else
- colour = 13 - j;
-
- if(colour_mask[colour][i])
- {
- *temp2 = 255; /* fill byte with colour */
- *temp = 255;
- }
- else
- {
- *temp2 = 0; /* set to background colour */
- *temp = 0;
- }
- }
-
- if(byte<9)
- {
- *(temp + 1) = 0; /* clear to right side */
- *(temp2 + 1) = 0;
- }
-
- temp += G/8;
- temp2 += G/8;
- }
- }
- }
-
- void UpdateSpeed(void)
- /*
- Updates the speed meter on the user display. For some strange
- reason this code doesn't work on an Amiga 3000 the way it does on
- a 2000. ie. bugs
- */
- {
- unsigned int i;
-
- for(i=0; i<DEPTH; i++)
- {
- register PLANEPTR temp, temp2;
- register unsigned int j;
-
- temp = front_sp[i] + velocity;
- temp2 = back_sp[i] + velocity;
-
- for(j=1; j<=9; j++)
- {
- register unsigned int colour;
-
- if(velocity)
- {
- if(j>5)
- colour = j + 4;
- else
- colour = 13 - j;
-
- if(colour_mask[colour][i])
- {
- *temp2 = 255; /* fill byte with colour */
- *temp = 255;
- }
- else
- {
- *temp2 = 0; /* set to background colour */
- *temp = 0;
- }
- }
-
- if(velocity<9)
- {
- *(temp + 1) = 0; /* clear to right side */
- *(temp2 + 1) = 0;
- }
-
- temp += G/8;
- temp2 += G/8;
- }
- }
- }
-
- void UpdateRadar(void)
- /* updates the radar on the user display */
- {
-
- static PLANEPTR last_bytes_front[TOTAL_MAX_OBJECTS][DEPTH];
- static PLANEPTR last_bytes_back[TOTAL_MAX_OBJECTS][DEPTH];
-
- unsigned int i, loop;
- object *obj;
-
- for(loop=0; loop<last_draw; loop++)
- {
- for(i=0; i<DEPTH; i++)
- {
- *last_bytes_front[loop][i] = 0;
- *last_bytes_back[loop][i] = 0;
- }
- }
-
- last_draw = no_objects + 1;
-
- for(loop=0; loop<=no_objects; loop++)
- {
- register int y, byte, offset, colour, x;
-
- if(loop!=no_objects)
- {
- obj = active_list[loop];
-
- x = obj->trans_x;
- y = obj->trans_z / (MAX_WORLD_Z/65);
-
- switch(obj->type)
- {
- case FIXED: colour = 9; break;
- case ENEMYMISSILE: colour = 10; break;
- case MYMISSILE: colour = 1; break;
- case SHUTTLE: colour = 14; break;
- case KRAIT: colour = 12; break;
- case GECKO: colour = 15; break;
- case THARGOID: colour = 11; break;
- case MAMBA: colour = 8; break;
- case GUIDEDMISSILE: colour = 3; break;
- case EXPLOSION: colour = 0; break;
- }
- }
- else
- {
- x = ex;
- y = ez / (MAX_WORLD_Z/65);
- colour = 8;
- }
-
- byte = x/(MAX_WORLD_X/7); /* get byte number */
- offset = x- (byte*(MAX_WORLD_X/7)); /* get bit offset */
- offset = 7 - (offset/((MAX_WORLD_X/7)/7));
-
- for(i=0; i<DEPTH; i++)
- {
- register PLANEPTR temp, temp2;
- register UBYTE s_read;
-
- temp = front_radar[y][i] + byte;
- temp2 = back_radar[y][i] + byte;
-
- last_bytes_front[loop][i] = temp;
- last_bytes_back[loop][i] = temp2;
-
- if(colour_mask[colour][i]) /* set bit in this plane */
- {
- s_read = *temp2;
- s_read |= on_pat[offset];
- *temp2 = s_read;
-
- s_read = *temp;
- s_read |= on_pat[offset];
- *temp = s_read;
- }
- else /* have to clear the bit in this plane */
- {
- s_read = *temp2;
- s_read &= off_pat[offset];
- *temp2 = s_read;
-
- s_read = *temp;
- s_read &= off_pat[offset];
- *temp = s_read;
- }
- }
- }
- }
-
- void Setupangles(void)
- {
- FILE *fp;
- int i, j;
- double d;
-
- if(!(fp=fopen("moretrig.pre","r")))
- {
- printf("Calculating fixed point sin/cos\n");
-
- for(i=0; i<=359; i++)
- {
- d = sin(deg(i))*1000;
- j = d;
-
- sin_angle[i] = -j;
-
- d = cos(deg(i))*1000;
- j = d;
-
- cos_angle[i] = j;
-
- }
-
- for(i=0; i<=4096; i++)
- {
- double t = i;
- anti_sin[i] = asin(t/4096) * 57.29578;
- }
-
- if(!(fp=fopen("moretrig.pre","w")))
- {
- printf("Failed to save sin/cos data!\n");
- return;
- }
-
- fwrite((void *) &sin_angle[0], sizeof(int), 360, fp);
- fwrite((void *) &cos_angle[0], sizeof(int), 360, fp);
- fwrite((void *) &anti_sin[0], sizeof(int), 4097, fp);
- fclose(fp);
- }
- else
- {
- fread((void *) &sin_angle[0], sizeof(int), 360, fp);
- fread((void *) &cos_angle[0], sizeof(int), 360, fp);
- fread((void *) &anti_sin[0], sizeof(int), 4097, fp);
- fclose(fp);
- }
- }
-
- void PrintShip(char *name)
- {
- struct rastport *temp = rastport;
- rastport = &my_rast_port;
- SetAPen(rastport, 0);
- RectFill(rastport, 129, 183, 189, 243);
- SetAPen(rastport, 11);
- Move(rastport, 132, 215);
- Text(rastport, name, strlen(name));
- rastport = &back_rast_port;
- SetAPen(rastport, 0);
- RectFill(rastport, 129, 183, 189, 243);
- SetAPen(rastport, 11);
- Move(rastport, 132, 215);
- Text(rastport, name, strlen(name));
- rastport = temp;
- }
-
- void Print2Ship(char *name)
- {
- struct rastport *temp = rastport;
- rastport = &my_rast_port;
- SetAPen(rastport, 11);
- Move(rastport, 132, 230);
- Text(rastport, name, strlen(name));
- rastport = &back_rast_port;
- SetAPen(rastport, 11);
- Move(rastport, 132, 230);
- Text(rastport, name, strlen(name));
- rastport = temp;
- }
-
- void IntroShips(void)
- /*
- Spins each ship in the game around for a while.
- Note the hidden surface bug in the shuttle!
- */
- {
- int counter = 10, timeout = 0, timeoutlim = 300;
- UBYTE value = 0;
-
- AddNewObject(counter, 4000, 360, 2000);
- PrintShip("Player"); Print2Ship("Ship");
-
- while(value!=FIRE)
- {
- register int i;
-
- value = Joystick();
-
- timeout++;
-
- if(timeout==timeoutlim) /* make it blow up! */
- {
- active_list[0]->i_am_dying = 1;
- active_list[0]->explode = 1;
- StartSound(2);
- }
-
- if(no_objects==0) /* create a new object */
- {
- Delay(100);
- counter--;
- if(counter<0) counter = 10;
- if(counter==9) counter = 7;
-
- switch(counter)
- {
- case 0: PrintShip("Enemy"); Print2Ship("Missile"); break;
- case 1: PrintShip("Space"); Print2Ship("Station"); break;
- case 2: PrintShip("Shuttle"); break;
- case 3: PrintShip("Krait"); break;
- case 4: PrintShip("Gecko"); break;
- case 5: PrintShip("Thargoid"); break;
- case 6: PrintShip("Cruiser"); break;
- case 7: PrintShip("Player"); Print2Ship("Missile"); break;
- case 10: PrintShip("Player"); Print2Ship("Ship"); break;
- }
-
- KillAllObjects();
- SetUp3d();
- AddNewObject(counter, 4000, 360, 2000);
- timeoutlim = (active_list[0]->numpoints > 10) ? 150 : 300;
- timeout = 0;
- }
-
- for(i=0; i<no_objects; i++)
- {
- register object *obj = active_list[i];
-
- if(!obj->i_am_dying)
- obj->drawme = 1;
- else
- continue;
-
- if(obj->type==EXPLOSION)
- {
- int rad;
-
- if(--obj->timeinflight==0)
- {
- obj->i_am_dying = 1;
- 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;
- }
- else
- Rotate_Obj_Rel(obj, 5, 5, 5);
- }
-
- /* still interactive */
-
- if(value & LEFT)
- {
- U_rot+=2;
- W_rot+=2;
- }
- else if(value & RIGHT)
- {
- U_rot-=2;
- W_rot-=2;
-
- }
-
- if(value & UP)
- {
- if(ey <= MAX_WORLD_Y-Y_OFFSET)
- {
- UpdateAlt();
- ey += Y_OFFSET;
- }
- }
- else if(value & DOWN)
- {
- if(ey>0)
- {
- ey -= Y_OFFSET;
- UpdateAlt();
- }
- }
-
- if(U_rot>359)
- U_rot-=360;
- else if(U_rot<0)
- U_rot+= 360;
-
- if(W_rot>359)
- W_rot-=360;
- else if(W_rot<0)
- W_rot+= 360;
-
- ux.numer = cos_angle[U_rot];
- uz.numer = sin_angle[U_rot];
-
- wx.numer = cos_angle[W_rot];
- wz.numer = sin_angle[W_rot];
-
- View_Angle = U_rot;
-
- SpinObjCentres();
- CalculateObjects();
- ClearObjects();
- DisplayObjects();
-
- if(swapflag)
- {
- rastport = &my_rast_port;
- swapflag = 0;
- WaitBOVP(&my_view_port);
- LoadView(&back_view);
- }
- else
- {
- rastport = &back_rast_port;
- swapflag = 1;
- WaitBOVP(&back_view_port);
- LoadView(&my_view);
- }
- }
- }
-
- void PrintView(char *name)
- {
- register struct rastport *temp = rastport;
- rastport = &my_rast_port;
- SetAPen(rastport, 0);
- RectFill(rastport, 245, 196, 280,210);
- SetAPen(rastport, 11);
- Move(rastport, 245, 206);
- Text(rastport, name, strlen(name));
- rastport = &back_rast_port;
- SetAPen(rastport, 0);
- RectFill(rastport, 245, 196, 280 , 210);
- SetAPen(rastport, 11);
- Move(rastport, 245, 206);
- Text(rastport, name, strlen(name));
- rastport = temp;
- }
-
- void PrintRot(void)
- {
- register struct rastport *temp = rastport;
- register short t = U_rot;
-
- rotate[0] = t / 100;
- t = t - (rotate[0]*100);
- rotate[1] = t / 10;
- t = t - (rotate[1]*10);
-
- rotate[2] = t + '0';
- rotate[0] += '0';
- rotate[1] += '0';
-
- rastport = &my_rast_port;
- SetAPen(rastport, 0);
- RectFill(rastport, 245, 210, 280, 221);
- SetAPen(rastport, 11);
- Move(rastport, 245, 220);
-
- Text(rastport, rotate, 3);
- rastport = &back_rast_port;
- SetAPen(rastport, 0);
- RectFill(rastport, 245, 210, 280 , 221);
- SetAPen(rastport, 11);
- Move(rastport, 245, 220);
- Text(rastport, rotate, 3);
- rastport = temp;
- }
-
- void Do3d(void)
- {
- SetUp3d();
- KillAllObjects();
-
- AddObject("cube.object", FIXED);
- AddObject("ops_missile.object", ENEMYMISSILE);
- AddObject("missile.object", MYMISSILE);
- AddObject("krait.object", KRAIT);
- AddObject("shuttle.object",SHUTTLE);
- AddObject("gecko.object", GECKO);
- AddObject("thargoid.object", THARGOID);
- AddObject("cruiser.object", MAMBA);
- AddObject("guided.object",GUIDEDMISSILE);
- AddObject("player.object",PLAYER);
-
- SetUpViews();
- SetUpConsole();
-
- player_score = player_scale = last_draw = 0;
-
- Delay(25);
-
- IntroShips();
-
- SetUp3d();
- KillAllObjects();
- loadpic("screen.iff");
-
- /* clear radar area and screen display */
- {
- struct rastport *temp = rastport;
- rastport = &my_rast_port;
- SetAPen(rastport, 0);
- RectFill(rastport, 129, 183, 189, 243);
- RectFill(rastport, X_MIN, Y_MIN, X_MAX, Y_MAX);
- rastport = &back_rast_port;
- SetAPen(rastport, 0);
- RectFill(rastport, 129, 183, 189, 243);
- RectFill(rastport, X_MIN, Y_MIN, X_MAX, Y_MAX);
- rastport = temp;
- }
-
- ez = 4000;
- player_missiles = 25;
-
- PrintView("Front");
- PrintRot();
-
- while(!am_i_dead)
- {
- register UBYTE value = Joystick();
- register int speed;
- static int fireframe = 21;
-
- fireframe++;
-
- if(value & FIRE)
- {
- if(fireframe>5)
- {
- int tx = ex + FastCos(150, View_Angle);
- int tz = ez - FastSin(150, View_Angle);
-
- AddNewObject(MYMISSILE, tx, ey-100, tz);
- StartSound(0);
- fireframe = 0;
- }
- }
-
- if(value & LEFT)
- {
- U_rot+=2;
- W_rot+=2;
- PrintRot();
- }
- else if(value & RIGHT)
- {
- U_rot-=2;
- W_rot-=2;
- PrintRot();
-
- }
-
- if(value & UP)
- {
- if(ey <= MAX_WORLD_Y-Y_OFFSET)
- {
- UpdateAlt();
- ey += Y_OFFSET;
- }
- }
- else if(value & DOWN)
- {
- if(ey>0)
- {
- ey -= Y_OFFSET;
- UpdateAlt();
- }
- }
-
- value = Keyboard(); /* read keyboard */
-
- if(value==0x40) /* space, increase speed */
- {
- if(velocity<9)
- {
- velocity++;
- UpdateSpeed();
- }
- }
- else if(value==0x41) /* backspace, decrease speed */
- {
- if(velocity)
- {
- velocity--;
- UpdateSpeed(); /* only updates if changed */
- }
- }
- else if(value==0x45) /* escape */
- break;
- else if(value==0x19) /* P key, pause */
- while(Keyboard()!=0x16); /* wait for a u key press */
- else if(value==0x50) /* front view */
- {
- PrintView("Front");
- view_mode = 0;
- }
- else if(value==0x51) /* left view */
- {
- PrintView("Left");
- view_mode = 1;
- }
- else if(value==0x52) /* right view */
- {
- PrintView("Right");
- view_mode = 3;
- }
- else if(value==0x53) /* back view */
- {
- PrintView("Rear");
- view_mode = 2;
- }
- else if(value==0x37)
- {
- if(fireframe>5 && player_missiles)
- {
- int tx = ex + FastCos(150, View_Angle);
- int tz = ez - FastSin(150, View_Angle);
-
- AddNewObject(GUIDEDMISSILE, tx, ey-100, tz);
- StartSound(0);
- fireframe = 0;
- player_missiles--;
- }
- }
-
- /* correct rotations in case it went over 360 or under 0 */
-
- if(U_rot>359)
- U_rot-=360;
- else if(U_rot<0)
- U_rot+= 360;
-
- if(W_rot>359)
- W_rot-=360;
- else if(W_rot<0)
- W_rot+= 360;
-
- switch(view_mode)
- {
- case 0: View_Angle = U_rot; break;
- case 1: View_Angle = U_rot + 90; break;
- case 2: View_Angle = U_rot + 180; break;
- case 3: View_Angle = U_rot + 270; break;
- }
-
- if(View_Angle>359) View_Angle -= 360;
-
- View2_Angle = View_Angle - 90;
-
- if(View2_Angle<0) View2_Angle += 360;
-
- ux.numer = cos_angle[View_Angle];
- uz.numer = sin_angle[View_Angle];
-
- wx.numer = cos_angle[View2_Angle];
- wz.numer = sin_angle[View2_Angle];
-
- /* Very simple code to move the ship according to velocity */
-
- speed = velocity * 2;
- ex += FastCos(speed, U_rot);
- ez -= FastSin(speed, U_rot);
-
- /* Keep ship in the world */
-
- if(ex<0)
- ex = MAX_WORLD_X;
- else if(ex>MAX_WORLD_X)
- ex = 0;
-
- if(ez<0)
- ez = MAX_WORLD_Z;
- else if(ez>MAX_WORLD_Z)
- ez = 0;
-
- SpinObjCentres();
- MoveObjects();
- UpdateObjects();
- CalculateObjects();
- ClearObjects();
- UpdateRadar();
- DisplayObjects();
-
- /* swap views */
-
- if(swapflag)
- {
- rastport = &my_rast_port;
- swapflag = 0;
- WaitBOVP(&my_view_port);
- LoadView(&back_view);
- }
- else
- {
- rastport = &back_rast_port;
- swapflag = 1;
- WaitBOVP(&back_view_port);
- LoadView(&my_view);
- }
- }
-
- if(am_i_dead)
- /*
- A really cool extern death sequence! Soon the wonder of external
- views won't be confined to the death sequence
- */
- {
- int i;
-
- StartSound(1);
-
- PrintView("Death");
- AddNewObject(PLAYER, ex-100, ey-50, ez-50); /* add a ship then blow it up! */
- active_list[no_objects-1]->i_am_dying = 1;
- active_list[no_objects-1]->explode = 1;
-
- for(i=0; i<30; i++)
- {
- register int px, py, pz, speed;
-
- speed = velocity * 2;
- ex += FastCos(speed, U_rot);
- ez -= FastSin(speed, U_rot);
-
- /* Keep ship in the world */
-
- if(ex<0)
- ex = MAX_WORLD_X;
- else if(ex>MAX_WORLD_X)
- ex = 0;
-
- if(ez<0)
- ez = MAX_WORLD_Z;
- else if(ez>MAX_WORLD_Z)
- ez = 0;
-
-
- if(ex>(MAX_WORLD_X/2))
- px = ex - 1000;
- else
- px = ex + 1000;
-
- py = ey+150;
-
- if(ez>(MAX_WORLD_Y/2))
- pz = ez - 1000;
- else
- pz = ez + 1000;
-
-
- SpinObjCentres();
-
- {
- int dummy;
- View_Angle = GetPointAngle(&dummy, px, pz);
- }
-
- View2_Angle = View_Angle - 90;
-
- if(View2_Angle<0) View2_Angle += 360;
-
- ux.numer = cos_angle[View_Angle];
- uz.numer = sin_angle[View_Angle];
-
- wx.numer = cos_angle[View2_Angle];
- wz.numer = sin_angle[View2_Angle];
-
- {
- register int tempx, tempy, tempz;
-
- tempx = ex;
- tempy = ey;
- tempz = ez;
- ex = px;
- ey = py;
- ez = pz;
-
-
- MoveObjects();
- CalculateObjects();
- ClearObjects();
- UpdateRadar();
- DisplayObjects();
-
- ex = tempx;
- ey = tempy;
- ez = tempz;
- }
-
- /* swap views */
-
- if(swapflag)
- {
- rastport = &my_rast_port;
- swapflag = 0;
- WaitBOVP(&my_view_port);
- LoadView(&back_view);
- }
- else
- {
- rastport = &back_rast_port;
- swapflag = 1;
- WaitBOVP(&back_view_port);
- LoadView(&my_view);
- }
- }
- }
-
- KillAllObjects();
- FreeView();
- }
-
- /* end of module */
-