home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Hack-Phreak Scene Programs
/
cleanhpvac.zip
/
cleanhpvac
/
SLOWRUNS.ZIP
/
SLOWSRC.ZIP
/
NEWGAME5.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-12-07
|
169KB
|
6,543 lines
// COPYRIGHT 1997 - by James McCue
// This is SOME of the main module to the source code of
// the game "Slow Runnings 1.11".
// It's stupid to dump all the code into one source module...
// I just ripped most of it out!
// This code was such a pigsty - it was embarrassing!
// ...it still is!
// I'M REFINING THE CODE - AND BEGINNING WORK ON SOMETHING ELSE
// 3D!!!
// THIS SOURCE CODE AND IT'S ASSOCIATED FILES ARE DISTRIBUTED AS IS,
// AND WITHOUT WARRANTY OF ANY KIND!
// JAMES MCCUE MAKES NO CLAIMS AS TO THE MARKETABLITY OF THIS
// SOURCE CODE, OR ANYTHING MADE WITH IT.
// NOR DOES JAMES MCCUE MAKE ANY CLAIMS ABOUT THIS SOFTWARE'S
// USEFULNESS FOR ANY PURPOSE.
// JAMES MCCUE IS NOT RESPONSIBLE FOR ANY DAMAGE (SOFTWARE OR
// HARDWARE) THAT ARISES FROM THE USE OF THIS CODE - NOR ANY
// EXECUTABLES MADE WITH/FROM IT...
// I hope you can learn something from this...
#include <io.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <bios.h>
#include <fcntl.h>
#include <memory.h>
#include <malloc.h>
#include <math.h>
#include <errno.h>
#include <string.h>
#include <search.h> // this one is needed for qsort()
#include "magic3.h"
#include "magic4.h"
#include "magic5.h"
#include "magic6.h"
#include "magic8.h"
//#include <time.h>
// D E F I N E S /////////////////////////////////////////////////////////////
// #define DEBUG 1
#define OVERBOARD 44 // the absolute closest a player can get to a wall
#define INTERSECTION_FOUND 1
// enemy states...
#define PURSUING 0
#define WAITING 1
#define FIRING 2
#define DEAD 3
#define EVADING 4
#define DYING 5
#define STANDING_AND_FIRING 6
#define HIT 7
// PLAYER STATES..... //////////////////////////////////////////////
#define PLAYER_NOT_FIRING 0
#define PLAYER_FIRING 1
// SOUNDS //////////////////////////////////////////////
#define door_sound 0
#define firing_sound 1
#define enemy_death_sound 2
#define enemy_shoot_sound 3
#define map_warp_sound 4
// for Math stuff..../////////////////////////////
#define Pi (float)3.1415926
#define DEG_TO_RAD ((float)3.1415926/(float)180)
#define WORLD_ROWS 32
#define WORLD_COLUMNS 32
#define CELL_X_SIZE 64
#define CELL_Y_SIZE 64
#define SWATCH_WIDTH 64
#define CELL_X_SIZE_FP 6 // <- used for bit-wize shifting
#define CELL_Y_SIZE_FP 6 // because it is faster than
// multiplication and division
// size of overall game world
#define WORLD_X_SIZE (WORLD_COLUMNS * CELL_X_SIZE)
#define WORLD_Y_SIZE (WORLD_ROWS * CELL_Y_SIZE)
#define MAX_SCALE 235 // maximum size and wall "sliver" can be
#define WALL_MIDDLE_OFFSET (32<<6)
#define WALL_MIDDLE_MINUS_OFFSET (31<<6)
#define WOIK_OFFSET_1(y_off) (WALL_MIDDLE_OFFSET - scale_row[y_off])
#define WOIK_OFFSET_2(y_off) (WALL_MIDDLE_OFFSET + scale_row[y_off])
#define BORDER_COLOR_1 42
#define BORDER_COLOR_2 48
#define BORDER_COLOR_3 54
#define BORDER_COLOR_4 48
#define OPENING 1
#define CLOSING 2
#define OPEN 3
#define CLOSED 4
#define DOSALLOC 0
#define MAX_OBJECTS 55
#define MAX_ENEMIES 20
// GLOBALS /////////////////////////////////////////////
// constants used to represent angles
int my_size = 1216; // for a 90 degree view cone
int my_v_scale = 9500; // for 90 big-ass degrees of view coneage carnage!
int my_height = 148;
int my_right = 312;
int my_left = 8;
int COLUMN_OFFSET= 311;
int ANGLE_360;
int ANGLE_180;
int ANGLE_90;
int ANGLE_75;
int ANGLE_60;
int ANGLE_45;
int ANGLE_30;
int ANGLE_15;
int ANGLE_6;
int ANGLE_5;
int ANGLE_4;
int ANGLE_2;
int ANGLE_1;
int ANGLE_0;
// some ODDBALL angles
int ANGLE_315;
int ANGLE_270;
int ANGLE_225;
int ANGLE_135;
int ANGLE_10;
int ANGLE_9;
int ANGLE_8;
int ANGLE_7;
// ... and some possible view cone values
int ANGLE_80;
int ANGLE_70;
// for 'shifting the parachute' (?!)
int ANGLE_23;
int VIEW_CONE;
int HALF_VIEW_CONE;
// conversion constants from radians to degrees and vice-versa
float ANGULAR_INCREMENT;
float RAD_TO_DEG;
// conversion constants from radians to degrees and vicversa
// MORE GLOBALS //////////////////////////////
int WINDOW_HEIGHT;
int WINDOW_HALF_HEIGHT;
int WINDOW_MIDDLE;
int WINDOW_MIDDLE_MINUS;
int WINDOW_TOP;
int WINDOW_BOTTOM;
int WINDOW_LEFT;
int WINDOW_RIGHT;
int VERTICAL_SCALE; // used to scale the "slivers" to get proper
int total_world_doors = 0;
typedef long fixed;
int toggle = 0;
// SOUND ////////////////
sound global_sounds[7];
// MUSIC //////////////////////////////////////////////
music song;
typedef struct object_type
{
int kind_of_object;
long x;
long y;
long dist;
long angle;
int id_number;
} objects, objects_ptr;
typedef struct statist_typ
{
float width_factor;
long Scale_Factor;
int Is_Multi_View;
int Is_Half_Height;
} stats, stats_ptr;
typedef struct Enemy_type
{
objects vitals;
int enem_num;
int state;
int threshold;
int hit_points;
int pat_num;
} enemy_objects, enemy_objects_ptr;
typedef struct door_type
{
int door_y;
int door_x;
int door_state;
int door_block_type;
int locked;
int door_speed;
int door_increment;
int door_wait_to_close;
} door, door_ptr;
typedef struct wall_type
{
char block_type;
short door_id;
} wall, wall_ptr;
typedef struct save_game
{
int cur_strength;
int cur_ammo;
int cur_map;
int cur_level;
} savestr, savestr_ptr;
typedef struct name_typ
{
unsigned char name[13];
} name_obj, name_obj_ptr;
name_obj names[5];
door doors[20];
int objects_found = 0;
int OVERBOARD_FOR_ENEMIES = 52; // absolute closest enemies can get to a wall
int got_key = 0;
// look up tables! ////////////////////////////////////////////////////////
wall world[WORLD_ROWS][WORLD_COLUMNS]; // pointer to matrix of cells that make up
// world
char far *Block_Map[WORLD_ROWS]; // pointer to block map...
float far *tan_table; // tangent tables used to compute initial
float far *inv_tan_table; // intersections with rays
float far *y_step; // x and y steps, used to find intersections
float far *x_step; // after initial one is found
float far *cos_table; // used to cancel out fishbowl effect
float far *inv_cos_table; // used to compute distances by calculating
float far *inv_sin_table; // the hypontenuse
int *scale_table[MAX_SCALE+1]; // table with pre-computed scale indices
// parmeter block used by assembly language sliver engine
char far *sliver_texture; // pointer to texture being rendered
int sliver_column; // index into texture i.e. which column of texture
int sliver_top; // starting Y position to render at
int sliver_bottom;
int sliver_scale; // overall height of sliver
int sliver_ray; // current ray being cast
int sliver_clip; // index into texture after clipping
int *scale_row; // row of scale value look up table to use
// OBJECT LISTS
objects *object_list;
stats obj_statistic_list[7];
objects *initial_object_list;
enemy_objects *enemies;
// G L O B A L S ////////////////////////////////////////////////////////////
pcx_picture back_pcx,
image_pcx;
sprite wall_frames;
sprite duck_frames;
sprite duck_death;
sprite ob_frames;
sprite the_gun;
int is_multi = 0; // for multiview sprites!
int Player_Strength = 63;
int just_grabbed_something = 0;
long x, y,view_angle;
int index1,
counter,
counter2;
int duck_pattern[24] = {0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,1};
int PAT_LIMIT = 24;
int increment=0; // used to determine how far a door is open
int color;
int what_obj = 0;
int gun_top = 108;
int Got_Rapid_Fire = 0;
long vz_buffer[320+1]; // vertical scanline Zbuffer for determining
// sprite_visibility
int Ammo_Color = 14;
int Vitality_Color = 119;
int Player_Ammo = 28;
int beat_it = 0;
// structure for slivers, used in order to interleave the ray casting
// with the time spent waiting for the PAGE FLIP to take hold!
// The elements of this structure are set in the function RAY_CASTER
// and used by DRAW_WALLS in it's subsequent calls to RENDER_SLIVER!
typedef struct buffer_typ
{
char far *sliv_texture; // pointer to texture being rendered
char sliv_hit_type;
unsigned short sliv_column; // index into texture i.e. which column of texture
unsigned short sliv_top; // starting Y position to render at
unsigned short sliv_bottom;
int sliv_scale; // overall height of sliver
int sliv_ray; // current ray being cast
int sliv_clip; // index into texture after clipping
int scale_r; // row of scale value look up table to use
} sliv_buff, sliv_ptr;
sliv_buff sliver_buffer[320+1]; // one structure for all columns drawn
int v_320[200]; // lookups to speed up the math for drawing pixels
int v_80[200];
int h_320[320];
int Number_Of_Fixed_Objects = 0;
int Number_Of_Enemies = 0;
int player_state = PLAYER_NOT_FIRING;
int AIMED = 0;
int digital_enabled = 0;
int music_enabled = 0;
long color_1, color_ceil, color_floor;
unsigned char far *back_up = (unsigned char far *)0xA000C000L;
RGB_color global_color;
RGB_color color_all;
RGB_color old_all[256];
int which_map = 0;
int Red_Factor = 16;
int at_end = 0, really_at_end = 0;
int aimed_sort_of = 0;
int in_view = 0;
int New_Lease_On_Life = 0;
int pal_reg, id_number;
int Restore_Black = 0;
int Damage = 0;
int pat_start = 0;
int rotate_em = 1;
char where_am_i[80];
// F U N C T I O N P R O T O T Y P E S /////////////////////////////
void (*rend_func_ptr) ();
int Object_Sort_Function(objects *arg1, objects *arg2);
// creates the scale table
void Create_Scale_Data(int scale, int *row);
void Create_Scale_Data2(int scale, int *row);
// Blits...
int Parse_Commands(int argc, char **argv);
void Draw_Walls(void);
// allocates/initializes tables
void Build_Tables(void);
void Load_64x64_Sprites(sprite_ptr sprite_set, char *filename, int num_cells);
// World Initialization functions...
void Allocate_World(void);
int Load_World(int lev_numb);
// the RAY CASTER!
void Ray_Caster(void);
void Draw_ReDraw_Frame(void);
// self explanatory...
// again, self explanatory...
void Translate_Player(long dx, long dy);
void Process_Doors(void);
void Render_Sliver(void);
void Render_Sliver_Mask(void);
void Render_Sliver_Mask_Special(void);
void Render_Sliver_Mask_Just_Bottom(void);
void Render_UpsideDwn_Mask_Bottom(void);
void Level_Select(int well);
int Slot_Selection(void);
void Refresh_Name_List(int what_shade);
int Load_Game(void);
void New_Game(void);
void Save_Game(void);
void Make_Light_Metallic_Blue_Palette(void);
void Make_Gold_Palette(void);
void Make_Gray_Palette(void);
void Make_Blue_Palette(void);
void Make_Blue_Palette_OAAT(int delta, int erase_trail);
void Make_Cyan_Palette_OAAT(int delta, int erase_trail);
void Make_Gold_Palette_OAAT(int delta, int erase_trail);
void Make_Gray_Palette_OAAT(int delta, int erase_trail);
void Rotate_Em(int well);
// BEGINNING OF CODE //////////////////////////////////////////////////////
void Render_Sliver(void)
{
// this is yet another version of the sliver scaler, however it uses look up
// tables with pre-computed scale indices.
// this draws vertical slivers from the middle of the strip to the top,
// and from the middle of the strip to the bottom.
register char far *work_sprite;
int far *row;
register int work_offset=0,offset,temp_offset,y_off,scale_off;
// alias a pointer to sprite for ease of access
work_sprite = sliver_texture;
// compute offset of sprite in video buffer
temp_offset = v_80[WINDOW_MIDDLE_MINUS] + h_320[sliver_ray];
// render top half of wall sliver
offset = temp_offset;
work_offset = WALL_MIDDLE_OFFSET - scale_row[0];
video_buffer[offset] = work_sprite[work_offset+sliver_column];
for (y_off=1; y_off<sliver_scale; y_off++)
{
offset -= 80;
work_offset = WALL_MIDDLE_OFFSET - scale_row[y_off];
video_buffer[offset] = work_sprite[work_offset+sliver_column];
} // end for y
// render bottom half of wall sliver
offset = temp_offset + 80;
work_offset = WALL_MIDDLE_OFFSET;
video_buffer[offset] = work_sprite[work_offset+sliver_column];
for (y_off=0; y_off<(sliver_scale-1); y_off++)
{
offset += 80;
work_offset = WALL_MIDDLE_OFFSET + scale_row[y_off];
video_buffer[offset] = work_sprite[work_offset+sliver_column];
} // end for y
} // end Render_Sliver
void Render_Sliver_Mask(void)
{
// this is yet another version of the sliver scaler, however it uses look up
// tables with pre-computed scale indices. in the end I converted this to
// assembly for speed
register char far *work_sprite;
int far *row;
register int work_offset=0,offset,y_off,scale_off;
// alias proper data row
scale_off = sliver_clip;
// alias a pointer to sprite for ease of access
work_sprite = sliver_texture;
// compute offset of sprite in video buffer
offset = v_80[WINDOW_MIDDLE_MINUS] + h_320[sliver_ray];
work_offset = WALL_MIDDLE_OFFSET - scale_row[0];
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
for (y_off=1; y_off<sliver_scale; y_off++)
{
offset -= 80;
work_offset = WALL_MIDDLE_OFFSET - scale_row[y_off];
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
} // end for y
offset = v_80[WINDOW_MIDDLE] + h_320[sliver_ray];
work_offset = WALL_MIDDLE_OFFSET;
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
for (y_off=0; y_off<(sliver_scale-1); y_off++)
{
offset += 80;
work_offset = WALL_MIDDLE_OFFSET + scale_row[y_off];
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
} // end for y
} // end Render_Sliver_Mask
void Render_Sliver_Mask_Special(void)
{
// this is yet another version of the sliver scaler, however it uses look up
// tables with pre-computed scale indices. in the end I converted this to
// assembly for speed
register char far *work_sprite;
int far *row;
register int work_offset=0,offset,y_off,scale_off;
register int Special_Offset;
// alias proper data row
scale_off = sliver_clip;
// alias a pointer to sprite for ease of access
work_sprite = sliver_texture;
// compute offset of sprite in video buffer
Special_Offset = sliver_scale-(sliver_scale/3);
offset = v_80[WINDOW_MIDDLE_MINUS-(Special_Offset-1)] + h_320[sliver_ray];
work_offset = WALL_MIDDLE_OFFSET - scale_row[0];
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
for (y_off=Special_Offset; y_off<sliver_scale; y_off++)
{
offset -= 80;
work_offset = WALL_MIDDLE_OFFSET - scale_row[y_off];
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
} // end for y
offset = v_80[WINDOW_MIDDLE+(Special_Offset)] + h_320[sliver_ray];
work_offset = WALL_MIDDLE_OFFSET;
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
for (y_off=Special_Offset; y_off<(sliver_scale-1); y_off++)
{
offset += 80;
work_offset = WALL_MIDDLE_OFFSET + scale_row[y_off];
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
} // end for y
} // end Render_Sliver_Mask_Special
void Render_Sliver_Mask_Just_Bottom(void)
{
// this is yet another version of the sliver scaler, however it uses look up
// tables with pre-computed scale indices. in the end I converted this to
// assembly for speed
register char far *work_sprite;
int far *row;
register int work_offset=0,offset,y_off,scale_off;
// alias proper data row
// alias a pointer to sprite for ease of access
work_sprite = sliver_texture;
// compute offset of sprite in video buffer
offset = v_80[WINDOW_MIDDLE] + h_320[sliver_ray];
work_offset = WALL_MIDDLE_OFFSET;
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
for (y_off=0; y_off<(sliver_scale-1); y_off++)
{
offset += 80;
work_offset = WALL_MIDDLE_OFFSET + scale_row[y_off];
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
} // end for y
} // end Render_Sliver_Mask_Just_Bottom
void Render_UpsideDwn_Mask_Bottom(void)
{
// this is yet another version of the sliver scaler, however it uses look up
// tables with pre-computed scale indices. in the end I converted this to
// assembly for speed
register char far *work_sprite;
int far *row;
register int work_offset=0,offset,y_off,scale_off;
// alias proper data row
// alias a pointer to sprite for ease of access
work_sprite = sliver_texture;
// compute offset of sprite in video buffer
offset = v_80[WINDOW_MIDDLE] + h_320[sliver_ray];
work_offset = WALL_MIDDLE_OFFSET;
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
for (y_off=0; y_off<(sliver_scale-1); y_off++)
{
offset -= 80;
work_offset = WALL_MIDDLE_OFFSET + scale_row[y_off];
if (work_sprite[work_offset+sliver_column]!=0)
video_buffer[offset] = work_sprite[work_offset+sliver_column];
} // end for y
} // end Render_UpsideDwn_Mask_Bottom
int Build_Object_Tables(char *file)
{
// this function opens the input file and loads the OBJECT data from it
FILE *fp, *fopen();
int index,row,column,ob_num,gunner_num;
char buffer[WORLD_COLUMNS+2],ch;
// allocate space for object lists...
// init ob counter
ob_num = 0;
gunner_num = 0;
// open the file
if (!(fp = fopen(file,"r")))
return(0);
// load in the data
for (row=0; row<WORLD_ROWS; row++)
{
// load in the next row
for (column=0; column<WORLD_COLUMNS; column++)
{
while((ch = getc(fp))==10){} // filter out CR
// translate character to integer
if ((ch == '0') || (ch == '1') || (ch == '6'))
{
ch = ch - '0';
initial_object_list[ob_num].x = (column<<CELL_X_SIZE_FP)+32;
initial_object_list[ob_num].y = (((WORLD_ROWS-1) - row)<<CELL_Y_SIZE_FP)+32;
initial_object_list[ob_num].angle = ANGLE_0;
initial_object_list[ob_num].kind_of_object = ch;
initial_object_list[ob_num].dist = 0;
ob_num++;
}
} // end for column
// process the row
} // end for row
// close the file
fclose(fp);
if (!(fp = fopen(file,"r")))
return(0);
// load in the data
for (row=0; row<WORLD_ROWS; row++)
{
// load in the next row
for (column=0; column<WORLD_COLUMNS; column++)
{
while((ch = getc(fp))==10){} // filter out CR
// translate character to integer
if ((ch == '4') || (ch == '5'))
{
ch = ch - '0';
initial_object_list[ob_num].x = (column<<CELL_X_SIZE_FP)+32;
initial_object_list[ob_num].y = (((WORLD_ROWS-1) - row)<<CELL_Y_SIZE_FP)+32;
initial_object_list[ob_num].angle = ANGLE_0;
initial_object_list[ob_num].kind_of_object = ch;
initial_object_list[ob_num].dist = 0;
ob_num++;
}
} // end for column
// process the row
} // end for row
// close the file
fclose(fp);
Number_Of_Fixed_Objects = ob_num;
ob_num = 0;
if (!(fp = fopen(file,"r")))
return(0);
// load in the data
for (row=0; row<WORLD_ROWS; row++)
{
// load in the next row
for (column=0; column<WORLD_COLUMNS; column++)
{
while((ch = getc(fp))==10){} // filter out CR
// translate character to integer
if ((ch == '2') || (ch == '3'))
{
ch = ch - '0';
enemies[ob_num].vitals.x = (column<<CELL_X_SIZE_FP)+32;
enemies[ob_num].vitals.y = (((WORLD_ROWS-1) - row)<<CELL_Y_SIZE_FP)+32;
enemies[ob_num].vitals.angle = ANGLE_0;
enemies[ob_num].vitals.kind_of_object = ch;
enemies[ob_num].vitals.dist = 0;
enemies[ob_num].enem_num = ob_num;
enemies[ob_num].state = WAITING;
enemies[ob_num].threshold = 0;
enemies[ob_num].hit_points = 5;
enemies[ob_num].pat_num = 0;
ob_num++;
}
} // end for column
// process the row
} // end for row
// close the file
fclose(fp);
Number_Of_Enemies = ob_num;
//return(1);
} // end Build_Object_Tables
void Find_and_Maybe_Plot_Objects(objects any_object, int ID_Number, int threshold)
{
long sub_view_left,sub_view_right;
long sub2_view_right;
long relative_angle;
float diff_x,diff_y;
long temp_buffer_check;
long buffer_check;
int *scale_column;
int i;
int indice;
int scale;
long object_x, object_y, object_dist, object_angle;
fixed scale_factor;
fixed planar_scale_factor;
fixed sprite_dist;
fixed adjusted_index;
int sprite_width,sprite_index,left,x_location;
int sprite_left,sprite_right;
int which_object;
int sides_per_object = 8;
int angles_per_side = ANGLE_45;
static int temp_what_half = 0;
int what_half;
int pquad;
int oquad;
int j;
// beginning of function code
object_x = any_object.x;
object_y = any_object.y;
object_dist = any_object.dist;
object_angle = any_object.angle;
which_object = any_object.kind_of_object;
what_half = 0;
diff_x = (x - object_x);
diff_y = (y - object_y);
if ((diff_x>1000) || (diff_x < -1000)) return;
if ((diff_y>1000) || (diff_y < -1000)) return;
sprite_dist = object_dist;
if ((sprite_dist<(30)) || (sprite_dist>(1000))) return;
if (diff_y == 0)
{
if (diff_x < 0)
relative_angle = ANGLE_0;
else
relative_angle = ANGLE_180;
}
else
if (diff_x == 0)
{
if (diff_y < 0)
relative_angle = ANGLE_90;
else
relative_angle = ANGLE_270;
}
else
{
if (diff_x < 0) diff_x = diff_x *-1;
if (diff_y < 0) diff_y = diff_y *-1;
relative_angle = (long)((atan((double)diff_y/(double)diff_x))*(RAD_TO_DEG));
diff_x = (x - object_x);
diff_y = (y - object_y);
if (diff_x > 0)
{
if(diff_y > 0)
relative_angle = ANGLE_180 + relative_angle;
else
if(diff_y < 0)
relative_angle = ANGLE_180 - relative_angle;
}
else
if (diff_x < 0)
{
if(diff_y > 0)
relative_angle = ANGLE_360 - relative_angle;
}
}
sub_view_left = view_angle + HALF_VIEW_CONE + ANGLE_5;
sub_view_right = view_angle - HALF_VIEW_CONE - ANGLE_5;
sub2_view_right = view_angle - HALF_VIEW_CONE;
// Adjust angles, because around view_angle 0 things
// get tricky...
if (sub2_view_right<ANGLE_5)
{
sub2_view_right += ANGLE_360;
}
if (sub_view_left>ANGLE_360) sub_view_left -= ANGLE_360;
if (sub_view_right<ANGLE_0)
{
sub_view_right += ANGLE_360;
}
if (sub_view_left>ANGLE_360) sub_view_left -= ANGLE_360;
if (sub_view_right<ANGLE_0)
{
sub_view_right += ANGLE_360;
}
if (sub_view_right > sub_view_left) // If looking towards the right
{
if (relative_angle >= sub_view_right) // Cal. view column of object
buffer_check = relative_angle - sub2_view_right;
else
buffer_check = (relative_angle+ANGLE_360) - sub2_view_right;
}
else
{
buffer_check = relative_angle - sub2_view_right; // Calc. view column of object
}
// if ((buffer_check < ANGLE_0) || (buffer_check > ANGLE_60)) return;
if (buffer_check < ANGLE_0)
scale=(int)(cos_table[ANGLE_0]/(sprite_dist))>>1;
else
if (buffer_check > VIEW_CONE)
scale=(int)(cos_table[VIEW_CONE]/(sprite_dist))>>1;
else
scale=(int)(cos_table[buffer_check]/(sprite_dist))>>1;
sprite_width = scale*obj_statistic_list[which_object].width_factor;
scale_factor = (obj_statistic_list[which_object].Scale_Factor)/((fixed)sprite_width);
planar_scale_factor = scale_factor<<2;
left = COLUMN_OFFSET-(buffer_check);
if (scale>(MAX_SCALE-1))
scale=(MAX_SCALE-1);
scale_row = scale_table[scale-1];
scale_column = scale_table[sprite_width-1];
if (scale>(WINDOW_HALF_HEIGHT))
{
scale=(WINDOW_HALF_HEIGHT);
}
sliver_scale = scale-1;
// set up parameters for assembly language
switch(which_object)
{
case 0:
{
sliver_texture = ob_frames.frames[0];
rend_func_ptr = Render_Sliver_Mask;
}
break;
case 1:
{
sliver_texture = ob_frames.frames[1];
rend_func_ptr = Render_Sliver_Mask_Special;
}
break;
case 2:
{
if (enemies[ID_Number].state == FIRING)
{
sliver_texture = duck_frames.frames[8];
}
else
if (enemies[ID_Number].state == HIT)
{
sliver_texture = duck_frames.frames[10];
}
else
if (enemies[ID_Number].state == DEAD)
{
sliver_texture = duck_frames.frames[9];
}
else
if (enemies[ID_Number].state == DYING)
{
sliver_texture = duck_death.frames[(7-threshold)/2];
what_half = (7-threshold) % 2;
}
else
{
pquad = (relative_angle+ANGLE_23)/angles_per_side;
oquad = (object_angle+ANGLE_23)/angles_per_side;
j = (pquad - oquad)+(sides_per_object>>1);
if (j >= sides_per_object)
j -= sides_per_object;
if (j < 0)
j += sides_per_object;
sliver_texture = duck_frames.frames[j];
}
rend_func_ptr = Render_Sliver_Mask_Just_Bottom;
}
break;
case 3:
{
if (enemies[ID_Number].state == FIRING)
{
sliver_texture = duck_frames.frames[8];
}
else
if (enemies[ID_Number].state == HIT)
{
sliver_texture = duck_frames.frames[10];
}
else
if (enemies[ID_Number].state == DEAD)
{
sliver_texture = duck_frames.frames[9];
}
else
if (enemies[ID_Number].state == DYING)
{
sliver_texture = duck_death.frames[(7-threshold)/2];
what_half = (7-threshold) % 2;
}
else
{
pquad = (relative_angle+ANGLE_23)/angles_per_side;
oquad = (object_angle+ANGLE_23)/angles_per_side;
j = (pquad - oquad)+(sides_per_object>>1);
if (j >= sides_per_object)
j -= sides_per_object;
if (j < 0)
j += sides_per_object;
sliver_texture = duck_frames.frames[j];
}
rend_func_ptr = Render_UpsideDwn_Mask_Bottom;
}
break;
case 4:
{
sliver_texture = ob_frames.frames[2];
rend_func_ptr = Render_Sliver_Mask_Just_Bottom;
}
break;
case 5:
{
sliver_texture = ob_frames.frames[3];
rend_func_ptr = Render_Sliver_Mask_Just_Bottom;
}
break;
case 6:
{
sliver_texture = ob_frames.frames[4];
rend_func_ptr = Render_Sliver_Mask_Just_Bottom;
}
break;
}
sprite_left = left+(sprite_width>>1);
sprite_right = sprite_left-sprite_width;
sliver_column = 0;
adjusted_index = 0;
sliver_top = WINDOW_MIDDLE - (scale >> 1);
buffer_check = buffer_check - (sprite_width>>1);
temp_buffer_check = buffer_check;
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov cl,BYTE PTR sprite_left // extract lower byte from x
and cl,03h // extract the plane number = x MOD 4
mov ah,1 // a "1" selects the plane in the plane enable
shl ah,cl // shift the "1" bit proper number of times
out dx,ax // do it baby!
}
for (sprite_index = sprite_left; sprite_index > sprite_right; sprite_index-=4)
{
if ((temp_buffer_check >= ANGLE_0) && (temp_buffer_check < VIEW_CONE))
{
if (sprite_dist < vz_buffer[temp_buffer_check])
{
sliver_column = (what_half<<5) + adjusted_index>>16;
sliver_ray = sprite_index;
// render the sliver in assembly
(*rend_func_ptr) ();
}
}
temp_buffer_check+=4;
adjusted_index+=planar_scale_factor;
}
temp_buffer_check = buffer_check+1;
sprite_left -= 1;
adjusted_index = scale_factor;
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov cl,BYTE PTR sprite_left // extract lower byte from x
and cl,03h // extract the plane number = x MOD 4
mov ah,1 // a "1" selects the plane in the plane enable
shl ah,cl // shift the "1" bit proper number of times
out dx,ax // do it baby!
}
for (sprite_index = sprite_left; sprite_index > sprite_right; sprite_index-=4)
{
if ((temp_buffer_check >= ANGLE_0) && (temp_buffer_check < VIEW_CONE))
{
if (sprite_dist < vz_buffer[temp_buffer_check])
{
sliver_column = (what_half<<5) + adjusted_index>>16;
sliver_ray = sprite_index;
// render the sliver in assembly
(*rend_func_ptr) ();
}
}
temp_buffer_check+=4;
adjusted_index+=planar_scale_factor;
}
temp_buffer_check = buffer_check+2;
sprite_left -= 1;
adjusted_index = scale_factor<<1;
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov cl,BYTE PTR sprite_left // extract lower byte from x
and cl,03h // extract the plane number = x MOD 4
mov ah,1 // a "1" selects the plane in the plane enable
shl ah,cl // shift the "1" bit proper number of times
out dx,ax // do it baby!
}
for (sprite_index = sprite_left; sprite_index > sprite_right; sprite_index-=4)
{
if ((temp_buffer_check >= ANGLE_0) && (temp_buffer_check < VIEW_CONE))
{
if (sprite_dist < vz_buffer[temp_buffer_check])
{
sliver_column = (what_half<<5) + adjusted_index>>16;
sliver_ray = sprite_index;
// render the sliver in assembly
(*rend_func_ptr) ();
}
}
temp_buffer_check+=4;
adjusted_index+=planar_scale_factor;
}
temp_buffer_check = buffer_check+3;
sprite_left -= 1;
adjusted_index = scale_factor<<1;
adjusted_index += scale_factor;
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov cl,BYTE PTR sprite_left // extract lower byte from x
and cl,03h // extract the plane number = x MOD 4
mov ah,1 // a "1" selects the plane in the plane enable
shl ah,cl // shift the "1" bit proper number of times
out dx,ax // do it baby!
}
for (sprite_index = sprite_left; sprite_index > sprite_right; sprite_index-=4)
{
if ((temp_buffer_check >= ANGLE_0) && (temp_buffer_check < VIEW_CONE))
{
if (sprite_dist < vz_buffer[temp_buffer_check])
{
sliver_column = (what_half<<5) + adjusted_index>>16;
sliver_ray = sprite_index;
// render the sliver in assembly
(*rend_func_ptr) ();
}
}
temp_buffer_check+=4;
adjusted_index+=planar_scale_factor;
}
} // END FIND AND MAYBE PLOT OBJECTS
void Make_Light_Metallic_Blue_Palette(void)
{
// this function generates 64 shades of Light_Metallic_Blue and places them in the palette
// at locations 16 to 80
int index;
RGB_color color;
// generate 64 shades of Light_Metallic_Blue
for (index = 0; index < 40; index++)
{
color.red = 0;
color.green = index;
color.blue = index;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
}
} // end Make_Light_Metallic_Blue_Palette
void Make_Gold_Palette(void)
{
// this function generates 64 shades of gold and places them in the palette
// at locations 16 to 80
int index;
RGB_color color;
// generate 64 shades of gold
for (index = 0; index < 40; index++)
{
color.red = index;
color.green = index;
color.blue = 0;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
}
} // end Make_Gold_Palette
void Make_Gray_Palette(void)
{
// this function generates 64 shades of gray and places them in the palette
// at locations 16 to 80
int index;
RGB_color color;
// generate 64 shades of gray
for (index = 0; index < 40; index++)
{
color.red = index;
color.green = index;
color.blue = index;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
}
} // end Make_Gold_Palette
void Make_Blue_Palette(void)
{
// this function generates 64 shades of gray and places them in the palette
// at locations 16 to 80
int index;
RGB_color color;
// generate 64 shades of gray
for (index = 0; index < 64; index++)
{
color.red = 0;
color.green = 0;
color.blue = index;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
}
} // end Make_Gold_Palette
void Make_Gray_Palette_OAAT(int delta, int erase_trail)
{
// this function generates 64 shades of gray and places them in the palette
// at locations 16 to 80
int index;
RGB_color color;
// generate 64 shades of gray
index = delta;
color.red = index;
color.green = index;
color.blue = index;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
} // end Make_Gray_Palette_OAAT
void Make_Blue_Palette_OAAT(int delta, int erase_trail)
{
// this function generates 64 shades of gray and places them in the palette
// at locations 16 to 80
int index;
RGB_color color;
// generate 64 shades of gray
index = delta;
// gray equals equal percentage of Red, Green and Blue
if (index!=39)
{
color.red = 0;
color.green = 0;
color.blue = index;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
}
if ((index!=0) && (erase_trail))
{
--index;
color.red = index;
color.green = index;
color.blue = index;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
}
} // end Make_Blue_Palette_OAAT
void Make_Gold_Palette_OAAT(int delta, int erase_trail)
{
// this function generates 64 shades of gray and places them in the palette
// at locations 16 to 80
int index;
RGB_color color;
// generate 64 shades of gray
index = delta;
if (index!=39)
{
// gray equals equal percentage of Red, Green and Blue
color.red = 0;
color.green = index;
color.blue = index;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
}
if ((index!=0) && (erase_trail))
{
--index;
color.red = index;
color.green = index;
color.blue = index;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
}
} // end Make_Gold_Palette_OAAT
void Make_Cyan_Palette_OAAT(int delta, int erase_trail)
{
// this function generates 64 shades of gray and places them in the palette
// at locations 16 to 80
int index;
RGB_color color;
index = delta;
// generate 64 shades of gray
if (index!=39)
{
// gray equals equal percentage of Red, Green and Blue
color.red = index;
color.green = index;
color.blue = 0;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
}
if ((index!=0) && (erase_trail))
{
--index;
color.red = index;
color.green = index;
color.blue = index;
old_all[16+index] = color;
// write the color in the palette starting at location 16, so as not to
// fry the EGA palette
Write_Color_Reg(16+index,(RGB_color_ptr)&color);
}
} // end Make_Cyan_Palette_OAAT
void Process_Doors(void)
{
// Checks the list of doors, and processes them if they are
// OPENING, OPEN, OR CLOSING
int cells_x,cells_y,row,column;
int index = total_world_doors;
int enem_index;
int in_the_doorway = 0;
int x_player,y_player;
int x_cell_d,y_cell_d;
int processed_doors;
// you might want to put the active doors in a linked list...
// but I did it this way, because there aren't many doors per map
// ALOT OF THE THINGS I DO HERE ARE DOPEY!
for (index = 0; index < total_world_doors; index++)
{
// get the x & y map coordinates for the door
x_cell_d = doors[index].door_x;
y_cell_d = doors[index].door_y;
if (doors[index].door_state != CLOSED)
{
if (doors[index].door_state == OPENING)
{
// open the door some more...
doors[index].door_increment+=6;
// when the door is all the way open - STOP OPENING IT!
if (doors[index].door_increment > 64)
{
// this holds the door open a little while...
doors[index].door_wait_to_close = 80;
// this simply ensures the door is set open
doors[index].door_increment = 64;
// Take the door out of the world map... so that
// the rendering engine can ignore it completely
// (not the smartest way...)
world[y_cell_d][x_cell_d].block_type = 0;
// Allow the player to pass through the vacant doorway
Block_Map[y_cell_d][x_cell_d] = 0;
// set door state to OPEN
doors[index].door_state = OPEN;
}
}
else
if (doors[index].door_state == CLOSING)
{
// close the door some more...
doors[index].door_increment-=6;
if (doors[index].door_increment < 0) // is it all the way
{ // closed?
doors[index].door_state = CLOSED;
doors[index].door_increment = 0;
}
}
else
if (doors[index].door_state == OPEN)
{
doors[index].door_wait_to_close--; // countdown to closing...
if (doors[index].door_wait_to_close < 0)
{
in_the_doorway = 0;
x_player = x / CELL_X_SIZE;
y_player = y / CELL_Y_SIZE;
// is the player in the doorway?
if ((y_player == (y_cell_d)) && // NOPE!
(x_player == x_cell_d))
in_the_doorway = 1;
if (!in_the_doorway)
{
for (enem_index=0; enem_index <= Number_Of_Enemies; enem_index++)
{
if(!in_the_doorway)
{
x_player = enemies[enem_index].vitals.x / CELL_X_SIZE;
y_player = enemies[enem_index].vitals.y / CELL_Y_SIZE;
if ((y_player == (y_cell_d)) && // NOPE!
(x_player == x_cell_d))
in_the_doorway = 1;
}
}
}
if (!in_the_doorway)
{
// put door back into the world map
world[y_cell_d][x_cell_d].block_type=
doors[index].door_block_type;
// make block impassable
Block_Map[y_cell_d][x_cell_d] = 1;
// the door is closing
doors[index].door_state = CLOSING;
doors[index].door_wait_to_close = 0;
}
else
{
doors[index].door_state = OPEN;
doors[index].door_wait_to_close = 10;
}
}
}
}
} // end while
} // end Process_Doors
void Create_Scale_Data(int scaler, int *row)
{
// this function synthesizes the scaling of a texture sliver to all possible
// sizes and creates a huge look up table of the data.
int y_off;
float y_scale_index=0,
y_scale_step;
// compute scale step or number of source pixels to map to destination/cycle
y_scale_step = (float)32/(float)scaler;
y_scale_index+=y_scale_step;
for (y_off=0; y_off<scaler; y_off++)
{
// place data into proper array position for later use
row[y_off] = ((int)(y_scale_index+.4)) * SWATCH_WIDTH;
// test if we slightly went overboard
if (row[y_off] > WALL_MIDDLE_OFFSET) row[y_off] = WALL_MIDDLE_OFFSET;
// next index please
y_scale_index+=y_scale_step;
} // end for y_off
} // end Create_Scale_Data
void Create_Scale_Data2(int scaler, int *row)
{
// this function synthesizes the scaling of a texture sliver to all possible
// sizes and creates a huge look up table of the data.
// this adds data for cases where the vertical extents of the "sliver" are
// beyond the vertical extents of the viewport
int y_off;
float y_scale_index=0,
y_scale_step;
// compute scale step or number of source pixels to map to destination/cycle
y_scale_step = (float)32/(float)scaler;
y_scale_index+=y_scale_step;
for (y_off=0; y_off<WINDOW_HALF_HEIGHT+1; y_off++)
{
// place data into proper array position for later use
row[y_off] = ((int)(y_scale_index+.4)) * SWATCH_WIDTH;
// test if we slightly went overboard
if (row[y_off] > WALL_MIDDLE_OFFSET) row[y_off] = WALL_MIDDLE_OFFSET;
// next index please
y_scale_index+=y_scale_step;
} // end for y_off
} // end Create_Scale_Data2
void Build_Tables(void)
{
// this function builds all the look up tables for the system
// the ANGLE_?s are assigned values here because I wanted to make the
// viewport resizable(!?) (probably not the best way)
int ang,scale;
float rad_angle;
ANGLE_360= my_size;
ANGLE_180= (ANGLE_360>>1);
ANGLE_90= (ANGLE_360>>2);
ANGLE_75= (ANGLE_360/4.8);
ANGLE_60= (ANGLE_360/6);
ANGLE_45= (ANGLE_360/8);
ANGLE_30= (ANGLE_360/12);
ANGLE_15= (ANGLE_360/24);
ANGLE_6= (ANGLE_360/60);
ANGLE_5= (ANGLE_360/72);
ANGLE_4= (ANGLE_360/90);
ANGLE_2= (ANGLE_360/180);
ANGLE_1= (ANGLE_360/360);
ANGLE_0= 0;
// some ODDBALL angles
ANGLE_315= (ANGLE_360-ANGLE_45);
ANGLE_270= (ANGLE_360-ANGLE_90);
ANGLE_225= (ANGLE_270-ANGLE_45);
ANGLE_135= (ANGLE_180-ANGLE_45);
ANGLE_10= (ANGLE_5+ANGLE_5);
ANGLE_9= (ANGLE_5+ANGLE_4);
ANGLE_8= (ANGLE_4+ANGLE_4);
ANGLE_7= (ANGLE_8-ANGLE_1);
//... and some possible 'view cones'...
ANGLE_80 = (ANGLE_90-ANGLE_10);
ANGLE_70 = (ANGLE_60+ANGLE_10);
// for 'shifting the parachute' (?!)
ANGLE_23= (ANGLE_15 + ANGLE_5 + ANGLE_2 + ANGLE_1);
// VIEW CONE VALUES...
VIEW_CONE = ANGLE_90;
HALF_VIEW_CONE = (VIEW_CONE>>1);
// conversion constants from radians to degrees and vice-versa
ANGULAR_INCREMENT =((float)360/(float)ANGLE_360);
RAD_TO_DEG = (((float)180/(float)ANGULAR_INCREMENT)/(float)3.1415926);
WINDOW_HEIGHT= my_height;
WINDOW_HALF_HEIGHT= (WINDOW_HEIGHT>>1);
WINDOW_MIDDLE= 79;
WINDOW_MIDDLE_MINUS= 78;
WINDOW_TOP= WINDOW_MIDDLE-WINDOW_HALF_HEIGHT+1;
WINDOW_BOTTOM= WINDOW_MIDDLE+WINDOW_HALF_HEIGHT-1;
WINDOW_LEFT= my_left;
WINDOW_RIGHT= my_right;
VERTICAL_SCALE= my_v_scale; // used to scale the "slivers" to get proper
// allocate memory for all look up tables
// tangent tables equivalent to slopes
tan_table = (float far *)_fmalloc(sizeof(float) * (ANGLE_360+1) );
inv_tan_table = (float far *)_fmalloc(sizeof(float) * (ANGLE_360+1) );
// step tables used to find next intersections, equivalent to slopes
// times width and height of cell
y_step = (float far *)_fmalloc(sizeof(float) * (ANGLE_360+1) );
x_step = (float far *)_fmalloc(sizeof(float) * (ANGLE_360+1) );
// cos table used to fix view distortion caused by caused by radial projection
cos_table = (float far *)_fmalloc(sizeof(float) * (VIEW_CONE+1) );
// 1/cos and 1/sin tables used to compute distance of intersection very
// quickly
inv_cos_table = (float far *)_fmalloc(sizeof(float) * (ANGLE_360+1) );
inv_sin_table = (float far *)_fmalloc(sizeof(float) * (ANGLE_360+1) );
// create the lookup tables for the scaler
// there have the form of an array of pointers, where each pointer points
// another another array of data where the 'data' are the scale indices
for (scale=0; scale<=WINDOW_HALF_HEIGHT; scale++)
{
scale_table[scale] = (int *)malloc(scale*sizeof(int)+1);
} // end for scale
for (scale=WINDOW_HALF_HEIGHT+1; scale<=MAX_SCALE; scale++)
{
scale_table[scale] = (int *)malloc((WINDOW_HALF_HEIGHT+1)*sizeof(int)+1);
} // end for scale
// create tables, sit back for a sec!
for (ang=ANGLE_0; ang<=ANGLE_360; ang++)
{
rad_angle = (float)((3.272e-4) + ang * 2*3.141592654/ANGLE_360);
tan_table[ang] = (float)tan(rad_angle);
inv_tan_table[ang] = (float)(1/tan_table[ang]);
// tangent has the incorrect signs in all quadrants except 1, so
// manually fix the signs of each quadrant since the tangent is
// equivalent to the slope of a line and if the tangent is wrong
// then the ray that is case will be wrong
if (ang>=ANGLE_0 && ang<ANGLE_180)
{
y_step[ang] = (float)(fabs(tan_table[ang] * CELL_Y_SIZE));
}
else
y_step[ang] = (float)(-fabs(tan_table[ang] * CELL_Y_SIZE));
if (ang>=ANGLE_90 && ang<ANGLE_270)
{
x_step[ang] = (float)(-fabs(inv_tan_table[ang] * CELL_X_SIZE));
}
else
{
x_step[ang] = (float)(fabs(inv_tan_table[ang] * CELL_X_SIZE));
}
// create the sin and cosine tables to copute distances
inv_cos_table[ang] = (float)(1/cos(rad_angle));
inv_sin_table[ang] = (float)(1/sin(rad_angle));
} // end for ang
///////////////////////////////////////////////////////
// THE FOLLOWING LINES ARE THE FOSSILIZED REMAINS OF WHAT I NEED TO
// DO WHEN I IMPLEMENTED FIXED POINT MATH, W/ LONG INTEGERS FOR VALUES
// IN THE LOOKUP TABLES
///////////////////////////////////////////////////////
tan_table[ANGLE_0] = tan_table[ANGLE_0+1];
inv_tan_table[ANGLE_0] = inv_tan_table[ANGLE_0+1];
tan_table[ANGLE_90] = tan_table[ANGLE_90+1];
inv_tan_table[ANGLE_90] = inv_tan_table[ANGLE_90+1];
tan_table[ANGLE_180] = tan_table[ANGLE_180+1];
inv_tan_table[ANGLE_180] = inv_tan_table[ANGLE_180+1];
tan_table[ANGLE_270] = tan_table[ANGLE_270+1];
inv_tan_table[ANGLE_270] = inv_tan_table[ANGLE_270+1];
y_step[ANGLE_0] = y_step[ANGLE_0+1];
x_step[ANGLE_0] = x_step[ANGLE_0+1];
y_step[ANGLE_90] = y_step[ANGLE_90+1];
x_step[ANGLE_90] = x_step[ANGLE_90+1];
y_step[ANGLE_180] = y_step[ANGLE_180+1];
x_step[ANGLE_180] = x_step[ANGLE_180+1];
y_step[ANGLE_270] = y_step[ANGLE_270+1];
x_step[ANGLE_270] = x_step[ANGLE_270+1];
// create the sin and cosine tables to copute distances
inv_cos_table[ANGLE_0] = inv_cos_table[ANGLE_0+1];
inv_sin_table[ANGLE_0] = inv_sin_table[ANGLE_0+1];
inv_cos_table[ANGLE_90] = inv_cos_table[ANGLE_90+1];
inv_sin_table[ANGLE_90] = inv_sin_table[ANGLE_90+1];
inv_cos_table[ANGLE_180] = inv_cos_table[ANGLE_180+1];
inv_sin_table[ANGLE_180] = inv_sin_table[ANGLE_180+1];
inv_cos_table[ANGLE_270] = inv_cos_table[ANGLE_270+1];
inv_sin_table[ANGLE_270] = inv_sin_table[ANGLE_270+1];
// create view filter table. There is a cosine wave modulated on top of
// the view distance as a side effect of casting from a fixed point.
// to cancel this effect out, we multiple by the inverse of the cosine
// and the result is the proper scale. Without this we would see a
// fishbowl effect, which might be desired in some cases?
for (ang=(-HALF_VIEW_CONE); ang<=(HALF_VIEW_CONE); ang++)
{
rad_angle = (float)((3.272e-4) + ang * 2*3.141592654/ANGLE_360);
cos_table[ang+HALF_VIEW_CONE] = (float)(VERTICAL_SCALE/cos(rad_angle));
} // end for
// build the scaler table. This table holds MAX_SCALE different arrays. Each
// array consists of the pre-computed indices for an object to be scaled
for (scale=1; scale<=WINDOW_HALF_HEIGHT; scale++)
{
// create the indices for this scale
Create_Scale_Data(scale, (int *)scale_table[scale]);
} // end for scale
// THE SECOND Create_Scale_Data FUNCTION REFERED TO HERE IS USED
// TO COMPUTE SCALES FOR CASES WHERE THE BOTTOM AND THE TOP OF A WALL
// SLIVER ARE BEYOND THE VERTICAL EXTENTS OF THE VIEWPORT!
for (scale=WINDOW_HALF_HEIGHT+1; scale<=MAX_SCALE; scale++)
{
// create the indices for this scale
Create_Scale_Data2(scale, (int *)scale_table[scale]);
} // end for scale
// I saved a few multiplies with these...
for (ang = 0; ang<200; ang++)
v_320[ang] = ang*320;
for (ang = 0; ang<200; ang++)
v_80[ang] = ang*80;
for (ang = 0; ang<320; ang++)
h_320[ang] = ang>>2;
} // end Build_Tables
/////////////////////////////////////////////////////////////////////////////
void Allocate_World(void)
{
// this function allocates the memory for the world
// I had initially allocated the world[][] array here...
// ... and believe it or not... even though there are always fewer
// than say, 15 doors to a map - I allocated a doors[][] array here too.
// NEEDLESS TO SAY - I WAS VERY WASTEFUL OF RESOURCES
int index;
// allocate each row
for (index=0; index<WORLD_ROWS; index++)
{
Block_Map[index] = (char far *)_fmalloc(WORLD_COLUMNS+1);
} // end for index
} // end Allocate_World
////////////////////////////////////////////////////////////////////////////////
int Load_World(int lev_number)
{
// this function opens the input file and loads the world data from it
// the maps for this 'game' are 32x32 text files (you can makem' with
// notepad). 2s and 3s make doors.
// 4s were used to make impassable, invisible walls (for objects)
FILE *fp, *fopen();
int ob_num,gunner_num;
int index,row,column;
char buffer[WORLD_COLUMNS+2],ch;
int door_num = 0;
int result;
long pos;
// open the file
if (!(fp = fopen("world.dat","r")))
return(0);
pos = (1088L*(long)(lev_number<<1));
result = fseek( fp, pos, SEEK_SET);
if( result )
Print_String_Mode_Y(10,10,79,"Fseek failure",0);
// load in the data
for (row=0; row<WORLD_ROWS; row++)
{
// load in the next row
for (column=0; column<WORLD_COLUMNS; column++)
{
while((ch = getc(fp))==10){} // filter out CR
// translate character to integer
if (ch == ' ')
ch=0;
else
ch = ch - '0';
// insert data into world
if (ch==4)
world[(WORLD_ROWS-1) - row][column].block_type = 0;
else
world[(WORLD_ROWS-1) - row][column].block_type = ch;
Block_Map[(WORLD_ROWS-1) - row][column] = ch;
if ((ch == 2) || (ch == 3)) // if it's a door
{
world[(WORLD_ROWS-1) - row][column].door_id = door_num;
doors[door_num].door_y = (WORLD_ROWS-1) - row;
doors[door_num].door_x = column;
doors[door_num].door_state = CLOSED;
doors[door_num].door_block_type = ch;
doors[door_num].locked=0;
doors[door_num].door_speed=5;
doors[door_num].door_increment=0;
doors[door_num].door_wait_to_close=0;
door_num++;
}
} // end for column
// process the row
} // end for row
total_world_doors = door_num; // used by Process_Doors
// allocate space for object lists...
// init ob counter
ob_num = 0;
gunner_num = 0;
// load in the data
for (row=0; row<WORLD_ROWS; row++)
{
// load in the next row
for (column=0; column<WORLD_COLUMNS; column++)
{
while((ch = getc(fp))==10){} // filter out CR
// translate character to integer
if ((ch == '0') || (ch == '1') || (ch == '6'))
{
ch = ch - '0';
initial_object_list[ob_num].x = (column<<CELL_X_SIZE_FP)+32;
initial_object_list[ob_num].y = (((WORLD_ROWS-1) - row)<<CELL_Y_SIZE_FP)+32;
initial_object_list[ob_num].angle = ANGLE_0;
initial_object_list[ob_num].kind_of_object = ch;
initial_object_list[ob_num].dist = 0;
ob_num++;
}
} // end for column
// process the row
} // end for row
// close the file
result = fseek( fp, pos+1088L, SEEK_SET);
if( result )
Print_String_Mode_Y(10,10,79,"Fseek failure",0);
// load in the data
for (row=0; row<WORLD_ROWS; row++)
{
// load in the next row
for (column=0; column<WORLD_COLUMNS; column++)
{
while((ch = getc(fp))==10){} // filter out CR
// translate character to integer
if ((ch == '4') || (ch == '5'))
{
ch = ch - '0';
initial_object_list[ob_num].x = (column<<CELL_X_SIZE_FP)+32;
initial_object_list[ob_num].y = (((WORLD_ROWS-1) - row)<<CELL_Y_SIZE_FP)+32;
initial_object_list[ob_num].angle = ANGLE_0;
initial_object_list[ob_num].kind_of_object = ch;
initial_object_list[ob_num].dist = 0;
ob_num++;
}
} // end for column
// process the row
} // end for row
// close the file
Number_Of_Fixed_Objects = ob_num;
ob_num = 0;
result = fseek( fp, pos+1088L, SEEK_SET);
if( result )
Print_String_Mode_Y(10,10,79,"Fseek failure",0);
// load in the data
for (row=0; row<WORLD_ROWS; row++)
{
// load in the next row
for (column=0; column<WORLD_COLUMNS; column++)
{
while((ch = getc(fp))==10){} // filter out CR
// translate character to integer
if ((ch == '2') || (ch == '3'))
{
ch = ch - '0';
enemies[ob_num].vitals.x = (column<<CELL_X_SIZE_FP)+32;
enemies[ob_num].vitals.y = (((WORLD_ROWS-1) - row)<<CELL_Y_SIZE_FP)+32;
enemies[ob_num].vitals.angle = ANGLE_0;
enemies[ob_num].vitals.kind_of_object = ch;
enemies[ob_num].vitals.dist = 0;
enemies[ob_num].enem_num = ob_num;
enemies[ob_num].state = WAITING;
enemies[ob_num].threshold = 0;
enemies[ob_num].hit_points = 5;
enemies[ob_num].pat_num = 0;
ob_num++;
}
} // end for column
// process the row
} // end for row
// close the file
fclose(fp);
Number_Of_Enemies = ob_num;
// close the file
//return(1);
} // end Load_World
/////////////////////////////////////////////////////////////////////////////
void Ray_Caster(void)
{
// This is the heart of the system. it casts out 320 rays and builds the
// 3-D image from their intersections with the walls. It was derived from
// the previous version used in "RAY.C", however, it has been extremely
// optimized for speed by the use of many more lookup tables and fixed
// point math
register int
curr_ang,
cell_x, // the current cell that the ray is in
cell_y,
ray, // the current ray being cast 0-320
casting=2, // tracks the progress of the X and Y component of the ray
x_hit_type, // records the block that was intersected, used to figure
y_hit_type, // out which texture to use
x_bound, // the next vertical and horizontal intersection point
y_bound,
next_y_cell, // used to figure out the quadrant of the ray
next_x_cell,
xray=0, // tracks the progress of a ray looking for Y interesctions
yray=0, // tracks the progress of a ray looking for X interesctions
x_delta, // the amount needed to move to get to the next cell
y_delta, // position
xb_save,
yb_save,
xi_save, // used to save exact x and y intersection points
yi_save,
scale;
int x_anded,y_anded;
int door_sliver;
int in_bounds;
register long
cast=0,
dist_x, // the distance of the x and y ray intersections from
dist_y; // the viewpoint
register float xi, // used to track the x and y intersections
yi;
int temp_ray;
int a_toggle, b_toggle;
// variables to handle a door being partially open (one of many ways to do this)
int dor_y_inc=0;
int dor_x_inc=0;
int doorx_num, doory_num;
// S E C T I O N 1 /////////////////////////////////////////////////////////v
// initialization
// compute starting angle from player. Field of view is 90 degrees, so
// subtract half of that current view angle
// start the current angle off -45 degrees to the left of the player's
// current viewing direction
// The following inline assembly instructions determine which
// plane(s) pixels will be written to.
// The value moved into AH (1-15... or 0001 - 1111{binary})
// determines the plane enabled!
// P L A N E # ? ////////////////////////////////////////////////////
/////////////////////// E N A B L E D ////////////////////////////////////
// NOTE: I DECIDED TO DO THIS OUTSIDE OF THE RAY-CASTER! /////////////
// In the procedure Draw_Walls /////////////////////////////
curr_ang = view_angle;
if ( (curr_ang-=HALF_VIEW_CONE) < 0)
{
curr_ang=ANGLE_360 + curr_ang;
} // end if
// loop through all 320 rays
x_anded = (int)(x & 0xffc0);
y_anded = (int)(y & 0xffc0);
for (ray=0; ray<(VIEW_CONE); ray++)
{
// S E C T I O N 2 /////////////////////////////////////////////////////////
dor_y_inc=0;
dor_x_inc=0;
temp_ray = ray;
// compute first x intersection
// need to know which half plane we are casting from relative to Y axis
y_bound = y_anded;
y_delta = -CELL_Y_SIZE;
next_y_cell = -1;
a_toggle = 0;
if (curr_ang >= ANGLE_0 && curr_ang < ANGLE_180)
{
// compute first horizontal line that could be intersected with ray
// note: it will be above player
y_bound = (CELL_Y_SIZE + y_anded);
// compute delta to get to next horizontal line
y_delta = CELL_Y_SIZE;
// set cell delta
next_y_cell = 0;
a_toggle = 1;
} // end if upper half plane
// based on first possible horizontal intersection line, compute X
// intercept, so that casting can begin
xi = inv_tan_table[curr_ang] * (y_bound - y) + x;
// S E C T I O N 3 /////////////////////////////////////////////////////////
// compute first y intersection
x_bound = x_anded;
x_delta = -CELL_X_SIZE;
next_x_cell = -1;
b_toggle = 0;
// need to know which half plane we are casting from relative to X axis
if (curr_ang < ANGLE_90 || curr_ang >= ANGLE_270)
{
// compute first vertical line that could be intersected with ray
// note: it will be to the right of player
x_bound = (int)(CELL_X_SIZE + x_anded);
// compute delta to get to next vertical line
x_delta = CELL_X_SIZE;
// set cell delta
next_x_cell = 0;
b_toggle = 1;
} // end if right half plane
// based on first possible vertical intersection line, compute Y
// intercept, so that casting can begin
yi = tan_table[curr_ang] * (x_bound - x) + y;
// begin cast
xray=yray = 0; // reset intersection flags
// PREAMBLE TO S E C T I O N 4 /////////////////////////////////////////////////////////
cell_x = ( (x_bound+next_x_cell) >> CELL_X_SIZE_FP);
cell_y = (int)yi;
cell_y>>=CELL_Y_SIZE_FP;
// test if there is a block where the current x ray is intersecting
if ((x_hit_type = world[cell_y][cell_x].block_type)!=0)
{
if (x_hit_type == 2) // is this an East/West door?
{
// get the door's identification number
doorx_num = world[cell_y][cell_x].door_id;
// move the ray a half step forward
yi += y_step[curr_ang]/2;
// what column of the door's bitmap would we use?
door_sliver = ((int)yi & 0x003f);
if (doors[doorx_num].door_state!=CLOSED)
{
// if door isn't closed...
// slide the texture over to the right...
dor_x_inc = door_sliver + doors[doorx_num].door_increment;
if (dor_x_inc > 63) // the door isn't blocking
{ // this ray from a wall beyond...
//back the ray up a half step
yi -= y_step[curr_ang]/2;
}
else
{
// confirmed: Door hit
x_hit_type = 3;
xray = INTERSECTION_FOUND;
}
}
else
{
// confirmed: Door hit
x_hit_type = 3;
dor_x_inc = door_sliver;
xray = INTERSECTION_FOUND;
}
}
else
xray = INTERSECTION_FOUND;
} // end if a hit
// S E C T I O N 4 /////////////////////////////////////////////////////////
while(xray!=INTERSECTION_FOUND)
{
// continue casting each ray in parallel
yi += y_step[curr_ang];
// find next possible x intercept point
x_bound += x_delta;
// compute current map position to inspect
cell_x = ( (x_bound+next_x_cell) >> CELL_X_SIZE_FP);
cell_y = (int)yi;
cell_y>>=CELL_Y_SIZE_FP;
// test if there is a block where the current x ray is intersecting
if ((x_hit_type = world[cell_y][cell_x].block_type)!=0)
{
if (x_hit_type == 2) // is this an East/West door?
{
// get the door's identification number
doorx_num = world[cell_y][cell_x].door_id;
// move the ray a half step forward
yi += y_step[curr_ang]/2;
// what column of the door's bitmap would we use?
door_sliver = ((int)yi & 0x003f);
if (doors[doorx_num].door_state!=CLOSED)
{
// if door isn't closed...
// slide the texture over to the right...
dor_x_inc = door_sliver + doors[doorx_num].door_increment;
if (dor_x_inc > 63) // the door isn't blocking
{ // this ray from a wall beyond...
//back the ray up a half step
yi -= y_step[curr_ang]/2;
}
else
{
// confirmed: Door hit
x_hit_type = 3;
xray = INTERSECTION_FOUND;
}
}
else
{
// confirmed: Door hit
x_hit_type = 3;
dor_x_inc = door_sliver;
xray = INTERSECTION_FOUND;
}
}
else
xray = INTERSECTION_FOUND;
} // end if a hit
} // end if x ray has intersected
dist_x = (long)((yi - y) * inv_sin_table[curr_ang]);
yi_save = (int)yi; // what column of the wall (or door's) bitmap
// do we use.
xb_save = x_bound;
// PREAMBLE TO S E C T I O N 5 /////////////////////////////////////////////////////////
cell_x = xi;
cell_x>>=CELL_X_SIZE_FP;
cell_y = ( (y_bound + next_y_cell) >> CELL_Y_SIZE_FP);
// test if there is a block where the current y ray is intersecting
if ((y_hit_type = world[cell_y][cell_x].block_type)!=0)
{
if (y_hit_type == 3) // is this a north/south doorway?
{
// extract door identification #
doory_num = world[cell_y][cell_x].door_id;
// move forward a half step
xi += x_step[curr_ang]/2;
// what column of the door are we looking at?
door_sliver = ((int)xi & 0x003f);
if (doors[doory_num].door_state!=CLOSED)
{
// slide door over...
dor_y_inc = door_sliver + doors[doory_num].door_increment;
// does this ray miss the partially opened door?
if (dor_y_inc > 63) // yep!
{
// backup half a step
xi -= x_step[curr_ang]/2;
}
else
{
// it's a hit!
y_hit_type = 3;
yray = INTERSECTION_FOUND;
}
}
else
{
// it's a hit!
dor_y_inc = door_sliver;
yray = INTERSECTION_FOUND;
}
}
else // not a door... it's a hit!
yray = INTERSECTION_FOUND;
}
// S E C T I O N 5 /////////////////////////////////////////////////////////
while (yray!=INTERSECTION_FOUND)
{
xi += x_step[curr_ang];
// compute next possible y intercept
y_bound += y_delta;
// compute current map position to inspect
cell_x = xi;
cell_x>>=CELL_X_SIZE_FP;
cell_y = ( (y_bound + next_y_cell) >> CELL_Y_SIZE_FP);
// test if there is a block where the current y ray is intersecting
if ((y_hit_type = world[cell_y][cell_x].block_type)!=0)
{
if (y_hit_type == 3) // is this a north/south doorway?
{
// extract door identification #
doory_num = world[cell_y][cell_x].door_id;
// move forward a half step
xi += x_step[curr_ang]/2;
// what column of the door are we looking at?
door_sliver = ((int)xi & 0x003f);
if (doors[doory_num].door_state!=CLOSED)
{
// slide door over...
dor_y_inc = door_sliver + doors[doory_num].door_increment;
// does this ray miss the partially opened door?
if (dor_y_inc > 63) // yep!
{
// backup half a step
xi -= x_step[curr_ang]/2;
}
else
{
// it's a hit!
y_hit_type = 3;
yray = INTERSECTION_FOUND;
}
}
else
{
// it's a hit!
dor_y_inc = door_sliver;
yray = INTERSECTION_FOUND;
}
}
else // not a door... it's a hit!
yray = INTERSECTION_FOUND;
}
} // end while not done
dist_y = (long)((xi - x) * inv_cos_table[curr_ang]);
xi_save = (int)xi;
yb_save = y_bound;
// S E C T I O N 6 /////////////////////////////////////////////////////////
// at this point, we know that the ray has succesfully hit both a
// vertical wall and a horizontal wall, so we need to see which one
// was closer and then render it
if (dist_x < dist_y)
{
// there was a vertical wall closer than the horizontal
// compute actual scale and multiply by view filter so that spherical
// distortion is cancelled
scale = (int)(cos_table[temp_ray]/(dist_x))>>1;
vz_buffer[ray] = dist_x;
sliver_buffer[ray].sliv_hit_type = 0+(2*b_toggle);
// clip wall sliver against view port
if (scale>(MAX_SCALE-1)) scale=(MAX_SCALE-1);
sliver_buffer[ray].scale_r = scale-1;
if (scale>(WINDOW_HALF_HEIGHT))
{
scale=(WINDOW_HALF_HEIGHT);
}
sliver_buffer[ray].sliv_scale = scale-1;
// set up parameters for assembly language
sliver_buffer[ray].sliv_texture = wall_frames.frames[x_hit_type-1];
if (x_hit_type != 3)
sliver_buffer[ray].sliv_column = (yi_save & 0x003f);
else
sliver_buffer[ray].sliv_column = dor_x_inc;
sliver_buffer[ray].sliv_top = WINDOW_MIDDLE - (scale >> 1);
sliver_buffer[ray].sliv_ray = COLUMN_OFFSET-ray;
} // end if
else // must of hit a horizontal wall first
{
// there was a vertical wall closer than the horizontal
// compute actual scale and multiply by view filter so that spherical
// distortion is cancelled
scale = (int)(cos_table[temp_ray]/(dist_y))>>1;
vz_buffer[ray] = dist_y;
sliver_buffer[ray].sliv_hit_type = 1+(2*a_toggle);
// do clipping again
if (scale>(MAX_SCALE-1)) scale=(MAX_SCALE-1);
sliver_buffer[ray].scale_r = scale-1;
if (scale>(WINDOW_HALF_HEIGHT))
{
scale=(WINDOW_HALF_HEIGHT);
}
sliver_buffer[ray].sliv_scale = scale-1;
// set up parameters for assembly language
sliver_buffer[ray].sliv_texture = wall_frames.frames[y_hit_type];
if (y_hit_type != 3)
sliver_buffer[ray].sliv_column = (xi_save & 0x003f);
else
sliver_buffer[ray].sliv_column = dor_y_inc;
sliver_buffer[ray].sliv_top = WINDOW_MIDDLE - (scale >> 1);
sliver_buffer[ray].sliv_ray = COLUMN_OFFSET-ray;
} // end else
// S E C T I O N 7 /////////////////////////////////////////////////////////
// cast next ray
// test if view angle need to wrap around
if ((++curr_ang)>=ANGLE_360)
{
curr_ang-=ANGLE_360;
//curr_ang=0;
} // end if
} // end for ray
} // end Ray_Caster
void Weak_Attempt(void)
{
// This is a weak attempt at applying some linear interpolation in the ray casting
// It does speed up things a little bit... but it definitely has it's flaws...
// essential... since the ray caster casts rays FOR EVERY OTHER COLUMN of the screen...
// ...this procedure fills in the blanks... (i.e. puts data into the sliver_buffer at
// IN BETWEEN points in the array)
int index,temp1,temp2;
for (index = 1 ; index < (VIEW_CONE); index+=2)
{
sliver_buffer[index].sliv_ray=COLUMN_OFFSET-index;
if ((index)==(VIEW_CONE-1)) //index-1
{
sliver_buffer[index].sliv_hit_type=sliver_buffer[index-1].sliv_hit_type;
sliver_buffer[index].sliv_column=sliver_buffer[index-1].sliv_column;
sliver_buffer[index].sliv_top=sliver_buffer[index-1].sliv_column;
vz_buffer[index] = vz_buffer[index-1];
sliver_buffer[index].sliv_scale=sliver_buffer[index-1].sliv_scale;
sliver_buffer[index].scale_r=sliver_buffer[index-1].scale_r;
sliver_buffer[index].sliv_texture=sliver_buffer[index-1].sliv_texture;
}
else
if (sliver_buffer[index-1].sliv_hit_type!=sliver_buffer[index+1].sliv_hit_type)
{
sliver_buffer[index].sliv_hit_type=sliver_buffer[index+1].sliv_hit_type;
sliver_buffer[index].sliv_column = sliver_buffer[index+1].sliv_column;
sliver_buffer[index].sliv_top = sliver_buffer[index+1].sliv_top;
vz_buffer[index] = vz_buffer[index+1];
// clip wall sliver against view port
sliver_buffer[index].sliv_scale = sliver_buffer[index+1].sliv_scale;
sliver_buffer[index].scale_r = sliver_buffer[index+1].scale_r;
sliver_buffer[index].sliv_texture = sliver_buffer[index+1].sliv_texture;
}
else
if ((sliver_buffer[index-1].sliv_hit_type==sliver_buffer[index+1].sliv_hit_type) &&
(((vz_buffer[index-1] - vz_buffer[index+1]) > 64) ||
((vz_buffer[index-1] - vz_buffer[index+1]) < -64)))
{
sliver_buffer[index].sliv_hit_type=sliver_buffer[index+1].sliv_hit_type;
sliver_buffer[index].sliv_column = sliver_buffer[index+1].sliv_column;
sliver_buffer[index].sliv_top = sliver_buffer[index+1].sliv_top;
vz_buffer[index] = vz_buffer[index+1];
sliver_buffer[index].sliv_scale = sliver_buffer[index+1].sliv_scale;
sliver_buffer[index].scale_r = sliver_buffer[index+1].scale_r;
sliver_buffer[index].sliv_texture = sliver_buffer[index+1].sliv_texture;
}
else
{
sliver_buffer[index].sliv_hit_type=sliver_buffer[index+1].sliv_hit_type;
vz_buffer[index] = (vz_buffer[index-1]+vz_buffer[index+1])>>1;
sliver_buffer[index].sliv_scale = (sliver_buffer[index-1].sliv_scale+sliver_buffer[index+1].sliv_scale)>>1;
sliver_buffer[index].scale_r = (sliver_buffer[index-1].scale_r+sliver_buffer[index+1].scale_r)>>1;
sliver_buffer[index].sliv_texture = sliver_buffer[index-1].sliv_texture;
temp2 = sliver_buffer[index+1].sliv_column;
temp1 = sliver_buffer[index-1].sliv_column;
if (sliver_buffer[index-1].sliv_hit_type==0)
{
if (sliver_buffer[index-1].sliv_column < sliver_buffer[index+1].sliv_column)
temp1 = sliver_buffer[index-1].sliv_column + 64;
}
else
if (sliver_buffer[index-1].sliv_hit_type==1)
{
if (sliver_buffer[index-1].sliv_column > sliver_buffer[index+1].sliv_column)
temp2 = sliver_buffer[index+1].sliv_column + 64;
}
else
if (sliver_buffer[index-1].sliv_hit_type==2)
{
if (sliver_buffer[index-1].sliv_column > sliver_buffer[index+1].sliv_column)
temp2 = sliver_buffer[index+1].sliv_column + 64;
}
else
if (sliver_buffer[index-1].sliv_hit_type==3)
{
if (sliver_buffer[index-1].sliv_column < sliver_buffer[index+1].sliv_column)
temp1 = sliver_buffer[index-1].sliv_column + 64;
}
sliver_buffer[index].sliv_column = ((temp1+temp2)>>1)&0x003f;
sliver_buffer[index].sliv_top = WINDOW_MIDDLE - (sliver_buffer[index].sliv_scale-1);
}
}
} // end Weak_Attempt
/////////////////////////////////////////////////////////////////////////////
void Draw_Walls(void)
{
// This function draws each plane of the final screen image separately
int ray;
unsigned short temp_column_offset;
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov ah,08h // select plane 3
out dx,ax // do it baby!
} // end asm
for (ray = 0; ray < VIEW_CONE; ray+=4)
{
scale_row = scale_table[sliver_buffer[ray].scale_r];
sliver_scale = sliver_buffer[ray].sliv_scale;
// set up parameters for assembly language
sliver_texture = sliver_buffer[ray].sliv_texture;
sliver_column = sliver_buffer[ray].sliv_column;
sliver_top = sliver_buffer[ray].sliv_top;
sliver_ray = sliver_buffer[ray].sliv_ray;
// render the sliver
Render_Sliver();
}
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov ah,04h // select plane 2
out dx,ax // do it baby!
} // end asm
for (ray = 1; ray < VIEW_CONE; ray+=4)
{
scale_row = scale_table[sliver_buffer[ray].scale_r];
sliver_scale = sliver_buffer[ray].sliv_scale;
// set up parameters for assembly language
sliver_texture = sliver_buffer[ray].sliv_texture;
sliver_column = sliver_buffer[ray].sliv_column;
sliver_top = sliver_buffer[ray].sliv_top;
sliver_ray = sliver_buffer[ray].sliv_ray;
// render the sliver
Render_Sliver();
}
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov ah,02h // select plane 1
out dx,ax // do it baby!
} // end asm
for (ray = 2; ray < VIEW_CONE; ray+=4)
{
scale_row = scale_table[sliver_buffer[ray].scale_r];
sliver_scale = sliver_buffer[ray].sliv_scale;
// set up parameters for assembly language
sliver_texture = sliver_buffer[ray].sliv_texture;
sliver_column = sliver_buffer[ray].sliv_column;
sliver_top = sliver_buffer[ray].sliv_top;
sliver_ray = sliver_buffer[ray].sliv_ray;
// render the sliver
Render_Sliver();
}
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov ah,01h // select plane 0
out dx,ax // do it baby!
} // end asm
for (ray = 3; ray < VIEW_CONE; ray+=4)
{
scale_row = scale_table[sliver_buffer[ray].scale_r];
sliver_scale = sliver_buffer[ray].sliv_scale;
// set up parameters for assembly language
sliver_texture = sliver_buffer[ray].sliv_texture;
sliver_column = sliver_buffer[ray].sliv_column;
sliver_top = sliver_buffer[ray].sliv_top;
sliver_ray = sliver_buffer[ray].sliv_ray;
// render the sliver
Render_Sliver();
}
} // end Draw_Walls
int Enemy_Line_Of_Sight(long en_x, long en_y, long en_ang, long en_dist)
{
// This function is like a completely stripped Ray Caster...
// it casts rays out along only one vector...
// ... to "see" if a wall sliver is in between the player and the enemy!
register int
curr_ang,
cell_x, // the current cell that the ray is in
cell_y,
ray, // the current ray being cast 0-320
x_hit_type, // records the block that was intersected, used to figure
y_hit_type, // out which texture to use
x_bound, // the next vertical and horizontal intersection point
y_bound,
next_y_cell, // used to figure out the quadrant of the ray
next_x_cell,
xray=0, // tracks the progress of a ray looking for Y interesctions
yray=0, // tracks the progress of a ray looking for X interesctions
x_delta, // the amount needed to move to get to the next cell
y_delta, // position
xb_save,
yb_save,
xi_save, // used to save exact x and y intersection points
yi_save;
int x_anded,y_anded;
register long
dist_x, // the distance of the x and y ray intersections from
dist_y; // the viewpoint
register float xi, // used to track the x and y intersections
yi;
int temp_ray;
curr_ang = en_ang;
x_anded = (int)(en_x & 0xffc0);
y_anded = (int)(en_y & 0xffc0);
// S E C T I O N 2 /////////////////////////////////////////////////////////
// compute first x intersection
// need to know which half plane we are casting from relative to Y axis
if (curr_ang >= ANGLE_0 && curr_ang < ANGLE_180)
{
// compute first horizontal line that could be intersected with ray
// note: it will be above player
y_bound = (CELL_Y_SIZE + y_anded);
// compute delta to get to next horizontal line
y_delta = CELL_Y_SIZE;
// based on first possible horizontal intersection line, compute X
// intercept, so that casting can begin
xi = inv_tan_table[curr_ang] * (y_bound - en_y) + en_x;
// set cell delta
next_y_cell = 0;
} // end if upper half plane
else
{
// compute first horizontal line that could be intersected with ray
// note: it will be below player
y_bound = y_anded;
// compute delta to get to next horizontal line
y_delta = -CELL_Y_SIZE;
// based on first possible horizontal intersection line, compute X
// intercept, so that casting can begin
xi = inv_tan_table[curr_ang] * (y_bound - en_y) + en_x;
// set cell delta
next_y_cell = -1;
} // end else lower half plane
// S E C T I O N 3 /////////////////////////////////////////////////////////
// compute first y intersection
// need to know which half plane we are casting from relative to X axis
if (curr_ang < ANGLE_90 || curr_ang >= ANGLE_270)
{
// compute first vertical line that could be intersected with ray
// note: it will be to the right of player
x_bound = (int)(CELL_X_SIZE + x_anded);
// compute delta to get to next vertical line
x_delta = CELL_X_SIZE;
// based on first possible vertical intersection line, compute Y
// intercept, so that casting can begin
yi = tan_table[curr_ang] * (x_bound - en_x) + en_y;
// set cell delta
next_x_cell = 0;
} // end if right half plane
else
{
// compute first vertical line that could be intersected with ray
// note: it will be to the left of player
x_bound = x_anded;
// compute delta to get to next vertical line
x_delta = -CELL_X_SIZE;
// based on first possible vertical intersection line, compute Y
// intercept, so that casting can begin
yi = tan_table[curr_ang] * (x_bound - en_x) + en_y;
// set cell delta
next_x_cell = -1;
} // end else right half plane
// begin cast
// casting = 2; // two rays to cast simultaneously
xray=yray = 0; // reset intersection flags
cell_x = ( (x_bound+next_x_cell) >> CELL_X_SIZE_FP);
cell_y = (int)yi;
cell_y>>=CELL_Y_SIZE_FP;
// test if there is a block where the current x ray is intersecting
if (world[cell_y][cell_x].block_type!=0)
{
xray = INTERSECTION_FOUND;
}
// S E C T I O N 4 /////////////////////////////////////////////////////////
while(xray!=INTERSECTION_FOUND)
{
// continue casting each ray in parallel
yi += y_step[curr_ang];
// find next possible x intercept point
x_bound += x_delta;
// compute current map position to inspect
cell_x = ( (x_bound+next_x_cell) >> CELL_X_SIZE_FP);
cell_y = (int)yi;
cell_y>>=CELL_Y_SIZE_FP;
// test if there is a block where the current x ray is intersecting
if (world[cell_y][cell_x].block_type!=0)
{
xray = INTERSECTION_FOUND;
} // end if a hit
} // end if x ray has intersected
dist_x = (long)((yi - en_y) * inv_sin_table[curr_ang]);
yi_save = (int)yi;
xb_save = x_bound;
// S E C T I O N 5 /////////////////////////////////////////////////////////
cell_x = xi;
cell_x>>=CELL_X_SIZE_FP;
cell_y = ( (y_bound + next_y_cell) >> CELL_Y_SIZE_FP);
// test if there is a block where the current y ray is intersecting
if (world[cell_y][cell_x].block_type!=0)
{
yray = INTERSECTION_FOUND;
}
while (yray!=INTERSECTION_FOUND)
{
xi += x_step[curr_ang];
// compute next possible y intercept
y_bound += y_delta;
// compute current map position to inspect
cell_x = xi;
cell_x>>=CELL_X_SIZE_FP;
cell_y = ( (y_bound + next_y_cell) >> CELL_Y_SIZE_FP);
// test if there is a block where the current y ray is intersecting
if (world[cell_y][cell_x].block_type!=0)
{
yray = INTERSECTION_FOUND;
} // end if a hit
} // end while not done
dist_y = (long)((xi - en_x) * inv_cos_table[curr_ang]);
xi_save = (int)xi;
yb_save = y_bound;
// S E C T I O N 6 /////////////////////////////////////////////////////////
// at this point, we know that the ray has succesfully hit both a
// vertical wall and a horizontal wall, so we need to see which one
// was closer and then render it
if ((dist_x < en_dist) || (dist_y < en_dist))
return(0);
else
return(1);
} // end Enemy_Line_Of_Sight
void Translate_Player(long dx, long dy)
{
long x_cell,y_cell,x_sub_cell,y_sub_cell;
// test if user has bumped into a wall i.e. test if there
// is a cell within the direction of motion, if so back up !
// compute cell position
x_cell = x/CELL_X_SIZE;
y_cell = y/CELL_Y_SIZE;
// compute position relative to cell
x_sub_cell = x % CELL_X_SIZE;
y_sub_cell = y % CELL_Y_SIZE;
// test if player is bumping into a wall
// resolve motion into it's x and y components
if (dx>0 )
{
// moving right
if ((Block_Map[y_cell][x_cell+1] != 0) &&
(x_sub_cell > (OVERBOARD ) ) )
{
// back player up amount he steped over the line
x = ((x_cell)<<CELL_X_SIZE_FP) + OVERBOARD;
} // end if need to back up
else
if ((Block_Map[y_cell+1][x_cell+1] != 0) &&
(x_sub_cell > (OVERBOARD ) ) &&
(y_sub_cell > (OVERBOARD ) ) &&
(Block_Map[y_cell+1][x_cell] == 0) )
{
x = ((x_cell)<<CELL_X_SIZE_FP) + OVERBOARD;
}
else
if ((Block_Map[y_cell-1][x_cell+1] != 0) &&
(x_sub_cell > (OVERBOARD ) ) &&
(y_sub_cell < (CELL_Y_SIZE-OVERBOARD ) ) &&
(Block_Map[y_cell-1][x_cell] == 0) )
{
x = ((x_cell)<<CELL_X_SIZE_FP) + OVERBOARD;
}
}
else
{
// moving left
if ((Block_Map[y_cell][x_cell-1] != 0) &&
(x_sub_cell < (CELL_X_SIZE-OVERBOARD) ) )
{
// back player up amount he steped over the line
x = ((x_cell)<<CELL_X_SIZE_FP) + (CELL_X_SIZE-OVERBOARD);
} // end if need to back up
else
if ((Block_Map[y_cell+1][x_cell-1] != 0) &&
(x_sub_cell < (CELL_X_SIZE-OVERBOARD) ) &&
(y_sub_cell > (OVERBOARD ) ) &&
(Block_Map[y_cell+1][x_cell] == 0) )
{
x = ((x_cell)<<CELL_X_SIZE_FP) + (CELL_X_SIZE-OVERBOARD);
}
else
if ((Block_Map[y_cell-1][x_cell-1] != 0) &&
(x_sub_cell < (CELL_X_SIZE-OVERBOARD) ) &&
(y_sub_cell < (CELL_Y_SIZE-OVERBOARD ) ) &&
(Block_Map[y_cell-1][x_cell] == 0) )
{
x = ((x_cell)<<CELL_X_SIZE_FP) + (CELL_X_SIZE-OVERBOARD);
}
} // end else
// compute cell position
x_cell = x/CELL_X_SIZE;
y_cell = y/CELL_Y_SIZE;
// compute position relative to cell
x_sub_cell = x % CELL_X_SIZE;
y_sub_cell = y % CELL_Y_SIZE;
if (dy>0 )
{
// moving up
if ((Block_Map[(y_cell+1)][x_cell] != 0) &&
(y_sub_cell > ( OVERBOARD ) ) )
{
// back player up amount he steped over the line
y = ((y_cell)<<CELL_Y_SIZE_FP) + OVERBOARD;
} // end if need to back up
else
if ((Block_Map[(y_cell+1)][x_cell+1] != 0) &&
(y_sub_cell > ( OVERBOARD ) ) &&
(x_sub_cell > (OVERBOARD) ) &&
(Block_Map[y_cell][x_cell+1] == 0) )
{
// back player up amount he steped over the line
y = ((y_cell)<<CELL_Y_SIZE_FP) + OVERBOARD;
} // end if need to back up
else
if ((Block_Map[(y_cell+1)][x_cell-1] != 0) &&
(y_sub_cell > (OVERBOARD ) ) &&
(x_sub_cell < (CELL_X_SIZE-OVERBOARD ) ) &&
(Block_Map[y_cell][x_cell-1] == 0) )
{
// back player up amount he steped over the line
y = ((y_cell)<<CELL_Y_SIZE_FP) + OVERBOARD;
} // end if need to back up
}
else
{
// moving down
if ((Block_Map[(y_cell-1)][x_cell] != 0) &&
(y_sub_cell < (CELL_X_SIZE-OVERBOARD) ) )
{
// back player up amount he steped over the line
y = ((y_cell)<<CELL_Y_SIZE_FP) + (CELL_Y_SIZE-OVERBOARD);
} // end if need to back up
else
if ((Block_Map[(y_cell-1)][x_cell+1] != 0) &&
(y_sub_cell < (CELL_Y_SIZE-OVERBOARD ) ) &&
(x_sub_cell > (OVERBOARD) ) &&
(Block_Map[y_cell][x_cell+1] == 0) )
{
// back player up amount he steped over the line
y = ((y_cell)<<CELL_Y_SIZE_FP) + (CELL_Y_SIZE-OVERBOARD);
} // end if need to back up
else
if ((Block_Map[(y_cell-1)][x_cell-1] != 0) &&
(y_sub_cell < (CELL_Y_SIZE-OVERBOARD ) ) &&
(x_sub_cell < (CELL_X_SIZE-OVERBOARD ) ) &&
(Block_Map[y_cell][x_cell-1] == 0) )
{
// back player up amount he steped over the line
y = ((y_cell)<<CELL_Y_SIZE_FP) + (CELL_Y_SIZE-OVERBOARD);
} // end if need to back up
} // end else
}
void Translate_Enemy(int enem_num, long dx, long dy)
{
long x_cell,y_cell,x_sub_cell,y_sub_cell;
// test if user has bumped into a wall i.e. test if there
// is a cell within the direction of motion, if so back up !
// compute cell position
x_cell = enemies[enem_num].vitals.x/CELL_X_SIZE;
y_cell = enemies[enem_num].vitals.y/CELL_Y_SIZE;
// compute position relative to cell
x_sub_cell = enemies[enem_num].vitals.x % CELL_X_SIZE;
y_sub_cell = enemies[enem_num].vitals.y % CELL_Y_SIZE;
// test if player is bumping into a wall
// resolve motion into it's x and y components
if (dx>0 )
{
// moving right
if ((Block_Map[y_cell][x_cell+1] != 0) &&
(x_sub_cell > (OVERBOARD_FOR_ENEMIES ) ) )
{
// back player up amount he steped over the line
enemies[enem_num].vitals.x = ((x_cell)<<CELL_X_SIZE_FP) + OVERBOARD_FOR_ENEMIES;
if (((world[y_cell][x_cell+1].block_type == 2) || (world[y_cell][x_cell+1].block_type == 3)) &&
((doors[world[y_cell][x_cell+1].door_id].door_state == CLOSED) ||
(doors[world[y_cell][x_cell+1].door_id].door_state == CLOSING)))
{
// make door disappear by starting process
doors[world[y_cell][x_cell+1].door_id].door_state = OPENING;
doors[world[y_cell][x_cell+1].door_id].door_increment += 6;
}
} // end if need to back up
else
if ((Block_Map[y_cell+1][x_cell+1] != 0) &&
(x_sub_cell > (OVERBOARD_FOR_ENEMIES ) ) &&
(y_sub_cell > (OVERBOARD_FOR_ENEMIES ) ) &&
(Block_Map[y_cell+1][x_cell] == 0) )
{
enemies[enem_num].vitals.x = ((x_cell)<<CELL_X_SIZE_FP) + OVERBOARD_FOR_ENEMIES;
}
else
if ((Block_Map[y_cell-1][x_cell+1] != 0) &&
(x_sub_cell > (OVERBOARD_FOR_ENEMIES ) ) &&
(y_sub_cell < (CELL_Y_SIZE-OVERBOARD_FOR_ENEMIES ) ) &&
(Block_Map[y_cell-1][x_cell] == 0) )
{
enemies[enem_num].vitals.x = ((x_cell)<<CELL_X_SIZE_FP) + OVERBOARD_FOR_ENEMIES;
}
}
else
{
// moving left
if ((Block_Map[y_cell][x_cell-1] != 0) &&
(x_sub_cell < (CELL_X_SIZE-OVERBOARD_FOR_ENEMIES) ) )
{
// back player up amount he steped over the line
enemies[enem_num].vitals.x = ((x_cell)<<CELL_X_SIZE_FP) + (CELL_X_SIZE-OVERBOARD_FOR_ENEMIES);
if (((world[y_cell][x_cell-1].block_type == 2) || (world[y_cell][x_cell-1].block_type == 3)) &&
((doors[world[y_cell][x_cell-1].door_id].door_state == CLOSED) ||
(doors[world[y_cell][x_cell-1].door_id].door_state == CLOSING)))
{
// make door disappear by starting process
doors[world[y_cell][x_cell-1].door_id].door_state = OPENING;
doors[world[y_cell][x_cell-1].door_id].door_increment += 6;
}
} // end if need to back up
else
if ((Block_Map[y_cell+1][x_cell-1] != 0) &&
(x_sub_cell < (CELL_X_SIZE-OVERBOARD_FOR_ENEMIES) ) &&
(y_sub_cell > (OVERBOARD_FOR_ENEMIES ) ) &&
(Block_Map[y_cell+1][x_cell] == 0) )
{
enemies[enem_num].vitals.x = ((x_cell)<<CELL_X_SIZE_FP) + (CELL_X_SIZE-OVERBOARD_FOR_ENEMIES);
}
else
if ((Block_Map[y_cell-1][x_cell-1] != 0) &&
(x_sub_cell < (CELL_X_SIZE-OVERBOARD_FOR_ENEMIES) ) &&
(y_sub_cell < (CELL_Y_SIZE-OVERBOARD_FOR_ENEMIES ) ) &&
(Block_Map[y_cell-1][x_cell] == 0) )
{
enemies[enem_num].vitals.x = ((x_cell)<<CELL_X_SIZE_FP) + (CELL_X_SIZE-OVERBOARD_FOR_ENEMIES);
}
} // end else
// compute cell position
x_cell = enemies[enem_num].vitals.x/CELL_X_SIZE;
y_cell = enemies[enem_num].vitals.y/CELL_Y_SIZE;
// compute position relative to cell
x_sub_cell = enemies[enem_num].vitals.x % CELL_X_SIZE;
y_sub_cell = enemies[enem_num].vitals.y % CELL_Y_SIZE;
if (dy>0 )
{
// moving up
if ((Block_Map[(y_cell+1)][x_cell] != 0) &&
(y_sub_cell > ( OVERBOARD_FOR_ENEMIES ) ) )
{
// back player up amount he steped over the line
enemies[enem_num].vitals.y = ((y_cell)<<CELL_Y_SIZE_FP) + OVERBOARD_FOR_ENEMIES;
if (((world[y_cell+1][x_cell].block_type == 2) || (world[y_cell+1][x_cell].block_type == 3)) &&
((doors[world[y_cell+1][x_cell].door_id].door_state == CLOSED) ||
(doors[world[y_cell+1][x_cell].door_id].door_state == CLOSING)))
{
// make door disappear by starting process
doors[world[y_cell+1][x_cell].door_id].door_state = OPENING;
doors[world[y_cell+1][x_cell].door_id].door_increment += 6;
}
} // end if need to back up
else
if ((Block_Map[(y_cell+1)][x_cell+1] != 0) &&
(y_sub_cell > ( OVERBOARD_FOR_ENEMIES ) ) &&
(x_sub_cell > (OVERBOARD_FOR_ENEMIES) ) &&
(Block_Map[y_cell][x_cell+1] == 0) )
{
// back player up amount he steped over the line
enemies[enem_num].vitals.y = ((y_cell)<<CELL_Y_SIZE_FP) + OVERBOARD_FOR_ENEMIES;
} // end if need to back up
else
if ((Block_Map[(y_cell+1)][x_cell-1] != 0) &&
(y_sub_cell > (OVERBOARD_FOR_ENEMIES ) ) &&
(x_sub_cell < (CELL_X_SIZE-OVERBOARD_FOR_ENEMIES ) ) &&
(Block_Map[y_cell][x_cell-1] == 0) )
{
// back player up amount he steped over the line
enemies[enem_num].vitals.y = ((y_cell)<<CELL_Y_SIZE_FP) + OVERBOARD_FOR_ENEMIES;
} // end if need to back up
}
else
{
// moving down
if ((Block_Map[(y_cell-1)][x_cell] != 0) &&
(y_sub_cell < (CELL_X_SIZE-OVERBOARD_FOR_ENEMIES) ) )
{
// back player up amount he steped over the line
enemies[enem_num].vitals.y = ((y_cell)<<CELL_Y_SIZE_FP) + (CELL_Y_SIZE-OVERBOARD_FOR_ENEMIES);
if (((world[y_cell-1][x_cell].block_type == 2) || (world[y_cell-1][x_cell].block_type == 3)) &&
((doors[world[y_cell-1][x_cell].door_id].door_state == CLOSED) ||
(doors[world[y_cell-1][x_cell].door_id].door_state == CLOSING)))
{
// make door disappear by starting process
doors[world[y_cell-1][x_cell].door_id].door_state = OPENING;
doors[world[y_cell-1][x_cell].door_id].door_increment += 6;
}
} // end if need to back up
else
if ((Block_Map[(y_cell-1)][x_cell+1] != 0) &&
(y_sub_cell < (CELL_Y_SIZE-OVERBOARD_FOR_ENEMIES ) ) &&
(x_sub_cell > (OVERBOARD_FOR_ENEMIES) ) &&
(Block_Map[y_cell][x_cell+1] == 0) )
{
// back player up amount he steped over the line
enemies[enem_num].vitals.y = ((y_cell)<<CELL_Y_SIZE_FP) + (CELL_Y_SIZE-OVERBOARD_FOR_ENEMIES);
} // end if need to back up
else
if ((Block_Map[(y_cell-1)][x_cell-1] != 0) &&
(y_sub_cell < (CELL_Y_SIZE-OVERBOARD_FOR_ENEMIES ) ) &&
(x_sub_cell < (CELL_X_SIZE-OVERBOARD_FOR_ENEMIES ) ) &&
(Block_Map[y_cell][x_cell-1] == 0) )
{
// back player up amount he steped over the line
enemies[enem_num].vitals.y = ((y_cell)<<CELL_Y_SIZE_FP) + (CELL_Y_SIZE-OVERBOARD_FOR_ENEMIES);
} // end if need to back up
} // end else
}
void Draw_ReDraw_Frame(void)
{
// DRAW LINES FOR TOP OF VIEWPORT
Line_H_Mode_Y(WINDOW_LEFT-4,WINDOW_RIGHT+3,WINDOW_TOP-4,BORDER_COLOR_1);
Line_H_Mode_Y(WINDOW_LEFT-3,WINDOW_RIGHT+2,WINDOW_TOP-3,BORDER_COLOR_2);
Line_H_Mode_Y(WINDOW_LEFT-2,WINDOW_RIGHT+1,WINDOW_TOP-2,BORDER_COLOR_3);
Line_H_Mode_Y(WINDOW_LEFT-1,WINDOW_RIGHT,WINDOW_TOP-1,BORDER_COLOR_4);
// DRAW LINES FOR BOTTOM OF VIEWPORT
Line_H_Mode_Y(WINDOW_LEFT-4,WINDOW_RIGHT+3,WINDOW_BOTTOM+3,BORDER_COLOR_1);
Line_H_Mode_Y(WINDOW_LEFT-3,WINDOW_RIGHT+2,WINDOW_BOTTOM+2,BORDER_COLOR_2);
Line_H_Mode_Y(WINDOW_LEFT-2,WINDOW_RIGHT+1,WINDOW_BOTTOM+1,BORDER_COLOR_3);
Line_H_Mode_Y(WINDOW_LEFT-1,WINDOW_RIGHT,WINDOW_BOTTOM,BORDER_COLOR_4);
// DRAW LINES FOR LEFT OF VIEWPORT
Line_V_Mode_Y(WINDOW_TOP-4,WINDOW_BOTTOM+3,WINDOW_LEFT-4,BORDER_COLOR_1);
Line_V_Mode_Y(WINDOW_TOP-3,WINDOW_BOTTOM+2,WINDOW_LEFT-3,BORDER_COLOR_2);
Line_V_Mode_Y(WINDOW_TOP-2,WINDOW_BOTTOM+1,WINDOW_LEFT-2,BORDER_COLOR_3);
Line_V_Mode_Y(WINDOW_TOP-1,WINDOW_BOTTOM,WINDOW_LEFT-1,BORDER_COLOR_4);
// DRAW LINES FOR RIGHT OF VIEWPORT
Line_V_Mode_Y(WINDOW_TOP-4,WINDOW_BOTTOM+3,WINDOW_RIGHT+3,BORDER_COLOR_1);
Line_V_Mode_Y(WINDOW_TOP-3,WINDOW_BOTTOM+2,WINDOW_RIGHT+2,BORDER_COLOR_2);
Line_V_Mode_Y(WINDOW_TOP-2,WINDOW_BOTTOM+1,WINDOW_RIGHT+1,BORDER_COLOR_3);
Line_V_Mode_Y(WINDOW_TOP-1,WINDOW_BOTTOM,WINDOW_RIGHT,BORDER_COLOR_4);
} // end Draw_ReDraw_Frame
int Parse_Commands(int argc, char **argv)
{
// this function is used to parse the commands line parameters that are to be
// used as switched to enable different modes of operation
int index; // looping variable
int a_flag = 1;
for (index=1; index<argc; index++)
{
// get the first character from the string
switch(argv[index][0])
{
case 's': // enable sound effects
case 'S':
{
digital_enabled=1;
} break;
case 'm': // enable nusic
case 'M':
{
music_enabled=1;
} break;
// more commands would go here...
case 'a': // enable nusic
case 'A':
{
a_flag=0;
} break;
default:break;
} // end switch
} // end for index
return(a_flag);
} // end Parse_Commands
void Update_Weapon_Statis_Display(int nw_wp_stat)
{
unsigned char far *buffer;
int x_index, y_index;
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov ah,0eh // enable last three planes
out dx,ax // do it baby!
} // end inline asm
for (x_index = 0; x_index < 56; x_index+=4)
{
for (y_index = 0; y_index<3; y_index++)
{
buffer = pagey_0_buffer + ((169+y_index)<<6) +
((169+y_index)<<4) + ((216+x_index)>>2);
if ((x_index>>2) < nw_wp_stat)
*buffer = Ammo_Color;
else
*buffer = 0;
}
}
for (x_index = 0; x_index < 56; x_index+=4)
{
for (y_index = 0; y_index<3; y_index++)
{
buffer = pagey_1_buffer + ((169+y_index)<<6) +
((169+y_index)<<4) + ((216+x_index)>>2);
if ((x_index>>2) < nw_wp_stat)
*buffer = Ammo_Color;
else
*buffer = 0;
}
}
} // end Update_Weapon_Statis_Display
void Update_Life_Statis_Display(int nw_life_stat)
{
unsigned char far *buffer;
int x_index, y_index;
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov ah,0eh // enable last three planes
out dx,ax // do it baby!
} // end inline asm
for (x_index = 0; x_index < 120; x_index+=4)
{
for (y_index = 0; y_index<3; y_index++)
{
buffer = pagey_0_buffer + ((185+y_index)<<6) +
((185+y_index)<<4) + ((184+x_index)>>2);
if ((x_index>>2) < nw_life_stat)
*buffer = Vitality_Color;
else
*buffer = 0;
}
}
for (x_index = 0; x_index < 120; x_index+=4)
{
for (y_index = 0; y_index<3; y_index++)
{
buffer = pagey_1_buffer + ((185+y_index)<<6) +
((185+y_index)<<4) + ((184+x_index)>>2);
if ((x_index>>2) < nw_life_stat)
*buffer = Vitality_Color;
else
*buffer = 0;
}
}
} // end Update_Life_Statis_Display
void Load_PCX_and_Page_Flip(char *filename, int load_palette_or_not)
{
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(mode_y_page);
PCX_Init((pcx_picture_ptr)&image_pcx);
// load in the textures
PCX_Load((char *)filename, (pcx_picture_ptr)&image_pcx,load_palette_or_not);
PCX_Copy_To_Buffer_XYZ_Mode((pcx_picture_ptr)&image_pcx, video_buffer);
PCX_Delete((pcx_picture_ptr)&image_pcx);
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(mode_y_page);
mode_y_page = !mode_y_page;
} // end Load_PCX_and_Page_Flip
void Fade_to_Black_and_Paint_Both(int effect)
{
if (effect == SCREEN_DARKNESS)
Screen_Transition(SCREEN_DARKNESS);
else
Screen_Transition(FULL_SCREEN_DARKNESS);
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(mode_y_page);
outp(SEQUENCER,SEQ_PLANE_ENABLE);
outp(SEQUENCER+1,0x0f);
// clear the screen, remember it is 320x200, but that is divided into four
// planes, hence we need only to clear 16k out since there will be four planes
// each being cleared in parallel for a total of 4*16k or 64 = 320x200
// note: "k" in this example means 1000 not 1024
_asm
{
les di,video_buffer // point es:di to video buffer, same addre for mode Y
xor ax,ax // move a zero into al and ah
mov cx,320*200/8 // number of words to fill(using word is faster than bytes)
rep stosw // move the color into the video buffer really fast!
} // end inline asm
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(mode_y_page);
mode_y_page = !mode_y_page;
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(mode_y_page);
outp(SEQUENCER,SEQ_PLANE_ENABLE);
outp(SEQUENCER+1,0x0f);
// clear the screen, remember it is 320x200, but that is divided into four
// planes, hence we need only to clear 16k out since there will be four planes
// each being cleared in parallel for a total of 4*16k or 64 = 320x200
// note: "k" in this example means 1000 not 1024
_asm
{
les di,video_buffer // point es:di to video buffer, same addre for mode Y
xor ax,ax // move a zero into al and ah
mov cx,320*200/8 // number of words to fill(using word is faster than bytes)
rep stosw // move the color into the video buffer really fast!
} // end inline asm
} // end Fade_to_Black_and_Paint_Both
void Paint_All_Four_Black(void)
{
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(PAGE_0);
outp(SEQUENCER,SEQ_PLANE_ENABLE);
outp(SEQUENCER+1,0x0f);
// clear the screen, remember it is 320x200, but that is divided into four
// planes, hence we need only to clear 16k out since there will be four planes
// each being cleared in parallel for a total of 4*16k or 64 = 320x200
// note: "k" in this example means 1000 not 1024
_asm
{
les di,video_buffer // point es:di to video buffer, same addre for mode Z
xor ax,ax // move a zero into al and ah
mov cx,320*200/8 // number of words to fill(using word is faster than bytes)
rep stosw // move the color into the video buffer really fast!
} // end inline asm
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(PAGE_1);
outp(SEQUENCER,SEQ_PLANE_ENABLE);
outp(SEQUENCER+1,0x0f);
// clear the screen, remember it is 320x200, but that is divided into four
// planes, hence we need only to clear 16k out since there will be four planes
// each being cleared in parallel for a total of 4*16k or 64 = 320x200
// note: "k" in this example means 1000 not 1024
_asm
{
les di,video_buffer // point es:di to video buffer, same addre for mode Z
xor ax,ax // move a zero into al and ah
mov cx,320*200/8 // number of words to fill(using word is faster than bytes)
rep stosw // move the color into the video buffer really fast!
} // end inline asm
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(PAGE_2);
outp(SEQUENCER,SEQ_PLANE_ENABLE);
outp(SEQUENCER+1,0x0f);
// clear the screen, remember it is 320x200, but that is divided into four
// planes, hence we need only to clear 16k out since there will be four planes
// each being cleared in parallel for a total of 4*16k or 64 = 320x200
// note: "k" in this example means 1000 not 1024
_asm
{
les di,video_buffer // point es:di to video buffer, same addre for mode Y
xor ax,ax // move a zero into al and ah
mov cx,320*200/8 // number of words to fill(using word is faster than bytes)
rep stosw // move the color into the video buffer really fast!
} // end inline asm
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(PAGE_3);
outp(SEQUENCER,SEQ_PLANE_ENABLE);
outp(SEQUENCER+1,0x0f);
// clear the screen, remember it is 320x200, but that is divided into four
// planes, hence we need only to clear 16k out since there will be four planes
// each being cleared in parallel for a total of 4*16k or 64 = 320x200
// note: "k" in this example means 1000 not 1024
_asm
{
les di,video_buffer // point es:di to video buffer, same addre for mode Z
xor ax,ax // move a zero into al and ah
mov cx,320*200/8 // number of words to fill(using word is faster than bytes)
rep stosw // move the color into the video buffer really fast!
} // end inline asm
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(mode_y_page);
} // end Paint_All_Four_Black
void Setup_Initial_Display(void)
{
int index;
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(mode_y_page);
mode_y_page = !mode_y_page;
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(mode_y_page);
Copy_From_Unseen_Vram_to_Page(pagey_0_buffer, video_buffer, 200);
Draw_ReDraw_Frame();
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov ah,0fh // enable all four planes
out dx,ax // do it baby!
} // end inline asm
for (index=WINDOW_TOP; index < WINDOW_MIDDLE; index++)
{
fwordset(video_buffer + (index<<6) + (index<<4) + (WINDOW_LEFT>>2),
0,((WINDOW_RIGHT-WINDOW_LEFT)>>3));
}
for (index=WINDOW_MIDDLE; index < WINDOW_BOTTOM; index++)
{
fwordset(video_buffer + (index<<6) + (index<<4) + (WINDOW_LEFT>>2),
color_1,((WINDOW_RIGHT-WINDOW_LEFT)>>3));
}
} // end Setup_Initial_Display
void Erase_Scene(void)
{
int index;
_asm
{
mov dx,SEQUENCER // address the sequencer
mov al,SEQ_PLANE_ENABLE // select the plane enable register
mov ah,0fh // enable all four planes
out dx,ax // do it baby!
les di,video_buffer
} // end inline asm
for (index=WINDOW_TOP; index < WINDOW_MIDDLE; index++)
{
fwordset(video_buffer + (index<<6) + (index<<4) + (WINDOW_LEFT>>2),
0,((WINDOW_RIGHT-WINDOW_LEFT)>>3));
}
for (index=WINDOW_MIDDLE; index < WINDOW_BOTTOM; index++)
{
fwordset(video_buffer + (index<<6) + (index<<4) + (WINDOW_LEFT>>2),
color_1,((WINDOW_RIGHT-WINDOW_LEFT)>>3));
}
} // end Erase_Scene
long Angle_Between(long play_x, long play_y, long enem_x, long enem_y, int enem_num)
{
long x_away, y_away;
long difference_x, difference_y;
long total_dist;
long new_obj_angle;
x_away = x-enem_x;
y_away = y-enem_y;
if ((x_away>1000) || (x_away < -1000)) return(ANGLE_0);
if ((y_away>1000) || (y_away < -1000)) return(ANGLE_0);
if ((y_away == 0) && (x_away == 0))
return(ANGLE_0);
if (y_away == 0)
{
if (x_away < 0)
return(ANGLE_0);
else
if (x_away > 0)
return(ANGLE_180);
}
else
if (x_away == 0)
{
if (y_away < 0)
return(ANGLE_90);
else
if (y_away > 0)
return(ANGLE_270);
}
else
{
new_obj_angle = (long)((atan((double)abs(y_away)/(double)abs(x_away)))*(RAD_TO_DEG));
if (x_away > 0)
{
if(y_away > 0)
new_obj_angle = ANGLE_180+new_obj_angle;
else
if(y_away < 0)
new_obj_angle = ANGLE_180-new_obj_angle;
}
else
if (x_away < 0)
{
if(y_away > 0)
new_obj_angle = ANGLE_360-new_obj_angle;
}
}
return(new_obj_angle);
}
void Find_Object_Distance(void)
{
// I packed alot of junk into this routine...
// finding the fixed objects' distances from the player is done at the
// very beginning of this "function"...
// then... if the user gets REAL CLOSE to an object that can be
// picked up (ammo, food, or gun upgrade) some other work has to be done...
// I suppose using a linked-list for objects would have been easier,
// but I've been out of school for a while, and even though I used to
// be a wiz at linked list related things - I need a memory refresher - badly!
// if an object is picked up, the entire array of object structures is rotated
// up one notch, from the item picked up, to the end of the object list
// - including enemies.
long diff_x, diff_y;
int index;
int data_move_indice;
int skip_it;
for (index = 0; index < (Number_Of_Fixed_Objects); index++)
{
skip_it = 0;
diff_x = x - object_list[index].x;
diff_y = y - object_list[index].y;
object_list[index].dist = (long)(sqrt((diff_x * diff_x) + (diff_y * diff_y)));
if (object_list[index].dist < 30L)
{
if ((object_list[index].kind_of_object == 4) ||
(object_list[index].kind_of_object == 5) ||
(object_list[index].kind_of_object == 6))
{
what_obj = object_list[index].kind_of_object;
if (object_list[index].kind_of_object == 4)
{
if (Player_Ammo == 56)
skip_it = 1;
Player_Ammo += 8;
if (Player_Ammo>56)
Player_Ammo = 56;
}
if (object_list[index].kind_of_object == 5)
Got_Rapid_Fire = 1;
if (object_list[index].kind_of_object == 6)
{
if (Player_Strength == 120)
skip_it = 1;
Player_Strength += 15;
if (Player_Strength > 120)
Player_Strength = 120;
}
if (!skip_it)
{
--Number_Of_Fixed_Objects;
for(data_move_indice = index;
data_move_indice < (Number_Of_Fixed_Objects);
data_move_indice++)
{
object_list[data_move_indice].kind_of_object = object_list[data_move_indice+1].kind_of_object;
object_list[data_move_indice].x = object_list[data_move_indice+1].x;
object_list[data_move_indice].y = object_list[data_move_indice+1].y;
object_list[data_move_indice].dist = object_list[data_move_indice+1].dist;
object_list[data_move_indice].angle = object_list[data_move_indice+1].angle;
object_list[data_move_indice].id_number = object_list[data_move_indice+1].id_number;
initial_object_list[data_move_indice].kind_of_object = initial_object_list[data_move_indice+1].kind_of_object;
initial_object_list[data_move_indice].x = initial_object_list[data_move_indice+1].x;
initial_object_list[data_move_indice].y = initial_object_list[data_move_indice+1].y;
initial_object_list[data_move_indice].dist = initial_object_list[data_move_indice+1].dist;
initial_object_list[data_move_indice].angle = initial_object_list[data_move_indice+1].angle;
initial_object_list[data_move_indice].id_number = initial_object_list[data_move_indice+1].id_number;
}
for (data_move_indice = Number_Of_Fixed_Objects; data_move_indice <= (Number_Of_Fixed_Objects+Number_Of_Enemies); data_move_indice++)
{
object_list[data_move_indice].x =
enemies[data_move_indice-Number_Of_Fixed_Objects].vitals.x;
object_list[data_move_indice].y =
enemies[data_move_indice-Number_Of_Fixed_Objects].vitals.y;
object_list[data_move_indice].angle =
enemies[data_move_indice-Number_Of_Fixed_Objects].vitals.angle;
object_list[data_move_indice].kind_of_object =
enemies[data_move_indice-Number_Of_Fixed_Objects].vitals.kind_of_object;
object_list[data_move_indice].dist =
enemies[data_move_indice-Number_Of_Fixed_Objects].vitals.dist;
object_list[data_move_indice].id_number =
enemies[data_move_indice-Number_Of_Fixed_Objects].enem_num;
}
--index;
just_grabbed_something = 1;
} // end if you grabbed an object!
}
}
}
for ( ; index<(Number_Of_Fixed_Objects+Number_Of_Enemies); index++)
{
diff_x = x - object_list[index].x;
diff_y = y - object_list[index].y;
object_list[index].dist = (long)(sqrt((diff_x * diff_x) + (diff_y * diff_y)));
}
}
long Find_Object_Distance_Special(int NUMBER)
{
long diff_x, diff_y;
long Boogie;
diff_x = x - enemies[NUMBER].vitals.x;
diff_y = y - enemies[NUMBER].vitals.y;
Boogie = (long)(sqrt((diff_x * diff_x) + (diff_y * diff_y)));
return(Boogie);
}
int Object_Sort_Function(objects *arg1, objects *arg2)
{
// this function comapares the average z's of two object and is used by the
// depth sort surface ordering algorithm
long obj_1;
long obj_2;
// dereference the poly pointers
obj_1 = arg1->dist;
obj_2 = arg2->dist;
if (obj_1 > obj_2)
return(1);
if (obj_1 < obj_2)
return(-1);
else
return(0);
}
void Sort_Object_List(void)
{
qsort( (void *)object_list, (Number_Of_Fixed_Objects+Number_Of_Enemies), sizeof( objects ), Object_Sort_Function );
}
void Init_Objects(void)
{
obj_statistic_list[0].width_factor = .66;
obj_statistic_list[0].Is_Multi_View = 0;
obj_statistic_list[0].Is_Half_Height = 0;
obj_statistic_list[0].Scale_Factor = 21L<<16;
obj_statistic_list[1].width_factor = 1.00;
obj_statistic_list[1].Is_Multi_View = 0;
obj_statistic_list[1].Is_Half_Height = 0;
obj_statistic_list[1].Scale_Factor = 64L<<16;
obj_statistic_list[2].width_factor = .75;
obj_statistic_list[2].Is_Multi_View = 1;
obj_statistic_list[2].Is_Half_Height = 1;
obj_statistic_list[2].Scale_Factor = 32L<<16;
obj_statistic_list[3].width_factor = .75;
obj_statistic_list[3].Is_Multi_View = 1;
obj_statistic_list[3].Is_Half_Height = 1;
obj_statistic_list[3].Scale_Factor = 32L<<16;
obj_statistic_list[4].width_factor = .75;
obj_statistic_list[4].Is_Multi_View = 0;
obj_statistic_list[4].Is_Half_Height = 1;
obj_statistic_list[4].Scale_Factor = 32L<<16;
obj_statistic_list[5].width_factor = .75;
obj_statistic_list[5].Is_Multi_View = 0;
obj_statistic_list[5].Is_Half_Height = 1;
obj_statistic_list[5].Scale_Factor = 32L<<16;
obj_statistic_list[6].width_factor = .75;
obj_statistic_list[6].Is_Multi_View = 0;
obj_statistic_list[6].Is_Half_Height = 1;
obj_statistic_list[6].Scale_Factor = 32L<<16;
object_list = (objects *)malloc(sizeof(objects) * (MAX_OBJECTS+1) );
initial_object_list = (objects *)malloc(sizeof(objects) * (MAX_OBJECTS+1) );
enemies = (enemy_objects *)malloc(sizeof(enemy_objects) * (MAX_ENEMIES+1) );
} // end Init_Objects
void Begin_Object_List(void)
{
int looper;
for (looper = 0; looper < Number_Of_Fixed_Objects; looper++)
{
object_list[looper].x =
initial_object_list[looper].x;
object_list[looper].y =
initial_object_list[looper].y;
object_list[looper].angle =
initial_object_list[looper].angle;
object_list[looper].kind_of_object =
initial_object_list[looper].kind_of_object;
object_list[looper].dist =
initial_object_list[looper].dist;
}
for (looper = Number_Of_Fixed_Objects; looper < (Number_Of_Fixed_Objects+Number_Of_Enemies); looper++)
{
object_list[looper].x =
enemies[looper-Number_Of_Fixed_Objects].vitals.x;
object_list[looper].y =
enemies[looper-Number_Of_Fixed_Objects].vitals.y;
object_list[looper].angle =
enemies[looper-Number_Of_Fixed_Objects].vitals.angle;
object_list[looper].kind_of_object =
enemies[looper-Number_Of_Fixed_Objects].vitals.kind_of_object;
object_list[looper].dist =
enemies[looper-Number_Of_Fixed_Objects].vitals.dist;
object_list[looper].id_number =
enemies[looper-Number_Of_Fixed_Objects].enem_num;
}
} // end Begin_Object_List
void Load_64x64_Sprites(sprite_ptr sprite_set, char *filename, int num_cells)
{
int index, sprite_row, sprite_column;
int set = 1;
PCX_Init((pcx_picture_ptr)&image_pcx);
PCX_Load(filename, (pcx_picture_ptr)&image_pcx,1);
Sprite_Init(sprite_set,0,0,64,64,0,0,0,0,0,0);
sprite_row = 0;
sprite_column = 0;
for (index = 0; index < num_cells; index++)
{
if ((index > 0) && ((index % 4) == 0))
{
sprite_row+=1;
sprite_column=0;
}
PCX_Get_Sprite((pcx_picture_ptr)&image_pcx, sprite_set,
index,sprite_column,sprite_row);
sprite_column++;
}
PCX_Delete((pcx_picture_ptr)&image_pcx);
} // end Load_64x64_Sprites
void Did_Player_Die(void)
{
int index;
if (Player_Strength <= 0)
{
for (index = 0; index <= 255; index++)
{
Read_Color_Reg(index, (RGB_color_ptr)&color_all);
color_all.red += 48;
if (color_all.red > 63)
color_all.red = 63;
Write_Color_Reg(index, (RGB_color_ptr)&color_all);
}
for(index=0; index<20; index++)
{
// loop thru all palette registers
for(pal_reg=0; pal_reg<=255; pal_reg++)
{
// get the next color to fade
Read_Color_Reg(pal_reg,(RGB_color_ptr)&color_all);
// test if this color register is already black
if (color_all.red > 4) color_all.red-=3;
else
color_all.red = 0;
if (color_all.green > 4) color_all.green-=3;
else
color_all.green = 0;
if (color_all.blue > 4) color_all.blue-=3;
else
color_all.blue = 0;
// set the color to a diminshed intensity
Write_Color_Reg(pal_reg,(RGB_color_ptr)&color_all);
} // end for pal reg
// wait a bit
Time_Delay(1);
} // end for index
if (digital_enabled)
{
Sound_Stop();
Sound_Play((sound_ptr)&global_sounds[4]);
}
x=(8<<CELL_X_SIZE_FP)+(CELL_X_SIZE>>1);
y=(8<<CELL_X_SIZE_FP)+(CELL_X_SIZE>>1);
view_angle=ANGLE_60;
Level_Select(which_map);
New_Lease_On_Life = 1;
Player_Strength = 63;
Player_Ammo = 28;
Got_Rapid_Fire = 0;
}
} // end Did_Player_Die?
void Level_Select(int well)
{
if (well == 4)
{
Load_World(4);
at_end = 0;
}
else
if (well == 3)
{
Load_World(3);
at_end = 0;
}
else
if (well == 2)
{
Load_World(2);
}
else
if (well == 1)
{
Load_World(1);
}
else
{
Load_World(0);
}
} // end Level_Select
void Process_Flashes(void)
{
int index;
if (New_Lease_On_Life)
{
for (index = 0; index <= 255; index++)
{
Write_Color_Reg(index, (RGB_color_ptr)&old_all[index]);
}
New_Lease_On_Life = 0;
}
if (just_grabbed_something)
{
for (index = 0; index <= 255; index++)
{
Write_Color_Reg(index, (RGB_color_ptr)&old_all[index]);
}
just_grabbed_something = 0;
}
if (Restore_Black)
{
color_all.red = 0;
color_all.blue = 0;
color_all.green = 0;
Write_Color_Reg(0, (RGB_color_ptr)&color_all);
Restore_Black = 0;
}
} // end Process_Flashes
void Process_Enemy_Events(void)
{
int index;
int enemy_distance;
int player_weapon_trajectory;
int AIMED, aimed_sort_of;
int hitable_arc;
float enemy_dx, enemy_dy;
long tempor;
for (index = 0; index < (Number_Of_Enemies); index++)
{
if ((enemies[index].state != DYING) && (enemies[index].state != DEAD))
{
tempor = Angle_Between(x, y, enemies[index].vitals.x, enemies[index].vitals.y, index);
if (tempor>=ANGLE_360)
tempor-=ANGLE_360;
player_weapon_trajectory =
(tempor+ANGLE_360)-(view_angle+ANGLE_360);
enemy_distance = Find_Object_Distance_Special(index);
if (((int)enemy_distance) < 100)
hitable_arc = ANGLE_10;
else
if (((int)enemy_distance) < 200)
hitable_arc = ANGLE_8;
else
if (((int)enemy_distance) < 300)
hitable_arc = ANGLE_6;
else
if (((int)enemy_distance) < 400)
hitable_arc = ANGLE_4;
else
if (((int)enemy_distance) < 500)
hitable_arc = ANGLE_2;
if((player_weapon_trajectory < hitable_arc) &&
(player_weapon_trajectory > -hitable_arc) &&
(enemy_distance<500L) &&
(vz_buffer[ANGLE_45+player_weapon_trajectory] > enemy_distance))
{
AIMED = 1;
aimed_sort_of = 1;
}
else
{
AIMED = 0;
if((player_weapon_trajectory < (ANGLE_10)) &&
(player_weapon_trajectory > (-ANGLE_10)))
{
aimed_sort_of = 1;
}
else
aimed_sort_of = 0;
}
tempor += ANGLE_180;
if (tempor > ANGLE_360)
tempor-=ANGLE_360;
enemies[(index)].vitals.angle = tempor;
if (enemies[(index)].state == EVADING)
{
switch(duck_pattern[enemies[(index)].pat_num])
{
case 0: enemies[(index)].vitals.angle+=ANGLE_30; break;
case 1: enemies[(index)].vitals.angle; break;
case 2: enemies[(index)].vitals.angle-=ANGLE_30; break;
}
enemies[(index)].pat_num++;
if (enemies[(index)].pat_num > PAT_LIMIT)
enemies[(index)].pat_num = 0;
}
if (enemies[(index)].vitals.angle>ANGLE_360)
enemies[(index)].vitals.angle-=ANGLE_360;
if (enemies[(index)].vitals.angle<0)
enemies[(index)].vitals.angle+=ANGLE_360;
if ((player_state == PLAYER_FIRING) &&
(AIMED) &&
(the_gun.curr_frame == 4))
{
if (Player_Ammo)
{
enemies[(index)].state = HIT;
--enemies[(index)].hit_points;
if (enemies[(index)].hit_points <= 0)
{
if (digital_enabled)
{
Sound_Stop();
Sound_Play((sound_ptr)&global_sounds[2]);
}
enemies[(index)].state = DYING;
enemies[(index)].threshold = 8;
enemies[(index)].hit_points = 5;
}
}
}
else
if ((player_state == PLAYER_FIRING) &&
(aimed_sort_of) &&
(the_gun.curr_frame == 5) &&
(!Player_Ammo))
{
if (enemy_distance < 60)
{
enemies[(index)].state = HIT;
--enemies[(index)].hit_points;
if (enemies[(index)].hit_points <= 0)
{
if (digital_enabled)
{
Sound_Stop();
Sound_Play((sound_ptr)&global_sounds[2]);
}
enemies[(index)].state = DYING;
enemies[(index)].threshold = 8;
enemies[(index)].hit_points = 5;
Damage = 250/enemy_distance;
if (Damage > 5) Damage = 5;
Player_Strength -= Damage;
Red_Factor = 63-(Player_Strength>>1);
color_all.red = Red_Factor;
color_all.blue = 0;
color_all.green = 0;
Write_Color_Reg(0, (RGB_color_ptr)&color_all);
// Red_Factor++;
// if (Red_Factor == 64)
// Red_Factor = 16;
Restore_Black = 1;
}
}
}
else
if (enemy_distance>500L)
{
enemies[index].state = WAITING;
}
else
if ((enemy_distance<50L) ||
(enemies[(index)].state == EVADING))
{
if (enemies[(index)].state!=EVADING)
enemies[(index)].pat_num = (rand()%2)*2;
enemies[(index)].vitals.angle -= ANGLE_180;
if (enemies[(index)].vitals.angle < ANGLE_0)
enemies[(index)].vitals.angle += ANGLE_360;
tempor = enemies[(index)].vitals.angle;
enemy_dx=cos(6.28*tempor/ANGLE_360)*7;
enemy_dy=sin(6.28*tempor/ANGLE_360)*7;
enemies[(index)].vitals.x+=enemy_dx;
enemies[(index)].vitals.y+=enemy_dy;
enemies[(index)].state = EVADING;
Translate_Enemy((index), enemy_dx, enemy_dy);
}
else
if ((enemy_distance<500L) ||
(enemies[(index)].state == PURSUING))
{
enemies[(index)].state = PURSUING;
in_view = 0;
// if (enemies[(index)].pat_num == 1)
// {
// get enemy position to see if player is really
// in it's sights...
in_view=Enemy_Line_Of_Sight(enemies[(index)].vitals.x,
enemies[(index)].vitals.y,
enemies[(index)].vitals.angle,
enemy_distance);
// }
if (((rand()%15) < 3) && in_view) //(in_view)
{
enemies[(index)].state = FIRING;
if (digital_enabled)
{
Sound_Stop();
Sound_Play((sound_ptr)&global_sounds[3]);
}
Damage = 250/enemy_distance;
if (Damage > 5) Damage = 5;
Player_Strength -= Damage;
Red_Factor = 63-(Player_Strength>>1);
color_all.red = Red_Factor;
color_all.blue = 0;
color_all.green = 0;
Write_Color_Reg(0, (RGB_color_ptr)&color_all);
// Red_Factor++;
// if (Red_Factor == 64)
// Red_Factor = 16;
Restore_Black = 1;
}
tempor = enemies[(index)].vitals.angle;
enemy_dx=cos(6.28*tempor/ANGLE_360)*7;
enemy_dy=sin(6.28*tempor/ANGLE_360)*7;
enemies[(index)].vitals.x+=enemy_dx;
enemies[(index)].vitals.y+=enemy_dy;
Translate_Enemy((index), enemy_dx, enemy_dy);
}
}
}
pat_start = Restore_Black;
} // end Process_Enemy_Events
/////////////////////////////////////////////////////////
void New_Game(void)
{
int scale;
Player_Strength = 63;
Got_Rapid_Fire = 0;
Player_Ammo = 28;
which_map = 0;
Level_Select(which_map);
x=(8<<CELL_X_SIZE_FP)+(CELL_X_SIZE>>1);
y=(8<<CELL_X_SIZE_FP)+(CELL_X_SIZE>>1);
view_angle=ANGLE_60;
Make_Gray_Palette();
// build the scaler table. This table holds MAX_SCALE different arrays. Each
// array consists of the pre-computed indices for an object to be scaled
for (scale=1; scale<=WINDOW_HALF_HEIGHT; scale++)
{
// create the indices for this scale
Create_Scale_Data(scale, (int *)scale_table[scale]);
} // end for scale
// THE SECOND Create_Scale_Data FUNCTION REFERED TO HERE IS USED
// TO COMPUTE SCALES FOR CASES WHERE THE BOTTOM AND THE TOP OF A WALL
// SLIVER ARE BEYOND THE VERTICAL EXTENTS OF THE VIEWPORT!
for (scale=WINDOW_HALF_HEIGHT+1; scale<=MAX_SCALE; scale++)
{
// create the indices for this scale
Create_Scale_Data2(scale, (int *)scale_table[scale]);
} // end for scale
beat_it = 0;
}
void Level_Just_Map(int lev_number)
{
FILE *fp, *fopen();
int ob_num,gunner_num;
int index,row,column;
char buffer[WORLD_COLUMNS+2],ch;
int door_num = 0;
int result;
long pos;
// open the file
if (!(fp = fopen("world.dat","r")))
return(0);
pos = (1088L*(long)(lev_number<<1));
result = fseek( fp, pos, SEEK_SET);
if( result )
Print_String_Mode_Y(10,10,79,"Fseek failure",0);
// load in the data
for (row=0; row<WORLD_ROWS; row++)
{
// load in the next row
for (column=0; column<WORLD_COLUMNS; column++)
{
while((ch = getc(fp))==10){} // filter out CR
// translate character to integer
if (ch == ' ')
ch=0;
else
ch = ch - '0';
// insert data into world
if (ch==4)
world[(WORLD_ROWS-1) - row][column].block_type = 0;
else
world[(WORLD_ROWS-1) - row][column].block_type = ch;
Block_Map[(WORLD_ROWS-1) - row][column] = ch;
if ((ch == 2) || (ch == 3)) // if it's a door
{
world[(WORLD_ROWS-1) - row][column].door_id = door_num;
doors[door_num].door_y = (WORLD_ROWS-1) - row;
doors[door_num].door_x = column;
doors[door_num].door_state = CLOSED;
doors[door_num].door_block_type = ch;
doors[door_num].locked=0;
doors[door_num].door_speed=5;
doors[door_num].door_increment=0;
doors[door_num].door_wait_to_close=0;
door_num++;
}
} // end for column
// process the row
} // end for row
total_world_doors = door_num; // used by Process_Doors
fclose(fp);
if (which_map<4)
{
rotate_em = 1;
Make_Gray_Palette();
}
else
{
rotate_em = 0;
Make_Light_Metallic_Blue_Palette();
}
}
int Load_Game(void)
{
FILE *fp, *fopen();
int looper, Cur[10];
int numb = 0, scale;
char buff[14]="player_d.at";
if (!(fp = fopen("plynames.dat","rb")))
{
Print_String_Mode_Y(20,150,170,"No saved games on record...",0);
Print_String_Mode_Y(20,170,170,"...press space...",0);
while(!keyboard_state[MAKE_SPACE]){};
Print_String_Mode_Y(20,150,0,"No saved games on record...",0);
Print_String_Mode_Y(20,170,0,"...press space...",0);
return(1);
}
else
{
fread(names, sizeof(name_obj)*5, 1, fp);
Refresh_Name_List(170);
fclose(fp);
while(keyboard_state[MAKE_2] || keyboard_state[MAKE_3]);
numb = Slot_Selection();
buff[11] = (char)(numb+49);
}
Refresh_Name_List(0);
if ((fp = fopen(buff,"rb")))
{
fread(Cur, sizeof(Cur), 1, fp);
Player_Strength=Cur[0];
Player_Ammo=Cur[1];
which_map=Cur[2];
Got_Rapid_Fire=Cur[3];
x=Cur[4];
y=Cur[5];
view_angle=Cur[6];
Number_Of_Fixed_Objects=Cur[7];
Number_Of_Enemies=Cur[8];
total_world_doors=Cur[9];
fread(initial_object_list, sizeof(objects)*Number_Of_Fixed_Objects, 1, fp);
fread(enemies, sizeof(enemy_objects)*Number_Of_Enemies, 1, fp);
Level_Just_Map(which_map);
fread(doors, sizeof(doors)*total_world_doors, 1, fp);
fclose(fp);
}
for (looper=0; looper < total_world_doors; looper++)
{
if (doors[looper].door_state == OPEN)
{
world[doors[looper].door_y][doors[looper].door_x].block_type = 0;
// Allow the player to pass through the vacant doorway
Block_Map[doors[looper].door_y][doors[looper].door_x] = 0;
}
}
// build the scaler table. This table holds MAX_SCALE different arrays. Each
// array consists of the pre-computed indices for an object to be scaled
for (scale=1; scale<=WINDOW_HALF_HEIGHT; scale++)
{
// create the indices for this scale
Create_Scale_Data(scale, (int *)scale_table[scale]);
} // end for scale
// THE SECOND Create_Scale_Data FUNCTION REFERED TO HERE IS USED
// TO COMPUTE SCALES FOR CASES WHERE THE BOTTOM AND THE TOP OF A WALL
// SLIVER ARE BEYOND THE VERTICAL EXTENTS OF THE VIEWPORT!
for (scale=WINDOW_HALF_HEIGHT+1; scale<=MAX_SCALE; scale++)
{
// create the indices for this scale
Create_Scale_Data2(scale, (int *)scale_table[scale]);
} // end for scale
Update_Weapon_Statis_Display(Player_Ammo/4);
Update_Life_Statis_Display(Player_Strength/4);
beat_it = 0;
switch(which_map)
{
case 0:sprintf(where_am_i,"...somewhere in map 1");break;
case 1:sprintf(where_am_i,"...somewhere in map 2");break;
case 2:sprintf(where_am_i,"...somewhere in map 3");break;
case 3:sprintf(where_am_i,"...somewhere in map 4");break;
case 4:sprintf(where_am_i,"...somewhere in map 5");break;
default:break;
} //end switch
}
int Slot_Selection(void)
{
int done = 0;
while(!done)
{
if (keyboard_state[MAKE_1])
return(0);
if (keyboard_state[MAKE_2])
return(1);
if (keyboard_state[MAKE_3])
return(2);
if (keyboard_state[MAKE_4])
return(3);
if (keyboard_state[MAKE_5])
return(4);
}
} // end Slot_Selection
void Refresh_Name_List(int what_shade)
{
Print_String_Mode_Y(10,30,what_shade,"1.",0);
Print_String_Mode_Y(10,40,what_shade,"2.",0);
Print_String_Mode_Y(10,50,what_shade,"3.",0);
Print_String_Mode_Y(10,60,what_shade,"4.",0);
Print_String_Mode_Y(10,70,what_shade,"5.",0);
Print_String_Mode_Y(30,30,what_shade,names[0].name,0);
Print_String_Mode_Y(30,40,what_shade,names[1].name,0);
Print_String_Mode_Y(30,50,what_shade,names[2].name,0);
Print_String_Mode_Y(30,60,what_shade,names[3].name,0);
Print_String_Mode_Y(30,70,what_shade,names[4].name,0);
}
void Save_Game(void)
{
FILE *fp, *fopen();
int looper, Cur[10];
int numb = 0;
char buff[14]="player_d.at", ch;
int character;
int done = 0;
int sel_choice;
if (!(fp = fopen("plynames.dat","rb")))
{
sprintf(names[0].name,"Unused Slot");
sprintf(names[1].name,"Unused Slot");
sprintf(names[2].name,"Unused Slot");
sprintf(names[3].name,"Unused Slot");
sprintf(names[4].name,"Unused Slot");
}
else
{
fread(names, sizeof(name_obj)*5, 1, fp);
}
Refresh_Name_List(170);
Print_String_Mode_Y(10,10,170,"Select a slot #",0);
while(keyboard_state[MAKE_2]);
sel_choice = Slot_Selection();
buff[11] = (char)(sel_choice+49);
// if (!strncmp( names[sel_choice].name, "Unused Slot", 11 ))
sprintf(names[sel_choice].name," ");
// while(keys_active);
Refresh_Name_List(170);
Keyboard_Remove_Driver();
character = 0;
done = 0;
while(!done)
{
ch = getch();
if (ch == 13)
done = 1;
else
if (ch == 8)
{
--character;
if (character < 0) character = 0;
else names[sel_choice].name[character]=32;
Refresh_Name_List(170);
}
else
{
keys_active = 0;
if (character < 11)
{
names[sel_choice].name[character] = ch;
++character;
Refresh_Name_List(170);
}
if (character>11) character = 11;
}
}
Keyboard_Install_Driver();
Refresh_Name_List(0);
fp = fopen("plynames.dat","wb");
fwrite(names, sizeof(name_obj)*5, 1, fp);
fclose(fp);
Cur[0]=Player_Strength;
Cur[1]=Player_Ammo;
Cur[2]=which_map;
Cur[3]=Got_Rapid_Fire;
Cur[4]=x;
Cur[5]=y;
Cur[6]=view_angle;
Cur[7]=Number_Of_Fixed_Objects;
Cur[8]=Number_Of_Enemies;
Cur[9]=total_world_doors;
if ((fp = fopen(buff,"wb")))
{
fwrite(Cur, sizeof(Cur), 1, fp);
fwrite(initial_object_list, sizeof(objects)*Number_Of_Fixed_Objects, 1, fp);
fwrite(enemies, sizeof(enemy_objects)*Number_Of_Enemies, 1, fp);
fwrite(doors, sizeof(doors)*total_world_doors, 1, fp);
fclose(fp);
}
} // end Save_Game
void Rotate_Em(int well)
{
static int color_counter = -1;
if (well==0) return;
color_counter++;
if (well == 1)
{
if ((color_counter >= 0) && (color_counter<40))
Make_Gray_Palette_OAAT(color_counter-0,1);
if ((color_counter >= 40) && (color_counter<80))
Make_Blue_Palette_OAAT(color_counter-40,1);
if ((color_counter >= 80) && (color_counter<120))
Make_Gray_Palette_OAAT(color_counter-80,1);
if ((color_counter >= 120) && (color_counter<160))
Make_Cyan_Palette_OAAT(color_counter-120,1);
if ((color_counter >= 160) && (color_counter<200))
Make_Gray_Palette_OAAT(color_counter-160,1);
if ((color_counter >= 200) && (color_counter<240))
Make_Gold_Palette_OAAT(color_counter-200,1);
if (color_counter >= 240)
color_counter = -1;
}
else
if (well == 2)
{
if ((color_counter >= 0) && (color_counter<40))
Make_Gray_Palette_OAAT(color_counter-1,1);
if ((color_counter >= 40) && (color_counter<80))
Make_Blue_Palette_OAAT(color_counter-40,1);
if ((color_counter >= 41) && (color_counter<81))
Make_Blue_Palette_OAAT(color_counter-41,1);
if ((color_counter >= 80) && (color_counter<120))
Make_Cyan_Palette_OAAT(color_counter-80,1);
if ((color_counter >= 81) && (color_counter<121))
Make_Cyan_Palette_OAAT(color_counter-81,1);
if ((color_counter >= 120) && (color_counter<160))
Make_Gold_Palette_OAAT(color_counter-120,1);
if ((color_counter >= 121) && (color_counter<161))
Make_Gold_Palette_OAAT(color_counter-121,1);
if (color_counter >= 161)
color_counter = -1;
}
else
if (well == 3)
{
if ((color_counter >= 0) && (color_counter<40))
Make_Gray_Palette_OAAT(color_counter-0,0);
if ((color_counter >= 40) && (color_counter<80))
Make_Blue_Palette_OAAT(color_counter-40,1);
if ((color_counter >= 41) && (color_counter<81))
Make_Gold_Palette_OAAT(color_counter-41,0);
if ((color_counter >= 51) && (color_counter<91))
Make_Blue_Palette_OAAT(color_counter-51,1);
if (color_counter >= 91)
color_counter = -1;
}
else
if (well == 4)
{
Make_Light_Metallic_Blue_Palette();
rotate_em = 0;
}
} // end Rotate_Em
// M A I N ///////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
char buffer[80];
long player_weapon_trajectory, enemy_distance;
int x_door,y_door,feel_x,feel_y;
int done=0;
int sequence;
int scaler,Did_he=0;
int show_help = 0;
int choose, frames;
long tempor;
int index;
int fat;
long query;
int sub_array[7];
int how_long=0;
int obj_id, obj_threshold;
int just_print_mess;
int sub_view_angle;
int color_counter = 0;
long dx,dy;
FILE *file_pointer, *fopen();
int old_weapon_statis, new_weapon_statis;
int old_life_statis, new_life_statis;
// beginning of code
color_floor = 8;
color_floor = color_floor | (color_floor << 8);
color_ceil = 0;
color_ceil = color_ceil | (color_ceil << 8);
color_1 = 8;
color_1 = color_1 | (color_1 << 8);
color_1 = color_1 | (color_1 << 16);
// seed random number generator
srand(13);
printf("\"\Slow Runnings\"\ version 1.5 is FREEWARE by James McCue.\n");
printf("Slow Runnings - Copyright 1997!\n");
printf("\nPress any key to continue...");
getch();
just_print_mess = Parse_Commands(argc,argv);
if (music_enabled)
{
Music_Load("test.xmi",(music_ptr)&song);
Music_Play((music_ptr)&song,0);
}
Keyboard_Install_Driver();
Set_Mode_Y();
_outp(CRT_CONTROLLER,CRT_ADDR_LOW);
_outp(CRT_CONTROLLER+1,0x00);
Set_Visual_Page_Mode_Y_Half(mode_y_page);
mode_y_page = !mode_y_page;
Load_PCX_and_Page_Flip("opening.pcx",1);
while (!keys_active);
Fade_to_Black_and_Paint_Both(SCREEN_DARKNESS);
Paint_All_Four_Black();
Load_PCX_and_Page_Flip("story1.pcx",1);
Make_Blue_Palette();
while (!keys_active);
Load_PCX_and_Page_Flip("story2.pcx",0);
while (!keys_active);
Load_PCX_and_Page_Flip("story3.pcx",0);
while (!keys_active);
Load_PCX_and_Page_Flip("story4.pcx",0);
while (!keys_active);
Load_PCX_and_Page_Flip("story5.pcx",0);
while (!keys_active);
Fade_to_Black_and_Paint_Both(SCREEN_DARKNESS);
Paint_All_Four_Black();
sprintf(buffer,"Beginning Initialization");
Print_String_Mode_Y(10,10,170,buffer,0);
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(mode_y_page);
mode_y_page = !mode_y_page;
PCX_Init((pcx_picture_ptr)&image_pcx);
PCX_Load("backw2.pcx", (pcx_picture_ptr)&image_pcx,1);
PCX_Copy_To_Video_Mem((pcx_picture_ptr)&image_pcx, pagey_0_buffer);
PCX_Delete((pcx_picture_ptr)&image_pcx);
PCX_Init((pcx_picture_ptr)&image_pcx);
PCX_Load("keyhelp.pcx", (pcx_picture_ptr)&image_pcx,0);
PCX_Copy_To_Video_Mem((pcx_picture_ptr)&image_pcx, pagey_2_buffer);
PCX_Delete((pcx_picture_ptr)&image_pcx);
sprintf(buffer,"Background to Vid Mem - done!");
Print_String_Mode_Y(10,20,170,buffer,0);
// render initial view
Load_64x64_Sprites((sprite_ptr)&wall_frames,"objectmp.pcx",12);
Load_64x64_Sprites((sprite_ptr)&ob_frames,"objects.pcx",5);
Load_64x64_Sprites((sprite_ptr)&duck_frames,"multi2.pcx",11);
Load_64x64_Sprites((sprite_ptr)&duck_death,"multid.pcx",4);
Load_64x64_Sprites((sprite_ptr)&the_gun,"thegun.pcx",8);
the_gun.x = 128;
the_gun.y = 88;
the_gun.curr_frame = 0;
// load in the textures
sprintf(buffer,"Keyboard Driver Installed");
Print_String_Mode_Y(10,50,170,buffer,0);
// initialize sound system
Allocate_World();
sprintf(buffer,"Level Allocated");
Print_String_Mode_Y(10,60,170,buffer,0);
// build all the lookup tables
if ((file_pointer = fopen("data.pov","rb")))
{
fread(sub_array, sizeof(sub_array), 1, file_pointer);
my_size = sub_array[0];
COLUMN_OFFSET = sub_array[1];
my_height= sub_array[2];
my_left = sub_array[3];
my_right = sub_array[4];
my_v_scale = sub_array[5];
choose = sub_array[6];
fclose(file_pointer);
}
Build_Tables();
sprintf(buffer,"Trig/Scale tables made.");
Print_String_Mode_Y(10,70,170,buffer,0);
which_map = 0;
Init_Objects();
Level_Select(which_map);
x=(8<<CELL_X_SIZE_FP)+(CELL_X_SIZE>>1);
y=(8<<CELL_X_SIZE_FP)+(CELL_X_SIZE>>1);
view_angle=ANGLE_60;
sprintf(buffer,"Map Loaded...");
Print_String_Mode_Y(10,80,170,buffer,0);
// Number_Of_Movable_Objects = 0;
sprintf(buffer,"Remember 'K' for keyboard help!");
Print_String_Mode_Y(35,125,252,buffer,0);
sprintf(buffer,"Press any key to Play.");
Print_String_Mode_Y(70,185,253,buffer,0);
while(!keys_active);
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(PAGE_3);
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(PAGE_3);
Print_String_Mode_Y(40,80,170,"1. New Game",0);
Print_String_Mode_Y(40,120,170,"2. Load Game",0);
keys_active = 0;
if (keys_active < 0) keys_active = 0;
fat = 0;
while(!fat)
{
if(keyboard_state[MAKE_1])
{
Print_String_Mode_Y(40,80,0,"1. New Game",0);
Print_String_Mode_Y(40,120,0,"2. Load Game",0);
New_Game();
fat=1;
}
if(keyboard_state[MAKE_2])
{
Print_String_Mode_Y(40,80,0,"1. New Game",0);
Print_String_Mode_Y(40,120,0,"2. Load Game",0);
Load_Game();
how_long=18;
fat=1;
}
}
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(PAGE_3);
mode_y_page = !mode_y_page;
fat = 0;
mode_y_page = PAGE_0;
for (index = 0; index <=255; index++)
Read_Color_Reg(index, (RGB_color_ptr)&old_all[index]);
// Start by copying bitmap to both pages
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(mode_y_page);
mode_y_page = !mode_y_page;
Setup_Initial_Display();
Ray_Caster();
// Weak_Attempt();
Draw_Walls();
Setup_Initial_Display();
if (digital_enabled)
{
Sound_Load("pickup.voc",(sound_ptr)&global_sounds[0],1);
Sound_Load("plyrshot.voc",(sound_ptr)&global_sounds[1],1);
Sound_Load("boom.voc",(sound_ptr)&global_sounds[2],1);
Sound_Load("enemshot.voc",(sound_ptr)&global_sounds[3],1);
Sound_Load("nextmap.voc",(sound_ptr)&global_sounds[4],1);
Sound_Load("dooropen.voc",(sound_ptr)&global_sounds[5],1);
Sound_Load("click.voc",(sound_ptr)&global_sounds[6],1);
}
Ray_Caster();
// Weak_Attempt();
Draw_Walls();
// wait for user to press ESC to quit
if (music_enabled)
{
Music_Stop();
if (which_map<4)
Music_Play((music_ptr)&song,1);
else
Music_Play((music_ptr)&song,2);
}
Begin_Object_List();
color_counter =-1;
query = Timer_Query();
while(!done)
{
Process_Doors();
while ((Timer_Query() - query)<1);
query = Timer_Query();
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(mode_y_page);
if (pat_start)
{
if (pat_start<2)
{
Process_Flashes();
++pat_start;
}
else
pat_start = 0;
}
if (rotate_em)
{
Rotate_Em(which_map);
} // end if rotate_em
old_weapon_statis = Player_Ammo / 4;
old_life_statis = Player_Strength /4;
if (Did_he)
{
for (index = 0; index <= 255; index++)
{
Write_Color_Reg(index, (RGB_color_ptr)&old_all[index]);
}
Did_he=0;
}
Did_he = Did_Player_Die();
mode_y_page = !mode_y_page;
dx=dy=0;
if (keyboard_state[MAKE_SPACE])
{
// test if there is a door in front of player
// project a "feeler" 3 steps in front of player and test for a door
x_door = (int)(x + cos(6.28*view_angle/ANGLE_360)*3*15);
y_door = (int)(y + sin(6.28*view_angle/ANGLE_360)*3*15);
// compute cell position
feel_x = x_door/CELL_X_SIZE;
feel_y = y_door/CELL_Y_SIZE;
// test for door
if ((world[feel_y][feel_x].block_type == 2) || (world[feel_y][feel_x].block_type == 3))
{
id_number = world[feel_y][feel_x].door_id;
if ((doors[id_number].door_state == CLOSED) ||
(doors[id_number].door_state == CLOSING))
{
if (doors[id_number].door_state == CLOSED)
{
if (digital_enabled)
{
Sound_Stop();
Sound_Play((sound_ptr)&global_sounds[0]);
}
}
// make door disappear by starting process
doors[id_number].door_y = feel_y;
doors[id_number].door_x = feel_x;
doors[id_number].door_state = OPENING;
doors[id_number].door_increment += 6;
}
} // end if a door was found
else
if (world[feel_y][feel_x].block_type==7)
{
if (digital_enabled)
{
Sound_Stop();
Sound_Play((sound_ptr)&global_sounds[4]);
}
x=(8<<CELL_X_SIZE_FP)+(CELL_X_SIZE>>1);
y=(8<<CELL_X_SIZE_FP)+(CELL_X_SIZE>>1);
view_angle=ANGLE_60;
++which_map;
if (which_map == 5)
{
at_end = 1;
really_at_end = 1;
done = 1;
while(keyboard_state[MAKE_SPACE]){};
}
else
{
if(which_map<4)
{
Level_Select(which_map);
}
else
{
Level_Select(which_map);
if (music_enabled)
{
Music_Stop();
Music_Play((music_ptr)&song,2);
}
}
}
}
else
if (world[feel_y][feel_x].block_type==9)
{
if (digital_enabled)
{
Sound_Stop();
Sound_Play((sound_ptr)&global_sounds[4]);
}
x=(8<<CELL_X_SIZE_FP)+(CELL_X_SIZE>>1);
y=(8<<CELL_X_SIZE_FP)+(CELL_X_SIZE>>1);
view_angle=ANGLE_60;
if (which_map == 4)
{
at_end = 1;
really_at_end = 1;
done = 1;
while(keyboard_state[MAKE_SPACE]){};
}
}
}
if (keyboard_state[MAKE_F])
{
if (player_state==PLAYER_NOT_FIRING)
{
if (digital_enabled)
{
Sound_Stop();
if (Player_Ammo)
Sound_Play((sound_ptr)&global_sounds[1]);
else
Sound_Play((sound_ptr)&global_sounds[6]);
}
player_state = PLAYER_FIRING;
}
if ((player_state==PLAYER_FIRING) && (the_gun.curr_frame > 5) && (Got_Rapid_Fire))
{
if (digital_enabled)
{
Sound_Stop();
if (Player_Ammo)
Sound_Play((sound_ptr)&global_sounds[1]);
else
Sound_Play((sound_ptr)&global_sounds[6]);
}
the_gun.curr_frame = 2;
}
}
if (keyboard_state[MAKE_P])
{
Print_String_Mode_Y(20,70,255,"Paused - press SPACE to continue...",1);
while (!keyboard_state[MAKE_SPACE]);
}
if (keyboard_state[MAKE_K])
{
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(PAGE_2);
while (!keyboard_state[MAKE_G]) {};
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(!mode_y_page);
}
if (keyboard_state[MAKE_F5])
{
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(PAGE_3);
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(PAGE_3);
Print_String_Mode_Y(40,80,170,"1. New Game",0);
Print_String_Mode_Y(40,100,170,"2. Save Game",0);
Print_String_Mode_Y(40,120,170,"3. Load Game",0);
while(!fat)
{
if(keyboard_state[MAKE_1])
{
Print_String_Mode_Y(40,80,0,"1. New Game",0);
Print_String_Mode_Y(40,100,0,"2. Save Game",0);
Print_String_Mode_Y(40,120,0,"3. Load Game",0);
New_Game();
fat=1;
}
if(keyboard_state[MAKE_2])
{
Print_String_Mode_Y(40,80,0,"1. New Game",0);
Print_String_Mode_Y(40,100,0,"2. Save Game",0);
Print_String_Mode_Y(40,120,0,"3. Load Game",0);
Save_Game();
fat=1;
}
if(keyboard_state[MAKE_3])
{
Print_String_Mode_Y(40,80,0,"1. New Game",0);
Print_String_Mode_Y(40,100,0,"2. Save Game",0);
Print_String_Mode_Y(40,120,0,"3. Load Game",0);
Load_Game();
if (music_enabled)
{
Music_Stop();
if (which_map<4)
Music_Play((music_ptr)&song,1);
else
Music_Play((music_ptr)&song,2);
}
how_long=18;
fat=1;
}
}
mode_y_page = !mode_y_page;
Wait_Display_Mode();
Set_Visual_Page_Mode_Y_Half(mode_y_page);
mode_y_page = !mode_y_page;
fat = 0;
}
if (keyboard_state[MAKE_RIGHT])
{
if ((view_angle-=ANGLE_7)<ANGLE_0)
view_angle+=ANGLE_360;
sub_view_angle = view_angle + ANGLE_90;
if (sub_view_angle>=ANGLE_360)
sub_view_angle-=ANGLE_360;
// move player along view vector foward
dx=cos(6.28*sub_view_angle/ANGLE_360)*3;
dy=sin(6.28*sub_view_angle/ANGLE_360)*3;
x+=dx;
y+=dy;
Translate_Player(dx, dy);
}
if (keyboard_state[MAKE_LEFT])
{
if ((view_angle+=ANGLE_7)>=ANGLE_360)
view_angle-=ANGLE_360;
sub_view_angle = view_angle - ANGLE_90;
if (sub_view_angle<0)
sub_view_angle+=ANGLE_360;
// move player along view vector foward
dx=cos(6.28*sub_view_angle/ANGLE_360)*3;
dy=sin(6.28*sub_view_angle/ANGLE_360)*3;
x+=dx;
y+=dy;
Translate_Player(dx, dy);
}
if (keyboard_state[MAKE_UP] || keyboard_state[MAKE_DOWN])
{
if (keyboard_state[MAKE_UP])
{
// move player along view vector foward
dx=cos(6.28*view_angle/ANGLE_360)*15;
dy=sin(6.28*view_angle/ANGLE_360)*15;
x+=dx;
y+=dy;
}
if (keyboard_state[MAKE_DOWN])
{
// move player along view vector backward
dx=-cos(6.28*view_angle/ANGLE_360)*15;
dy=-sin(6.28*view_angle/ANGLE_360)*15;
x+=dx;
y+=dy;
}
Translate_Player(dx, dy);
} // end if player in motion
if (keyboard_state[MAKE_C] || keyboard_state[MAKE_V])
{
if (keyboard_state[MAKE_C])
{
sub_view_angle = view_angle + ANGLE_90;
if (sub_view_angle>ANGLE_360)
sub_view_angle-=ANGLE_360;
// move player along view vector foward
dx=cos(6.28*sub_view_angle/ANGLE_360)*10;
dy=sin(6.28*sub_view_angle/ANGLE_360)*10;
x+=dx;
y+=dy;
}
if (keyboard_state[MAKE_V])
{
sub_view_angle = view_angle - ANGLE_90;
if (sub_view_angle<0)
sub_view_angle+=ANGLE_360;
// move player along view vector backward
dx=cos(6.28*sub_view_angle/ANGLE_360)*10;
dy=sin(6.28*sub_view_angle/ANGLE_360)*10;
x+=dx;
y+=dy;
}
Translate_Player(dx, dy);
} // end if player in motion
if (keyboard_state[MAKE_ESC])
{
done=1;
}
// render the view
// THE FOLLOWING FUNCTION: Ray_Caster(); -has been modified so that
// the actual drawing is done elsewhere, in order to interleave the
// ray casting with the time spent waiting for VGA page flipping to
// take hold!!! Gad Zooks! - IT WORKS!
Ray_Caster();
// Weak_Attempt();
/// CODE THAT NEEDS A BATH!
/////////////////////////////////////////////////////////
Process_Enemy_Events();
if (just_grabbed_something)
{
if (digital_enabled)
{
Sound_Stop();
Sound_Play((sound_ptr)&global_sounds[5]);
}
pat_start = 1;
for (index = 0; index <= 15; index++)
{
Read_Color_Reg(index, (RGB_color_ptr)&color_all);
switch (what_obj)
{
case 4:
{
color_all.green += 32;
if (color_all.green > 63)
color_all.green = 63;
} break;
case 5:
{
color_all.green += 32;
if (color_all.green > 63)
color_all.green = 63;
} break;
case 6:
{
color_all.blue += 32;
if (color_all.blue > 63)
color_all.blue = 63;
} break;
}
Write_Color_Reg(index, (RGB_color_ptr)&color_all);
}
for (index = 16; index <= 80; index++)
{
Read_Color_Reg(index, (RGB_color_ptr)&old_all[index]);
switch (what_obj)
{
case 4:
{
color_all.green = old_all[index].green + 32;
if (color_all.green > 63)
color_all.green = 63;
} break;
case 5:
{
color_all.green = old_all[index].green + 32;
if (color_all.green > 63)
color_all.green = 63;
} break;
case 6:
{
color_all.blue = old_all[index].blue + 32;
if (color_all.blue > 63)
color_all.blue = 63;
} break;
}
Write_Color_Reg(index, (RGB_color_ptr)&color_all);
}
for (index = 81; index <= 255; index++)
{
Read_Color_Reg(index, (RGB_color_ptr)&color_all);
switch (what_obj)
{
case 4:
{
color_all.green += 32;
if (color_all.green > 63)
color_all.green = 63;
} break;
case 5:
{
color_all.green += 32;
if (color_all.green > 63)
color_all.green = 63;
} break;
case 6:
{
color_all.blue += 32;
if (color_all.blue > 63)
color_all.blue = 63;
} break;
}
Write_Color_Reg(index, (RGB_color_ptr)&color_all);
}
}
Begin_Object_List();
Find_Object_Distance();
Sort_Object_List();
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(mode_y_page);
Erase_Scene();
Draw_Walls();
for (index = (Number_Of_Fixed_Objects+Number_Of_Enemies); index >= 0; index--)
{
if (object_list[index].dist < 1000)
{
if ((object_list[index].kind_of_object == 2) ||
(object_list[index].kind_of_object == 3))
{
obj_id = object_list[index].id_number;
if (enemies[object_list[index].id_number].state == DYING)
{
--enemies[object_list[index].id_number].threshold;
if (enemies[object_list[index].id_number].threshold == 0)
enemies[object_list[index].id_number].state = DEAD;
}
obj_threshold = enemies[object_list[index].id_number].threshold;
}
Find_and_Maybe_Plot_Objects(object_list[index],obj_id,obj_threshold);
}
}
if (player_state == PLAYER_FIRING)
{
++the_gun.curr_frame;
if ((the_gun.curr_frame == 4) && (Player_Ammo))
--Player_Ammo;
else
if (the_gun.curr_frame == 4)
++the_gun.curr_frame;
if (the_gun.curr_frame > 7)
{
the_gun.curr_frame = 0;
player_state = PLAYER_NOT_FIRING;
}
}
Sprite_Draw_Clip_Special((sprite_ptr)&the_gun, video_buffer);
new_weapon_statis = Player_Ammo / 4;
if (new_weapon_statis!=old_weapon_statis)
Update_Weapon_Statis_Display(new_weapon_statis);
new_life_statis = Player_Strength / 4;
if (new_life_statis!=old_life_statis)
Update_Life_Statis_Display(new_life_statis);
if (doors[0].door_state != CLOSED && which_map==4 && !beat_it)
{
Make_Gold_Palette();
beat_it = 1;
}
if (doors[0].door_state != CLOSED && which_map==4)
{
sprintf(buffer,"You have not seen the last of me!");
Print_String_Mode_Y(15,15,170,buffer,1);
sprintf(buffer,"hmmm... actually - you haven't");
Print_String_Mode_Y(15,25,170,buffer,1);
sprintf(buffer,"even seen me YET!...oh well...");
Print_String_Mode_Y(15,35,170,buffer,1);
}
if(how_long)
{
Print_String_Mode_Y(15,20,255,where_am_i,1);
--how_long;
}
} //end while
// De-allocate Memory
Sprite_Delete((sprite_ptr)&wall_frames);
Sprite_Delete((sprite_ptr)&duck_frames);
Sprite_Delete((sprite_ptr)&duck_death);
Sprite_Delete((sprite_ptr)&ob_frames);
Sprite_Delete((sprite_ptr)&the_gun);
// free memory associated with lookup tables...
for (index = 0; index < WORLD_ROWS; index++)
{
_ffree(Block_Map[index]);
}
_ffree(tan_table);
_ffree(inv_tan_table);
_ffree(x_step);
_ffree(y_step);
_ffree(cos_table);
_ffree(inv_cos_table);
_ffree(inv_sin_table);
for (scaler=0; scaler<=MAX_SCALE; scaler++)
{
free(scale_table[scaler]);
} // end for scaler
// pot up the lights...
if (at_end)
{
for(index=0; index<20; index++)
{
for(pal_reg=0; pal_reg<=255; pal_reg++)
{
// get the next color to fade
Read_Color_Reg(pal_reg,(RGB_color_ptr)&color_all);
// test if this color register is already at peak intensity
color_all.red += 4;
// test if this color register is already white
if (color_all.red > 63)
color_all.red=63;
color_all.green += 4;
if (color_all.green > 63)
color_all.green=63;
// set the color to a diminshed intensity
Write_Color_Reg(pal_reg,(RGB_color_ptr)&color_all);
} // end for pal reg
// wait a bit
Time_Delay(1);
} // end for index
}
else
{
Screen_Transition(SCREEN_WHITENESS);
}
if (really_at_end)
{
if (music_enabled)
{
Music_Stop();
Music_Play((music_ptr)&song,3);
}
mode_y_page = !mode_y_page;
Wait_Retrace_Mode();
Set_Working_Page_Mode_Y(mode_y_page);
// erase the screen
outp(SEQUENCER,SEQ_PLANE_ENABLE);
outp(SEQUENCER+1,0x0f);
_asm
{
les di,video_buffer // point es:di to video buffer, same addre for mode Z
xor ax,ax // zero out AH and AL
mov cx,320*200/8 // number of words to fill(using word is faster than bytes)
rep stosw // move the color into the video buffer really fast!
} // end inline asm
Load_PCX_and_Page_Flip("winning.pcx",0);
for (index = 0; index <=15; index++)
Write_Color_Reg(index, (RGB_color_ptr)&old_all[index]);
for (index = 16; index <= 60; index++)
{
color_all.red = 0;
color_all.green = 0;
color_all.blue = (index-16);
Write_Color_Reg(index, (RGB_color_ptr)&color_all);
}
for (index = 61; index <=255; index++)
Write_Color_Reg(index, (RGB_color_ptr)&old_all[index]);
keys_active=0;
while(!keys_active){};
Fade_to_Black_and_Paint_Both(FULL_SCREEN_DARKNESS);
}
free(object_list);
free(initial_object_list);
if (digital_enabled)
{
Sound_Stop();
Sound_Unload((sound_ptr)&global_sounds[0]);
Sound_Unload((sound_ptr)&global_sounds[1]);
Sound_Unload((sound_ptr)&global_sounds[2]);
Sound_Unload((sound_ptr)&global_sounds[3]);
Sound_Unload((sound_ptr)&global_sounds[4]);
Sound_Unload((sound_ptr)&global_sounds[5]);
Sound_Unload((sound_ptr)&global_sounds[6]);
}
if (music_enabled)
{
Music_Stop();
Music_Unload((music_ptr)&song);
}
Set_Graphics_Mode(TEXT_MODE);
printf("\nProgramming: James McCue!\n");
printf(" -with the help of the great Andre' Lamothe's BLACK ART OF 3D\n");
printf("GAME PROGRAMMING (Waite Group Press) graphics library - and his WRITINGS!!!\n\n");
printf("Concept: Not much of one - is there? - by James McCue\n");
printf("'Art?': Walls, Enemies and most stuff - James McCue\n");
printf("ART: Doors, and that face, That face, THAT COVER GIRL FACE\n");
printf(" - BY MY BROTHER ROBERT MCCUE\n\n");
printf("If you wish, contact me via e-mail at QBALL1723@AOL.COM\n\n");
printf("This program is completely free, but if you'd wish to contribute to my\n");
printf("game programming cause... please send $5.00 to:\n\n");
printf("James McCue, P.O. Box 151, Bethpage, NY 11714-4831\n\n");
printf("Thank you for playing Slow Runnings!\n\n");
printf("Visit my website: http://members.aol.com/qball1723/index.htm\n\n");
Keyboard_Remove_Driver();
getch();
return(0);
} // end main