/*************************************************************************/
/*** ***/
/*** R A Y (C) 1995 NPS Software ***/
/*** ***/
/*** Writen By: Brad Broerman ***/
/*** Started: June 1994 ***/
/*** Last Modified: July 2, 2000 ***/
/*** Version: 1.5 ***/
/*** ***/
/*** ***/
/*** A 3-D Raycasting graphics engine with up to a 64x64 cell map, ***/
/*** 35 textures (256 color 128x128 PCX files), textured floor and ***/
/*** ceiling, sprites, 3 types of animated doors, 20 levels of ***/
/*** transparency, translucency, animated textures,lighting and ***/
/*** depth cueing (with fog effects), zone maps, and triggers. ***/
/*** ***/
/*** To be added: 2 more door types, door side texturing, door api, ***/
/*** sprite logic api, lighting api, var. height floors, look up/down,***/
/*** animated palette section, main menu, stats updating, ***/
/*** trigger api. ***/
/*** ***/
/*************************************************************************/
/*** Change Log: ***/
/*** ***/
/*** 06/15/94 Started RAY project ***/
/*** 06/30/94 Basic raycaster engine finished. ***/
/*** 07/30/94 Base engine optimized. ***/
/*** 09/10/94 Floor / ceiling texturing added. ***/
/*** 09/15/94 RAY first distributed. ***/
/*** -- 4 years later -- ***/
/*** 09/25/98 Started working on Ray again... ***/
/*** 10/03/98 Added depth cueing/fog effects ***/
/*** 10/06/98 Added garage and elevator door styles ***/
/*** 10/10/98 Fixed doors, now recessed 1/2 way back ***/
/*** 10/14/98 Fixed array overruns ... Thx to Jorge A. Martin ***/
/*** 10/29/98 Added animated textures, translucency, and ***/
/*** recesed tile flags. Combined T & X tiles. ***/
/*** 11/01/98 Finally got it to run in Protected Mode! ***/
/*** 11/10/98 Added tiled light maps. ***/
/*** 12/05/98 Added animated lighting ***/
/*** 01/11/99 Increased PCX file resolution to 128x128 ***/
/*** 02/24/99 Added zone maps and zone options. ***/
/*** 03/11/99 Added Triggers (except 2,3,&10) (see triggers.txt) ***/
/*** Released Ray version 1.5 ***/
/*** 07/02/00 Did windows port of RAY. Added resize capability. ***/
/*** Thanks to Jorge for showin me how to do the Windows ***/
/*** port. ***/
/*** ***/
/*************************************************************************/
#include <windows.h>
#include <time.h>
#include <io.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <memory.h>
#include <malloc.h>
#include <math.h>
#include <string.h>
// Windows defined stuff (from resource.h)
#define IDM_EXIT 100
#define IDB_BITMAP1 101
#define IDC_WINRAY2 104
#define IDM_TEST 200
#define IDM_ABOUT 301
#define IDM_RUN 40001
#define IDM_DISPLAY_320 40002
#define IDM_DISPLAY_640 40003
#define IDM_DISPLAY_960 40004
#define IDM_SHOWKEYS 40005
// If defined, then floor and ceiling are rendered.
#define CAST_FLOORCIEL
// How close you can get to a wall.
#define TOOCLOSE 60
// Size of the viewport.
#define VIEWPORT_WIDTH 240
#define VIEWPORT_HEIGHT 200
// For keyboard handling (in moving player), these query the keyboard in real-time
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
// Our definitions for the angles. ANGLE_60 = width of viewport. (60 deg. FOV)
// All the other angles are based on this.
#define ANGLE_0 0
#define ANGLE_1 4
#define ANGLE_6 24
#define ANGLE_30 120
#define ANGLE_45 180
#define ANGLE_60 240
#define ANGLE_90 360
#define ANGLE_120 480
#define ANGLE_150 600
#define ANGLE_180 720
#define ANGLE_210 840
#define ANGLE_225 900
#define ANGLE_240 960
#define ANGLE_270 1080
#define ANGLE_300 1200
#define ANGLE_330 1320
#define ANGLE_360 1440
// The size of each cell. 128 makes the math easier. (also textures are 128 pixels wide)
#define CELL_X_SIZE 128
#define CELL_Y_SIZE 128
// The maximum size of our world 64x64 cells.
#define MAX_WORLD_ROWS 64
#define MAX_WORLD_COLS 64
// These defines are used for lighting.
#define MAX_LIGHT_LEVELS 128
#define PALETTE_SIZE 256ul
#define MAX_DISTANCE (MAX_WORLD_ROWS * MAX_WORLD_COLS)
// We need a large stack.
extern unsigned _stklen = 20480U;
// The generic PCX header structure. I've listed some important fields, but
// I won't check for them until this code is "officially" released.
typedef struct PCX_HEADER_TYPE
{
char manufacturer; // We don't care about these...
char version;
char encoding;
char bits_per_pixel; // We want an 8 here...
short x,y; // We ignore these.
short width,height; // Will be either 64x64 or 320x200
short horiz_rez; // Forget about these...
short vert_rez;
char EGA_palette[48]; // We won't even touch this.
char reserved;
char Num_Planes; // We want 1
short bytes_per_line; // Either 64 or 320
short palette_type; // We can forget about these too..
char padding[58];
} PCX_HEADER;
// Stores slice information for rendering. This is used so that we can
// add sprites, transparency, etc. and have the rendering engine draw them too.
struct col_obj
{
int top, // Wihch row to begin drawing this slice.
col, // Which screen column this slice is in.
scale, // How much do I scale this slice
row, // Which texture column to render for this slice.
texnum, // The number of the wall/sprite texture to use.
lightnum, // The number of the lighting tile to use. If -1, then use sptlight as the light for the whole sliver.
sptlight, // Flat light value (if used).
zoneambient, // Ambient light for the zone the sliver is in.
usefog; // Use the fog table or the darkness table for the sliver.
long dist; // How far away is it (Used for sorting in sprites and light sourcing.)
};
// This implements the multiple levels of transparency we can use. The
// objecs are ordered from nearest to farthest.
struct scan_line_t
{
col_obj line[10]; // We can go to 10 levels of transparency, sprites, etc.
int num_objs;
};
// This structure is kept for every texture map loaded into the game. It is
// used (mainly) for doors and transparent items.
struct TextureFlagsTYPE
{
char IsTransparent, // 1=transparent, 0=not.
IsTranslucent, // 1=Translucent, 0=not.
IsDoor, // 1= door, 0= regular wall.
DoorType, // 1=normal, 2=elevator, 3=garage
IsSecretDoor, // 1=Secret door, 0=Normal door.
IsRecessed, // 1=Recessed texture(walls), 0=Not recessed
DoorSideTxt, // This holds the texture number for the door sides. (Not used yet.)
CanWalkThru, // 1 = you can walk trough it, 0 = Can not walk through it.
speed, // How fast the door opens and closes. (cols per frame)
delay, // How many frames to wait before closing the door.
bc, // Upper left corner of the door
br,
ec, // Lower right corner of the door
er;
int AnimNbr;
};
// This structure keeps the parameters for the lights, including light type,
// and blink parameters.
struct LightFlagsTYPE
{
char LightType; // Either a 1, or a 2. 1: Regular blink, 2: Custom blink.
int PulseWidth, // For a regular blink, defines the pulse.
Period,
CurrPatternIndx; // counter... see ProcessBlinkLights() for usage.
char *PulsePattern; // For a custom blinking light, this is the pattern: 1 - on, 0= off.
char *OriginalBitmap; // Used to track the original bitmap. see ProcessBlinkLights() for usage.
int AnimNbr;
};
// This structure keeps track of all the doors that are opening and closing
// at any particular time.
struct Open_Doors_Info
{
char USED; // Used in finding an empty spot to use. See the code.
int x, // Map location of the door.
y,
delay, // The door's delay from above.
Orig_Txt_Num, // The texture number of the original (un-opened) door.
New_Txt_Num, // Points to the working copy of the door tex.
Pcnt_opened, // Percent opened.
Num_Col_Opnd, // The number of columns the door is opening.
Opening; // 1=opening, 0=closing.
};
// This structure keeps track of information associated with all doors on the map.
// Work in progress.
struct Door_Info
{
int x, // Map location of the door.
y,
locked, // Can I open it or not? 1 = Locked , 0 = Un-Locked.
opening; // lets up know if the texture is not the original one. (!= 0) --> Don't touch!
};
// This is the basic structure for the sprites.
struct Sprite_Type
{
char *Frames[8]; // Stores the views (angles object can be viewed from)
int translucent; // Specifies wether or not this sprites texture is translucent. (Sprites are always transparent)
};
// Sprite instance variables.
// Work in progrss,
struct object
{
int sprite_num, // The sprite array object we're using.
x, // The sprites position in the map (fine coordiates)
y,
angle, // The angle the sprite is facing.
state; // The sprites state (To be used later)
};
// The struct that holds the player information. (I am keeping this separate from object since I
// plan on changing the two considerably.
struct player_t
{
long x, // The players X position, in fine coordinates.
y, // The players Y position, in fine coordinates.
view_angle; // The angle which the player is facing.
};
// This structure holds information about anumated textures. This includes the
// frames, and counter / timing information.
struct Animations_Typ
{
char **Frames; // Array of pointers to the frames.
int Flagged, // 1=Animate this texture, 0=Show only 1st frame.
Txt_Nbr, // Which texture in the map this applies to.
Delay, // Delay time between frames.
Timer, // Counts the delay for this texture.
Curr_Frame, // The frame we are currently showing.
Nbr_Frames; // The number of frames.
};
// This structure holds information about the various defined zones. These zones
// could be rooms, the outside, etc.
struct zone_info
{
char ambient, // Ambient light level 0-64 for this zone.
inside, // 1=inside, 0=outside (turns on/off ceiling lighting)
fog; // 1=Use fog, 0=use normal depth cueing.
};
// This structure is used to record trigger information.
// Work in progrss...
struct trigger_info
{
int Trigger_Nbr,
Trigger_Type,
Trigger_Area_Type,
X1, Y1,
X2, Y2,
Radius,
MapX,
Mapy,
ZoneNbr,
NewLightLvl,
NewAngle,
TxtNbr;
char NewFileName[13];
};
//
// This enum is used in the window procedure to change the procedures functionality
// based on game state (displaying the title, displaying the menu, or running the game ).
//
enum { SEQ_TITLESCREEN = 1,
SEQ_FADETOGAME,
SEQ_PLAYGAME,
SEQ_FADETOLEVEL,
SEQ_MENUDISPLAY
} GameState_Typ;
// These globals are used for speeding up the tracing and rendering parts.
// These are copied from the col_obj structure above.
long sliver_dist;
int sliver_start, // Where (y) to begin drawing the slice.
sliver_column, // Screen column to draw in.
sliver_scale, // Height of the sliver (pixels).
sliver_row, // Column of the texture to draw.
sliver_map, // Which texture to use.
sliver_light, // Which lighting tile to use.
sliver_sptlt, // Lighting level for sprites.
sliver_zoneamb,// Ambient light delta for the current zone.
sliver_usefog, // If 1, use fog table, else use darkness table.
// These are used in the tracing process. They are global for the same reason as above.
cell_xx, // These store the coordinates for the horiz. trace.
cell_yx, //
cell_xy, // These store the coordinates for the vert. trace.
cell_yy; //
// These are global because they're used all over, and I wanted to generate them ONLY
// at the beginning of the program. It also saves us on stack usage.
// Information needed by the application itself.
HWND ghWnd; // Handle to the main window.
BOOL bIsActive; // Tells us when we should be rendering, and when we should stop.
BOOL bRunGame; // Tells us wether we are running the game or showing the title screen.
HINSTANCE hInst; // current application instance
LPCTSTR lpszAppName = "WinRay2"; // The application and window class name.
LPCTSTR lpszTitle = "WinRay"; // The main window title.
// Pointers to double buffer info and address.
BITMAPINFO *BitMapInfo ;
HBITMAP DblBuff;
unsigned char *double_buffer;
// Vaarious pointers and constants used while rendering the images.
int WORLD_ROWS = 64; // Current size of the map.
int WORLD_COLUMNS = 64;
long WORLD_X_SIZE = 8192; // Total size of the world (64cells x 128 per cell)
long WORLD_Y_SIZE = 8192;
char *AutoMapBkgd;
char *world = NULL; // pointer to matrix of cells that make up world
char *FloorMap = NULL; // pointer to the matrix of cells that define the floor textures.
char *CeilMap = NULL; // pointer to the matrix of cells that define the ceiling textures.
char *ZoneMap = NULL; // pointer to the matrix of calls that define the 'zones' for various effects.
char TriggerMap[64][64]; // Assists in quick detection of simple triggers. Maps location to trigger number.
char *CeilLightMap = NULL; // pointer to the ceiling light map.
char *FloorLightMap = NULL; // pointer to the floor light map.
int Num_Textures = 0; // The number of textures we've loaded.
char *WallTextures[90]; // The 64x64 wall textures, door textures, and visible sprites.
int Num_Light_Tiles = 0; // The number of lighting tiles for the floor/ceiling light maps.
char *LightMapTiles[30]; // The 64x64 lighting map tiles.
char *LightLevel = NULL; // Gives the lighting level as a function of distance.
char *LightMap = NULL; // Maps a color/light pair into a pallete value for depth cueing. 32*256 in size.
char *FogMap = NULL; // Maps a color/light pair into a pallete value for fog effects. 32*256 in size.
char *Translucency = NULL; // Trans. lookup. Blends a color/color pair with 10% color 1, 90% color 2. Gives palette value.
char *BkgBuffer = NULL; // The background picture.
long *tan_table = NULL; // tangent tables used to compute initial
long *inv_tan_table = NULL; // intersections with ray
long *y_step = NULL; // x and y steps, used to find intersections
long *x_step = NULL; // after initial one is found
long *cos_table = NULL; // used to cacell out fishbowl effect
long *sin_table = NULL; // Used for movement in different directions.
long *inv_cos_table = NULL; // used to compute distances by calculating
long *inv_sin_table = NULL; // the hypontenuse
long *sliver_factor = NULL; // Scale factor for texture slivers.
long Floor_Row_Table[151]; // Pre-calculated row start values.
long *Floor_inv_cos_table = NULL; // The following tables are used in the math for the floor/ceiling.
long *Floor_cos_table = NULL;
long *Floor_sin_table = NULL;
long *Floor_Dx_table = NULL;
long row[200]; // Pre-calculates 320*row.
int oldmode; // Original grahics/text mode when the game starts.
char palette[256][3]; // The current palette.
int Num_Sprites = 0; // The number of sprites defined.
int Num_Objects = 0; // The number of objects defined.
int Sprite_Frame[361]; // Determines frame to display for sprites.
int Num_Animations = 0; // The number of animated textures we are using.
int Num_LightAnimations = 0; // The number of animated lighting tiles we are using.
int Num_Triggers = 0; // The number of defined triggers.
short ambient_level = 3; // The global ambient light level.
struct scan_line_t scan_lines[240]; // Stores the scan-line info.
struct TextureFlagsTYPE TextureFlags[81]; // Stores the texture flags for each loaded texture.
struct LightFlagsTYPE LightFlags[30]; // Stores the flags for the lights.
struct Open_Doors_Info Opening_Doors[10]; // Moving door info.
struct zone_info ZoneAttr[20]; // Attributes for the zones. Currently: ambient light, fog, and inside/outside
struct Sprite_Type Sprites[10]; // The sprites. These are the bitmaps.
struct object Objects[30]; // The actual objects that use the sprites.
struct Animations_Typ Animations[10]; // Up to 10 animated textures.
struct Animations_Typ Light_Animations[10]; // Up to 10 animated lighting tiles.
struct trigger_info Triggers[10]; // The loaded triggers.
// The following items are game state information:
char ShowAutomap = 0; // This flag tells if the automap is on or off.
char TorchLevel = 8; // This is the light level the players torch is putting out.
short ClientWidth = 320; // The current screen dimentions.
short ClientHeight = 200; //
short ClientxPos; // The current screen position.
short ClientyPos; //
struct player_t Player_1; // The player.
enum GameState_Typ GameState; // This is a state variable that guides us in the WM_TIMER message.
// This is used for the title animation sequence.
char *FireSrc;
//
// Function Prototypes:
//
// Thses functions are the primitive screen handling functions:
void clearscrn(char c);
void copyscrn (char far *Buffer);
void dissolveto(char far *Buffer);
void blit(void);
// These functions build and maintain the data tables.
void free_tables(void);
int Die(char *string);
int Build_Tables(void);
void CalcTorchLevel(int level);
// These functions handle loading and saving game graohics.
int Save_Pcx(char *filename, unsigned char far *Buffer, unsigned long width, unsigned long height);
char *Load_PCX(char *filename, unsigned long size, int load_pal);
int transpose(char far *Bitmap);
int load_bkgd(char *filename);
int Load_Wall(char *filename,int offset);
int Load_Light_Tile(char *filename,int offset);
char far *Load_Sprite (char *filename);
// This function loads a map file.
unsigned char translateChar(unsigned char ch);
void Clear_Map(void);
int Load_Map(long &initx, long &inity, long &initang, char *MapFileName);
// The following functions render the world...
void draw_sliver_transparent(void);
void draw_sliver_trans(void);
void draw_sliver(void);
int Cast_X_Ray(long x, long y, long view_angle, long &yi_save, long &x_save, int &lighttile, int &zone);
int Cast_Y_Ray(long x, long y, long view_angle, long &xi_save, long &y_save, int &lighttile, int &zone);
void Texture_FloorCeil(long x, long y, long view_angle);
void process_sprites(long x, long y, long view_angle);
void DrawAutomap(long Xpos, long Ypos);
void Render_View(long x,long y,long view_angle);
// The last few functions perform the game logic...
void delay2(long time);
int start_door(int x, int y);
void open_doors();
void close_doors();
void ProcessTrigger(long &x, long &y, long &view_angle, int TriggerNbr);
void CheckTriggers(long &x, long &y, long &view_angle);
int Rotate_Animations(void);
void processblinklights(void);
void ProccessUserMovement( void );
void MainLoop(void);
int InitTitleAnimation (void);
void AnimateFireScreen (void);
int EndTitleAnimation (void);
// And finally, the main process.
int InitEngine(void);
void init_double_buffer(void);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);